1235537Sgber/*- 2235537Sgber * Copyright (c) 2010-2012 Semihalf 3235537Sgber * Copyright (c) 2008, 2009 Reinoud Zandijk 4235537Sgber * All rights reserved. 5235537Sgber * 6235537Sgber * Redistribution and use in source and binary forms, with or without 7235537Sgber * modification, are permitted provided that the following conditions 8235537Sgber * are met: 9235537Sgber * 1. Redistributions of source code must retain the above copyright 10235537Sgber * notice, this list of conditions and the following disclaimer. 11235537Sgber * 2. Redistributions in binary form must reproduce the above copyright 12235537Sgber * notice, this list of conditions and the following disclaimer in the 13235537Sgber * documentation and/or other materials provided with the distribution. 14235537Sgber * 15235537Sgber * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16235537Sgber * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17235537Sgber * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18235537Sgber * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19235537Sgber * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20235537Sgber * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21235537Sgber * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22235537Sgber * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23235537Sgber * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24235537Sgber * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25235537Sgber * 26235537Sgber * From: NetBSD: nilfs_subr.c,v 1.4 2009/07/29 17:06:57 reinoud 27235537Sgber */ 28235537Sgber 29235537Sgber#include <sys/cdefs.h> 30235537Sgber__FBSDID("$FreeBSD$"); 31235537Sgber 32235537Sgber#include <sys/param.h> 33235537Sgber#include <sys/systm.h> 34235537Sgber#include <sys/namei.h> 35235537Sgber#include <sys/resourcevar.h> 36235537Sgber#include <sys/kernel.h> 37235537Sgber#include <sys/file.h> 38235537Sgber#include <sys/stat.h> 39235537Sgber#include <sys/buf.h> 40235537Sgber#include <sys/bio.h> 41235537Sgber#include <sys/proc.h> 42235537Sgber#include <sys/mount.h> 43235537Sgber#include <sys/vnode.h> 44235537Sgber#include <sys/signalvar.h> 45235537Sgber#include <sys/malloc.h> 46235537Sgber#include <sys/dirent.h> 47235537Sgber#include <sys/lockf.h> 48235537Sgber#include <sys/libkern.h> 49235537Sgber 50235537Sgber#include <geom/geom.h> 51235537Sgber#include <geom/geom_vfs.h> 52235537Sgber 53235537Sgber#include <vm/vm.h> 54235537Sgber#include <vm/vm_extern.h> 55235537Sgber 56235537Sgber#include <machine/_inttypes.h> 57235537Sgber#include "nandfs_mount.h" 58235537Sgber#include "nandfs.h" 59235537Sgber#include "nandfs_subr.h" 60235537Sgber 61241844SeadlerMALLOC_DEFINE(M_NANDFSMNT, "nandfs_mount", "NANDFS mount"); 62235537SgberMALLOC_DEFINE(M_NANDFSTEMP, "nandfs_tmt", "NANDFS tmp"); 63235537Sgber 64235537Sgberuma_zone_t nandfs_node_zone; 65235537Sgber 66235537Sgbervoid nandfs_bdflush(struct bufobj *bo, struct buf *bp); 67235537Sgberint nandfs_bufsync(struct bufobj *bo, int waitfor); 68235537Sgber 69235537Sgberstruct buf_ops buf_ops_nandfs = { 70235537Sgber .bop_name = "buf_ops_nandfs", 71235537Sgber .bop_write = bufwrite, 72235537Sgber .bop_strategy = bufstrategy, 73235537Sgber .bop_sync = nandfs_bufsync, 74235537Sgber .bop_bdflush = nandfs_bdflush, 75235537Sgber}; 76235537Sgber 77235537Sgberint 78235537Sgbernandfs_bufsync(struct bufobj *bo, int waitfor) 79235537Sgber{ 80235537Sgber struct vnode *vp; 81235537Sgber int error = 0; 82235537Sgber 83235537Sgber vp = bo->__bo_vnode; 84235537Sgber 85235537Sgber ASSERT_VOP_LOCKED(vp, __func__); 86235537Sgber error = nandfs_sync_file(vp); 87235537Sgber if (error) 88235537Sgber nandfs_warning("%s: cannot flush buffers err:%d\n", 89235537Sgber __func__, error); 90235537Sgber 91235537Sgber return (error); 92235537Sgber} 93235537Sgber 94235537Sgbervoid 95235537Sgbernandfs_bdflush(bo, bp) 96235537Sgber struct bufobj *bo; 97235537Sgber struct buf *bp; 98235537Sgber{ 99235537Sgber struct vnode *vp; 100235537Sgber int error; 101235537Sgber 102235537Sgber if (bo->bo_dirty.bv_cnt <= ((dirtybufthresh * 8) / 10)) 103235537Sgber return; 104235537Sgber 105235537Sgber vp = bp->b_vp; 106235537Sgber if (NANDFS_SYS_NODE(VTON(vp)->nn_ino)) 107235537Sgber return; 108235537Sgber 109235537Sgber if (NANDFS_IS_INDIRECT(bp)) 110235537Sgber return; 111235537Sgber 112235537Sgber error = nandfs_sync_file(vp); 113235537Sgber if (error) 114235537Sgber nandfs_warning("%s: cannot flush buffers err:%d\n", 115235537Sgber __func__, error); 116235537Sgber} 117235537Sgber 118235537Sgberint 119235537Sgbernandfs_init(struct vfsconf *vfsp) 120235537Sgber{ 121235537Sgber 122235537Sgber nandfs_node_zone = uma_zcreate("nandfs node zone", 123235537Sgber sizeof(struct nandfs_node), NULL, NULL, NULL, NULL, 0, 0); 124235537Sgber 125235537Sgber return (0); 126235537Sgber} 127235537Sgber 128235537Sgberint 129235537Sgbernandfs_uninit(struct vfsconf *vfsp) 130235537Sgber{ 131235537Sgber 132235537Sgber uma_zdestroy(nandfs_node_zone); 133235537Sgber return (0); 134235537Sgber} 135235537Sgber 136235537Sgber/* Basic calculators */ 137235537Sgberuint64_t 138235537Sgbernandfs_get_segnum_of_block(struct nandfs_device *nandfsdev, 139235537Sgber nandfs_daddr_t blocknr) 140235537Sgber{ 141235537Sgber uint64_t segnum, blks_per_seg; 142235537Sgber 143235537Sgber MPASS(blocknr >= nandfsdev->nd_fsdata.f_first_data_block); 144235537Sgber 145235537Sgber blks_per_seg = nandfsdev->nd_fsdata.f_blocks_per_segment; 146235537Sgber 147235537Sgber segnum = blocknr / blks_per_seg; 148235537Sgber segnum -= nandfsdev->nd_fsdata.f_first_data_block / blks_per_seg; 149235537Sgber 150235537Sgber DPRINTF(SYNC, ("%s: returning blocknr %jx -> segnum %jx\n", __func__, 151235537Sgber blocknr, segnum)); 152235537Sgber 153235537Sgber return (segnum); 154235537Sgber} 155235537Sgber 156235537Sgbervoid 157235537Sgbernandfs_get_segment_range(struct nandfs_device *nandfsdev, uint64_t segnum, 158235537Sgber uint64_t *seg_start, uint64_t *seg_end) 159235537Sgber{ 160235537Sgber uint64_t blks_per_seg; 161235537Sgber 162235537Sgber blks_per_seg = nandfsdev->nd_fsdata.f_blocks_per_segment; 163235537Sgber *seg_start = nandfsdev->nd_fsdata.f_first_data_block + 164235537Sgber blks_per_seg * segnum; 165235537Sgber if (seg_end != NULL) 166235537Sgber *seg_end = *seg_start + blks_per_seg -1; 167235537Sgber} 168235537Sgber 169235537Sgbervoid nandfs_calc_mdt_consts(struct nandfs_device *nandfsdev, 170235537Sgber struct nandfs_mdt *mdt, int entry_size) 171235537Sgber{ 172235537Sgber uint32_t blocksize = nandfsdev->nd_blocksize; 173235537Sgber 174235537Sgber mdt->entries_per_group = blocksize * 8; 175235537Sgber mdt->entries_per_block = blocksize / entry_size; 176235537Sgber 177235537Sgber mdt->blocks_per_group = 178235537Sgber (mdt->entries_per_group -1) / mdt->entries_per_block + 1 + 1; 179235537Sgber mdt->groups_per_desc_block = 180235537Sgber blocksize / sizeof(struct nandfs_block_group_desc); 181235537Sgber mdt->blocks_per_desc_block = 182235537Sgber mdt->groups_per_desc_block * mdt->blocks_per_group + 1; 183235537Sgber} 184235537Sgber 185235537Sgberint 186235537Sgbernandfs_dev_bread(struct nandfs_device *nandfsdev, nandfs_lbn_t blocknr, 187235537Sgber struct ucred *cred, int flags, struct buf **bpp) 188235537Sgber{ 189235537Sgber int blk2dev = nandfsdev->nd_blocksize / DEV_BSIZE; 190235537Sgber int error; 191235537Sgber 192235537Sgber DPRINTF(BLOCK, ("%s: read from block %jx vp %p\n", __func__, 193235537Sgber blocknr * blk2dev, nandfsdev->nd_devvp)); 194235537Sgber error = bread(nandfsdev->nd_devvp, blocknr * blk2dev, 195235537Sgber nandfsdev->nd_blocksize, NOCRED, bpp); 196235537Sgber if (error) 197235537Sgber nandfs_error("%s: cannot read from device - blk:%jx\n", 198235537Sgber __func__, blocknr); 199235537Sgber return (error); 200235537Sgber} 201235537Sgber 202235537Sgber/* Read on a node */ 203235537Sgberint 204235537Sgbernandfs_bread(struct nandfs_node *node, nandfs_lbn_t blocknr, 205235537Sgber struct ucred *cred, int flags, struct buf **bpp) 206235537Sgber{ 207235537Sgber nandfs_daddr_t vblk; 208235537Sgber int error; 209235537Sgber 210235537Sgber DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node), 211235537Sgber blocknr)); 212235537Sgber 213235537Sgber error = bread(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize, 214235537Sgber cred, bpp); 215235537Sgber 216235537Sgber KASSERT(error == 0, ("%s: vp:%p lbn:%#jx err:%d\n", __func__, 217235537Sgber NTOV(node), blocknr, error)); 218235537Sgber 219235537Sgber if (!nandfs_vblk_get(*bpp) && 220235537Sgber ((*bpp)->b_flags & B_CACHE) && node->nn_ino != NANDFS_DAT_INO) { 221235537Sgber nandfs_bmap_lookup(node, blocknr, &vblk); 222235537Sgber nandfs_vblk_set(*bpp, vblk); 223235537Sgber } 224235537Sgber return (error); 225235537Sgber} 226235537Sgber 227235537Sgberint 228235537Sgbernandfs_bread_meta(struct nandfs_node *node, nandfs_lbn_t blocknr, 229235537Sgber struct ucred *cred, int flags, struct buf **bpp) 230235537Sgber{ 231235537Sgber nandfs_daddr_t vblk; 232235537Sgber int error; 233235537Sgber 234235537Sgber DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node), 235235537Sgber blocknr)); 236235537Sgber 237235537Sgber error = bread(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize, 238235537Sgber cred, bpp); 239235537Sgber 240235537Sgber KASSERT(error == 0, ("%s: vp:%p lbn:%#jx err:%d\n", __func__, 241235537Sgber NTOV(node), blocknr, error)); 242235537Sgber 243235537Sgber if (!nandfs_vblk_get(*bpp) && 244235537Sgber ((*bpp)->b_flags & B_CACHE) && node->nn_ino != NANDFS_DAT_INO) { 245235537Sgber nandfs_bmap_lookup(node, blocknr, &vblk); 246235537Sgber nandfs_vblk_set(*bpp, vblk); 247235537Sgber } 248235537Sgber 249235537Sgber return (error); 250235537Sgber} 251235537Sgber 252235537Sgberint 253235537Sgbernandfs_bdestroy(struct nandfs_node *node, nandfs_daddr_t vblk) 254235537Sgber{ 255235537Sgber int error; 256235537Sgber 257235537Sgber if (!NANDFS_SYS_NODE(node->nn_ino)) 258235537Sgber NANDFS_WRITEASSERT(node->nn_nandfsdev); 259235537Sgber 260235537Sgber error = nandfs_vblock_end(node->nn_nandfsdev, vblk); 261235537Sgber if (error) { 262235537Sgber nandfs_error("%s: ending vblk: %jx failed\n", 263235537Sgber __func__, (uintmax_t)vblk); 264235537Sgber return (error); 265235537Sgber } 266235537Sgber node->nn_inode.i_blocks--; 267235537Sgber 268235537Sgber return (0); 269235537Sgber} 270235537Sgber 271235537Sgberint 272235537Sgbernandfs_bcreate(struct nandfs_node *node, nandfs_lbn_t blocknr, 273235537Sgber struct ucred *cred, int flags, struct buf **bpp) 274235537Sgber{ 275235537Sgber int error; 276235537Sgber 277235537Sgber ASSERT_VOP_LOCKED(NTOV(node), __func__); 278235537Sgber if (!NANDFS_SYS_NODE(node->nn_ino)) 279235537Sgber NANDFS_WRITEASSERT(node->nn_nandfsdev); 280235537Sgber 281235537Sgber DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node), 282235537Sgber blocknr)); 283235537Sgber 284235537Sgber *bpp = getblk(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize, 285235537Sgber 0, 0, 0); 286235537Sgber 287235537Sgber KASSERT((*bpp), ("%s: vp:%p lbn:%#jx\n", __func__, 288235537Sgber NTOV(node), blocknr)); 289235537Sgber 290235537Sgber if (*bpp) { 291235537Sgber vfs_bio_clrbuf(*bpp); 292235537Sgber (*bpp)->b_blkno = ~(0); /* To avoid VOP_BMAP in bdwrite */ 293235537Sgber error = nandfs_bmap_insert_block(node, blocknr, *bpp); 294235537Sgber if (error) { 295235537Sgber nandfs_warning("%s: failed bmap insert node:%p" 296235537Sgber " blk:%jx\n", __func__, node, blocknr); 297235537Sgber brelse(*bpp); 298235537Sgber return (error); 299235537Sgber } 300235537Sgber node->nn_inode.i_blocks++; 301235537Sgber 302235537Sgber return (0); 303235537Sgber } 304235537Sgber 305235537Sgber return (-1); 306235537Sgber} 307235537Sgber 308235537Sgberint 309235537Sgbernandfs_bcreate_meta(struct nandfs_node *node, nandfs_lbn_t blocknr, 310235537Sgber struct ucred *cred, int flags, struct buf **bpp) 311235537Sgber{ 312235537Sgber struct nandfs_device *fsdev; 313235537Sgber nandfs_daddr_t vblk; 314235537Sgber int error; 315235537Sgber 316235537Sgber ASSERT_VOP_LOCKED(NTOV(node), __func__); 317235537Sgber NANDFS_WRITEASSERT(node->nn_nandfsdev); 318235537Sgber 319235537Sgber DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node), 320235537Sgber blocknr)); 321235537Sgber 322235537Sgber fsdev = node->nn_nandfsdev; 323235537Sgber 324235537Sgber *bpp = getblk(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize, 325235537Sgber 0, 0, 0); 326235537Sgber 327235537Sgber KASSERT((*bpp), ("%s: vp:%p lbn:%#jx\n", __func__, 328235537Sgber NTOV(node), blocknr)); 329235537Sgber 330235537Sgber memset((*bpp)->b_data, 0, fsdev->nd_blocksize); 331235537Sgber 332235537Sgber vfs_bio_clrbuf(*bpp); 333235537Sgber (*bpp)->b_blkno = ~(0); /* To avoid VOP_BMAP in bdwrite */ 334235537Sgber 335235537Sgber nandfs_buf_set(*bpp, NANDFS_VBLK_ASSIGNED); 336235537Sgber 337235537Sgber if (node->nn_ino != NANDFS_DAT_INO) { 338235537Sgber error = nandfs_vblock_alloc(fsdev, &vblk); 339235537Sgber if (error) { 340235537Sgber nandfs_buf_clear(*bpp, NANDFS_VBLK_ASSIGNED); 341235537Sgber brelse(*bpp); 342235537Sgber return (error); 343235537Sgber } 344235537Sgber } else 345235537Sgber vblk = fsdev->nd_fakevblk++; 346235537Sgber 347235537Sgber nandfs_vblk_set(*bpp, vblk); 348235537Sgber 349235537Sgber nandfs_bmap_insert_block(node, blocknr, *bpp); 350235537Sgber return (0); 351235537Sgber} 352235537Sgber 353235537Sgber/* Translate index to a file block number and an entry */ 354235537Sgbervoid 355235537Sgbernandfs_mdt_trans(struct nandfs_mdt *mdt, uint64_t index, 356235537Sgber nandfs_lbn_t *blocknr, uint32_t *entry_in_block) 357235537Sgber{ 358235537Sgber uint64_t blknr; 359235537Sgber uint64_t group, group_offset, blocknr_in_group; 360235537Sgber uint64_t desc_block, desc_offset; 361235537Sgber 362235537Sgber /* Calculate our offset in the file */ 363235537Sgber group = index / mdt->entries_per_group; 364235537Sgber group_offset = index % mdt->entries_per_group; 365235537Sgber desc_block = group / mdt->groups_per_desc_block; 366235537Sgber desc_offset = group % mdt->groups_per_desc_block; 367235537Sgber blocknr_in_group = group_offset / mdt->entries_per_block; 368235537Sgber 369235537Sgber /* To descgroup offset */ 370235537Sgber blknr = 1 + desc_block * mdt->blocks_per_desc_block; 371235537Sgber 372235537Sgber /* To group offset */ 373235537Sgber blknr += desc_offset * mdt->blocks_per_group; 374235537Sgber 375235537Sgber /* To actual file block */ 376235537Sgber blknr += 1 + blocknr_in_group; 377235537Sgber 378235537Sgber *blocknr = blknr; 379235537Sgber *entry_in_block = group_offset % mdt->entries_per_block; 380235537Sgber} 381235537Sgber 382235537Sgbervoid 383235537Sgbernandfs_mdt_trans_blk(struct nandfs_mdt *mdt, uint64_t index, 384235537Sgber uint64_t *desc, uint64_t *bitmap, nandfs_lbn_t *blocknr, 385235537Sgber uint32_t *entry_in_block) 386235537Sgber{ 387235537Sgber uint64_t blknr; 388235537Sgber uint64_t group, group_offset, blocknr_in_group; 389235537Sgber uint64_t desc_block, desc_offset; 390235537Sgber 391235537Sgber /* Calculate our offset in the file */ 392235537Sgber group = index / mdt->entries_per_group; 393235537Sgber group_offset = index % mdt->entries_per_group; 394235537Sgber desc_block = group / mdt->groups_per_desc_block; 395235537Sgber desc_offset = group % mdt->groups_per_desc_block; 396235537Sgber blocknr_in_group = group_offset / mdt->entries_per_block; 397235537Sgber 398235537Sgber /* To descgroup offset */ 399235537Sgber *desc = desc_block * mdt->blocks_per_desc_block; 400235537Sgber blknr = 1 + desc_block * mdt->blocks_per_desc_block; 401235537Sgber 402235537Sgber /* To group offset */ 403235537Sgber blknr += desc_offset * mdt->blocks_per_group; 404235537Sgber *bitmap = blknr; 405235537Sgber 406235537Sgber /* To actual file block */ 407235537Sgber blknr += 1 + blocknr_in_group; 408235537Sgber 409235537Sgber *blocknr = blknr; 410235537Sgber *entry_in_block = group_offset % mdt->entries_per_block; 411235537Sgber 412235537Sgber DPRINTF(ALLOC, 413235537Sgber ("%s: desc_buf: %jx bitmap_buf: %jx entry_buf: %jx entry: %x\n", 414235537Sgber __func__, (uintmax_t)*desc, (uintmax_t)*bitmap, 415235537Sgber (uintmax_t)*blocknr, *entry_in_block)); 416235537Sgber} 417235537Sgber 418235537Sgberint 419235537Sgbernandfs_vtop(struct nandfs_node *node, nandfs_daddr_t vblocknr, 420235537Sgber nandfs_daddr_t *pblocknr) 421235537Sgber{ 422235537Sgber struct nandfs_node *dat_node; 423235537Sgber struct nandfs_dat_entry *entry; 424235537Sgber struct buf *bp; 425235537Sgber nandfs_lbn_t ldatblknr; 426235537Sgber uint32_t entry_in_block; 427235537Sgber int locked, error; 428235537Sgber 429235537Sgber if (node->nn_ino == NANDFS_DAT_INO || node->nn_ino == NANDFS_GC_INO) { 430235537Sgber *pblocknr = vblocknr; 431235537Sgber return (0); 432235537Sgber } 433235537Sgber 434235537Sgber /* only translate valid vblocknrs */ 435235537Sgber if (vblocknr == 0) 436235537Sgber return (0); 437235537Sgber 438235537Sgber dat_node = node->nn_nandfsdev->nd_dat_node; 439235537Sgber nandfs_mdt_trans(&node->nn_nandfsdev->nd_dat_mdt, vblocknr, &ldatblknr, 440235537Sgber &entry_in_block); 441235537Sgber 442235537Sgber locked = NANDFS_VOP_ISLOCKED(NTOV(dat_node)); 443235537Sgber if (!locked) 444235537Sgber VOP_LOCK(NTOV(dat_node), LK_SHARED); 445235537Sgber error = nandfs_bread(dat_node, ldatblknr, NOCRED, 0, &bp); 446235537Sgber if (error) { 447235537Sgber DPRINTF(TRANSLATE, ("vtop: can't read in DAT block %#jx!\n", 448235537Sgber (uintmax_t)ldatblknr)); 449235537Sgber brelse(bp); 450235537Sgber VOP_UNLOCK(NTOV(dat_node), 0); 451235537Sgber return (error); 452235537Sgber } 453235537Sgber 454235537Sgber /* Get our translation */ 455235537Sgber entry = ((struct nandfs_dat_entry *) bp->b_data) + entry_in_block; 456235537Sgber DPRINTF(TRANSLATE, ("\tentry %p data %p entry_in_block %x\n", 457235537Sgber entry, bp->b_data, entry_in_block)) 458235537Sgber DPRINTF(TRANSLATE, ("\tvblk %#jx -> %#jx for cp [%#jx-%#jx]\n", 459235537Sgber (uintmax_t)vblocknr, (uintmax_t)entry->de_blocknr, 460235537Sgber (uintmax_t)entry->de_start, (uintmax_t)entry->de_end)); 461235537Sgber 462235537Sgber *pblocknr = entry->de_blocknr; 463235537Sgber brelse(bp); 464235537Sgber if (!locked) 465235537Sgber VOP_UNLOCK(NTOV(dat_node), 0); 466235537Sgber 467235537Sgber MPASS(*pblocknr >= node->nn_nandfsdev->nd_fsdata.f_first_data_block || 468235537Sgber *pblocknr == 0); 469235537Sgber 470235537Sgber return (0); 471235537Sgber} 472235537Sgber 473235537Sgberint 474235537Sgbernandfs_segsum_valid(struct nandfs_segment_summary *segsum) 475235537Sgber{ 476235537Sgber 477235537Sgber return (segsum->ss_magic == NANDFS_SEGSUM_MAGIC); 478235537Sgber} 479235537Sgber 480235537Sgberint 481235537Sgbernandfs_load_segsum(struct nandfs_device *fsdev, nandfs_daddr_t blocknr, 482235537Sgber struct nandfs_segment_summary *segsum) 483235537Sgber{ 484235537Sgber struct buf *bp; 485235537Sgber int error; 486235537Sgber 487235537Sgber DPRINTF(VOLUMES, ("nandfs: try segsum at block %jx\n", 488235537Sgber (uintmax_t)blocknr)); 489235537Sgber 490235537Sgber error = nandfs_dev_bread(fsdev, blocknr, NOCRED, 0, &bp); 491235537Sgber if (error) 492235537Sgber return (error); 493235537Sgber 494235537Sgber memcpy(segsum, bp->b_data, sizeof(struct nandfs_segment_summary)); 495235537Sgber brelse(bp); 496235537Sgber 497235537Sgber if (!nandfs_segsum_valid(segsum)) { 498235537Sgber DPRINTF(VOLUMES, ("%s: bad magic pseg:%jx\n", __func__, 499235537Sgber blocknr)); 500235537Sgber return (EINVAL); 501235537Sgber } 502235537Sgber 503235537Sgber return (error); 504235537Sgber} 505235537Sgber 506235537Sgberstatic int 507235537Sgbernandfs_load_super_root(struct nandfs_device *nandfsdev, 508235537Sgber struct nandfs_segment_summary *segsum, uint64_t pseg) 509235537Sgber{ 510235537Sgber struct nandfs_super_root super_root; 511235537Sgber struct buf *bp; 512235537Sgber uint64_t blocknr; 513235537Sgber uint32_t super_root_crc, comp_crc; 514235537Sgber int off, error; 515235537Sgber 516235537Sgber /* Check if there is a superroot */ 517235537Sgber if ((segsum->ss_flags & NANDFS_SS_SR) == 0) { 518235537Sgber DPRINTF(VOLUMES, ("%s: no super root in pseg:%jx\n", __func__, 519235537Sgber pseg)); 520235537Sgber return (ENOENT); 521235537Sgber } 522235537Sgber 523235537Sgber /* Get our super root, located at the end of the pseg */ 524235537Sgber blocknr = pseg + segsum->ss_nblocks - 1; 525235537Sgber DPRINTF(VOLUMES, ("%s: try at %#jx\n", __func__, (uintmax_t)blocknr)); 526235537Sgber 527235537Sgber error = nandfs_dev_bread(nandfsdev, blocknr, NOCRED, 0, &bp); 528235537Sgber if (error) 529235537Sgber return (error); 530235537Sgber 531235537Sgber memcpy(&super_root, bp->b_data, sizeof(struct nandfs_super_root)); 532235537Sgber brelse(bp); 533235537Sgber 534235537Sgber /* Check super root CRC */ 535235537Sgber super_root_crc = super_root.sr_sum; 536235537Sgber off = sizeof(super_root.sr_sum); 537235537Sgber comp_crc = crc32((uint8_t *)&super_root + off, 538235537Sgber NANDFS_SR_BYTES - off); 539235537Sgber 540235537Sgber if (super_root_crc != comp_crc) { 541235537Sgber DPRINTF(VOLUMES, ("%s: invalid crc:%#x [expect:%#x]\n", 542235537Sgber __func__, super_root_crc, comp_crc)); 543235537Sgber return (EINVAL); 544235537Sgber } 545235537Sgber 546235537Sgber nandfsdev->nd_super_root = super_root; 547235537Sgber DPRINTF(VOLUMES, ("%s: got valid superroot\n", __func__)); 548235537Sgber 549235537Sgber return (0); 550235537Sgber} 551235537Sgber 552235537Sgber/* 553235537Sgber * Search for the last super root recorded. 554235537Sgber */ 555235537Sgberint 556235537Sgbernandfs_search_super_root(struct nandfs_device *nandfsdev) 557235537Sgber{ 558235537Sgber struct nandfs_super_block *super; 559235537Sgber struct nandfs_segment_summary segsum; 560235537Sgber uint64_t seg_start, seg_end, cno, seq, create, pseg; 561235537Sgber uint64_t segnum; 562235537Sgber int error, found; 563235537Sgber 564235537Sgber error = found = 0; 565235537Sgber 566235537Sgber /* Search for last super root */ 567235537Sgber pseg = nandfsdev->nd_super.s_last_pseg; 568235537Sgber segnum = nandfs_get_segnum_of_block(nandfsdev, pseg); 569235537Sgber 570235537Sgber cno = nandfsdev->nd_super.s_last_cno; 571235537Sgber create = seq = 0; 572235537Sgber DPRINTF(VOLUMES, ("%s: start in pseg %#jx\n", __func__, 573235537Sgber (uintmax_t)pseg)); 574235537Sgber 575235537Sgber for (;;) { 576235537Sgber error = nandfs_load_segsum(nandfsdev, pseg, &segsum); 577235537Sgber if (error) 578235537Sgber break; 579235537Sgber 580235537Sgber if (segsum.ss_seq < seq || segsum.ss_create < create) 581235537Sgber break; 582235537Sgber 583235537Sgber /* Try to load super root */ 584235537Sgber if (segsum.ss_flags & NANDFS_SS_SR) { 585235537Sgber error = nandfs_load_super_root(nandfsdev, &segsum, pseg); 586235537Sgber if (error) 587235537Sgber break; /* confused */ 588235537Sgber found = 1; 589235537Sgber 590235537Sgber super = &nandfsdev->nd_super; 591235537Sgber nandfsdev->nd_last_segsum = segsum; 592235537Sgber super->s_last_pseg = pseg; 593235537Sgber super->s_last_cno = cno++; 594235537Sgber super->s_last_seq = segsum.ss_seq; 595235537Sgber super->s_state = NANDFS_VALID_FS; 596235537Sgber seq = segsum.ss_seq; 597235537Sgber create = segsum.ss_create; 598235537Sgber } else { 599235537Sgber seq = segsum.ss_seq; 600235537Sgber create = segsum.ss_create; 601235537Sgber } 602235537Sgber 603235537Sgber /* Calculate next partial segment location */ 604235537Sgber pseg += segsum.ss_nblocks; 605235537Sgber DPRINTF(VOLUMES, ("%s: next partial seg is %jx\n", __func__, 606235537Sgber (uintmax_t)pseg)); 607235537Sgber 608235537Sgber /* Did we reach the end of the segment? if so, go to the next */ 609235537Sgber nandfs_get_segment_range(nandfsdev, segnum, &seg_start, 610235537Sgber &seg_end); 611235537Sgber if (pseg >= seg_end) { 612235537Sgber pseg = segsum.ss_next; 613235537Sgber DPRINTF(VOLUMES, 614235537Sgber (" partial seg oor next is %jx[%jx - %jx]\n", 615235537Sgber (uintmax_t)pseg, (uintmax_t)seg_start, 616235537Sgber (uintmax_t)seg_end)); 617235537Sgber } 618235537Sgber segnum = nandfs_get_segnum_of_block(nandfsdev, pseg); 619235537Sgber } 620235537Sgber 621235537Sgber if (error && !found) 622235537Sgber return (error); 623235537Sgber 624235537Sgber return (0); 625235537Sgber} 626235537Sgber 627235537Sgberint 628235537Sgbernandfs_get_node_raw(struct nandfs_device *nandfsdev, struct nandfsmount *nmp, 629235537Sgber uint64_t ino, struct nandfs_inode *inode, struct nandfs_node **nodep) 630235537Sgber{ 631235537Sgber struct nandfs_node *node; 632235537Sgber struct vnode *nvp; 633235537Sgber struct mount *mp; 634235537Sgber int error; 635235537Sgber 636235537Sgber *nodep = NULL; 637235537Sgber 638235537Sgber /* Associate with mountpoint if present */ 639235537Sgber if (nmp) { 640235537Sgber mp = nmp->nm_vfs_mountp; 641235537Sgber error = getnewvnode("nandfs", mp, &nandfs_vnodeops, &nvp); 642269420Simp if (error) 643235537Sgber return (error); 644235537Sgber } else { 645235537Sgber mp = NULL; 646235537Sgber error = getnewvnode("snandfs", mp, &nandfs_system_vnodeops, 647235537Sgber &nvp); 648269420Simp if (error) 649235537Sgber return (error); 650235537Sgber } 651235537Sgber 652235537Sgber if (mp) 653235537Sgber NANDFS_WRITELOCK(nandfsdev); 654235537Sgber 655235537Sgber DPRINTF(IFILE, ("%s: ino: %#jx -> vp: %p\n", 656235537Sgber __func__, (uintmax_t)ino, nvp)); 657235537Sgber /* Lock node */ 658235537Sgber lockmgr(nvp->v_vnlock, LK_EXCLUSIVE, NULL); 659235537Sgber 660235537Sgber if (mp) { 661235537Sgber error = insmntque(nvp, mp); 662235537Sgber if (error != 0) { 663235537Sgber *nodep = NULL; 664235537Sgber return (error); 665235537Sgber } 666235537Sgber } 667235537Sgber 668235537Sgber node = uma_zalloc(nandfs_node_zone, M_WAITOK | M_ZERO); 669235537Sgber 670235537Sgber /* Crosslink */ 671235537Sgber node->nn_vnode = nvp; 672235537Sgber nvp->v_bufobj.bo_ops = &buf_ops_nandfs; 673235537Sgber node->nn_nmp = nmp; 674235537Sgber node->nn_nandfsdev = nandfsdev; 675235537Sgber nvp->v_data = node; 676235537Sgber 677235537Sgber /* Initiase NANDFS node */ 678235537Sgber node->nn_ino = ino; 679235537Sgber if (inode != NULL) 680235537Sgber node->nn_inode = *inode; 681235537Sgber 682235537Sgber nandfs_vinit(nvp, ino); 683235537Sgber 684235537Sgber /* Return node */ 685235537Sgber *nodep = node; 686235537Sgber DPRINTF(IFILE, ("%s: ino:%#jx vp:%p node:%p\n", 687235537Sgber __func__, (uintmax_t)ino, nvp, *nodep)); 688235537Sgber 689235537Sgber return (0); 690235537Sgber} 691235537Sgber 692235537Sgberint 693235537Sgbernandfs_get_node(struct nandfsmount *nmp, uint64_t ino, 694235537Sgber struct nandfs_node **nodep) 695235537Sgber{ 696235537Sgber struct nandfs_device *nandfsdev; 697235537Sgber struct nandfs_inode inode, *entry; 698235537Sgber struct vnode *nvp, *vpp; 699235537Sgber struct thread *td; 700235537Sgber struct buf *bp; 701235537Sgber uint64_t ivblocknr; 702235537Sgber uint32_t entry_in_block; 703235537Sgber int error; 704235537Sgber 705235537Sgber /* Look up node in hash table */ 706235537Sgber td = curthread; 707235537Sgber *nodep = NULL; 708235537Sgber 709235537Sgber if ((ino < NANDFS_ATIME_INO) && (ino != NANDFS_ROOT_INO)) { 710235537Sgber printf("nandfs_get_node: system ino %"PRIu64" not in mount " 711235537Sgber "point!\n", ino); 712235537Sgber return (ENOENT); 713235537Sgber } 714235537Sgber 715235537Sgber error = vfs_hash_get(nmp->nm_vfs_mountp, ino, LK_EXCLUSIVE, td, &nvp, 716235537Sgber NULL, NULL); 717235537Sgber if (error) 718235537Sgber return (error); 719235537Sgber 720235537Sgber if (nvp != NULL) { 721235537Sgber *nodep = (struct nandfs_node *)nvp->v_data; 722235537Sgber return (0); 723235537Sgber } 724235537Sgber 725235537Sgber /* Look up inode structure in mountpoints ifile */ 726235537Sgber nandfsdev = nmp->nm_nandfsdev; 727235537Sgber nandfs_mdt_trans(&nandfsdev->nd_ifile_mdt, ino, &ivblocknr, 728235537Sgber &entry_in_block); 729235537Sgber 730235537Sgber VOP_LOCK(NTOV(nmp->nm_ifile_node), LK_SHARED); 731235537Sgber error = nandfs_bread(nmp->nm_ifile_node, ivblocknr, NOCRED, 0, &bp); 732235537Sgber if (error) { 733235537Sgber brelse(bp); 734235537Sgber VOP_UNLOCK(NTOV(nmp->nm_ifile_node), 0); 735235537Sgber return (ENOENT); 736235537Sgber } 737235537Sgber 738235537Sgber /* Get inode entry */ 739235537Sgber entry = (struct nandfs_inode *) bp->b_data + entry_in_block; 740235537Sgber memcpy(&inode, entry, sizeof(struct nandfs_inode)); 741235537Sgber brelse(bp); 742235537Sgber VOP_UNLOCK(NTOV(nmp->nm_ifile_node), 0); 743235537Sgber 744235537Sgber /* Get node */ 745235537Sgber error = nandfs_get_node_raw(nmp->nm_nandfsdev, nmp, ino, &inode, nodep); 746235537Sgber if (error) { 747235537Sgber *nodep = NULL; 748235537Sgber return (error); 749235537Sgber } 750235537Sgber 751235537Sgber nvp = (*nodep)->nn_vnode; 752235537Sgber error = vfs_hash_insert(nvp, ino, 0, td, &vpp, NULL, NULL); 753235537Sgber if (error) { 754235537Sgber *nodep = NULL; 755235537Sgber return (error); 756235537Sgber } 757235537Sgber 758235537Sgber return (error); 759235537Sgber} 760235537Sgber 761235537Sgbervoid 762235537Sgbernandfs_dispose_node(struct nandfs_node **nodep) 763235537Sgber{ 764235537Sgber struct nandfs_node *node; 765235537Sgber struct vnode *vp; 766235537Sgber 767235537Sgber /* Protect against rogue values */ 768235537Sgber node = *nodep; 769235537Sgber if (!node) { 770235537Sgber return; 771235537Sgber } 772235537Sgber DPRINTF(NODE, ("nandfs_dispose_node: %p\n", *nodep)); 773235537Sgber 774235537Sgber vp = NTOV(node); 775235537Sgber vp->v_data = NULL; 776235537Sgber 777235537Sgber /* Free our associated memory */ 778235537Sgber uma_zfree(nandfs_node_zone, node); 779235537Sgber 780235537Sgber *nodep = NULL; 781235537Sgber} 782235537Sgber 783235537Sgberint 784235537Sgbernandfs_lookup_name_in_dir(struct vnode *dvp, const char *name, int namelen, 785235537Sgber uint64_t *ino, int *found, uint64_t *off) 786235537Sgber{ 787235537Sgber struct nandfs_node *dir_node = VTON(dvp); 788235537Sgber struct nandfs_dir_entry *ndirent; 789235537Sgber struct buf *bp; 790235537Sgber uint64_t file_size, diroffset, blkoff; 791235537Sgber uint64_t blocknr; 792235537Sgber uint32_t blocksize = dir_node->nn_nandfsdev->nd_blocksize; 793235537Sgber uint8_t *pos, name_len; 794235537Sgber int error; 795235537Sgber 796235537Sgber *found = 0; 797235537Sgber 798235537Sgber DPRINTF(VNCALL, ("%s: %s file\n", __func__, name)); 799235537Sgber if (dvp->v_type != VDIR) { 800235537Sgber return (ENOTDIR); 801235537Sgber } 802235537Sgber 803235537Sgber /* Get directory filesize */ 804235537Sgber file_size = dir_node->nn_inode.i_size; 805235537Sgber 806235537Sgber /* Walk the directory */ 807235537Sgber diroffset = 0; 808235537Sgber blocknr = 0; 809235537Sgber blkoff = 0; 810235537Sgber error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp); 811235537Sgber if (error) { 812235537Sgber brelse(bp); 813235537Sgber return (EIO); 814235537Sgber } 815235537Sgber 816235537Sgber while (diroffset < file_size) { 817235537Sgber if (blkoff >= blocksize) { 818235537Sgber blkoff = 0; blocknr++; 819235537Sgber brelse(bp); 820235537Sgber error = nandfs_bread(dir_node, blocknr, NOCRED, 0, 821235537Sgber &bp); 822235537Sgber if (error) { 823235537Sgber brelse(bp); 824235537Sgber return (EIO); 825235537Sgber } 826235537Sgber } 827235537Sgber 828235537Sgber /* Read in one dirent */ 829235537Sgber pos = (uint8_t *) bp->b_data + blkoff; 830235537Sgber ndirent = (struct nandfs_dir_entry *) pos; 831235537Sgber name_len = ndirent->name_len; 832235537Sgber 833235537Sgber if ((name_len == namelen) && 834235537Sgber (strncmp(name, ndirent->name, name_len) == 0) && 835235537Sgber (ndirent->inode != 0)) { 836235537Sgber *ino = ndirent->inode; 837235537Sgber *off = diroffset; 838235537Sgber DPRINTF(LOOKUP, ("found `%.*s` with ino %"PRIx64"\n", 839235537Sgber name_len, ndirent->name, *ino)); 840235537Sgber *found = 1; 841235537Sgber break; 842235537Sgber } 843235537Sgber 844235537Sgber /* Advance */ 845235537Sgber diroffset += ndirent->rec_len; 846235537Sgber blkoff += ndirent->rec_len; 847235537Sgber } 848235537Sgber brelse(bp); 849235537Sgber 850235537Sgber return (error); 851235537Sgber} 852235537Sgber 853235537Sgberint 854235537Sgbernandfs_get_fsinfo(struct nandfsmount *nmp, struct nandfs_fsinfo *fsinfo) 855235537Sgber{ 856235537Sgber struct nandfs_device *fsdev; 857235537Sgber 858235537Sgber fsdev = nmp->nm_nandfsdev; 859235537Sgber 860235537Sgber memcpy(&fsinfo->fs_fsdata, &fsdev->nd_fsdata, sizeof(fsdev->nd_fsdata)); 861235537Sgber memcpy(&fsinfo->fs_super, &fsdev->nd_super, sizeof(fsdev->nd_super)); 862235537Sgber snprintf(fsinfo->fs_dev, sizeof(fsinfo->fs_dev), 863235537Sgber "%s", nmp->nm_vfs_mountp->mnt_stat.f_mntfromname); 864235537Sgber 865235537Sgber return (0); 866235537Sgber} 867235537Sgber 868235537Sgbervoid 869235537Sgbernandfs_inode_init(struct nandfs_inode *inode, uint16_t mode) 870235537Sgber{ 871235537Sgber struct timespec ts; 872235537Sgber 873235537Sgber vfs_timestamp(&ts); 874235537Sgber 875235537Sgber inode->i_blocks = 0; 876235537Sgber inode->i_size = 0; 877235537Sgber inode->i_ctime = ts.tv_sec; 878235537Sgber inode->i_ctime_nsec = ts.tv_nsec; 879235537Sgber inode->i_mtime = ts.tv_sec; 880235537Sgber inode->i_mtime_nsec = ts.tv_nsec; 881235537Sgber inode->i_mode = mode; 882235537Sgber inode->i_links_count = 1; 883235537Sgber if (S_ISDIR(mode)) 884235537Sgber inode->i_links_count = 2; 885235537Sgber inode->i_flags = 0; 886235537Sgber 887235537Sgber inode->i_special = 0; 888235537Sgber memset(inode->i_db, 0, sizeof(inode->i_db)); 889235537Sgber memset(inode->i_ib, 0, sizeof(inode->i_ib)); 890235537Sgber} 891235537Sgber 892235537Sgbervoid 893235537Sgbernandfs_inode_destroy(struct nandfs_inode *inode) 894235537Sgber{ 895235537Sgber 896235537Sgber MPASS(inode->i_blocks == 0); 897235537Sgber bzero(inode, sizeof(*inode)); 898235537Sgber} 899235537Sgber 900235537Sgberint 901235537Sgbernandfs_fs_full(struct nandfs_device *nffsdev) 902235537Sgber{ 903235537Sgber uint64_t space, bps; 904235537Sgber 905235537Sgber bps = nffsdev->nd_fsdata.f_blocks_per_segment; 906235537Sgber space = (nffsdev->nd_clean_segs - 1) * bps; 907235537Sgber 908235537Sgber DPRINTF(BUF, ("%s: bufs:%jx space:%jx\n", __func__, 909235537Sgber (uintmax_t)nffsdev->nd_dirty_bufs, (uintmax_t)space)); 910235537Sgber 911264657Simp if (nffsdev->nd_dirty_bufs + (nffsdev->nd_segs_reserved * bps) >= space) 912235537Sgber return (1); 913235537Sgber 914235537Sgber return (0); 915235537Sgber} 916235537Sgber 917235537Sgberstatic int 918235537Sgber_nandfs_dirty_buf(struct buf *bp, int dirty_meta, int force) 919235537Sgber{ 920235537Sgber struct nandfs_device *nffsdev; 921235537Sgber struct nandfs_node *node; 922235537Sgber uint64_t ino, bps; 923235537Sgber 924235537Sgber if (NANDFS_ISGATHERED(bp)) { 925235537Sgber bqrelse(bp); 926235537Sgber return (0); 927235537Sgber } 928235537Sgber if ((bp->b_flags & (B_MANAGED | B_DELWRI)) == (B_MANAGED | B_DELWRI)) { 929235537Sgber bqrelse(bp); 930235537Sgber return (0); 931235537Sgber } 932235537Sgber 933235537Sgber node = VTON(bp->b_vp); 934235537Sgber nffsdev = node->nn_nandfsdev; 935235537Sgber DPRINTF(BUF, ("%s: buf:%p\n", __func__, bp)); 936235537Sgber ino = node->nn_ino; 937235537Sgber 938235537Sgber if (nandfs_fs_full(nffsdev) && !NANDFS_SYS_NODE(ino) && !force) { 939235537Sgber brelse(bp); 940235537Sgber return (ENOSPC); 941235537Sgber } 942235537Sgber 943235537Sgber bp->b_flags |= B_MANAGED; 944235537Sgber bdwrite(bp); 945235537Sgber 946235537Sgber nandfs_dirty_bufs_increment(nffsdev); 947235537Sgber 948235537Sgber KASSERT((bp->b_vp), ("vp missing for bp")); 949235537Sgber KASSERT((nandfs_vblk_get(bp) || ino == NANDFS_DAT_INO), 950235537Sgber ("bp vblk is 0")); 951235537Sgber 952235537Sgber /* 953235537Sgber * To maintain consistency of FS we need to force making 954235537Sgber * meta buffers dirty, even if free space is low. 955235537Sgber */ 956235537Sgber if (dirty_meta && ino != NANDFS_GC_INO) 957235537Sgber nandfs_bmap_dirty_blocks(VTON(bp->b_vp), bp, 1); 958235537Sgber 959235537Sgber bps = nffsdev->nd_fsdata.f_blocks_per_segment; 960235537Sgber 961235537Sgber if (nffsdev->nd_dirty_bufs >= (bps * nandfs_max_dirty_segs)) { 962235537Sgber mtx_lock(&nffsdev->nd_sync_mtx); 963235537Sgber if (nffsdev->nd_syncing == 0) { 964235537Sgber DPRINTF(SYNC, ("%s: wakeup gc\n", __func__)); 965235537Sgber nffsdev->nd_syncing = 1; 966235537Sgber wakeup(&nffsdev->nd_syncing); 967235537Sgber } 968235537Sgber mtx_unlock(&nffsdev->nd_sync_mtx); 969235537Sgber } 970235537Sgber 971235537Sgber return (0); 972235537Sgber} 973235537Sgber 974235537Sgberint 975235537Sgbernandfs_dirty_buf(struct buf *bp, int force) 976235537Sgber{ 977235537Sgber 978235537Sgber return (_nandfs_dirty_buf(bp, 1, force)); 979235537Sgber} 980235537Sgber 981235537Sgberint 982235537Sgbernandfs_dirty_buf_meta(struct buf *bp, int force) 983235537Sgber{ 984235537Sgber 985235537Sgber return (_nandfs_dirty_buf(bp, 0, force)); 986235537Sgber} 987235537Sgber 988235537Sgbervoid 989235537Sgbernandfs_undirty_buf_fsdev(struct nandfs_device *nffsdev, struct buf *bp) 990235537Sgber{ 991235537Sgber 992235537Sgber BUF_ASSERT_HELD(bp); 993235537Sgber 994235537Sgber if (bp->b_flags & B_DELWRI) { 995235537Sgber bp->b_flags &= ~(B_DELWRI|B_MANAGED); 996235537Sgber nandfs_dirty_bufs_decrement(nffsdev); 997235537Sgber } 998235537Sgber /* 999235537Sgber * Since it is now being written, we can clear its deferred write flag. 1000235537Sgber */ 1001235537Sgber bp->b_flags &= ~B_DEFERRED; 1002235537Sgber 1003235537Sgber brelse(bp); 1004235537Sgber} 1005235537Sgber 1006235537Sgbervoid 1007235537Sgbernandfs_undirty_buf(struct buf *bp) 1008235537Sgber{ 1009235537Sgber struct nandfs_node *node; 1010235537Sgber 1011235537Sgber node = VTON(bp->b_vp); 1012235537Sgber 1013235537Sgber nandfs_undirty_buf_fsdev(node->nn_nandfsdev, bp); 1014235537Sgber} 1015235537Sgber 1016235537Sgbervoid 1017235537Sgbernandfs_vblk_set(struct buf *bp, nandfs_daddr_t blocknr) 1018235537Sgber{ 1019235537Sgber 1020235537Sgber nandfs_daddr_t *vblk = (nandfs_daddr_t *)(&bp->b_fsprivate1); 1021235537Sgber *vblk = blocknr; 1022235537Sgber} 1023235537Sgber 1024235537Sgbernandfs_daddr_t 1025235537Sgbernandfs_vblk_get(struct buf *bp) 1026235537Sgber{ 1027235537Sgber 1028235537Sgber nandfs_daddr_t *vblk = (nandfs_daddr_t *)(&bp->b_fsprivate1); 1029235537Sgber return (*vblk); 1030235537Sgber} 1031235537Sgber 1032235537Sgbervoid 1033235537Sgbernandfs_buf_set(struct buf *bp, uint32_t bits) 1034235537Sgber{ 1035235537Sgber uintptr_t flags; 1036235537Sgber 1037235537Sgber flags = (uintptr_t)bp->b_fsprivate3; 1038235537Sgber flags |= (uintptr_t)bits; 1039235537Sgber bp->b_fsprivate3 = (void *)flags; 1040235537Sgber} 1041235537Sgber 1042235537Sgbervoid 1043235537Sgbernandfs_buf_clear(struct buf *bp, uint32_t bits) 1044235537Sgber{ 1045235537Sgber uintptr_t flags; 1046235537Sgber 1047235537Sgber flags = (uintptr_t)bp->b_fsprivate3; 1048235537Sgber flags &= ~(uintptr_t)bits; 1049235537Sgber bp->b_fsprivate3 = (void *)flags; 1050235537Sgber} 1051235537Sgber 1052235537Sgberint 1053235537Sgbernandfs_buf_check(struct buf *bp, uint32_t bits) 1054235537Sgber{ 1055235537Sgber uintptr_t flags; 1056235537Sgber 1057235537Sgber flags = (uintptr_t)bp->b_fsprivate3; 1058235537Sgber if (flags & bits) 1059235537Sgber return (1); 1060235537Sgber return (0); 1061235537Sgber} 1062235537Sgber 1063235537Sgberint 1064235537Sgbernandfs_erase(struct nandfs_device *fsdev, off_t offset, size_t size) 1065235537Sgber{ 1066235537Sgber DPRINTF(BLOCK, ("%s: performing erase at offset %jx size %zx\n", 1067235537Sgber __func__, offset, size)); 1068235537Sgber 1069235537Sgber MPASS(size % fsdev->nd_erasesize == 0); 1070235537Sgber 1071264658Simp return (g_delete_data(fsdev->nd_gconsumer, offset, size)); 1072235537Sgber} 1073235537Sgber 1074235537Sgberint 1075235537Sgbernandfs_vop_islocked(struct vnode *vp) 1076235537Sgber{ 1077235537Sgber int islocked; 1078235537Sgber 1079235537Sgber islocked = VOP_ISLOCKED(vp); 1080235537Sgber return (islocked == LK_EXCLUSIVE || islocked == LK_SHARED); 1081235537Sgber} 1082235537Sgber 1083235537Sgbernandfs_daddr_t 1084235537Sgbernandfs_block_to_dblock(struct nandfs_device *fsdev, nandfs_lbn_t block) 1085235537Sgber{ 1086235537Sgber 1087235537Sgber return (btodb(block * fsdev->nd_blocksize)); 1088235537Sgber} 1089