1235537Sgber/*- 2235537Sgber * Copyright (c) 2010-2012 Semihalf. 3235537Sgber * All rights reserved. 4235537Sgber * 5235537Sgber * Redistribution and use in source and binary forms, with or without 6235537Sgber * modification, are permitted provided that the following conditions 7235537Sgber * are met: 8235537Sgber * 1. Redistributions of source code must retain the above copyright 9235537Sgber * notice, this list of conditions and the following disclaimer. 10235537Sgber * 2. Redistributions in binary form must reproduce the above copyright 11235537Sgber * notice, this list of conditions and the following disclaimer in the 12235537Sgber * documentation and/or other materials provided with the distribution. 13235537Sgber * 14235537Sgber * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15235537Sgber * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16235537Sgber * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17235537Sgber * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18235537Sgber * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19235537Sgber * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20235537Sgber * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21235537Sgber * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22235537Sgber * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23235537Sgber * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24235537Sgber * SUCH DAMAGE. 25235537Sgber */ 26235537Sgber 27235537Sgber#include <sys/cdefs.h> 28235537Sgber__FBSDID("$FreeBSD: releng/11.0/sys/fs/nandfs/nandfs_sufile.c 298806 2016-04-29 20:51:24Z pfg $"); 29235537Sgber 30235537Sgber#include <sys/param.h> 31235537Sgber#include <sys/systm.h> 32235537Sgber#include <sys/conf.h> 33235537Sgber#include <sys/kernel.h> 34235537Sgber#include <sys/lock.h> 35235537Sgber#include <sys/malloc.h> 36235537Sgber#include <sys/mount.h> 37235537Sgber#include <sys/mutex.h> 38235537Sgber#include <sys/namei.h> 39235537Sgber#include <sys/sysctl.h> 40235537Sgber#include <sys/vnode.h> 41235537Sgber#include <sys/buf.h> 42235537Sgber#include <sys/bio.h> 43235537Sgber 44235537Sgber#include <vm/vm.h> 45235537Sgber#include <vm/vm_param.h> 46235537Sgber#include <vm/vm_kern.h> 47235537Sgber#include <vm/vm_page.h> 48235537Sgber 49235537Sgber#include <geom/geom.h> 50235537Sgber#include <geom/geom_vfs.h> 51235537Sgber 52235537Sgber#include <fs/nandfs/nandfs_mount.h> 53235537Sgber#include <fs/nandfs/nandfs.h> 54235537Sgber#include <fs/nandfs/nandfs_subr.h> 55235537Sgber 56235537Sgber#define SU_USAGE_OFF(bp, offset) \ 57235537Sgber ((struct nandfs_segment_usage *)((bp)->b_data + offset)) 58235537Sgber 59235537Sgberstatic int 60235537Sgbernandfs_seg_usage_blk_offset(struct nandfs_device *fsdev, uint64_t seg, 61235537Sgber uint64_t *blk, uint64_t *offset) 62235537Sgber{ 63235537Sgber uint64_t off; 64235537Sgber uint16_t seg_size; 65235537Sgber 66235537Sgber seg_size = fsdev->nd_fsdata.f_segment_usage_size; 67235537Sgber 68235537Sgber off = roundup(sizeof(struct nandfs_sufile_header), seg_size); 69235537Sgber off += (seg * seg_size); 70235537Sgber 71235537Sgber *blk = off / fsdev->nd_blocksize; 72235537Sgber *offset = off % fsdev->nd_blocksize; 73235537Sgber return (0); 74235537Sgber} 75235537Sgber 76235537Sgber/* Alloc new segment */ 77235537Sgberint 78235537Sgbernandfs_alloc_segment(struct nandfs_device *fsdev, uint64_t *seg) 79235537Sgber{ 80235537Sgber struct nandfs_node *su_node; 81235537Sgber struct nandfs_sufile_header *su_header; 82235537Sgber struct nandfs_segment_usage *su_usage; 83235537Sgber struct buf *bp_header, *bp; 84235537Sgber uint64_t blk, vblk, offset, i, rest, nsegments; 85235537Sgber uint16_t seg_size; 86235537Sgber int error, found; 87235537Sgber 88235537Sgber seg_size = fsdev->nd_fsdata.f_segment_usage_size; 89235537Sgber nsegments = fsdev->nd_fsdata.f_nsegments; 90235537Sgber 91235537Sgber su_node = fsdev->nd_su_node; 92235537Sgber ASSERT_VOP_LOCKED(NTOV(su_node), __func__); 93235537Sgber 94235537Sgber /* Read header buffer */ 95235537Sgber error = nandfs_bread(su_node, 0, NOCRED, 0, &bp_header); 96235537Sgber if (error) { 97235537Sgber brelse(bp_header); 98235537Sgber return (error); 99235537Sgber } 100235537Sgber 101235537Sgber su_header = (struct nandfs_sufile_header *)bp_header->b_data; 102235537Sgber 103235537Sgber /* Get last allocated segment */ 104235537Sgber i = su_header->sh_last_alloc + 1; 105235537Sgber 106235537Sgber found = 0; 107235537Sgber bp = NULL; 108235537Sgber while (!found) { 109235537Sgber nandfs_seg_usage_blk_offset(fsdev, i, &blk, &offset); 110235537Sgber if(blk != 0) { 111235537Sgber error = nandfs_bmap_lookup(su_node, blk, &vblk); 112235537Sgber if (error) { 113235537Sgber nandfs_error("%s: cannot find vblk for blk " 114235537Sgber "blk:%jx\n", __func__, blk); 115235537Sgber return (error); 116235537Sgber } 117235537Sgber if (vblk) 118235537Sgber error = nandfs_bread(su_node, blk, NOCRED, 0, 119235537Sgber &bp); 120235537Sgber else 121235537Sgber error = nandfs_bcreate(su_node, blk, NOCRED, 0, 122235537Sgber &bp); 123235537Sgber if (error) { 124235537Sgber nandfs_error("%s: cannot create/read " 125235537Sgber "vblk:%jx\n", __func__, vblk); 126235537Sgber if (bp) 127235537Sgber brelse(bp); 128235537Sgber return (error); 129235537Sgber } 130235537Sgber 131235537Sgber su_usage = SU_USAGE_OFF(bp, offset); 132235537Sgber } else { 133235537Sgber su_usage = SU_USAGE_OFF(bp_header, offset); 134235537Sgber bp = bp_header; 135235537Sgber } 136235537Sgber 137235537Sgber rest = (fsdev->nd_blocksize - offset) / seg_size; 138235537Sgber /* Go through all su usage in block */ 139235537Sgber while (rest) { 140298806Spfg /* When last check start from beginning */ 141235537Sgber if (i == nsegments) 142235537Sgber break; 143235537Sgber 144235537Sgber if (!su_usage->su_flags) { 145235537Sgber su_usage->su_flags = 1; 146235537Sgber found = 1; 147235537Sgber break; 148235537Sgber } 149235537Sgber su_usage++; 150235537Sgber i++; 151235537Sgber 152235537Sgber /* If all checked return error */ 153235537Sgber if (i == su_header->sh_last_alloc) { 154235537Sgber DPRINTF(SEG, ("%s: cannot allocate segment \n", 155235537Sgber __func__)); 156235537Sgber brelse(bp_header); 157235537Sgber if (blk != 0) 158235537Sgber brelse(bp); 159235537Sgber return (1); 160235537Sgber } 161235537Sgber rest--; 162235537Sgber } 163235537Sgber if (!found) { 164235537Sgber /* Otherwise read another block */ 165235537Sgber if (blk != 0) 166235537Sgber brelse(bp); 167235537Sgber if (i == nsegments) { 168235537Sgber blk = 0; 169235537Sgber i = 0; 170235537Sgber } else 171235537Sgber blk++; 172235537Sgber offset = 0; 173235537Sgber } 174235537Sgber } 175235537Sgber 176235537Sgber if (found) { 177235537Sgber *seg = i; 178235537Sgber su_header->sh_last_alloc = i; 179235537Sgber su_header->sh_ncleansegs--; 180235537Sgber su_header->sh_ndirtysegs++; 181235537Sgber 182235537Sgber fsdev->nd_super.s_free_blocks_count = su_header->sh_ncleansegs * 183235537Sgber fsdev->nd_fsdata.f_blocks_per_segment; 184235537Sgber fsdev->nd_clean_segs--; 185235537Sgber 186235537Sgber /* 187235537Sgber * It is mostly called from syncer() so we want to force 188235537Sgber * making buf dirty. 189235537Sgber */ 190235537Sgber error = nandfs_dirty_buf(bp_header, 1); 191235537Sgber if (error) { 192235537Sgber if (bp && bp != bp_header) 193235537Sgber brelse(bp); 194235537Sgber return (error); 195235537Sgber } 196235537Sgber if (bp && bp != bp_header) 197235537Sgber nandfs_dirty_buf(bp, 1); 198235537Sgber 199235537Sgber DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)i)); 200235537Sgber 201235537Sgber return (0); 202235537Sgber } 203235537Sgber 204235537Sgber DPRINTF(SEG, ("%s: failed\n", __func__)); 205235537Sgber 206235537Sgber return (1); 207235537Sgber} 208235537Sgber 209235537Sgber/* 210235537Sgber * Make buffer dirty, it will be updated soon but first it need to be 211235537Sgber * gathered by syncer. 212235537Sgber */ 213235537Sgberint 214235537Sgbernandfs_touch_segment(struct nandfs_device *fsdev, uint64_t seg) 215235537Sgber{ 216235537Sgber struct nandfs_node *su_node; 217235537Sgber struct buf *bp; 218235537Sgber uint64_t blk, offset; 219235537Sgber int error; 220235537Sgber 221235537Sgber su_node = fsdev->nd_su_node; 222235537Sgber ASSERT_VOP_LOCKED(NTOV(su_node), __func__); 223235537Sgber 224235537Sgber nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); 225235537Sgber 226235537Sgber error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); 227235537Sgber if (error) { 228235537Sgber brelse(bp); 229235537Sgber nandfs_error("%s: cannot preallocate new segment\n", __func__); 230235537Sgber return (error); 231235537Sgber } else 232235537Sgber nandfs_dirty_buf(bp, 1); 233235537Sgber 234235537Sgber DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); 235235537Sgber return (error); 236235537Sgber} 237235537Sgber 238235537Sgber/* Update block count of segment */ 239235537Sgberint 240235537Sgbernandfs_update_segment(struct nandfs_device *fsdev, uint64_t seg, uint32_t nblks) 241235537Sgber{ 242235537Sgber struct nandfs_node *su_node; 243235537Sgber struct nandfs_segment_usage *su_usage; 244235537Sgber struct buf *bp; 245235537Sgber uint64_t blk, offset; 246235537Sgber int error; 247235537Sgber 248235537Sgber su_node = fsdev->nd_su_node; 249235537Sgber ASSERT_VOP_LOCKED(NTOV(su_node), __func__); 250235537Sgber 251235537Sgber nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); 252235537Sgber 253235537Sgber error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); 254235537Sgber if (error) { 255235537Sgber nandfs_error("%s: read block:%jx to update\n", 256235537Sgber __func__, blk); 257235537Sgber brelse(bp); 258235537Sgber return (error); 259235537Sgber } 260235537Sgber 261235537Sgber su_usage = SU_USAGE_OFF(bp, offset); 262235537Sgber su_usage->su_lastmod = fsdev->nd_ts.tv_sec; 263235537Sgber su_usage->su_flags = NANDFS_SEGMENT_USAGE_DIRTY; 264235537Sgber su_usage->su_nblocks += nblks; 265235537Sgber 266235537Sgber DPRINTF(SEG, ("%s: seg:%#jx inc:%#x cur:%#x\n", __func__, 267235537Sgber (uintmax_t)seg, nblks, su_usage->su_nblocks)); 268235537Sgber 269235537Sgber nandfs_dirty_buf(bp, 1); 270235537Sgber 271235537Sgber return (0); 272235537Sgber} 273235537Sgber 274235537Sgber/* Make segment free */ 275235537Sgberint 276235537Sgbernandfs_free_segment(struct nandfs_device *fsdev, uint64_t seg) 277235537Sgber{ 278235537Sgber struct nandfs_node *su_node; 279235537Sgber struct nandfs_sufile_header *su_header; 280235537Sgber struct nandfs_segment_usage *su_usage; 281235537Sgber struct buf *bp_header, *bp; 282235537Sgber uint64_t blk, offset; 283235537Sgber int error; 284235537Sgber 285235537Sgber su_node = fsdev->nd_su_node; 286235537Sgber ASSERT_VOP_LOCKED(NTOV(su_node), __func__); 287235537Sgber 288235537Sgber /* Read su header */ 289235537Sgber error = nandfs_bread(su_node, 0, NOCRED, 0, &bp_header); 290235537Sgber if (error) { 291235537Sgber brelse(bp_header); 292235537Sgber return (error); 293235537Sgber } 294235537Sgber 295235537Sgber su_header = (struct nandfs_sufile_header *)bp_header->b_data; 296235537Sgber nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); 297235537Sgber 298235537Sgber /* Read su usage block if other than su header block */ 299235537Sgber if (blk != 0) { 300235537Sgber error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); 301235537Sgber if (error) { 302235537Sgber brelse(bp); 303235537Sgber brelse(bp_header); 304235537Sgber return (error); 305235537Sgber } 306235537Sgber } else 307235537Sgber bp = bp_header; 308235537Sgber 309235537Sgber /* Reset su usage data */ 310235537Sgber su_usage = SU_USAGE_OFF(bp, offset); 311235537Sgber su_usage->su_lastmod = fsdev->nd_ts.tv_sec; 312235537Sgber su_usage->su_nblocks = 0; 313235537Sgber su_usage->su_flags = 0; 314235537Sgber 315235537Sgber /* Update clean/dirty counter in header */ 316235537Sgber su_header->sh_ncleansegs++; 317235537Sgber su_header->sh_ndirtysegs--; 318235537Sgber 319235537Sgber /* 320235537Sgber * Make buffers dirty, called by cleaner 321235537Sgber * so force dirty even if no much space left 322235537Sgber * on device 323235537Sgber */ 324235537Sgber nandfs_dirty_buf(bp_header, 1); 325235537Sgber if (bp != bp_header) 326235537Sgber nandfs_dirty_buf(bp, 1); 327235537Sgber 328235537Sgber /* Update free block count */ 329235537Sgber fsdev->nd_super.s_free_blocks_count = su_header->sh_ncleansegs * 330235537Sgber fsdev->nd_fsdata.f_blocks_per_segment; 331235537Sgber fsdev->nd_clean_segs++; 332235537Sgber 333235537Sgber DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); 334235537Sgber 335235537Sgber return (0); 336235537Sgber} 337235537Sgber 338235537Sgberstatic int 339235537Sgbernandfs_bad_segment(struct nandfs_device *fsdev, uint64_t seg) 340235537Sgber{ 341235537Sgber struct nandfs_node *su_node; 342235537Sgber struct nandfs_segment_usage *su_usage; 343235537Sgber struct buf *bp; 344235537Sgber uint64_t blk, offset; 345235537Sgber int error; 346235537Sgber 347235537Sgber su_node = fsdev->nd_su_node; 348235537Sgber ASSERT_VOP_LOCKED(NTOV(su_node), __func__); 349235537Sgber 350235537Sgber nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); 351235537Sgber 352235537Sgber error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); 353235537Sgber if (error) { 354235537Sgber brelse(bp); 355235537Sgber return (error); 356235537Sgber } 357235537Sgber 358235537Sgber su_usage = SU_USAGE_OFF(bp, offset); 359235537Sgber su_usage->su_lastmod = fsdev->nd_ts.tv_sec; 360235537Sgber su_usage->su_flags = NANDFS_SEGMENT_USAGE_ERROR; 361235537Sgber 362235537Sgber DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); 363235537Sgber 364235537Sgber nandfs_dirty_buf(bp, 1); 365235537Sgber 366235537Sgber return (0); 367235537Sgber} 368235537Sgber 369235537Sgberint 370235537Sgbernandfs_markgc_segment(struct nandfs_device *fsdev, uint64_t seg) 371235537Sgber{ 372235537Sgber struct nandfs_node *su_node; 373235537Sgber struct nandfs_segment_usage *su_usage; 374235537Sgber struct buf *bp; 375235537Sgber uint64_t blk, offset; 376235537Sgber int error; 377235537Sgber 378235537Sgber su_node = fsdev->nd_su_node; 379235537Sgber 380235537Sgber VOP_LOCK(NTOV(su_node), LK_EXCLUSIVE); 381235537Sgber 382235537Sgber nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); 383235537Sgber 384235537Sgber error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); 385235537Sgber if (error) { 386235537Sgber brelse(bp); 387235537Sgber VOP_UNLOCK(NTOV(su_node), 0); 388235537Sgber return (error); 389235537Sgber } 390235537Sgber 391235537Sgber su_usage = SU_USAGE_OFF(bp, offset); 392235537Sgber MPASS((su_usage->su_flags & NANDFS_SEGMENT_USAGE_GC) == 0); 393235537Sgber su_usage->su_flags |= NANDFS_SEGMENT_USAGE_GC; 394235537Sgber 395235537Sgber brelse(bp); 396235537Sgber VOP_UNLOCK(NTOV(su_node), 0); 397235537Sgber 398235537Sgber DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); 399235537Sgber 400235537Sgber return (0); 401235537Sgber} 402235537Sgber 403235537Sgberint 404235537Sgbernandfs_clear_segment(struct nandfs_device *fsdev, uint64_t seg) 405235537Sgber{ 406235537Sgber uint64_t offset, segsize; 407235537Sgber uint32_t bps, bsize; 408235537Sgber int error = 0; 409235537Sgber 410235537Sgber bps = fsdev->nd_fsdata.f_blocks_per_segment; 411235537Sgber bsize = fsdev->nd_blocksize; 412235537Sgber segsize = bsize * bps; 413235537Sgber nandfs_get_segment_range(fsdev, seg, &offset, NULL); 414235537Sgber offset *= bsize; 415235537Sgber 416235537Sgber DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); 417235537Sgber 418235537Sgber /* Erase it and mark it bad when fail */ 419235537Sgber if (nandfs_erase(fsdev, offset, segsize)) 420235537Sgber error = nandfs_bad_segment(fsdev, seg); 421235537Sgber 422235537Sgber if (error) 423235537Sgber return (error); 424235537Sgber 425235537Sgber /* Mark it free */ 426235537Sgber error = nandfs_free_segment(fsdev, seg); 427235537Sgber 428235537Sgber return (error); 429235537Sgber} 430235537Sgber 431235537Sgberint 432235537Sgbernandfs_get_seg_stat(struct nandfs_device *nandfsdev, 433235537Sgber struct nandfs_seg_stat *nss) 434235537Sgber{ 435235537Sgber struct nandfs_sufile_header *suhdr; 436235537Sgber struct nandfs_node *su_node; 437235537Sgber struct buf *bp; 438235537Sgber int err; 439235537Sgber 440235537Sgber su_node = nandfsdev->nd_su_node; 441235537Sgber 442235537Sgber NANDFS_WRITELOCK(nandfsdev); 443235537Sgber VOP_LOCK(NTOV(su_node), LK_SHARED); 444235537Sgber err = nandfs_bread(nandfsdev->nd_su_node, 0, NOCRED, 0, &bp); 445235537Sgber if (err) { 446235537Sgber brelse(bp); 447235537Sgber VOP_UNLOCK(NTOV(su_node), 0); 448235537Sgber NANDFS_WRITEUNLOCK(nandfsdev); 449235537Sgber return (-1); 450235537Sgber } 451235537Sgber 452235537Sgber suhdr = (struct nandfs_sufile_header *)bp->b_data; 453235537Sgber nss->nss_nsegs = nandfsdev->nd_fsdata.f_nsegments; 454235537Sgber nss->nss_ncleansegs = suhdr->sh_ncleansegs; 455235537Sgber nss->nss_ndirtysegs = suhdr->sh_ndirtysegs; 456235537Sgber nss->nss_ctime = 0; 457235537Sgber nss->nss_nongc_ctime = nandfsdev->nd_ts.tv_sec; 458235537Sgber nss->nss_prot_seq = nandfsdev->nd_seg_sequence; 459235537Sgber 460235537Sgber brelse(bp); 461235537Sgber VOP_UNLOCK(NTOV(su_node), 0); 462235537Sgber 463235537Sgber NANDFS_WRITEUNLOCK(nandfsdev); 464235537Sgber 465235537Sgber return (0); 466235537Sgber} 467235537Sgber 468235537Sgberint 469235537Sgbernandfs_get_segment_info_ioctl(struct nandfs_device *fsdev, 470235537Sgber struct nandfs_argv *nargv) 471235537Sgber{ 472235537Sgber struct nandfs_suinfo *nsi; 473235537Sgber int error; 474235537Sgber 475235537Sgber if (nargv->nv_nmembs > NANDFS_SEGMENTS_MAX) 476235537Sgber return (EINVAL); 477235537Sgber 478235537Sgber nsi = malloc(sizeof(struct nandfs_suinfo) * nargv->nv_nmembs, 479235537Sgber M_NANDFSTEMP, M_WAITOK | M_ZERO); 480235537Sgber 481235537Sgber error = nandfs_get_segment_info(fsdev, nsi, nargv->nv_nmembs, 482235537Sgber nargv->nv_index); 483235537Sgber 484235537Sgber if (error == 0) 485235537Sgber error = copyout(nsi, (void *)(uintptr_t)nargv->nv_base, 486235537Sgber sizeof(struct nandfs_suinfo) * nargv->nv_nmembs); 487235537Sgber 488235537Sgber free(nsi, M_NANDFSTEMP); 489235537Sgber return (error); 490235537Sgber} 491235537Sgber 492235537Sgberint 493235537Sgbernandfs_get_segment_info(struct nandfs_device *fsdev, struct nandfs_suinfo *nsi, 494235537Sgber uint32_t nmembs, uint64_t segment) 495235537Sgber{ 496235537Sgber 497235537Sgber return (nandfs_get_segment_info_filter(fsdev, nsi, nmembs, segment, 498235537Sgber NULL, 0, 0)); 499235537Sgber} 500235537Sgber 501235537Sgberint 502235537Sgbernandfs_get_segment_info_filter(struct nandfs_device *fsdev, 503235537Sgber struct nandfs_suinfo *nsi, uint32_t nmembs, uint64_t segment, 504235537Sgber uint64_t *nsegs, uint32_t filter, uint32_t nfilter) 505235537Sgber{ 506235537Sgber struct nandfs_segment_usage *su; 507235537Sgber struct nandfs_node *su_node; 508235537Sgber struct buf *bp; 509235537Sgber uint64_t curr, blocknr, blockoff, i; 510235537Sgber uint32_t flags; 511235537Sgber int err = 0; 512235537Sgber 513235537Sgber curr = ~(0); 514235537Sgber 515235537Sgber lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL); 516235537Sgber su_node = fsdev->nd_su_node; 517235537Sgber 518235537Sgber VOP_LOCK(NTOV(su_node), LK_SHARED); 519235537Sgber 520235537Sgber bp = NULL; 521235537Sgber if (nsegs != NULL) 522235537Sgber *nsegs = 0; 523235537Sgber for (i = 0; i < nmembs; segment++) { 524235537Sgber if (segment == fsdev->nd_fsdata.f_nsegments) 525235537Sgber break; 526235537Sgber 527235537Sgber nandfs_seg_usage_blk_offset(fsdev, segment, &blocknr, 528235537Sgber &blockoff); 529235537Sgber 530235537Sgber if (i == 0 || curr != blocknr) { 531235537Sgber if (bp != NULL) 532235537Sgber brelse(bp); 533235537Sgber err = nandfs_bread(su_node, blocknr, NOCRED, 534235537Sgber 0, &bp); 535235537Sgber if (err) { 536235537Sgber goto out; 537235537Sgber } 538235537Sgber curr = blocknr; 539235537Sgber } 540235537Sgber 541235537Sgber su = SU_USAGE_OFF(bp, blockoff); 542235537Sgber flags = su->su_flags; 543235537Sgber if (segment == fsdev->nd_seg_num || 544235537Sgber segment == fsdev->nd_next_seg_num) 545235537Sgber flags |= NANDFS_SEGMENT_USAGE_ACTIVE; 546235537Sgber 547235537Sgber if (nfilter != 0 && (flags & nfilter) != 0) 548235537Sgber continue; 549235537Sgber if (filter != 0 && (flags & filter) == 0) 550235537Sgber continue; 551235537Sgber 552235537Sgber nsi->nsi_num = segment; 553235537Sgber nsi->nsi_lastmod = su->su_lastmod; 554235537Sgber nsi->nsi_blocks = su->su_nblocks; 555235537Sgber nsi->nsi_flags = flags; 556235537Sgber nsi++; 557235537Sgber i++; 558235537Sgber if (nsegs != NULL) 559235537Sgber (*nsegs)++; 560235537Sgber } 561235537Sgber 562235537Sgberout: 563235537Sgber if (bp != NULL) 564235537Sgber brelse(bp); 565235537Sgber VOP_UNLOCK(NTOV(su_node), 0); 566235537Sgber lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL); 567235537Sgber 568235537Sgber return (err); 569235537Sgber} 570