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$"); 29235537Sgber 30235537Sgber#include "opt_ddb.h" 31235537Sgber 32235537Sgber#include <sys/param.h> 33235537Sgber#include <sys/systm.h> 34235537Sgber#include <sys/conf.h> 35235537Sgber#include <sys/kernel.h> 36235537Sgber#include <sys/lock.h> 37235537Sgber#include <sys/malloc.h> 38235537Sgber#include <sys/mount.h> 39235537Sgber#include <sys/mutex.h> 40235537Sgber#include <sys/namei.h> 41251171Sjeff#include <sys/rwlock.h> 42235537Sgber#include <sys/sysctl.h> 43235537Sgber#include <sys/vnode.h> 44235537Sgber#include <sys/buf.h> 45235537Sgber#include <sys/bio.h> 46235537Sgber#include <sys/libkern.h> 47235537Sgber 48235537Sgber#include <ddb/ddb.h> 49235537Sgber 50235537Sgber#include <vm/vm.h> 51235537Sgber#include <vm/vm_param.h> 52235537Sgber#include <vm/vm_kern.h> 53235537Sgber#include <vm/vm_page.h> 54235537Sgber 55235537Sgber#include <geom/geom.h> 56235537Sgber#include <geom/geom_vfs.h> 57235537Sgber 58235537Sgber#include <fs/nandfs/nandfs_mount.h> 59235537Sgber#include <fs/nandfs/nandfs.h> 60235537Sgber#include <fs/nandfs/nandfs_subr.h> 61235537Sgber 62235537Sgberstatic int 63235537Sgbernandfs_new_segment(struct nandfs_device *fsdev) 64235537Sgber{ 65235537Sgber int error = 0; 66235537Sgber uint64_t new; 67235537Sgber 68235537Sgber error = nandfs_alloc_segment(fsdev, &new); 69235537Sgber if (!error) { 70235537Sgber fsdev->nd_seg_num = fsdev->nd_next_seg_num; 71235537Sgber fsdev->nd_next_seg_num = new; 72235537Sgber } 73235537Sgber DPRINTF(SYNC, ("%s: new segment %jx next %jx error %d\n", 74235537Sgber __func__, (uintmax_t)fsdev->nd_seg_num, (uintmax_t)new, error)); 75235537Sgber if (error) 76235537Sgber nandfs_error("%s: cannot create segment error %d\n", 77235537Sgber __func__, error); 78235537Sgber 79235537Sgber return (error); 80235537Sgber} 81235537Sgber 82235537Sgberstatic int 83235537Sgbercreate_segment(struct nandfs_seginfo *seginfo) 84235537Sgber{ 85235537Sgber struct nandfs_segment *seg; 86235537Sgber struct nandfs_device *fsdev; 87235537Sgber struct nandfs_segment *prev; 88235537Sgber struct buf *bp; 89235537Sgber uint64_t start_block, curr; 90235537Sgber uint32_t blks_per_seg, nblocks; 91235537Sgber int error; 92235537Sgber 93235537Sgber fsdev = seginfo->fsdev; 94235537Sgber prev = seginfo->curseg; 95235537Sgber blks_per_seg = fsdev->nd_fsdata.f_blocks_per_segment; 96235537Sgber nblocks = fsdev->nd_last_segsum.ss_nblocks; 97235537Sgber 98235537Sgber if (!prev) { 99235537Sgber vfs_timestamp(&fsdev->nd_ts); 100235537Sgber /* Touch current segment */ 101235537Sgber error = nandfs_touch_segment(fsdev, fsdev->nd_seg_num); 102235537Sgber if (error) { 103235537Sgber nandfs_error("%s: cannot preallocate segment %jx\n", 104235537Sgber __func__, fsdev->nd_seg_num); 105235537Sgber return (error); 106235537Sgber } 107235537Sgber error = nandfs_touch_segment(fsdev, 0); 108235537Sgber if (error) { 109235537Sgber nandfs_error("%s: cannot dirty block with segment 0\n", 110235537Sgber __func__); 111235537Sgber return (error); 112235537Sgber } 113235537Sgber start_block = fsdev->nd_last_pseg + (uint64_t)nblocks; 114235537Sgber /* 115235537Sgber * XXX Hack 116235537Sgber */ 117235537Sgber if (blks_per_seg - (start_block % blks_per_seg) - 1 == 0) 118235537Sgber start_block++; 119235537Sgber curr = nandfs_get_segnum_of_block(fsdev, start_block); 120235537Sgber /* Allocate new segment if last one is full */ 121235537Sgber if (fsdev->nd_seg_num != curr) { 122235537Sgber error = nandfs_new_segment(fsdev); 123235537Sgber if (error) { 124235537Sgber nandfs_error("%s: cannot create new segment\n", 125235537Sgber __func__); 126235537Sgber return (error); 127235537Sgber } 128235537Sgber /* 129235537Sgber * XXX Hack 130235537Sgber */ 131235537Sgber nandfs_get_segment_range(fsdev, fsdev->nd_seg_num, &start_block, NULL); 132235537Sgber } 133235537Sgber } else { 134235537Sgber nandfs_get_segment_range(fsdev, fsdev->nd_next_seg_num, 135235537Sgber &start_block, NULL); 136235537Sgber 137235537Sgber /* Touch current segment and allocate and touch new one */ 138235537Sgber error = nandfs_new_segment(fsdev); 139235537Sgber if (error) { 140235537Sgber nandfs_error("%s: cannot create next segment\n", 141235537Sgber __func__); 142235537Sgber return (error); 143235537Sgber } 144235537Sgber 145235537Sgber /* Reiterate in case new buf is dirty */ 146235537Sgber seginfo->reiterate = 1; 147235537Sgber } 148235537Sgber 149235537Sgber /* Allocate and initialize nandfs_segment structure */ 150235537Sgber seg = malloc(sizeof(*seg), M_DEVBUF, M_WAITOK|M_ZERO); 151235537Sgber TAILQ_INIT(&seg->segsum); 152235537Sgber TAILQ_INIT(&seg->data); 153235537Sgber seg->fsdev = fsdev; 154235537Sgber seg->start_block = start_block; 155235537Sgber seg->num_blocks = blks_per_seg - (start_block % blks_per_seg) - 1; 156235537Sgber seg->seg_num = fsdev->nd_seg_num; 157235537Sgber seg->seg_next = fsdev->nd_next_seg_num; 158235537Sgber seg->segsum_blocks = 1; 159235537Sgber seg->bytes_left = fsdev->nd_blocksize - 160235537Sgber sizeof(struct nandfs_segment_summary); 161235537Sgber seg->segsum_bytes = sizeof(struct nandfs_segment_summary); 162235537Sgber 163235537Sgber /* Allocate buffer for segment summary */ 164235537Sgber bp = getblk(fsdev->nd_devvp, nandfs_block_to_dblock(fsdev, 165235537Sgber seg->start_block), fsdev->nd_blocksize, 0, 0, 0); 166235537Sgber bzero(bp->b_data, seginfo->fsdev->nd_blocksize); 167235537Sgber bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; 168235537Sgber bp->b_flags |= B_MANAGED; 169235537Sgber 170235537Sgber /* Add buffer to segment */ 171235537Sgber TAILQ_INSERT_TAIL(&seg->segsum, bp, b_cluster.cluster_entry); 172235537Sgber seg->current_off = bp->b_data + sizeof(struct nandfs_segment_summary); 173235537Sgber 174235537Sgber DPRINTF(SYNC, ("%s: seg %p : initial settings: start %#jx size :%#x\n", 175235537Sgber __func__, seg, (uintmax_t)seg->start_block, seg->num_blocks)); 176235537Sgber DPRINTF(SYNC, ("%s: seg->seg_num %#jx cno %#jx next %#jx\n", __func__, 177235537Sgber (uintmax_t)seg->seg_num, (uintmax_t)(fsdev->nd_last_cno + 1), 178235537Sgber (uintmax_t)seg->seg_next)); 179235537Sgber 180235537Sgber if (!prev) 181235537Sgber LIST_INSERT_HEAD(&seginfo->seg_list, seg, seg_link); 182235537Sgber else 183235537Sgber LIST_INSERT_AFTER(prev, seg, seg_link); 184235537Sgber 185235537Sgber seginfo->curseg = seg; 186235537Sgber 187235537Sgber return (0); 188235537Sgber} 189235537Sgber 190235537Sgberstatic int 191235537Sgberdelete_segment(struct nandfs_seginfo *seginfo) 192235537Sgber{ 193235537Sgber struct nandfs_segment *seg, *tseg; 194235537Sgber struct buf *bp, *tbp; 195235537Sgber 196235537Sgber LIST_FOREACH_SAFE(seg, &seginfo->seg_list, seg_link, tseg) { 197235537Sgber TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, 198235537Sgber tbp) { 199235537Sgber TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry); 200235537Sgber bp->b_flags &= ~B_MANAGED; 201235537Sgber brelse(bp); 202297793Spfg } 203235537Sgber 204235537Sgber LIST_REMOVE(seg, seg_link); 205235537Sgber free(seg, M_DEVBUF); 206235537Sgber } 207235537Sgber 208235537Sgber return (0); 209235537Sgber} 210235537Sgber 211235537Sgberstatic int 212235537Sgbercreate_seginfo(struct nandfs_device *fsdev, struct nandfs_seginfo **seginfo) 213235537Sgber{ 214235537Sgber struct nandfs_seginfo *info; 215235537Sgber 216235537Sgber info = malloc(sizeof(*info), M_DEVBUF, M_WAITOK); 217235537Sgber 218235537Sgber LIST_INIT(&info->seg_list); 219235537Sgber info->fsdev = fsdev; 220235537Sgber info->curseg = NULL; 221235537Sgber info->blocks = 0; 222235537Sgber *seginfo = info; 223235537Sgber fsdev->nd_seginfo = info; 224235537Sgber return (0); 225235537Sgber} 226235537Sgber 227235537Sgberstatic int 228235537Sgberdelete_seginfo(struct nandfs_seginfo *seginfo) 229235537Sgber{ 230235537Sgber struct nandfs_device *nffsdev; 231235537Sgber 232235537Sgber nffsdev = seginfo->fsdev; 233235537Sgber delete_segment(seginfo); 234235537Sgber nffsdev->nd_seginfo = NULL; 235235537Sgber free(seginfo, M_DEVBUF); 236235537Sgber 237235537Sgber return (0); 238235537Sgber} 239235537Sgber 240235537Sgberstatic int 241235537Sgbernandfs_create_superroot_block(struct nandfs_seginfo *seginfo, 242235537Sgber struct buf **newbp) 243235537Sgber{ 244235537Sgber struct buf *bp; 245235537Sgber int error; 246235537Sgber 247235537Sgber bp = nandfs_geteblk(seginfo->fsdev->nd_blocksize, GB_NOWAIT_BD); 248235537Sgber 249235537Sgber bzero(bp->b_data, seginfo->fsdev->nd_blocksize); 250235537Sgber bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; 251235537Sgber bp->b_flags |= B_MANAGED; 252235537Sgber 253235537Sgber if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) { 254235537Sgber error = create_segment(seginfo); 255235537Sgber if (error) { 256235537Sgber brelse(bp); 257235537Sgber nandfs_error("%s: no segment for superroot\n", 258235537Sgber __func__); 259235537Sgber return (error); 260235537Sgber } 261235537Sgber } 262235537Sgber 263235537Sgber TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry); 264235537Sgber 265235537Sgber seginfo->curseg->nblocks++; 266235537Sgber seginfo->curseg->num_blocks--; 267235537Sgber seginfo->blocks++; 268235537Sgber 269235537Sgber *newbp = bp; 270235537Sgber return (0); 271235537Sgber} 272235537Sgber 273235537Sgberstatic int 274235537Sgbernandfs_add_superroot(struct nandfs_seginfo *seginfo) 275235537Sgber{ 276235537Sgber struct nandfs_device *fsdev; 277235537Sgber struct nandfs_super_root *sr; 278235537Sgber struct buf *bp = NULL; 279235537Sgber uint64_t crc_skip; 280235537Sgber uint32_t crc_calc; 281235537Sgber int error; 282235537Sgber 283235537Sgber fsdev = seginfo->fsdev; 284235537Sgber 285235537Sgber error = nandfs_create_superroot_block(seginfo, &bp); 286235537Sgber if (error) { 287235537Sgber nandfs_error("%s: cannot add superroot\n", __func__); 288235537Sgber return (error); 289235537Sgber } 290235537Sgber 291235537Sgber sr = (struct nandfs_super_root *)bp->b_data; 292235537Sgber /* Save superroot CRC */ 293235537Sgber sr->sr_bytes = NANDFS_SR_BYTES; 294235537Sgber sr->sr_flags = 0; 295235537Sgber sr->sr_nongc_ctime = 0; 296235537Sgber 297235537Sgber memcpy(&sr->sr_dat, &fsdev->nd_dat_node->nn_inode, 298235537Sgber sizeof(struct nandfs_inode)); 299235537Sgber memcpy(&sr->sr_cpfile, &fsdev->nd_cp_node->nn_inode, 300235537Sgber sizeof(struct nandfs_inode)); 301235537Sgber memcpy(&sr->sr_sufile, &fsdev->nd_su_node->nn_inode, 302235537Sgber sizeof(struct nandfs_inode)); 303235537Sgber 304235537Sgber crc_skip = sizeof(sr->sr_sum); 305235537Sgber crc_calc = crc32((uint8_t *)sr + crc_skip, NANDFS_SR_BYTES - crc_skip); 306235537Sgber 307235537Sgber sr->sr_sum = crc_calc; 308235537Sgber 309235537Sgber bp->b_flags |= B_MANAGED; 310235537Sgber bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; 311235537Sgber 312235537Sgber bp->b_flags &= ~B_INVAL; 313235537Sgber nandfs_dirty_bufs_increment(fsdev); 314235537Sgber DPRINTF(SYNC, ("%s: bp:%p\n", __func__, bp)); 315235537Sgber 316235537Sgber return (0); 317235537Sgber} 318235537Sgber 319235537Sgberstatic int 320235537Sgbernandfs_add_segsum_block(struct nandfs_seginfo *seginfo, struct buf **newbp) 321235537Sgber{ 322235537Sgber struct nandfs_device *fsdev; 323235537Sgber nandfs_daddr_t blk; 324235537Sgber struct buf *bp; 325235537Sgber int error; 326235537Sgber 327235537Sgber if (!(seginfo->curseg) || seginfo->curseg->num_blocks <= 1) { 328235537Sgber error = create_segment(seginfo); 329235537Sgber if (error) { 330235537Sgber nandfs_error("%s: error:%d when creating segment\n", 331235537Sgber __func__, error); 332235537Sgber return (error); 333235537Sgber } 334235537Sgber *newbp = TAILQ_FIRST(&seginfo->curseg->segsum); 335235537Sgber return (0); 336235537Sgber } 337235537Sgber 338235537Sgber fsdev = seginfo->fsdev; 339235537Sgber blk = nandfs_block_to_dblock(fsdev, seginfo->curseg->start_block + 340235537Sgber seginfo->curseg->segsum_blocks); 341235537Sgber 342235537Sgber bp = getblk(fsdev->nd_devvp, blk, fsdev->nd_blocksize, 0, 0, 0); 343235537Sgber 344235537Sgber bzero(bp->b_data, seginfo->fsdev->nd_blocksize); 345235537Sgber bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; 346235537Sgber bp->b_flags |= B_MANAGED; 347235537Sgber 348235537Sgber TAILQ_INSERT_TAIL(&seginfo->curseg->segsum, bp, 349235537Sgber b_cluster.cluster_entry); 350235537Sgber seginfo->curseg->num_blocks--; 351235537Sgber 352235537Sgber seginfo->curseg->segsum_blocks++; 353235537Sgber seginfo->curseg->bytes_left = seginfo->fsdev->nd_blocksize; 354235537Sgber seginfo->curseg->current_off = bp->b_data; 355235537Sgber seginfo->blocks++; 356235537Sgber 357235537Sgber *newbp = bp; 358235537Sgber 359235537Sgber DPRINTF(SYNC, ("%s: bp %p\n", __func__, bp)); 360235537Sgber 361235537Sgber return (0); 362235537Sgber} 363235537Sgber 364235537Sgberstatic int 365235537Sgbernandfs_add_blocks(struct nandfs_seginfo *seginfo, struct nandfs_node *node, 366235537Sgber struct buf *bp) 367235537Sgber{ 368235537Sgber union nandfs_binfo *binfo; 369235537Sgber struct buf *seg_bp; 370235537Sgber int error; 371235537Sgber 372235537Sgber if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) { 373235537Sgber error = create_segment(seginfo); 374235537Sgber if (error) { 375235537Sgber nandfs_error("%s: error:%d when creating segment\n", 376235537Sgber __func__, error); 377235537Sgber return (error); 378235537Sgber } 379235537Sgber } 380235537Sgber 381235537Sgber if (seginfo->curseg->bytes_left < sizeof(union nandfs_binfo)) { 382235537Sgber error = nandfs_add_segsum_block(seginfo, &seg_bp); 383235537Sgber if (error) { 384235537Sgber nandfs_error("%s: error:%d when adding segsum\n", 385235537Sgber __func__, error); 386235537Sgber return (error); 387235537Sgber } 388235537Sgber } 389235537Sgber binfo = (union nandfs_binfo *)seginfo->curseg->current_off; 390235537Sgber 391235537Sgber if (node->nn_ino != NANDFS_DAT_INO) { 392235537Sgber binfo->bi_v.bi_blkoff = bp->b_lblkno; 393235537Sgber binfo->bi_v.bi_ino = node->nn_ino; 394235537Sgber } else { 395235537Sgber binfo->bi_dat.bi_blkoff = bp->b_lblkno; 396235537Sgber binfo->bi_dat.bi_ino = node->nn_ino; 397235537Sgber if (NANDFS_IS_INDIRECT(bp)) 398235537Sgber binfo->bi_dat.bi_level = 1; 399235537Sgber else 400235537Sgber binfo->bi_dat.bi_level = 0; 401235537Sgber } 402235537Sgber binfo++; 403235537Sgber 404235537Sgber seginfo->curseg->bytes_left -= sizeof(union nandfs_binfo); 405235537Sgber seginfo->curseg->segsum_bytes += sizeof(union nandfs_binfo); 406235537Sgber seginfo->curseg->current_off = (char *)binfo; 407235537Sgber 408235537Sgber TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry); 409235537Sgber 410235537Sgber seginfo->curseg->nbinfos++; 411235537Sgber seginfo->curseg->nblocks++; 412235537Sgber seginfo->curseg->num_blocks--; 413235537Sgber seginfo->blocks++; 414235537Sgber 415235537Sgber DPRINTF(SYNC, ("%s: bp (%p) number %x (left %x)\n", 416235537Sgber __func__, bp, seginfo->curseg->nblocks, 417235537Sgber seginfo->curseg->num_blocks)); 418235537Sgber return (0); 419235537Sgber} 420235537Sgber 421235537Sgberstatic int 422235537Sgbernandfs_iterate_dirty_buf(struct vnode *vp, struct nandfs_seginfo *seginfo, 423235537Sgber uint8_t hold) 424235537Sgber{ 425235537Sgber struct buf *bp, *tbd; 426235537Sgber struct bufobj *bo; 427235537Sgber struct nandfs_node *node; 428235537Sgber int error; 429235537Sgber 430235537Sgber node = VTON(vp); 431235537Sgber bo = &vp->v_bufobj; 432235537Sgber 433235537Sgber ASSERT_VOP_ELOCKED(vp, __func__); 434235537Sgber 435235537Sgber /* Iterate dirty data bufs */ 436235537Sgber TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, tbd) { 437235537Sgber DPRINTF(SYNC, ("%s: vp (%p): bp (%p) with lblkno %jx ino %jx " 438235537Sgber "add buf\n", __func__, vp, bp, bp->b_lblkno, node->nn_ino)); 439235537Sgber 440235537Sgber if (!(NANDFS_ISGATHERED(bp))) { 441235537Sgber error = nandfs_bmap_update_dat(node, 442235537Sgber nandfs_vblk_get(bp), bp); 443235537Sgber if (error) 444235537Sgber return (error); 445235537Sgber NANDFS_GATHER(bp); 446235537Sgber nandfs_add_blocks(seginfo, node, bp); 447235537Sgber } 448235537Sgber } 449235537Sgber 450235537Sgber return (0); 451235537Sgber} 452235537Sgber 453235537Sgberstatic int 454235537Sgbernandfs_iterate_system_vnode(struct nandfs_node *node, 455235537Sgber struct nandfs_seginfo *seginfo) 456235537Sgber{ 457235537Sgber struct vnode *vp; 458235537Sgber int nblocks; 459235537Sgber uint8_t hold = 0; 460235537Sgber 461235537Sgber if (node->nn_ino != NANDFS_IFILE_INO) 462235537Sgber hold = 1; 463235537Sgber 464235537Sgber vp = NTOV(node); 465235537Sgber 466235537Sgber nblocks = vp->v_bufobj.bo_dirty.bv_cnt; 467235537Sgber DPRINTF(SYNC, ("%s: vp (%p): nblocks %x ino %jx\n", 468235537Sgber __func__, vp, nblocks, node->nn_ino)); 469235537Sgber 470235537Sgber if (nblocks) 471235537Sgber nandfs_iterate_dirty_buf(vp, seginfo, hold); 472235537Sgber 473235537Sgber return (0); 474235537Sgber} 475235537Sgber 476235537Sgberstatic int 477235537Sgbernandfs_iterate_dirty_vnodes(struct mount *mp, struct nandfs_seginfo *seginfo) 478235537Sgber{ 479235537Sgber struct nandfs_node *nandfs_node; 480235537Sgber struct vnode *vp, *mvp; 481235537Sgber struct thread *td; 482294200Srpokala struct bufobj *bo; 483245000Skib int error, update; 484235537Sgber 485235537Sgber td = curthread; 486235537Sgber 487245000Skib MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) { 488235537Sgber update = 0; 489235537Sgber 490245000Skib if (mp->mnt_syncer == vp || VOP_ISLOCKED(vp)) { 491235537Sgber VI_UNLOCK(vp); 492235537Sgber continue; 493235537Sgber } 494245000Skib if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK | LK_NOWAIT, td) != 0) 495235537Sgber continue; 496235537Sgber 497235537Sgber nandfs_node = VTON(vp); 498235537Sgber if (nandfs_node->nn_flags & IN_MODIFIED) { 499235537Sgber nandfs_node->nn_flags &= ~(IN_MODIFIED); 500235537Sgber update = 1; 501235537Sgber } 502235537Sgber 503294200Srpokala bo = &vp->v_bufobj; 504294200Srpokala BO_LOCK(bo); 505235537Sgber if (vp->v_bufobj.bo_dirty.bv_cnt) { 506235537Sgber error = nandfs_iterate_dirty_buf(vp, seginfo, 0); 507235537Sgber if (error) { 508235537Sgber nandfs_error("%s: cannot iterate vnode:%p " 509235537Sgber "err:%d\n", __func__, vp, error); 510235537Sgber vput(vp); 511294200Srpokala BO_UNLOCK(bo); 512235537Sgber return (error); 513235537Sgber } 514235537Sgber update = 1; 515235537Sgber } else 516235537Sgber vput(vp); 517294200Srpokala BO_UNLOCK(bo); 518235537Sgber 519235537Sgber if (update) 520235537Sgber nandfs_node_update(nandfs_node); 521235537Sgber } 522235537Sgber 523235537Sgber return (0); 524235537Sgber} 525235537Sgber 526235537Sgberstatic int 527235537Sgbernandfs_update_phys_block(struct nandfs_device *fsdev, struct buf *bp, 528235537Sgber uint64_t phys_blknr, union nandfs_binfo *binfo) 529235537Sgber{ 530235537Sgber struct nandfs_node *node, *dat; 531235537Sgber struct vnode *vp; 532235537Sgber uint64_t new_blknr; 533235537Sgber int error; 534235537Sgber 535235537Sgber vp = bp->b_vp; 536235537Sgber node = VTON(vp); 537235537Sgber new_blknr = nandfs_vblk_get(bp); 538235537Sgber dat = fsdev->nd_dat_node; 539235537Sgber 540235537Sgber DPRINTF(BMAP, ("%s: ino %#jx lblk %#jx: vblk %#jx -> %#jx\n", 541235537Sgber __func__, (uintmax_t)node->nn_ino, (uintmax_t)bp->b_lblkno, 542235537Sgber (uintmax_t)new_blknr, (uintmax_t)phys_blknr)); 543235537Sgber 544235537Sgber if (node->nn_ino != NANDFS_DAT_INO) { 545235537Sgber KASSERT((new_blknr != 0), ("vblk for bp %p is 0", bp)); 546235537Sgber 547235537Sgber nandfs_vblock_assign(fsdev, new_blknr, phys_blknr); 548235537Sgber binfo->bi_v.bi_vblocknr = new_blknr; 549235537Sgber binfo->bi_v.bi_blkoff = bp->b_lblkno; 550235537Sgber binfo->bi_v.bi_ino = node->nn_ino; 551235537Sgber } else { 552235537Sgber VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); 553235537Sgber error = nandfs_bmap_update_block(node, bp, phys_blknr); 554235537Sgber if (error) { 555235537Sgber nandfs_error("%s: error updating block:%jx for bp:%p\n", 556235537Sgber __func__, (uintmax_t)phys_blknr, bp); 557235537Sgber VOP_UNLOCK(NTOV(dat), 0); 558235537Sgber return (error); 559235537Sgber } 560235537Sgber VOP_UNLOCK(NTOV(dat), 0); 561235537Sgber binfo->bi_dat.bi_blkoff = bp->b_lblkno; 562235537Sgber binfo->bi_dat.bi_ino = node->nn_ino; 563235537Sgber if (NANDFS_IS_INDIRECT(bp)) 564235537Sgber binfo->bi_dat.bi_level = 1; 565235537Sgber else 566235537Sgber binfo->bi_dat.bi_level = 0; 567235537Sgber } 568235537Sgber 569235537Sgber return (0); 570235537Sgber} 571235537Sgber 572235537Sgber#define NBINFO(off) ((off) + sizeof(union nandfs_binfo)) 573235537Sgberstatic int 574235537Sgbernandfs_segment_assign_pblk(struct nandfs_segment *nfsseg) 575235537Sgber{ 576235537Sgber struct nandfs_device *fsdev; 577235537Sgber union nandfs_binfo *binfo; 578235537Sgber struct buf *bp, *seg_bp; 579235537Sgber uint64_t blocknr; 580235537Sgber uint32_t curr_off, blocksize; 581235537Sgber int error; 582235537Sgber 583235537Sgber fsdev = nfsseg->fsdev; 584235537Sgber blocksize = fsdev->nd_blocksize; 585235537Sgber 586235537Sgber blocknr = nfsseg->start_block + nfsseg->segsum_blocks; 587235537Sgber seg_bp = TAILQ_FIRST(&nfsseg->segsum); 588235537Sgber DPRINTF(SYNC, ("%s: seg:%p segsum bp:%p data:%p\n", 589235537Sgber __func__, nfsseg, seg_bp, seg_bp->b_data)); 590235537Sgber 591235537Sgber binfo = (union nandfs_binfo *)(seg_bp->b_data + 592235537Sgber sizeof(struct nandfs_segment_summary)); 593235537Sgber curr_off = sizeof(struct nandfs_segment_summary); 594235537Sgber 595235537Sgber TAILQ_FOREACH(bp, &nfsseg->data, b_cluster.cluster_entry) { 596235537Sgber KASSERT((bp->b_vp), ("bp %p has not vp", bp)); 597235537Sgber 598235537Sgber DPRINTF(BMAP, ("\n\n%s: assign buf %p for ino %#jx next %p\n", 599235537Sgber __func__, bp, (uintmax_t)VTON(bp->b_vp)->nn_ino, 600235537Sgber TAILQ_NEXT(bp, b_cluster.cluster_entry))); 601235537Sgber 602235537Sgber if (NBINFO(curr_off) > blocksize) { 603235537Sgber seg_bp = TAILQ_NEXT(seg_bp, b_cluster.cluster_entry); 604235537Sgber binfo = (union nandfs_binfo *)seg_bp->b_data; 605235537Sgber curr_off = 0; 606235537Sgber DPRINTF(SYNC, ("%s: next segsum %p data %p\n", 607235537Sgber __func__, seg_bp, seg_bp->b_data)); 608235537Sgber } 609235537Sgber 610235537Sgber error = nandfs_update_phys_block(fsdev, bp, blocknr, binfo); 611235537Sgber if (error) { 612235537Sgber nandfs_error("%s: err:%d when updatinng phys block:%jx" 613235537Sgber " for bp:%p and binfo:%p\n", __func__, error, 614235537Sgber (uintmax_t)blocknr, bp, binfo); 615235537Sgber return (error); 616235537Sgber } 617235537Sgber binfo++; 618235537Sgber curr_off = NBINFO(curr_off); 619235537Sgber 620235537Sgber blocknr++; 621235537Sgber } 622235537Sgber 623235537Sgber return (0); 624235537Sgber} 625235537Sgber 626235537Sgberstatic int 627235537Sgbernandfs_seginfo_assign_pblk(struct nandfs_seginfo *seginfo) 628235537Sgber{ 629235537Sgber struct nandfs_segment *nfsseg; 630235537Sgber int error = 0; 631235537Sgber 632235537Sgber LIST_FOREACH(nfsseg, &seginfo->seg_list, seg_link) { 633235537Sgber error = nandfs_segment_assign_pblk(nfsseg); 634235537Sgber if (error) 635235537Sgber break; 636235537Sgber } 637235537Sgber 638235537Sgber return (error); 639235537Sgber} 640235537Sgber 641235537Sgberstatic struct nandfs_segment_summary * 642235537Sgbernandfs_fill_segsum(struct nandfs_segment *seg, int has_sr) 643235537Sgber{ 644235537Sgber struct nandfs_segment_summary *ss; 645235537Sgber struct nandfs_device *fsdev; 646235537Sgber struct buf *bp; 647235537Sgber uint32_t rest, segsum_size, blocksize, crc_calc; 648235537Sgber uint16_t flags; 649235537Sgber uint8_t *crc_area, crc_skip; 650235537Sgber 651235537Sgber DPRINTF(SYNC, ("%s: seg %#jx nblocks %#x sumbytes %#x\n", 652235537Sgber __func__, (uintmax_t) seg->seg_num, 653235537Sgber seg->nblocks + seg->segsum_blocks, 654235537Sgber seg->segsum_bytes)); 655235537Sgber 656235537Sgber fsdev = seg->fsdev; 657235537Sgber 658235537Sgber flags = NANDFS_SS_LOGBGN | NANDFS_SS_LOGEND; 659235537Sgber if (has_sr) 660235537Sgber flags |= NANDFS_SS_SR; 661235537Sgber 662235537Sgber bp = TAILQ_FIRST(&seg->segsum); 663235537Sgber ss = (struct nandfs_segment_summary *) bp->b_data; 664235537Sgber ss->ss_magic = NANDFS_SEGSUM_MAGIC; 665235537Sgber ss->ss_bytes = sizeof(struct nandfs_segment_summary); 666235537Sgber ss->ss_flags = flags; 667235537Sgber ss->ss_seq = ++(fsdev->nd_seg_sequence); 668235537Sgber ss->ss_create = fsdev->nd_ts.tv_sec; 669235537Sgber nandfs_get_segment_range(fsdev, seg->seg_next, &ss->ss_next, NULL); 670235537Sgber ss->ss_nblocks = seg->nblocks + seg->segsum_blocks; 671235537Sgber ss->ss_nbinfos = seg->nbinfos; 672235537Sgber ss->ss_sumbytes = seg->segsum_bytes; 673235537Sgber 674235537Sgber crc_skip = sizeof(ss->ss_datasum) + sizeof(ss->ss_sumsum); 675235537Sgber blocksize = seg->fsdev->nd_blocksize; 676235537Sgber 677235537Sgber segsum_size = seg->segsum_bytes - crc_skip; 678235537Sgber rest = min(seg->segsum_bytes, blocksize) - crc_skip; 679235537Sgber crc_area = (uint8_t *)ss + crc_skip; 680235537Sgber crc_calc = ~0U; 681235537Sgber while (segsum_size > 0) { 682235537Sgber crc_calc = crc32_raw(crc_area, rest, crc_calc); 683235537Sgber segsum_size -= rest; 684235537Sgber if (!segsum_size) 685235537Sgber break; 686235537Sgber bp = TAILQ_NEXT(bp, b_cluster.cluster_entry); 687235537Sgber crc_area = (uint8_t *)bp->b_data; 688235537Sgber rest = segsum_size <= blocksize ? segsum_size : blocksize; 689235537Sgber } 690235537Sgber ss->ss_sumsum = crc_calc ^ ~0U; 691235537Sgber 692235537Sgber return (ss); 693235537Sgber 694235537Sgber} 695235537Sgber 696235537Sgberstatic int 697235537Sgbernandfs_save_buf(struct buf *bp, uint64_t blocknr, struct nandfs_device *fsdev) 698235537Sgber{ 699235537Sgber struct bufobj *bo; 700235537Sgber int error; 701235537Sgber 702235537Sgber bo = &fsdev->nd_devvp->v_bufobj; 703235537Sgber 704235537Sgber bp->b_blkno = nandfs_block_to_dblock(fsdev, blocknr); 705235537Sgber bp->b_iooffset = dbtob(bp->b_blkno); 706235537Sgber 707235537Sgber KASSERT(bp->b_bufobj != NULL, ("no bufobj for %p", bp)); 708235537Sgber if (bp->b_bufobj != bo) { 709235537Sgber BO_LOCK(bp->b_bufobj); 710235537Sgber BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, 711251171Sjeff BO_LOCKPTR(bp->b_bufobj)); 712235537Sgber KASSERT(BUF_ISLOCKED(bp), ("Problem with locking buffer")); 713235537Sgber } 714235537Sgber 715235537Sgber DPRINTF(SYNC, ("%s: buf: %p offset %#jx blk %#jx size %#x\n", 716235537Sgber __func__, bp, (uintmax_t)bp->b_offset, (uintmax_t)blocknr, 717235537Sgber fsdev->nd_blocksize)); 718235537Sgber 719235537Sgber NANDFS_UNGATHER(bp); 720235537Sgber nandfs_buf_clear(bp, 0xffffffff); 721235537Sgber bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED); 722235537Sgber error = bwrite(bp); 723235537Sgber if (error) { 724235537Sgber nandfs_error("%s: error:%d when writing buffer:%p\n", 725235537Sgber __func__, error, bp); 726235537Sgber return (error); 727235537Sgber } 728235537Sgber return (error); 729235537Sgber} 730235537Sgber 731235537Sgberstatic void 732235537Sgbernandfs_clean_buf(struct nandfs_device *fsdev, struct buf *bp) 733235537Sgber{ 734235537Sgber 735235537Sgber DPRINTF(SYNC, ("%s: buf: %p\n", __func__, bp)); 736235537Sgber 737235537Sgber NANDFS_UNGATHER(bp); 738235537Sgber nandfs_buf_clear(bp, 0xffffffff); 739235537Sgber bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED); 740235537Sgber nandfs_undirty_buf_fsdev(fsdev, bp); 741235537Sgber} 742235537Sgber 743235537Sgberstatic void 744235537Sgbernandfs_clean_segblocks(struct nandfs_segment *seg, uint8_t unlock) 745235537Sgber{ 746235537Sgber struct nandfs_device *fsdev = seg->fsdev; 747235537Sgber struct nandfs_segment *next_seg; 748235537Sgber struct buf *bp, *tbp, *next_bp; 749235537Sgber struct vnode *vp, *next_vp; 750235537Sgber 751235537Sgber VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE); 752235537Sgber TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) { 753235537Sgber TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry); 754235537Sgber nandfs_clean_buf(fsdev, bp); 755297793Spfg } 756235537Sgber 757235537Sgber TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) { 758235537Sgber TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry); 759235537Sgber 760235537Sgber /* 761235537Sgber * If bp is not super-root and vnode is not currently 762235537Sgber * locked lock it. 763235537Sgber */ 764235537Sgber vp = bp->b_vp; 765235537Sgber next_vp = NULL; 766235537Sgber next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry); 767235537Sgber if (!next_bp) { 768235537Sgber next_seg = LIST_NEXT(seg, seg_link); 769235537Sgber if (next_seg) 770235537Sgber next_bp = TAILQ_FIRST(&next_seg->data); 771235537Sgber } 772235537Sgber 773235537Sgber if (next_bp) 774235537Sgber next_vp = next_bp->b_vp; 775235537Sgber 776235537Sgber nandfs_clean_buf(fsdev, bp); 777235537Sgber 778235537Sgber if (unlock && vp != NULL && next_vp != vp && 779235537Sgber !NANDFS_SYS_NODE(VTON(vp)->nn_ino)) 780235537Sgber vput(vp); 781235537Sgber 782235537Sgber nandfs_dirty_bufs_decrement(fsdev); 783235537Sgber } 784235537Sgber 785235537Sgber VOP_UNLOCK(fsdev->nd_devvp, 0); 786235537Sgber} 787235537Sgber 788235537Sgberstatic int 789235537Sgbernandfs_save_segblocks(struct nandfs_segment *seg, uint8_t unlock) 790235537Sgber{ 791235537Sgber struct nandfs_device *fsdev = seg->fsdev; 792235537Sgber struct nandfs_segment *next_seg; 793235537Sgber struct buf *bp, *tbp, *next_bp; 794235537Sgber struct vnode *vp, *next_vp; 795235537Sgber uint64_t blocknr; 796235537Sgber uint32_t i = 0; 797235537Sgber int error = 0; 798235537Sgber 799235537Sgber VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE); 800235537Sgber TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) { 801235537Sgber TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry); 802235537Sgber blocknr = seg->start_block + i; 803235537Sgber error = nandfs_save_buf(bp, blocknr, fsdev); 804235537Sgber if (error) { 805235537Sgber nandfs_error("%s: error saving buf: %p blocknr:%jx\n", 806235537Sgber __func__, bp, (uintmax_t)blocknr); 807235537Sgber goto out; 808235537Sgber } 809235537Sgber i++; 810297793Spfg } 811235537Sgber 812235537Sgber i = 0; 813235537Sgber TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) { 814235537Sgber TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry); 815235537Sgber 816235537Sgber blocknr = seg->start_block + seg->segsum_blocks + i; 817235537Sgber /* 818235537Sgber * If bp is not super-root and vnode is not currently 819235537Sgber * locked lock it. 820235537Sgber */ 821235537Sgber vp = bp->b_vp; 822235537Sgber next_vp = NULL; 823235537Sgber next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry); 824235537Sgber if (!next_bp) { 825235537Sgber next_seg = LIST_NEXT(seg, seg_link); 826235537Sgber if (next_seg) 827235537Sgber next_bp = TAILQ_FIRST(&next_seg->data); 828235537Sgber } 829235537Sgber 830235537Sgber if (next_bp) 831235537Sgber next_vp = next_bp->b_vp; 832235537Sgber 833235537Sgber error = nandfs_save_buf(bp, blocknr, fsdev); 834235537Sgber if (error) { 835235537Sgber nandfs_error("%s: error saving buf: %p blknr: %jx\n", 836235537Sgber __func__, bp, (uintmax_t)blocknr); 837235537Sgber if (unlock && vp != NULL && next_vp != vp && 838235537Sgber !NANDFS_SYS_NODE(VTON(vp)->nn_ino)) 839235537Sgber vput(vp); 840235537Sgber goto out; 841235537Sgber } 842235537Sgber 843235537Sgber if (unlock && vp != NULL && next_vp != vp && 844235537Sgber !NANDFS_SYS_NODE(VTON(vp)->nn_ino)) 845235537Sgber vput(vp); 846235537Sgber 847235537Sgber i++; 848235537Sgber nandfs_dirty_bufs_decrement(fsdev); 849235537Sgber } 850235537Sgberout: 851235537Sgber if (error) { 852235537Sgber nandfs_clean_segblocks(seg, unlock); 853235537Sgber VOP_UNLOCK(fsdev->nd_devvp, 0); 854235537Sgber return (error); 855235537Sgber } 856235537Sgber 857235537Sgber VOP_UNLOCK(fsdev->nd_devvp, 0); 858235537Sgber return (error); 859235537Sgber} 860235537Sgber 861235537Sgber 862235537Sgberstatic void 863235537Sgberclean_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock) 864235537Sgber{ 865235537Sgber struct nandfs_segment *seg; 866235537Sgber 867235537Sgber DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo)); 868235537Sgber 869235537Sgber LIST_FOREACH(seg, &seginfo->seg_list, seg_link) { 870235537Sgber nandfs_clean_segblocks(seg, unlock); 871235537Sgber } 872235537Sgber} 873235537Sgber 874235537Sgberstatic int 875235537Sgbersave_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock) 876235537Sgber{ 877235537Sgber struct nandfs_segment *seg; 878235537Sgber struct nandfs_device *fsdev; 879235537Sgber struct nandfs_segment_summary *ss; 880235537Sgber int error = 0; 881235537Sgber 882235537Sgber fsdev = seginfo->fsdev; 883235537Sgber 884235537Sgber DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo)); 885235537Sgber 886235537Sgber LIST_FOREACH(seg, &seginfo->seg_list, seg_link) { 887235537Sgber if (LIST_NEXT(seg, seg_link)) { 888235537Sgber nandfs_fill_segsum(seg, 0); 889235537Sgber error = nandfs_save_segblocks(seg, unlock); 890235537Sgber if (error) { 891235537Sgber nandfs_error("%s: error:%d saving seg:%p\n", 892235537Sgber __func__, error, seg); 893235537Sgber goto out; 894235537Sgber } 895235537Sgber } else { 896235537Sgber ss = nandfs_fill_segsum(seg, 1); 897235537Sgber fsdev->nd_last_segsum = *ss; 898235537Sgber error = nandfs_save_segblocks(seg, unlock); 899235537Sgber if (error) { 900235537Sgber nandfs_error("%s: error:%d saving seg:%p\n", 901235537Sgber __func__, error, seg); 902235537Sgber goto out; 903235537Sgber } 904235537Sgber fsdev->nd_last_cno++; 905235537Sgber fsdev->nd_last_pseg = seg->start_block; 906235537Sgber } 907235537Sgber } 908235537Sgberout: 909235537Sgber if (error) 910235537Sgber clean_seginfo(seginfo, unlock); 911235537Sgber return (error); 912235537Sgber} 913235537Sgber 914235537Sgberstatic void 915235537Sgbernandfs_invalidate_bufs(struct nandfs_device *fsdev, uint64_t segno) 916235537Sgber{ 917235537Sgber uint64_t start, end; 918235537Sgber struct buf *bp, *tbd; 919235537Sgber struct bufobj *bo; 920235537Sgber 921235537Sgber nandfs_get_segment_range(fsdev, segno, &start, &end); 922235537Sgber 923235537Sgber bo = &NTOV(fsdev->nd_gc_node)->v_bufobj; 924235537Sgber 925235537Sgber BO_LOCK(bo); 926235537Sgberrestart_locked_gc: 927235537Sgber TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, tbd) { 928235537Sgber if (!(bp->b_lblkno >= start && bp->b_lblkno <= end)) 929235537Sgber continue; 930235537Sgber 931235537Sgber if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) 932235537Sgber goto restart_locked_gc; 933235537Sgber 934235537Sgber bremfree(bp); 935235537Sgber bp->b_flags |= (B_INVAL | B_RELBUF); 936235537Sgber bp->b_flags &= ~(B_ASYNC | B_MANAGED); 937235537Sgber BO_UNLOCK(bo); 938235537Sgber brelse(bp); 939235537Sgber BO_LOCK(bo); 940235537Sgber } 941235537Sgber BO_UNLOCK(bo); 942235537Sgber} 943235537Sgber 944235537Sgber/* Process segments marks to free by cleaner */ 945235537Sgberstatic void 946235537Sgbernandfs_process_segments(struct nandfs_device *fsdev) 947235537Sgber{ 948235537Sgber uint64_t saved_segment; 949235537Sgber int i; 950235537Sgber 951235537Sgber if (fsdev->nd_free_base) { 952235537Sgber saved_segment = nandfs_get_segnum_of_block(fsdev, 953235537Sgber fsdev->nd_super.s_last_pseg); 954235537Sgber for (i = 0; i < fsdev->nd_free_count; i++) { 955235537Sgber if (fsdev->nd_free_base[i] == NANDFS_NOSEGMENT) 956235537Sgber continue; 957235537Sgber /* Update superblock if clearing segment point by it */ 958235537Sgber if (fsdev->nd_free_base[i] == saved_segment) { 959235537Sgber nandfs_write_superblock(fsdev); 960235537Sgber saved_segment = nandfs_get_segnum_of_block( 961235537Sgber fsdev, fsdev->nd_super.s_last_pseg); 962235537Sgber } 963235537Sgber nandfs_invalidate_bufs(fsdev, fsdev->nd_free_base[i]); 964235537Sgber nandfs_clear_segment(fsdev, fsdev->nd_free_base[i]); 965235537Sgber } 966235537Sgber 967235537Sgber free(fsdev->nd_free_base, M_NANDFSTEMP); 968235537Sgber fsdev->nd_free_base = NULL; 969235537Sgber fsdev->nd_free_count = 0; 970235537Sgber } 971235537Sgber} 972235537Sgber 973235537Sgber/* Collect and write dirty buffers */ 974235537Sgberint 975235537Sgbernandfs_sync_file(struct vnode *vp) 976235537Sgber{ 977235537Sgber struct nandfs_device *fsdev; 978235537Sgber struct nandfs_node *nandfs_node; 979235537Sgber struct nandfsmount *nmp; 980235537Sgber struct nandfs_node *dat, *su, *ifile, *cp; 981235537Sgber struct nandfs_seginfo *seginfo = NULL; 982235537Sgber struct nandfs_segment *seg; 983235537Sgber int update, error; 984235537Sgber int cno_changed; 985235537Sgber 986235537Sgber ASSERT_VOP_LOCKED(vp, __func__); 987235537Sgber DPRINTF(SYNC, ("%s: START\n", __func__)); 988235537Sgber 989235537Sgber error = 0; 990235537Sgber nmp = VFSTONANDFS(vp->v_mount); 991235537Sgber fsdev = nmp->nm_nandfsdev; 992235537Sgber 993235537Sgber dat = fsdev->nd_dat_node; 994235537Sgber su = fsdev->nd_su_node; 995235537Sgber cp = fsdev->nd_cp_node; 996235537Sgber ifile = nmp->nm_ifile_node; 997235537Sgber 998235537Sgber NANDFS_WRITEASSERT(fsdev); 999235537Sgber if (lockmgr(&fsdev->nd_seg_const, LK_UPGRADE, NULL) != 0) { 1000235537Sgber DPRINTF(SYNC, ("%s: lost shared lock\n", __func__)); 1001235537Sgber if (lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL) != 0) 1002235537Sgber panic("couldn't lock exclusive"); 1003235537Sgber } 1004235537Sgber DPRINTF(SYNC, ("%s: got lock\n", __func__)); 1005235537Sgber 1006235537Sgber VOP_LOCK(NTOV(su), LK_EXCLUSIVE); 1007235537Sgber create_seginfo(fsdev, &seginfo); 1008235537Sgber 1009235537Sgber update = 0; 1010235537Sgber 1011235537Sgber nandfs_node = VTON(vp); 1012235537Sgber if (nandfs_node->nn_flags & IN_MODIFIED) { 1013235537Sgber nandfs_node->nn_flags &= ~(IN_MODIFIED); 1014235537Sgber update = 1; 1015235537Sgber } 1016235537Sgber 1017235537Sgber if (vp->v_bufobj.bo_dirty.bv_cnt) { 1018235537Sgber error = nandfs_iterate_dirty_buf(vp, seginfo, 0); 1019235537Sgber if (error) { 1020235537Sgber clean_seginfo(seginfo, 0); 1021235537Sgber delete_seginfo(seginfo); 1022235537Sgber VOP_UNLOCK(NTOV(su), 0); 1023235537Sgber lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); 1024235537Sgber nandfs_error("%s: err:%d iterating dirty bufs vp:%p", 1025235537Sgber __func__, error, vp); 1026235537Sgber return (error); 1027235537Sgber } 1028235537Sgber update = 1; 1029235537Sgber } 1030235537Sgber 1031235537Sgber if (update) { 1032235537Sgber VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE); 1033235537Sgber error = nandfs_node_update(nandfs_node); 1034235537Sgber if (error) { 1035235537Sgber clean_seginfo(seginfo, 0); 1036235537Sgber delete_seginfo(seginfo); 1037235537Sgber VOP_UNLOCK(NTOV(ifile), 0); 1038235537Sgber VOP_UNLOCK(NTOV(su), 0); 1039235537Sgber lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); 1040235537Sgber nandfs_error("%s: err:%d updating vp:%p", 1041235537Sgber __func__, error, vp); 1042235537Sgber return (error); 1043235537Sgber } 1044235537Sgber VOP_UNLOCK(NTOV(ifile), 0); 1045235537Sgber } 1046235537Sgber 1047235537Sgber cno_changed = 0; 1048235537Sgber if (seginfo->blocks) { 1049235537Sgber VOP_LOCK(NTOV(cp), LK_EXCLUSIVE); 1050235537Sgber cno_changed = 1; 1051235537Sgber /* Create new checkpoint */ 1052235537Sgber error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1); 1053235537Sgber if (error) { 1054235537Sgber clean_seginfo(seginfo, 0); 1055235537Sgber delete_seginfo(seginfo); 1056235537Sgber VOP_UNLOCK(NTOV(cp), 0); 1057235537Sgber VOP_UNLOCK(NTOV(su), 0); 1058235537Sgber lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); 1059235537Sgber nandfs_error("%s: err:%d getting cp:%jx", 1060235537Sgber __func__, error, fsdev->nd_last_cno + 1); 1061235537Sgber return (error); 1062235537Sgber } 1063235537Sgber 1064235537Sgber /* Reiterate all blocks and assign physical block number */ 1065235537Sgber nandfs_seginfo_assign_pblk(seginfo); 1066235537Sgber 1067235537Sgber /* Fill checkpoint data */ 1068235537Sgber error = nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1, 1069235537Sgber &ifile->nn_inode, seginfo->blocks); 1070235537Sgber if (error) { 1071235537Sgber clean_seginfo(seginfo, 0); 1072235537Sgber delete_seginfo(seginfo); 1073235537Sgber VOP_UNLOCK(NTOV(cp), 0); 1074235537Sgber VOP_UNLOCK(NTOV(su), 0); 1075235537Sgber lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); 1076235537Sgber nandfs_error("%s: err:%d setting cp:%jx", 1077235537Sgber __func__, error, fsdev->nd_last_cno + 1); 1078235537Sgber return (error); 1079235537Sgber } 1080235537Sgber 1081235537Sgber VOP_UNLOCK(NTOV(cp), 0); 1082235537Sgber LIST_FOREACH(seg, &seginfo->seg_list, seg_link) 1083235537Sgber nandfs_update_segment(fsdev, seg->seg_num, 1084235537Sgber seg->nblocks + seg->segsum_blocks); 1085235537Sgber 1086235537Sgber VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); 1087235537Sgber error = save_seginfo(seginfo, 0); 1088235537Sgber if (error) { 1089235537Sgber clean_seginfo(seginfo, 0); 1090235537Sgber delete_seginfo(seginfo); 1091235537Sgber VOP_UNLOCK(NTOV(dat), 0); 1092235537Sgber VOP_UNLOCK(NTOV(su), 0); 1093235537Sgber lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); 1094235537Sgber nandfs_error("%s: err:%d updating seg", 1095235537Sgber __func__, error); 1096235537Sgber return (error); 1097235537Sgber } 1098235537Sgber VOP_UNLOCK(NTOV(dat), 0); 1099235537Sgber } 1100235537Sgber 1101235537Sgber VOP_UNLOCK(NTOV(su), 0); 1102235537Sgber 1103235537Sgber delete_seginfo(seginfo); 1104235537Sgber lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); 1105235537Sgber 1106235537Sgber if (cno_changed && !error) { 1107235537Sgber if (nandfs_cps_between_sblocks != 0 && 1108235537Sgber fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) 1109235537Sgber nandfs_write_superblock(fsdev); 1110235537Sgber } 1111235537Sgber 1112235537Sgber ASSERT_VOP_LOCKED(vp, __func__); 1113235537Sgber DPRINTF(SYNC, ("%s: END error %d\n", __func__, error)); 1114235537Sgber return (error); 1115235537Sgber} 1116235537Sgber 1117235537Sgberint 1118235537Sgbernandfs_segment_constructor(struct nandfsmount *nmp, int flags) 1119235537Sgber{ 1120235537Sgber struct nandfs_device *fsdev; 1121235537Sgber struct nandfs_seginfo *seginfo = NULL; 1122235537Sgber struct nandfs_segment *seg; 1123235537Sgber struct nandfs_node *dat, *su, *ifile, *cp, *gc; 1124235537Sgber int cno_changed, error; 1125235537Sgber 1126235537Sgber DPRINTF(SYNC, ("%s: START\n", __func__)); 1127235537Sgber fsdev = nmp->nm_nandfsdev; 1128235537Sgber 1129235537Sgber lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL); 1130235537Sgber DPRINTF(SYNC, ("%s: git lock\n", __func__)); 1131235537Sgberagain: 1132235537Sgber create_seginfo(fsdev, &seginfo); 1133235537Sgber 1134235537Sgber dat = fsdev->nd_dat_node; 1135235537Sgber su = fsdev->nd_su_node; 1136235537Sgber cp = fsdev->nd_cp_node; 1137235537Sgber gc = fsdev->nd_gc_node; 1138235537Sgber ifile = nmp->nm_ifile_node; 1139235537Sgber 1140235537Sgber VOP_LOCK(NTOV(su), LK_EXCLUSIVE); 1141235537Sgber VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE); 1142235537Sgber VOP_LOCK(NTOV(gc), LK_EXCLUSIVE); 1143235537Sgber VOP_LOCK(NTOV(cp), LK_EXCLUSIVE); 1144235537Sgber 1145235537Sgber nandfs_iterate_system_vnode(gc, seginfo); 1146235537Sgber nandfs_iterate_dirty_vnodes(nmp->nm_vfs_mountp, seginfo); 1147235537Sgber nandfs_iterate_system_vnode(ifile, seginfo); 1148235537Sgber nandfs_iterate_system_vnode(su, seginfo); 1149235537Sgber 1150235537Sgber cno_changed = 0; 1151235537Sgber if (seginfo->blocks || flags) { 1152235537Sgber cno_changed = 1; 1153235537Sgber /* Create new checkpoint */ 1154235537Sgber error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1); 1155235537Sgber if (error) { 1156235537Sgber clean_seginfo(seginfo, 0); 1157235537Sgber delete_seginfo(seginfo); 1158235537Sgber goto error_locks; 1159235537Sgber } 1160235537Sgber 1161235537Sgber /* Collect blocks from system files */ 1162235537Sgber nandfs_iterate_system_vnode(cp, seginfo); 1163235537Sgber nandfs_iterate_system_vnode(su, seginfo); 1164235537Sgber VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); 1165235537Sgber nandfs_iterate_system_vnode(dat, seginfo); 1166235537Sgber VOP_UNLOCK(NTOV(dat), 0); 1167235537Sgberreiterate: 1168235537Sgber seginfo->reiterate = 0; 1169235537Sgber nandfs_iterate_system_vnode(su, seginfo); 1170235537Sgber VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); 1171235537Sgber nandfs_iterate_system_vnode(dat, seginfo); 1172235537Sgber VOP_UNLOCK(NTOV(dat), 0); 1173235537Sgber if (seginfo->reiterate) 1174235537Sgber goto reiterate; 1175235537Sgber if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) { 1176235537Sgber error = create_segment(seginfo); 1177235537Sgber if (error) { 1178235537Sgber clean_seginfo(seginfo, 0); 1179235537Sgber delete_seginfo(seginfo); 1180235537Sgber goto error_locks; 1181235537Sgber } 1182235537Sgber goto reiterate; 1183235537Sgber } 1184235537Sgber 1185235537Sgber /* Reiterate all blocks and assign physical block number */ 1186235537Sgber nandfs_seginfo_assign_pblk(seginfo); 1187235537Sgber 1188235537Sgber /* Fill superroot */ 1189235537Sgber error = nandfs_add_superroot(seginfo); 1190235537Sgber if (error) { 1191235537Sgber clean_seginfo(seginfo, 0); 1192235537Sgber delete_seginfo(seginfo); 1193235537Sgber goto error_locks; 1194235537Sgber } 1195235537Sgber KASSERT(!(seginfo->reiterate), ("reiteration after superroot")); 1196235537Sgber 1197235537Sgber /* Fill checkpoint data */ 1198235537Sgber nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1, 1199235537Sgber &ifile->nn_inode, seginfo->blocks); 1200235537Sgber 1201235537Sgber LIST_FOREACH(seg, &seginfo->seg_list, seg_link) 1202235537Sgber nandfs_update_segment(fsdev, seg->seg_num, 1203235537Sgber seg->nblocks + seg->segsum_blocks); 1204235537Sgber 1205235537Sgber VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); 1206235537Sgber error = save_seginfo(seginfo, 1); 1207235537Sgber if (error) { 1208235537Sgber clean_seginfo(seginfo, 1); 1209235537Sgber delete_seginfo(seginfo); 1210235537Sgber goto error_dat; 1211235537Sgber } 1212235537Sgber VOP_UNLOCK(NTOV(dat), 0); 1213235537Sgber } 1214235537Sgber 1215235537Sgber VOP_UNLOCK(NTOV(cp), 0); 1216235537Sgber VOP_UNLOCK(NTOV(gc), 0); 1217235537Sgber VOP_UNLOCK(NTOV(ifile), 0); 1218235537Sgber 1219235537Sgber nandfs_process_segments(fsdev); 1220235537Sgber 1221235537Sgber VOP_UNLOCK(NTOV(su), 0); 1222235537Sgber 1223235537Sgber delete_seginfo(seginfo); 1224235537Sgber 1225235537Sgber /* 1226235537Sgber * XXX: a hack, will go away soon 1227235537Sgber */ 1228235537Sgber if ((NTOV(dat)->v_bufobj.bo_dirty.bv_cnt != 0 || 1229235537Sgber NTOV(cp)->v_bufobj.bo_dirty.bv_cnt != 0 || 1230235537Sgber NTOV(gc)->v_bufobj.bo_dirty.bv_cnt != 0 || 1231235537Sgber NTOV(ifile)->v_bufobj.bo_dirty.bv_cnt != 0 || 1232235537Sgber NTOV(su)->v_bufobj.bo_dirty.bv_cnt != 0) && 1233235537Sgber (flags & NANDFS_UMOUNT)) { 1234235537Sgber DPRINTF(SYNC, ("%s: RERUN\n", __func__)); 1235235537Sgber goto again; 1236235537Sgber } 1237235537Sgber 1238235537Sgber MPASS(fsdev->nd_free_base == NULL); 1239235537Sgber 1240235537Sgber lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL); 1241235537Sgber 1242235537Sgber if (cno_changed) { 1243235537Sgber if ((nandfs_cps_between_sblocks != 0 && 1244235537Sgber fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) || 1245235537Sgber flags & NANDFS_UMOUNT) 1246235537Sgber nandfs_write_superblock(fsdev); 1247235537Sgber } 1248235537Sgber 1249235537Sgber DPRINTF(SYNC, ("%s: END\n", __func__)); 1250235537Sgber return (0); 1251235537Sgbererror_dat: 1252235537Sgber VOP_UNLOCK(NTOV(dat), 0); 1253235537Sgbererror_locks: 1254235537Sgber VOP_UNLOCK(NTOV(cp), 0); 1255235537Sgber VOP_UNLOCK(NTOV(gc), 0); 1256235537Sgber VOP_UNLOCK(NTOV(ifile), 0); 1257235537Sgber VOP_UNLOCK(NTOV(su), 0); 1258235537Sgber lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL); 1259235537Sgber 1260235537Sgber return (error); 1261235537Sgber} 1262235537Sgber 1263235537Sgber#ifdef DDB 1264235537Sgber/* 1265235537Sgber * Show details about the given NANDFS mount point. 1266235537Sgber */ 1267235537SgberDB_SHOW_COMMAND(nandfs, db_show_nandfs) 1268235537Sgber{ 1269235537Sgber struct mount *mp; 1270235537Sgber struct nandfs_device *nffsdev; 1271235537Sgber struct nandfs_segment *seg; 1272235537Sgber struct nandfsmount *nmp; 1273235537Sgber struct buf *bp; 1274235537Sgber struct vnode *vp; 1275235537Sgber 1276235537Sgber if (!have_addr) { 1277235537Sgber db_printf("\nUsage: show nandfs <mount_addr>\n"); 1278235537Sgber return; 1279235537Sgber } 1280235537Sgber 1281235537Sgber mp = (struct mount *)addr; 1282235537Sgber db_printf("%p %s on %s (%s)\n", mp, mp->mnt_stat.f_mntfromname, 1283235537Sgber mp->mnt_stat.f_mntonname, mp->mnt_stat.f_fstypename); 1284235537Sgber 1285235537Sgber 1286235537Sgber nmp = (struct nandfsmount *)(mp->mnt_data); 1287235537Sgber nffsdev = nmp->nm_nandfsdev; 1288235537Sgber db_printf("dev vnode:%p\n", nffsdev->nd_devvp); 1289235537Sgber db_printf("blocksize:%jx last cno:%jx last pseg:%jx seg num:%jx\n", 1290235537Sgber (uintmax_t)nffsdev->nd_blocksize, (uintmax_t)nffsdev->nd_last_cno, 1291235537Sgber (uintmax_t)nffsdev->nd_last_pseg, (uintmax_t)nffsdev->nd_seg_num); 1292235537Sgber db_printf("system nodes: dat:%p cp:%p su:%p ifile:%p gc:%p\n", 1293235537Sgber nffsdev->nd_dat_node, nffsdev->nd_cp_node, nffsdev->nd_su_node, 1294235537Sgber nmp->nm_ifile_node, nffsdev->nd_gc_node); 1295235537Sgber 1296235537Sgber if (nffsdev->nd_seginfo != NULL) { 1297235537Sgber LIST_FOREACH(seg, &nffsdev->nd_seginfo->seg_list, seg_link) { 1298235537Sgber db_printf("seg: %p\n", seg); 1299235537Sgber TAILQ_FOREACH(bp, &seg->segsum, 1300235537Sgber b_cluster.cluster_entry) 1301235537Sgber db_printf("segbp %p\n", bp); 1302235537Sgber TAILQ_FOREACH(bp, &seg->data, 1303235537Sgber b_cluster.cluster_entry) { 1304235537Sgber vp = bp->b_vp; 1305235537Sgber db_printf("bp:%p bp->b_vp:%p ino:%jx\n", bp, vp, 1306235537Sgber (uintmax_t)(vp ? VTON(vp)->nn_ino : 0)); 1307235537Sgber } 1308235537Sgber } 1309235537Sgber } 1310235537Sgber} 1311235537Sgber#endif 1312