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); 642235537Sgber if (error) { 643235537Sgber return (error); 644235537Sgber } 645235537Sgber } else { 646235537Sgber mp = NULL; 647235537Sgber error = getnewvnode("snandfs", mp, &nandfs_system_vnodeops, 648235537Sgber &nvp); 649235537Sgber if (error) { 650235537Sgber return (error); 651235537Sgber } 652235537Sgber } 653235537Sgber 654235537Sgber if (mp) 655235537Sgber NANDFS_WRITELOCK(nandfsdev); 656235537Sgber 657235537Sgber DPRINTF(IFILE, ("%s: ino: %#jx -> vp: %p\n", 658235537Sgber __func__, (uintmax_t)ino, nvp)); 659235537Sgber /* Lock node */ 660235537Sgber lockmgr(nvp->v_vnlock, LK_EXCLUSIVE, NULL); 661235537Sgber 662235537Sgber if (mp) { 663235537Sgber error = insmntque(nvp, mp); 664235537Sgber if (error != 0) { 665235537Sgber *nodep = NULL; 666235537Sgber return (error); 667235537Sgber } 668235537Sgber } 669235537Sgber 670235537Sgber node = uma_zalloc(nandfs_node_zone, M_WAITOK | M_ZERO); 671235537Sgber 672235537Sgber /* Crosslink */ 673235537Sgber node->nn_vnode = nvp; 674235537Sgber nvp->v_bufobj.bo_ops = &buf_ops_nandfs; 675235537Sgber node->nn_nmp = nmp; 676235537Sgber node->nn_nandfsdev = nandfsdev; 677235537Sgber nvp->v_data = node; 678235537Sgber 679235537Sgber /* Initiase NANDFS node */ 680235537Sgber node->nn_ino = ino; 681235537Sgber if (inode != NULL) 682235537Sgber node->nn_inode = *inode; 683235537Sgber 684235537Sgber nandfs_vinit(nvp, ino); 685235537Sgber 686235537Sgber /* Return node */ 687235537Sgber *nodep = node; 688235537Sgber DPRINTF(IFILE, ("%s: ino:%#jx vp:%p node:%p\n", 689235537Sgber __func__, (uintmax_t)ino, nvp, *nodep)); 690235537Sgber 691235537Sgber return (0); 692235537Sgber} 693235537Sgber 694235537Sgberint 695235537Sgbernandfs_get_node(struct nandfsmount *nmp, uint64_t ino, 696235537Sgber struct nandfs_node **nodep) 697235537Sgber{ 698235537Sgber struct nandfs_device *nandfsdev; 699235537Sgber struct nandfs_inode inode, *entry; 700235537Sgber struct vnode *nvp, *vpp; 701235537Sgber struct thread *td; 702235537Sgber struct buf *bp; 703235537Sgber uint64_t ivblocknr; 704235537Sgber uint32_t entry_in_block; 705235537Sgber int error; 706235537Sgber 707235537Sgber /* Look up node in hash table */ 708235537Sgber td = curthread; 709235537Sgber *nodep = NULL; 710235537Sgber 711235537Sgber if ((ino < NANDFS_ATIME_INO) && (ino != NANDFS_ROOT_INO)) { 712235537Sgber printf("nandfs_get_node: system ino %"PRIu64" not in mount " 713235537Sgber "point!\n", ino); 714235537Sgber return (ENOENT); 715235537Sgber } 716235537Sgber 717235537Sgber error = vfs_hash_get(nmp->nm_vfs_mountp, ino, LK_EXCLUSIVE, td, &nvp, 718235537Sgber NULL, NULL); 719235537Sgber if (error) 720235537Sgber return (error); 721235537Sgber 722235537Sgber if (nvp != NULL) { 723235537Sgber *nodep = (struct nandfs_node *)nvp->v_data; 724235537Sgber return (0); 725235537Sgber } 726235537Sgber 727235537Sgber /* Look up inode structure in mountpoints ifile */ 728235537Sgber nandfsdev = nmp->nm_nandfsdev; 729235537Sgber nandfs_mdt_trans(&nandfsdev->nd_ifile_mdt, ino, &ivblocknr, 730235537Sgber &entry_in_block); 731235537Sgber 732235537Sgber VOP_LOCK(NTOV(nmp->nm_ifile_node), LK_SHARED); 733235537Sgber error = nandfs_bread(nmp->nm_ifile_node, ivblocknr, NOCRED, 0, &bp); 734235537Sgber if (error) { 735235537Sgber brelse(bp); 736235537Sgber VOP_UNLOCK(NTOV(nmp->nm_ifile_node), 0); 737235537Sgber return (ENOENT); 738235537Sgber } 739235537Sgber 740235537Sgber /* Get inode entry */ 741235537Sgber entry = (struct nandfs_inode *) bp->b_data + entry_in_block; 742235537Sgber memcpy(&inode, entry, sizeof(struct nandfs_inode)); 743235537Sgber brelse(bp); 744235537Sgber VOP_UNLOCK(NTOV(nmp->nm_ifile_node), 0); 745235537Sgber 746235537Sgber /* Get node */ 747235537Sgber error = nandfs_get_node_raw(nmp->nm_nandfsdev, nmp, ino, &inode, nodep); 748235537Sgber if (error) { 749235537Sgber *nodep = NULL; 750235537Sgber return (error); 751235537Sgber } 752235537Sgber 753235537Sgber nvp = (*nodep)->nn_vnode; 754235537Sgber error = vfs_hash_insert(nvp, ino, 0, td, &vpp, NULL, NULL); 755235537Sgber if (error) { 756235537Sgber *nodep = NULL; 757235537Sgber return (error); 758235537Sgber } 759235537Sgber 760235537Sgber return (error); 761235537Sgber} 762235537Sgber 763235537Sgbervoid 764235537Sgbernandfs_dispose_node(struct nandfs_node **nodep) 765235537Sgber{ 766235537Sgber struct nandfs_node *node; 767235537Sgber struct vnode *vp; 768235537Sgber 769235537Sgber /* Protect against rogue values */ 770235537Sgber node = *nodep; 771235537Sgber if (!node) { 772235537Sgber return; 773235537Sgber } 774235537Sgber DPRINTF(NODE, ("nandfs_dispose_node: %p\n", *nodep)); 775235537Sgber 776235537Sgber vp = NTOV(node); 777235537Sgber vp->v_data = NULL; 778235537Sgber 779235537Sgber /* Free our associated memory */ 780235537Sgber uma_zfree(nandfs_node_zone, node); 781235537Sgber 782235537Sgber *nodep = NULL; 783235537Sgber} 784235537Sgber 785235537Sgberint 786235537Sgbernandfs_lookup_name_in_dir(struct vnode *dvp, const char *name, int namelen, 787235537Sgber uint64_t *ino, int *found, uint64_t *off) 788235537Sgber{ 789235537Sgber struct nandfs_node *dir_node = VTON(dvp); 790235537Sgber struct nandfs_dir_entry *ndirent; 791235537Sgber struct buf *bp; 792235537Sgber uint64_t file_size, diroffset, blkoff; 793235537Sgber uint64_t blocknr; 794235537Sgber uint32_t blocksize = dir_node->nn_nandfsdev->nd_blocksize; 795235537Sgber uint8_t *pos, name_len; 796235537Sgber int error; 797235537Sgber 798235537Sgber *found = 0; 799235537Sgber 800235537Sgber DPRINTF(VNCALL, ("%s: %s file\n", __func__, name)); 801235537Sgber if (dvp->v_type != VDIR) { 802235537Sgber return (ENOTDIR); 803235537Sgber } 804235537Sgber 805235537Sgber /* Get directory filesize */ 806235537Sgber file_size = dir_node->nn_inode.i_size; 807235537Sgber 808235537Sgber /* Walk the directory */ 809235537Sgber diroffset = 0; 810235537Sgber blocknr = 0; 811235537Sgber blkoff = 0; 812235537Sgber error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp); 813235537Sgber if (error) { 814235537Sgber brelse(bp); 815235537Sgber return (EIO); 816235537Sgber } 817235537Sgber 818235537Sgber while (diroffset < file_size) { 819235537Sgber if (blkoff >= blocksize) { 820235537Sgber blkoff = 0; blocknr++; 821235537Sgber brelse(bp); 822235537Sgber error = nandfs_bread(dir_node, blocknr, NOCRED, 0, 823235537Sgber &bp); 824235537Sgber if (error) { 825235537Sgber brelse(bp); 826235537Sgber return (EIO); 827235537Sgber } 828235537Sgber } 829235537Sgber 830235537Sgber /* Read in one dirent */ 831235537Sgber pos = (uint8_t *) bp->b_data + blkoff; 832235537Sgber ndirent = (struct nandfs_dir_entry *) pos; 833235537Sgber name_len = ndirent->name_len; 834235537Sgber 835235537Sgber if ((name_len == namelen) && 836235537Sgber (strncmp(name, ndirent->name, name_len) == 0) && 837235537Sgber (ndirent->inode != 0)) { 838235537Sgber *ino = ndirent->inode; 839235537Sgber *off = diroffset; 840235537Sgber DPRINTF(LOOKUP, ("found `%.*s` with ino %"PRIx64"\n", 841235537Sgber name_len, ndirent->name, *ino)); 842235537Sgber *found = 1; 843235537Sgber break; 844235537Sgber } 845235537Sgber 846235537Sgber /* Advance */ 847235537Sgber diroffset += ndirent->rec_len; 848235537Sgber blkoff += ndirent->rec_len; 849235537Sgber } 850235537Sgber brelse(bp); 851235537Sgber 852235537Sgber return (error); 853235537Sgber} 854235537Sgber 855235537Sgberint 856235537Sgbernandfs_get_fsinfo(struct nandfsmount *nmp, struct nandfs_fsinfo *fsinfo) 857235537Sgber{ 858235537Sgber struct nandfs_device *fsdev; 859235537Sgber 860235537Sgber fsdev = nmp->nm_nandfsdev; 861235537Sgber 862235537Sgber memcpy(&fsinfo->fs_fsdata, &fsdev->nd_fsdata, sizeof(fsdev->nd_fsdata)); 863235537Sgber memcpy(&fsinfo->fs_super, &fsdev->nd_super, sizeof(fsdev->nd_super)); 864235537Sgber snprintf(fsinfo->fs_dev, sizeof(fsinfo->fs_dev), 865235537Sgber "%s", nmp->nm_vfs_mountp->mnt_stat.f_mntfromname); 866235537Sgber 867235537Sgber return (0); 868235537Sgber} 869235537Sgber 870235537Sgbervoid 871235537Sgbernandfs_inode_init(struct nandfs_inode *inode, uint16_t mode) 872235537Sgber{ 873235537Sgber struct timespec ts; 874235537Sgber 875235537Sgber vfs_timestamp(&ts); 876235537Sgber 877235537Sgber inode->i_blocks = 0; 878235537Sgber inode->i_size = 0; 879235537Sgber inode->i_ctime = ts.tv_sec; 880235537Sgber inode->i_ctime_nsec = ts.tv_nsec; 881235537Sgber inode->i_mtime = ts.tv_sec; 882235537Sgber inode->i_mtime_nsec = ts.tv_nsec; 883235537Sgber inode->i_mode = mode; 884235537Sgber inode->i_links_count = 1; 885235537Sgber if (S_ISDIR(mode)) 886235537Sgber inode->i_links_count = 2; 887235537Sgber inode->i_flags = 0; 888235537Sgber 889235537Sgber inode->i_special = 0; 890235537Sgber memset(inode->i_db, 0, sizeof(inode->i_db)); 891235537Sgber memset(inode->i_ib, 0, sizeof(inode->i_ib)); 892235537Sgber} 893235537Sgber 894235537Sgbervoid 895235537Sgbernandfs_inode_destroy(struct nandfs_inode *inode) 896235537Sgber{ 897235537Sgber 898235537Sgber MPASS(inode->i_blocks == 0); 899235537Sgber bzero(inode, sizeof(*inode)); 900235537Sgber} 901235537Sgber 902235537Sgberint 903235537Sgbernandfs_fs_full(struct nandfs_device *nffsdev) 904235537Sgber{ 905235537Sgber uint64_t space, bps; 906235537Sgber 907235537Sgber bps = nffsdev->nd_fsdata.f_blocks_per_segment; 908235537Sgber space = (nffsdev->nd_clean_segs - 1) * bps; 909235537Sgber 910235537Sgber DPRINTF(BUF, ("%s: bufs:%jx space:%jx\n", __func__, 911235537Sgber (uintmax_t)nffsdev->nd_dirty_bufs, (uintmax_t)space)); 912235537Sgber 913235537Sgber if (nffsdev->nd_dirty_bufs + (10 * bps) >= space) 914235537Sgber return (1); 915235537Sgber 916235537Sgber return (0); 917235537Sgber} 918235537Sgber 919235537Sgberstatic int 920235537Sgber_nandfs_dirty_buf(struct buf *bp, int dirty_meta, int force) 921235537Sgber{ 922235537Sgber struct nandfs_device *nffsdev; 923235537Sgber struct nandfs_node *node; 924235537Sgber uint64_t ino, bps; 925235537Sgber 926235537Sgber if (NANDFS_ISGATHERED(bp)) { 927235537Sgber bqrelse(bp); 928235537Sgber return (0); 929235537Sgber } 930235537Sgber if ((bp->b_flags & (B_MANAGED | B_DELWRI)) == (B_MANAGED | B_DELWRI)) { 931235537Sgber bqrelse(bp); 932235537Sgber return (0); 933235537Sgber } 934235537Sgber 935235537Sgber node = VTON(bp->b_vp); 936235537Sgber nffsdev = node->nn_nandfsdev; 937235537Sgber DPRINTF(BUF, ("%s: buf:%p\n", __func__, bp)); 938235537Sgber ino = node->nn_ino; 939235537Sgber 940235537Sgber if (nandfs_fs_full(nffsdev) && !NANDFS_SYS_NODE(ino) && !force) { 941235537Sgber brelse(bp); 942235537Sgber return (ENOSPC); 943235537Sgber } 944235537Sgber 945235537Sgber bp->b_flags |= B_MANAGED; 946235537Sgber bdwrite(bp); 947235537Sgber 948235537Sgber nandfs_dirty_bufs_increment(nffsdev); 949235537Sgber 950235537Sgber KASSERT((bp->b_vp), ("vp missing for bp")); 951235537Sgber KASSERT((nandfs_vblk_get(bp) || ino == NANDFS_DAT_INO), 952235537Sgber ("bp vblk is 0")); 953235537Sgber 954235537Sgber /* 955235537Sgber * To maintain consistency of FS we need to force making 956235537Sgber * meta buffers dirty, even if free space is low. 957235537Sgber */ 958235537Sgber if (dirty_meta && ino != NANDFS_GC_INO) 959235537Sgber nandfs_bmap_dirty_blocks(VTON(bp->b_vp), bp, 1); 960235537Sgber 961235537Sgber bps = nffsdev->nd_fsdata.f_blocks_per_segment; 962235537Sgber 963235537Sgber if (nffsdev->nd_dirty_bufs >= (bps * nandfs_max_dirty_segs)) { 964235537Sgber mtx_lock(&nffsdev->nd_sync_mtx); 965235537Sgber if (nffsdev->nd_syncing == 0) { 966235537Sgber DPRINTF(SYNC, ("%s: wakeup gc\n", __func__)); 967235537Sgber nffsdev->nd_syncing = 1; 968235537Sgber wakeup(&nffsdev->nd_syncing); 969235537Sgber } 970235537Sgber mtx_unlock(&nffsdev->nd_sync_mtx); 971235537Sgber } 972235537Sgber 973235537Sgber return (0); 974235537Sgber} 975235537Sgber 976235537Sgberint 977235537Sgbernandfs_dirty_buf(struct buf *bp, int force) 978235537Sgber{ 979235537Sgber 980235537Sgber return (_nandfs_dirty_buf(bp, 1, force)); 981235537Sgber} 982235537Sgber 983235537Sgberint 984235537Sgbernandfs_dirty_buf_meta(struct buf *bp, int force) 985235537Sgber{ 986235537Sgber 987235537Sgber return (_nandfs_dirty_buf(bp, 0, force)); 988235537Sgber} 989235537Sgber 990235537Sgbervoid 991235537Sgbernandfs_undirty_buf_fsdev(struct nandfs_device *nffsdev, struct buf *bp) 992235537Sgber{ 993235537Sgber 994235537Sgber BUF_ASSERT_HELD(bp); 995235537Sgber 996235537Sgber if (bp->b_flags & B_DELWRI) { 997235537Sgber bp->b_flags &= ~(B_DELWRI|B_MANAGED); 998235537Sgber nandfs_dirty_bufs_decrement(nffsdev); 999235537Sgber } 1000235537Sgber /* 1001235537Sgber * Since it is now being written, we can clear its deferred write flag. 1002235537Sgber */ 1003235537Sgber bp->b_flags &= ~B_DEFERRED; 1004235537Sgber 1005235537Sgber brelse(bp); 1006235537Sgber} 1007235537Sgber 1008235537Sgbervoid 1009235537Sgbernandfs_undirty_buf(struct buf *bp) 1010235537Sgber{ 1011235537Sgber struct nandfs_node *node; 1012235537Sgber 1013235537Sgber node = VTON(bp->b_vp); 1014235537Sgber 1015235537Sgber nandfs_undirty_buf_fsdev(node->nn_nandfsdev, bp); 1016235537Sgber} 1017235537Sgber 1018235537Sgbervoid 1019235537Sgbernandfs_vblk_set(struct buf *bp, nandfs_daddr_t blocknr) 1020235537Sgber{ 1021235537Sgber 1022235537Sgber nandfs_daddr_t *vblk = (nandfs_daddr_t *)(&bp->b_fsprivate1); 1023235537Sgber *vblk = blocknr; 1024235537Sgber} 1025235537Sgber 1026235537Sgbernandfs_daddr_t 1027235537Sgbernandfs_vblk_get(struct buf *bp) 1028235537Sgber{ 1029235537Sgber 1030235537Sgber nandfs_daddr_t *vblk = (nandfs_daddr_t *)(&bp->b_fsprivate1); 1031235537Sgber return (*vblk); 1032235537Sgber} 1033235537Sgber 1034235537Sgbervoid 1035235537Sgbernandfs_buf_set(struct buf *bp, uint32_t bits) 1036235537Sgber{ 1037235537Sgber uintptr_t flags; 1038235537Sgber 1039235537Sgber flags = (uintptr_t)bp->b_fsprivate3; 1040235537Sgber flags |= (uintptr_t)bits; 1041235537Sgber bp->b_fsprivate3 = (void *)flags; 1042235537Sgber} 1043235537Sgber 1044235537Sgbervoid 1045235537Sgbernandfs_buf_clear(struct buf *bp, uint32_t bits) 1046235537Sgber{ 1047235537Sgber uintptr_t flags; 1048235537Sgber 1049235537Sgber flags = (uintptr_t)bp->b_fsprivate3; 1050235537Sgber flags &= ~(uintptr_t)bits; 1051235537Sgber bp->b_fsprivate3 = (void *)flags; 1052235537Sgber} 1053235537Sgber 1054235537Sgberint 1055235537Sgbernandfs_buf_check(struct buf *bp, uint32_t bits) 1056235537Sgber{ 1057235537Sgber uintptr_t flags; 1058235537Sgber 1059235537Sgber flags = (uintptr_t)bp->b_fsprivate3; 1060235537Sgber if (flags & bits) 1061235537Sgber return (1); 1062235537Sgber return (0); 1063235537Sgber} 1064235537Sgber 1065235537Sgberint 1066235537Sgbernandfs_erase(struct nandfs_device *fsdev, off_t offset, size_t size) 1067235537Sgber{ 1068235537Sgber struct buf *bp; 1069235537Sgber int read_size, error, i; 1070235537Sgber 1071235537Sgber DPRINTF(BLOCK, ("%s: performing erase at offset %jx size %zx\n", 1072235537Sgber __func__, offset, size)); 1073235537Sgber 1074235537Sgber MPASS(size % fsdev->nd_erasesize == 0); 1075235537Sgber 1076235537Sgber if (fsdev->nd_is_nand) { 1077235537Sgber error = g_delete_data(fsdev->nd_gconsumer, offset, size); 1078235537Sgber return (error); 1079235537Sgber } 1080235537Sgber 1081235537Sgber if (size > MAXBSIZE) 1082235537Sgber read_size = MAXBSIZE; 1083235537Sgber else 1084235537Sgber read_size = size; 1085235537Sgber 1086235537Sgber error = 0; 1087235537Sgber for (i = 0; i < size / MAXBSIZE; i++) { 1088235537Sgber error = bread(fsdev->nd_devvp, btodb(offset + i * read_size), 1089235537Sgber read_size, NOCRED, &bp); 1090235537Sgber if (error) { 1091235537Sgber brelse(bp); 1092235537Sgber return (error); 1093235537Sgber } 1094235537Sgber memset(bp->b_data, 0xff, read_size); 1095235537Sgber error = bwrite(bp); 1096235537Sgber if (error) { 1097235537Sgber nandfs_error("%s: err:%d from bwrite\n", 1098235537Sgber __func__, error); 1099235537Sgber return (error); 1100235537Sgber } 1101235537Sgber } 1102235537Sgber 1103235537Sgber return (error); 1104235537Sgber} 1105235537Sgber 1106235537Sgberint 1107235537Sgbernandfs_vop_islocked(struct vnode *vp) 1108235537Sgber{ 1109235537Sgber int islocked; 1110235537Sgber 1111235537Sgber islocked = VOP_ISLOCKED(vp); 1112235537Sgber return (islocked == LK_EXCLUSIVE || islocked == LK_SHARED); 1113235537Sgber} 1114235537Sgber 1115235537Sgbernandfs_daddr_t 1116235537Sgbernandfs_block_to_dblock(struct nandfs_device *fsdev, nandfs_lbn_t block) 1117235537Sgber{ 1118235537Sgber 1119235537Sgber return (btodb(block * fsdev->nd_blocksize)); 1120235537Sgber} 1121