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); 202235537Sgber }; 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; 482245000Skib int error, update; 483235537Sgber 484235537Sgber td = curthread; 485235537Sgber 486245000Skib MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) { 487235537Sgber update = 0; 488235537Sgber 489245000Skib if (mp->mnt_syncer == vp || VOP_ISLOCKED(vp)) { 490235537Sgber VI_UNLOCK(vp); 491235537Sgber continue; 492235537Sgber } 493245000Skib if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK | LK_NOWAIT, td) != 0) 494235537Sgber continue; 495235537Sgber 496235537Sgber nandfs_node = VTON(vp); 497235537Sgber if (nandfs_node->nn_flags & IN_MODIFIED) { 498235537Sgber nandfs_node->nn_flags &= ~(IN_MODIFIED); 499235537Sgber update = 1; 500235537Sgber } 501235537Sgber 502235537Sgber if (vp->v_bufobj.bo_dirty.bv_cnt) { 503235537Sgber error = nandfs_iterate_dirty_buf(vp, seginfo, 0); 504235537Sgber if (error) { 505235537Sgber nandfs_error("%s: cannot iterate vnode:%p " 506235537Sgber "err:%d\n", __func__, vp, error); 507235537Sgber vput(vp); 508235537Sgber return (error); 509235537Sgber } 510235537Sgber update = 1; 511235537Sgber } else 512235537Sgber vput(vp); 513235537Sgber 514235537Sgber if (update) 515235537Sgber nandfs_node_update(nandfs_node); 516235537Sgber } 517235537Sgber 518235537Sgber return (0); 519235537Sgber} 520235537Sgber 521235537Sgberstatic int 522235537Sgbernandfs_update_phys_block(struct nandfs_device *fsdev, struct buf *bp, 523235537Sgber uint64_t phys_blknr, union nandfs_binfo *binfo) 524235537Sgber{ 525235537Sgber struct nandfs_node *node, *dat; 526235537Sgber struct vnode *vp; 527235537Sgber uint64_t new_blknr; 528235537Sgber int error; 529235537Sgber 530235537Sgber vp = bp->b_vp; 531235537Sgber node = VTON(vp); 532235537Sgber new_blknr = nandfs_vblk_get(bp); 533235537Sgber dat = fsdev->nd_dat_node; 534235537Sgber 535235537Sgber DPRINTF(BMAP, ("%s: ino %#jx lblk %#jx: vblk %#jx -> %#jx\n", 536235537Sgber __func__, (uintmax_t)node->nn_ino, (uintmax_t)bp->b_lblkno, 537235537Sgber (uintmax_t)new_blknr, (uintmax_t)phys_blknr)); 538235537Sgber 539235537Sgber if (node->nn_ino != NANDFS_DAT_INO) { 540235537Sgber KASSERT((new_blknr != 0), ("vblk for bp %p is 0", bp)); 541235537Sgber 542235537Sgber nandfs_vblock_assign(fsdev, new_blknr, phys_blknr); 543235537Sgber binfo->bi_v.bi_vblocknr = new_blknr; 544235537Sgber binfo->bi_v.bi_blkoff = bp->b_lblkno; 545235537Sgber binfo->bi_v.bi_ino = node->nn_ino; 546235537Sgber } else { 547235537Sgber VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); 548235537Sgber error = nandfs_bmap_update_block(node, bp, phys_blknr); 549235537Sgber if (error) { 550235537Sgber nandfs_error("%s: error updating block:%jx for bp:%p\n", 551235537Sgber __func__, (uintmax_t)phys_blknr, bp); 552235537Sgber VOP_UNLOCK(NTOV(dat), 0); 553235537Sgber return (error); 554235537Sgber } 555235537Sgber VOP_UNLOCK(NTOV(dat), 0); 556235537Sgber binfo->bi_dat.bi_blkoff = bp->b_lblkno; 557235537Sgber binfo->bi_dat.bi_ino = node->nn_ino; 558235537Sgber if (NANDFS_IS_INDIRECT(bp)) 559235537Sgber binfo->bi_dat.bi_level = 1; 560235537Sgber else 561235537Sgber binfo->bi_dat.bi_level = 0; 562235537Sgber } 563235537Sgber 564235537Sgber return (0); 565235537Sgber} 566235537Sgber 567235537Sgber#define NBINFO(off) ((off) + sizeof(union nandfs_binfo)) 568235537Sgberstatic int 569235537Sgbernandfs_segment_assign_pblk(struct nandfs_segment *nfsseg) 570235537Sgber{ 571235537Sgber struct nandfs_device *fsdev; 572235537Sgber union nandfs_binfo *binfo; 573235537Sgber struct buf *bp, *seg_bp; 574235537Sgber uint64_t blocknr; 575235537Sgber uint32_t curr_off, blocksize; 576235537Sgber int error; 577235537Sgber 578235537Sgber fsdev = nfsseg->fsdev; 579235537Sgber blocksize = fsdev->nd_blocksize; 580235537Sgber 581235537Sgber blocknr = nfsseg->start_block + nfsseg->segsum_blocks; 582235537Sgber seg_bp = TAILQ_FIRST(&nfsseg->segsum); 583235537Sgber DPRINTF(SYNC, ("%s: seg:%p segsum bp:%p data:%p\n", 584235537Sgber __func__, nfsseg, seg_bp, seg_bp->b_data)); 585235537Sgber 586235537Sgber binfo = (union nandfs_binfo *)(seg_bp->b_data + 587235537Sgber sizeof(struct nandfs_segment_summary)); 588235537Sgber curr_off = sizeof(struct nandfs_segment_summary); 589235537Sgber 590235537Sgber TAILQ_FOREACH(bp, &nfsseg->data, b_cluster.cluster_entry) { 591235537Sgber KASSERT((bp->b_vp), ("bp %p has not vp", bp)); 592235537Sgber 593235537Sgber DPRINTF(BMAP, ("\n\n%s: assign buf %p for ino %#jx next %p\n", 594235537Sgber __func__, bp, (uintmax_t)VTON(bp->b_vp)->nn_ino, 595235537Sgber TAILQ_NEXT(bp, b_cluster.cluster_entry))); 596235537Sgber 597235537Sgber if (NBINFO(curr_off) > blocksize) { 598235537Sgber seg_bp = TAILQ_NEXT(seg_bp, b_cluster.cluster_entry); 599235537Sgber binfo = (union nandfs_binfo *)seg_bp->b_data; 600235537Sgber curr_off = 0; 601235537Sgber DPRINTF(SYNC, ("%s: next segsum %p data %p\n", 602235537Sgber __func__, seg_bp, seg_bp->b_data)); 603235537Sgber } 604235537Sgber 605235537Sgber error = nandfs_update_phys_block(fsdev, bp, blocknr, binfo); 606235537Sgber if (error) { 607235537Sgber nandfs_error("%s: err:%d when updatinng phys block:%jx" 608235537Sgber " for bp:%p and binfo:%p\n", __func__, error, 609235537Sgber (uintmax_t)blocknr, bp, binfo); 610235537Sgber return (error); 611235537Sgber } 612235537Sgber binfo++; 613235537Sgber curr_off = NBINFO(curr_off); 614235537Sgber 615235537Sgber blocknr++; 616235537Sgber } 617235537Sgber 618235537Sgber return (0); 619235537Sgber} 620235537Sgber 621235537Sgberstatic int 622235537Sgbernandfs_seginfo_assign_pblk(struct nandfs_seginfo *seginfo) 623235537Sgber{ 624235537Sgber struct nandfs_segment *nfsseg; 625235537Sgber int error = 0; 626235537Sgber 627235537Sgber LIST_FOREACH(nfsseg, &seginfo->seg_list, seg_link) { 628235537Sgber error = nandfs_segment_assign_pblk(nfsseg); 629235537Sgber if (error) 630235537Sgber break; 631235537Sgber } 632235537Sgber 633235537Sgber return (error); 634235537Sgber} 635235537Sgber 636235537Sgberstatic struct nandfs_segment_summary * 637235537Sgbernandfs_fill_segsum(struct nandfs_segment *seg, int has_sr) 638235537Sgber{ 639235537Sgber struct nandfs_segment_summary *ss; 640235537Sgber struct nandfs_device *fsdev; 641235537Sgber struct buf *bp; 642235537Sgber uint32_t rest, segsum_size, blocksize, crc_calc; 643235537Sgber uint16_t flags; 644235537Sgber uint8_t *crc_area, crc_skip; 645235537Sgber 646235537Sgber DPRINTF(SYNC, ("%s: seg %#jx nblocks %#x sumbytes %#x\n", 647235537Sgber __func__, (uintmax_t) seg->seg_num, 648235537Sgber seg->nblocks + seg->segsum_blocks, 649235537Sgber seg->segsum_bytes)); 650235537Sgber 651235537Sgber fsdev = seg->fsdev; 652235537Sgber 653235537Sgber flags = NANDFS_SS_LOGBGN | NANDFS_SS_LOGEND; 654235537Sgber if (has_sr) 655235537Sgber flags |= NANDFS_SS_SR; 656235537Sgber 657235537Sgber bp = TAILQ_FIRST(&seg->segsum); 658235537Sgber ss = (struct nandfs_segment_summary *) bp->b_data; 659235537Sgber ss->ss_magic = NANDFS_SEGSUM_MAGIC; 660235537Sgber ss->ss_bytes = sizeof(struct nandfs_segment_summary); 661235537Sgber ss->ss_flags = flags; 662235537Sgber ss->ss_seq = ++(fsdev->nd_seg_sequence); 663235537Sgber ss->ss_create = fsdev->nd_ts.tv_sec; 664235537Sgber nandfs_get_segment_range(fsdev, seg->seg_next, &ss->ss_next, NULL); 665235537Sgber ss->ss_nblocks = seg->nblocks + seg->segsum_blocks; 666235537Sgber ss->ss_nbinfos = seg->nbinfos; 667235537Sgber ss->ss_sumbytes = seg->segsum_bytes; 668235537Sgber 669235537Sgber crc_skip = sizeof(ss->ss_datasum) + sizeof(ss->ss_sumsum); 670235537Sgber blocksize = seg->fsdev->nd_blocksize; 671235537Sgber 672235537Sgber segsum_size = seg->segsum_bytes - crc_skip; 673235537Sgber rest = min(seg->segsum_bytes, blocksize) - crc_skip; 674235537Sgber crc_area = (uint8_t *)ss + crc_skip; 675235537Sgber crc_calc = ~0U; 676235537Sgber while (segsum_size > 0) { 677235537Sgber crc_calc = crc32_raw(crc_area, rest, crc_calc); 678235537Sgber segsum_size -= rest; 679235537Sgber if (!segsum_size) 680235537Sgber break; 681235537Sgber bp = TAILQ_NEXT(bp, b_cluster.cluster_entry); 682235537Sgber crc_area = (uint8_t *)bp->b_data; 683235537Sgber rest = segsum_size <= blocksize ? segsum_size : blocksize; 684235537Sgber } 685235537Sgber ss->ss_sumsum = crc_calc ^ ~0U; 686235537Sgber 687235537Sgber return (ss); 688235537Sgber 689235537Sgber} 690235537Sgber 691235537Sgberstatic int 692235537Sgbernandfs_save_buf(struct buf *bp, uint64_t blocknr, struct nandfs_device *fsdev) 693235537Sgber{ 694235537Sgber struct bufobj *bo; 695235537Sgber int error; 696235537Sgber 697235537Sgber bo = &fsdev->nd_devvp->v_bufobj; 698235537Sgber 699235537Sgber bp->b_blkno = nandfs_block_to_dblock(fsdev, blocknr); 700235537Sgber bp->b_iooffset = dbtob(bp->b_blkno); 701235537Sgber 702235537Sgber KASSERT(bp->b_bufobj != NULL, ("no bufobj for %p", bp)); 703235537Sgber if (bp->b_bufobj != bo) { 704235537Sgber BO_LOCK(bp->b_bufobj); 705235537Sgber BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, 706251171Sjeff BO_LOCKPTR(bp->b_bufobj)); 707235537Sgber KASSERT(BUF_ISLOCKED(bp), ("Problem with locking buffer")); 708235537Sgber } 709235537Sgber 710235537Sgber DPRINTF(SYNC, ("%s: buf: %p offset %#jx blk %#jx size %#x\n", 711235537Sgber __func__, bp, (uintmax_t)bp->b_offset, (uintmax_t)blocknr, 712235537Sgber fsdev->nd_blocksize)); 713235537Sgber 714235537Sgber NANDFS_UNGATHER(bp); 715235537Sgber nandfs_buf_clear(bp, 0xffffffff); 716235537Sgber bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED); 717235537Sgber error = bwrite(bp); 718235537Sgber if (error) { 719235537Sgber nandfs_error("%s: error:%d when writing buffer:%p\n", 720235537Sgber __func__, error, bp); 721235537Sgber return (error); 722235537Sgber } 723235537Sgber return (error); 724235537Sgber} 725235537Sgber 726235537Sgberstatic void 727235537Sgbernandfs_clean_buf(struct nandfs_device *fsdev, struct buf *bp) 728235537Sgber{ 729235537Sgber 730235537Sgber DPRINTF(SYNC, ("%s: buf: %p\n", __func__, bp)); 731235537Sgber 732235537Sgber NANDFS_UNGATHER(bp); 733235537Sgber nandfs_buf_clear(bp, 0xffffffff); 734235537Sgber bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED); 735235537Sgber nandfs_undirty_buf_fsdev(fsdev, bp); 736235537Sgber} 737235537Sgber 738235537Sgberstatic void 739235537Sgbernandfs_clean_segblocks(struct nandfs_segment *seg, uint8_t unlock) 740235537Sgber{ 741235537Sgber struct nandfs_device *fsdev = seg->fsdev; 742235537Sgber struct nandfs_segment *next_seg; 743235537Sgber struct buf *bp, *tbp, *next_bp; 744235537Sgber struct vnode *vp, *next_vp; 745235537Sgber 746235537Sgber VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE); 747235537Sgber TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) { 748235537Sgber TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry); 749235537Sgber nandfs_clean_buf(fsdev, bp); 750235537Sgber }; 751235537Sgber 752235537Sgber TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) { 753235537Sgber TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry); 754235537Sgber 755235537Sgber /* 756235537Sgber * If bp is not super-root and vnode is not currently 757235537Sgber * locked lock it. 758235537Sgber */ 759235537Sgber vp = bp->b_vp; 760235537Sgber next_vp = NULL; 761235537Sgber next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry); 762235537Sgber if (!next_bp) { 763235537Sgber next_seg = LIST_NEXT(seg, seg_link); 764235537Sgber if (next_seg) 765235537Sgber next_bp = TAILQ_FIRST(&next_seg->data); 766235537Sgber } 767235537Sgber 768235537Sgber if (next_bp) 769235537Sgber next_vp = next_bp->b_vp; 770235537Sgber 771235537Sgber nandfs_clean_buf(fsdev, bp); 772235537Sgber 773235537Sgber if (unlock && vp != NULL && next_vp != vp && 774235537Sgber !NANDFS_SYS_NODE(VTON(vp)->nn_ino)) 775235537Sgber vput(vp); 776235537Sgber 777235537Sgber nandfs_dirty_bufs_decrement(fsdev); 778235537Sgber } 779235537Sgber 780235537Sgber VOP_UNLOCK(fsdev->nd_devvp, 0); 781235537Sgber} 782235537Sgber 783235537Sgberstatic int 784235537Sgbernandfs_save_segblocks(struct nandfs_segment *seg, uint8_t unlock) 785235537Sgber{ 786235537Sgber struct nandfs_device *fsdev = seg->fsdev; 787235537Sgber struct nandfs_segment *next_seg; 788235537Sgber struct buf *bp, *tbp, *next_bp; 789235537Sgber struct vnode *vp, *next_vp; 790235537Sgber uint64_t blocknr; 791235537Sgber uint32_t i = 0; 792235537Sgber int error = 0; 793235537Sgber 794235537Sgber VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE); 795235537Sgber TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) { 796235537Sgber TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry); 797235537Sgber blocknr = seg->start_block + i; 798235537Sgber error = nandfs_save_buf(bp, blocknr, fsdev); 799235537Sgber if (error) { 800235537Sgber nandfs_error("%s: error saving buf: %p blocknr:%jx\n", 801235537Sgber __func__, bp, (uintmax_t)blocknr); 802235537Sgber goto out; 803235537Sgber } 804235537Sgber i++; 805235537Sgber }; 806235537Sgber 807235537Sgber i = 0; 808235537Sgber TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) { 809235537Sgber TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry); 810235537Sgber 811235537Sgber blocknr = seg->start_block + seg->segsum_blocks + i; 812235537Sgber /* 813235537Sgber * If bp is not super-root and vnode is not currently 814235537Sgber * locked lock it. 815235537Sgber */ 816235537Sgber vp = bp->b_vp; 817235537Sgber next_vp = NULL; 818235537Sgber next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry); 819235537Sgber if (!next_bp) { 820235537Sgber next_seg = LIST_NEXT(seg, seg_link); 821235537Sgber if (next_seg) 822235537Sgber next_bp = TAILQ_FIRST(&next_seg->data); 823235537Sgber } 824235537Sgber 825235537Sgber if (next_bp) 826235537Sgber next_vp = next_bp->b_vp; 827235537Sgber 828235537Sgber error = nandfs_save_buf(bp, blocknr, fsdev); 829235537Sgber if (error) { 830235537Sgber nandfs_error("%s: error saving buf: %p blknr: %jx\n", 831235537Sgber __func__, bp, (uintmax_t)blocknr); 832235537Sgber if (unlock && vp != NULL && next_vp != vp && 833235537Sgber !NANDFS_SYS_NODE(VTON(vp)->nn_ino)) 834235537Sgber vput(vp); 835235537Sgber goto out; 836235537Sgber } 837235537Sgber 838235537Sgber if (unlock && vp != NULL && next_vp != vp && 839235537Sgber !NANDFS_SYS_NODE(VTON(vp)->nn_ino)) 840235537Sgber vput(vp); 841235537Sgber 842235537Sgber i++; 843235537Sgber nandfs_dirty_bufs_decrement(fsdev); 844235537Sgber } 845235537Sgberout: 846235537Sgber if (error) { 847235537Sgber nandfs_clean_segblocks(seg, unlock); 848235537Sgber VOP_UNLOCK(fsdev->nd_devvp, 0); 849235537Sgber return (error); 850235537Sgber } 851235537Sgber 852235537Sgber VOP_UNLOCK(fsdev->nd_devvp, 0); 853235537Sgber return (error); 854235537Sgber} 855235537Sgber 856235537Sgber 857235537Sgberstatic void 858235537Sgberclean_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock) 859235537Sgber{ 860235537Sgber struct nandfs_segment *seg; 861235537Sgber 862235537Sgber DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo)); 863235537Sgber 864235537Sgber LIST_FOREACH(seg, &seginfo->seg_list, seg_link) { 865235537Sgber nandfs_clean_segblocks(seg, unlock); 866235537Sgber } 867235537Sgber} 868235537Sgber 869235537Sgberstatic int 870235537Sgbersave_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock) 871235537Sgber{ 872235537Sgber struct nandfs_segment *seg; 873235537Sgber struct nandfs_device *fsdev; 874235537Sgber struct nandfs_segment_summary *ss; 875235537Sgber int error = 0; 876235537Sgber 877235537Sgber fsdev = seginfo->fsdev; 878235537Sgber 879235537Sgber DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo)); 880235537Sgber 881235537Sgber LIST_FOREACH(seg, &seginfo->seg_list, seg_link) { 882235537Sgber if (LIST_NEXT(seg, seg_link)) { 883235537Sgber nandfs_fill_segsum(seg, 0); 884235537Sgber error = nandfs_save_segblocks(seg, unlock); 885235537Sgber if (error) { 886235537Sgber nandfs_error("%s: error:%d saving seg:%p\n", 887235537Sgber __func__, error, seg); 888235537Sgber goto out; 889235537Sgber } 890235537Sgber } else { 891235537Sgber ss = nandfs_fill_segsum(seg, 1); 892235537Sgber fsdev->nd_last_segsum = *ss; 893235537Sgber error = nandfs_save_segblocks(seg, unlock); 894235537Sgber if (error) { 895235537Sgber nandfs_error("%s: error:%d saving seg:%p\n", 896235537Sgber __func__, error, seg); 897235537Sgber goto out; 898235537Sgber } 899235537Sgber fsdev->nd_last_cno++; 900235537Sgber fsdev->nd_last_pseg = seg->start_block; 901235537Sgber } 902235537Sgber } 903235537Sgberout: 904235537Sgber if (error) 905235537Sgber clean_seginfo(seginfo, unlock); 906235537Sgber return (error); 907235537Sgber} 908235537Sgber 909235537Sgberstatic void 910235537Sgbernandfs_invalidate_bufs(struct nandfs_device *fsdev, uint64_t segno) 911235537Sgber{ 912235537Sgber uint64_t start, end; 913235537Sgber struct buf *bp, *tbd; 914235537Sgber struct bufobj *bo; 915235537Sgber 916235537Sgber nandfs_get_segment_range(fsdev, segno, &start, &end); 917235537Sgber 918235537Sgber bo = &NTOV(fsdev->nd_gc_node)->v_bufobj; 919235537Sgber 920235537Sgber BO_LOCK(bo); 921235537Sgberrestart_locked_gc: 922235537Sgber TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, tbd) { 923235537Sgber if (!(bp->b_lblkno >= start && bp->b_lblkno <= end)) 924235537Sgber continue; 925235537Sgber 926235537Sgber if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) 927235537Sgber goto restart_locked_gc; 928235537Sgber 929235537Sgber bremfree(bp); 930235537Sgber bp->b_flags |= (B_INVAL | B_RELBUF); 931235537Sgber bp->b_flags &= ~(B_ASYNC | B_MANAGED); 932235537Sgber BO_UNLOCK(bo); 933235537Sgber brelse(bp); 934235537Sgber BO_LOCK(bo); 935235537Sgber } 936235537Sgber BO_UNLOCK(bo); 937235537Sgber} 938235537Sgber 939235537Sgber/* Process segments marks to free by cleaner */ 940235537Sgberstatic void 941235537Sgbernandfs_process_segments(struct nandfs_device *fsdev) 942235537Sgber{ 943235537Sgber uint64_t saved_segment; 944235537Sgber int i; 945235537Sgber 946235537Sgber if (fsdev->nd_free_base) { 947235537Sgber saved_segment = nandfs_get_segnum_of_block(fsdev, 948235537Sgber fsdev->nd_super.s_last_pseg); 949235537Sgber for (i = 0; i < fsdev->nd_free_count; i++) { 950235537Sgber if (fsdev->nd_free_base[i] == NANDFS_NOSEGMENT) 951235537Sgber continue; 952235537Sgber /* Update superblock if clearing segment point by it */ 953235537Sgber if (fsdev->nd_free_base[i] == saved_segment) { 954235537Sgber nandfs_write_superblock(fsdev); 955235537Sgber saved_segment = nandfs_get_segnum_of_block( 956235537Sgber fsdev, fsdev->nd_super.s_last_pseg); 957235537Sgber } 958235537Sgber nandfs_invalidate_bufs(fsdev, fsdev->nd_free_base[i]); 959235537Sgber nandfs_clear_segment(fsdev, fsdev->nd_free_base[i]); 960235537Sgber } 961235537Sgber 962235537Sgber free(fsdev->nd_free_base, M_NANDFSTEMP); 963235537Sgber fsdev->nd_free_base = NULL; 964235537Sgber fsdev->nd_free_count = 0; 965235537Sgber } 966235537Sgber} 967235537Sgber 968235537Sgber/* Collect and write dirty buffers */ 969235537Sgberint 970235537Sgbernandfs_sync_file(struct vnode *vp) 971235537Sgber{ 972235537Sgber struct nandfs_device *fsdev; 973235537Sgber struct nandfs_node *nandfs_node; 974235537Sgber struct nandfsmount *nmp; 975235537Sgber struct nandfs_node *dat, *su, *ifile, *cp; 976235537Sgber struct nandfs_seginfo *seginfo = NULL; 977235537Sgber struct nandfs_segment *seg; 978235537Sgber int update, error; 979235537Sgber int cno_changed; 980235537Sgber 981235537Sgber ASSERT_VOP_LOCKED(vp, __func__); 982235537Sgber DPRINTF(SYNC, ("%s: START\n", __func__)); 983235537Sgber 984235537Sgber error = 0; 985235537Sgber nmp = VFSTONANDFS(vp->v_mount); 986235537Sgber fsdev = nmp->nm_nandfsdev; 987235537Sgber 988235537Sgber dat = fsdev->nd_dat_node; 989235537Sgber su = fsdev->nd_su_node; 990235537Sgber cp = fsdev->nd_cp_node; 991235537Sgber ifile = nmp->nm_ifile_node; 992235537Sgber 993235537Sgber NANDFS_WRITEASSERT(fsdev); 994235537Sgber if (lockmgr(&fsdev->nd_seg_const, LK_UPGRADE, NULL) != 0) { 995235537Sgber DPRINTF(SYNC, ("%s: lost shared lock\n", __func__)); 996235537Sgber if (lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL) != 0) 997235537Sgber panic("couldn't lock exclusive"); 998235537Sgber } 999235537Sgber DPRINTF(SYNC, ("%s: got lock\n", __func__)); 1000235537Sgber 1001235537Sgber VOP_LOCK(NTOV(su), LK_EXCLUSIVE); 1002235537Sgber create_seginfo(fsdev, &seginfo); 1003235537Sgber 1004235537Sgber update = 0; 1005235537Sgber 1006235537Sgber nandfs_node = VTON(vp); 1007235537Sgber if (nandfs_node->nn_flags & IN_MODIFIED) { 1008235537Sgber nandfs_node->nn_flags &= ~(IN_MODIFIED); 1009235537Sgber update = 1; 1010235537Sgber } 1011235537Sgber 1012235537Sgber if (vp->v_bufobj.bo_dirty.bv_cnt) { 1013235537Sgber error = nandfs_iterate_dirty_buf(vp, seginfo, 0); 1014235537Sgber if (error) { 1015235537Sgber clean_seginfo(seginfo, 0); 1016235537Sgber delete_seginfo(seginfo); 1017235537Sgber VOP_UNLOCK(NTOV(su), 0); 1018235537Sgber lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); 1019235537Sgber nandfs_error("%s: err:%d iterating dirty bufs vp:%p", 1020235537Sgber __func__, error, vp); 1021235537Sgber return (error); 1022235537Sgber } 1023235537Sgber update = 1; 1024235537Sgber } 1025235537Sgber 1026235537Sgber if (update) { 1027235537Sgber VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE); 1028235537Sgber error = nandfs_node_update(nandfs_node); 1029235537Sgber if (error) { 1030235537Sgber clean_seginfo(seginfo, 0); 1031235537Sgber delete_seginfo(seginfo); 1032235537Sgber VOP_UNLOCK(NTOV(ifile), 0); 1033235537Sgber VOP_UNLOCK(NTOV(su), 0); 1034235537Sgber lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); 1035235537Sgber nandfs_error("%s: err:%d updating vp:%p", 1036235537Sgber __func__, error, vp); 1037235537Sgber return (error); 1038235537Sgber } 1039235537Sgber VOP_UNLOCK(NTOV(ifile), 0); 1040235537Sgber } 1041235537Sgber 1042235537Sgber cno_changed = 0; 1043235537Sgber if (seginfo->blocks) { 1044235537Sgber VOP_LOCK(NTOV(cp), LK_EXCLUSIVE); 1045235537Sgber cno_changed = 1; 1046235537Sgber /* Create new checkpoint */ 1047235537Sgber error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1); 1048235537Sgber if (error) { 1049235537Sgber clean_seginfo(seginfo, 0); 1050235537Sgber delete_seginfo(seginfo); 1051235537Sgber VOP_UNLOCK(NTOV(cp), 0); 1052235537Sgber VOP_UNLOCK(NTOV(su), 0); 1053235537Sgber lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); 1054235537Sgber nandfs_error("%s: err:%d getting cp:%jx", 1055235537Sgber __func__, error, fsdev->nd_last_cno + 1); 1056235537Sgber return (error); 1057235537Sgber } 1058235537Sgber 1059235537Sgber /* Reiterate all blocks and assign physical block number */ 1060235537Sgber nandfs_seginfo_assign_pblk(seginfo); 1061235537Sgber 1062235537Sgber /* Fill checkpoint data */ 1063235537Sgber error = nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1, 1064235537Sgber &ifile->nn_inode, seginfo->blocks); 1065235537Sgber if (error) { 1066235537Sgber clean_seginfo(seginfo, 0); 1067235537Sgber delete_seginfo(seginfo); 1068235537Sgber VOP_UNLOCK(NTOV(cp), 0); 1069235537Sgber VOP_UNLOCK(NTOV(su), 0); 1070235537Sgber lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); 1071235537Sgber nandfs_error("%s: err:%d setting cp:%jx", 1072235537Sgber __func__, error, fsdev->nd_last_cno + 1); 1073235537Sgber return (error); 1074235537Sgber } 1075235537Sgber 1076235537Sgber VOP_UNLOCK(NTOV(cp), 0); 1077235537Sgber LIST_FOREACH(seg, &seginfo->seg_list, seg_link) 1078235537Sgber nandfs_update_segment(fsdev, seg->seg_num, 1079235537Sgber seg->nblocks + seg->segsum_blocks); 1080235537Sgber 1081235537Sgber VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); 1082235537Sgber error = save_seginfo(seginfo, 0); 1083235537Sgber if (error) { 1084235537Sgber clean_seginfo(seginfo, 0); 1085235537Sgber delete_seginfo(seginfo); 1086235537Sgber VOP_UNLOCK(NTOV(dat), 0); 1087235537Sgber VOP_UNLOCK(NTOV(su), 0); 1088235537Sgber lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); 1089235537Sgber nandfs_error("%s: err:%d updating seg", 1090235537Sgber __func__, error); 1091235537Sgber return (error); 1092235537Sgber } 1093235537Sgber VOP_UNLOCK(NTOV(dat), 0); 1094235537Sgber } 1095235537Sgber 1096235537Sgber VOP_UNLOCK(NTOV(su), 0); 1097235537Sgber 1098235537Sgber delete_seginfo(seginfo); 1099235537Sgber lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); 1100235537Sgber 1101235537Sgber if (cno_changed && !error) { 1102235537Sgber if (nandfs_cps_between_sblocks != 0 && 1103235537Sgber fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) 1104235537Sgber nandfs_write_superblock(fsdev); 1105235537Sgber } 1106235537Sgber 1107235537Sgber ASSERT_VOP_LOCKED(vp, __func__); 1108235537Sgber DPRINTF(SYNC, ("%s: END error %d\n", __func__, error)); 1109235537Sgber return (error); 1110235537Sgber} 1111235537Sgber 1112235537Sgberint 1113235537Sgbernandfs_segment_constructor(struct nandfsmount *nmp, int flags) 1114235537Sgber{ 1115235537Sgber struct nandfs_device *fsdev; 1116235537Sgber struct nandfs_seginfo *seginfo = NULL; 1117235537Sgber struct nandfs_segment *seg; 1118235537Sgber struct nandfs_node *dat, *su, *ifile, *cp, *gc; 1119235537Sgber int cno_changed, error; 1120235537Sgber 1121235537Sgber DPRINTF(SYNC, ("%s: START\n", __func__)); 1122235537Sgber fsdev = nmp->nm_nandfsdev; 1123235537Sgber 1124235537Sgber lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL); 1125235537Sgber DPRINTF(SYNC, ("%s: git lock\n", __func__)); 1126235537Sgberagain: 1127235537Sgber create_seginfo(fsdev, &seginfo); 1128235537Sgber 1129235537Sgber dat = fsdev->nd_dat_node; 1130235537Sgber su = fsdev->nd_su_node; 1131235537Sgber cp = fsdev->nd_cp_node; 1132235537Sgber gc = fsdev->nd_gc_node; 1133235537Sgber ifile = nmp->nm_ifile_node; 1134235537Sgber 1135235537Sgber VOP_LOCK(NTOV(su), LK_EXCLUSIVE); 1136235537Sgber VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE); 1137235537Sgber VOP_LOCK(NTOV(gc), LK_EXCLUSIVE); 1138235537Sgber VOP_LOCK(NTOV(cp), LK_EXCLUSIVE); 1139235537Sgber 1140235537Sgber nandfs_iterate_system_vnode(gc, seginfo); 1141235537Sgber nandfs_iterate_dirty_vnodes(nmp->nm_vfs_mountp, seginfo); 1142235537Sgber nandfs_iterate_system_vnode(ifile, seginfo); 1143235537Sgber nandfs_iterate_system_vnode(su, seginfo); 1144235537Sgber 1145235537Sgber cno_changed = 0; 1146235537Sgber if (seginfo->blocks || flags) { 1147235537Sgber cno_changed = 1; 1148235537Sgber /* Create new checkpoint */ 1149235537Sgber error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1); 1150235537Sgber if (error) { 1151235537Sgber clean_seginfo(seginfo, 0); 1152235537Sgber delete_seginfo(seginfo); 1153235537Sgber goto error_locks; 1154235537Sgber } 1155235537Sgber 1156235537Sgber /* Collect blocks from system files */ 1157235537Sgber nandfs_iterate_system_vnode(cp, seginfo); 1158235537Sgber nandfs_iterate_system_vnode(su, seginfo); 1159235537Sgber VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); 1160235537Sgber nandfs_iterate_system_vnode(dat, seginfo); 1161235537Sgber VOP_UNLOCK(NTOV(dat), 0); 1162235537Sgberreiterate: 1163235537Sgber seginfo->reiterate = 0; 1164235537Sgber nandfs_iterate_system_vnode(su, seginfo); 1165235537Sgber VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); 1166235537Sgber nandfs_iterate_system_vnode(dat, seginfo); 1167235537Sgber VOP_UNLOCK(NTOV(dat), 0); 1168235537Sgber if (seginfo->reiterate) 1169235537Sgber goto reiterate; 1170235537Sgber if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) { 1171235537Sgber error = create_segment(seginfo); 1172235537Sgber if (error) { 1173235537Sgber clean_seginfo(seginfo, 0); 1174235537Sgber delete_seginfo(seginfo); 1175235537Sgber goto error_locks; 1176235537Sgber } 1177235537Sgber goto reiterate; 1178235537Sgber } 1179235537Sgber 1180235537Sgber /* Reiterate all blocks and assign physical block number */ 1181235537Sgber nandfs_seginfo_assign_pblk(seginfo); 1182235537Sgber 1183235537Sgber /* Fill superroot */ 1184235537Sgber error = nandfs_add_superroot(seginfo); 1185235537Sgber if (error) { 1186235537Sgber clean_seginfo(seginfo, 0); 1187235537Sgber delete_seginfo(seginfo); 1188235537Sgber goto error_locks; 1189235537Sgber } 1190235537Sgber KASSERT(!(seginfo->reiterate), ("reiteration after superroot")); 1191235537Sgber 1192235537Sgber /* Fill checkpoint data */ 1193235537Sgber nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1, 1194235537Sgber &ifile->nn_inode, seginfo->blocks); 1195235537Sgber 1196235537Sgber LIST_FOREACH(seg, &seginfo->seg_list, seg_link) 1197235537Sgber nandfs_update_segment(fsdev, seg->seg_num, 1198235537Sgber seg->nblocks + seg->segsum_blocks); 1199235537Sgber 1200235537Sgber VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); 1201235537Sgber error = save_seginfo(seginfo, 1); 1202235537Sgber if (error) { 1203235537Sgber clean_seginfo(seginfo, 1); 1204235537Sgber delete_seginfo(seginfo); 1205235537Sgber goto error_dat; 1206235537Sgber } 1207235537Sgber VOP_UNLOCK(NTOV(dat), 0); 1208235537Sgber } 1209235537Sgber 1210235537Sgber VOP_UNLOCK(NTOV(cp), 0); 1211235537Sgber VOP_UNLOCK(NTOV(gc), 0); 1212235537Sgber VOP_UNLOCK(NTOV(ifile), 0); 1213235537Sgber 1214235537Sgber nandfs_process_segments(fsdev); 1215235537Sgber 1216235537Sgber VOP_UNLOCK(NTOV(su), 0); 1217235537Sgber 1218235537Sgber delete_seginfo(seginfo); 1219235537Sgber 1220235537Sgber /* 1221235537Sgber * XXX: a hack, will go away soon 1222235537Sgber */ 1223235537Sgber if ((NTOV(dat)->v_bufobj.bo_dirty.bv_cnt != 0 || 1224235537Sgber NTOV(cp)->v_bufobj.bo_dirty.bv_cnt != 0 || 1225235537Sgber NTOV(gc)->v_bufobj.bo_dirty.bv_cnt != 0 || 1226235537Sgber NTOV(ifile)->v_bufobj.bo_dirty.bv_cnt != 0 || 1227235537Sgber NTOV(su)->v_bufobj.bo_dirty.bv_cnt != 0) && 1228235537Sgber (flags & NANDFS_UMOUNT)) { 1229235537Sgber DPRINTF(SYNC, ("%s: RERUN\n", __func__)); 1230235537Sgber goto again; 1231235537Sgber } 1232235537Sgber 1233235537Sgber MPASS(fsdev->nd_free_base == NULL); 1234235537Sgber 1235235537Sgber lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL); 1236235537Sgber 1237235537Sgber if (cno_changed) { 1238235537Sgber if ((nandfs_cps_between_sblocks != 0 && 1239235537Sgber fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) || 1240235537Sgber flags & NANDFS_UMOUNT) 1241235537Sgber nandfs_write_superblock(fsdev); 1242235537Sgber } 1243235537Sgber 1244235537Sgber DPRINTF(SYNC, ("%s: END\n", __func__)); 1245235537Sgber return (0); 1246235537Sgbererror_dat: 1247235537Sgber VOP_UNLOCK(NTOV(dat), 0); 1248235537Sgbererror_locks: 1249235537Sgber VOP_UNLOCK(NTOV(cp), 0); 1250235537Sgber VOP_UNLOCK(NTOV(gc), 0); 1251235537Sgber VOP_UNLOCK(NTOV(ifile), 0); 1252235537Sgber VOP_UNLOCK(NTOV(su), 0); 1253235537Sgber lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL); 1254235537Sgber 1255235537Sgber return (error); 1256235537Sgber} 1257235537Sgber 1258235537Sgber#ifdef DDB 1259235537Sgber/* 1260235537Sgber * Show details about the given NANDFS mount point. 1261235537Sgber */ 1262235537SgberDB_SHOW_COMMAND(nandfs, db_show_nandfs) 1263235537Sgber{ 1264235537Sgber struct mount *mp; 1265235537Sgber struct nandfs_device *nffsdev; 1266235537Sgber struct nandfs_segment *seg; 1267235537Sgber struct nandfsmount *nmp; 1268235537Sgber struct buf *bp; 1269235537Sgber struct vnode *vp; 1270235537Sgber 1271235537Sgber if (!have_addr) { 1272235537Sgber db_printf("\nUsage: show nandfs <mount_addr>\n"); 1273235537Sgber return; 1274235537Sgber } 1275235537Sgber 1276235537Sgber mp = (struct mount *)addr; 1277235537Sgber db_printf("%p %s on %s (%s)\n", mp, mp->mnt_stat.f_mntfromname, 1278235537Sgber mp->mnt_stat.f_mntonname, mp->mnt_stat.f_fstypename); 1279235537Sgber 1280235537Sgber 1281235537Sgber nmp = (struct nandfsmount *)(mp->mnt_data); 1282235537Sgber nffsdev = nmp->nm_nandfsdev; 1283235537Sgber db_printf("dev vnode:%p\n", nffsdev->nd_devvp); 1284235537Sgber db_printf("blocksize:%jx last cno:%jx last pseg:%jx seg num:%jx\n", 1285235537Sgber (uintmax_t)nffsdev->nd_blocksize, (uintmax_t)nffsdev->nd_last_cno, 1286235537Sgber (uintmax_t)nffsdev->nd_last_pseg, (uintmax_t)nffsdev->nd_seg_num); 1287235537Sgber db_printf("system nodes: dat:%p cp:%p su:%p ifile:%p gc:%p\n", 1288235537Sgber nffsdev->nd_dat_node, nffsdev->nd_cp_node, nffsdev->nd_su_node, 1289235537Sgber nmp->nm_ifile_node, nffsdev->nd_gc_node); 1290235537Sgber 1291235537Sgber if (nffsdev->nd_seginfo != NULL) { 1292235537Sgber LIST_FOREACH(seg, &nffsdev->nd_seginfo->seg_list, seg_link) { 1293235537Sgber db_printf("seg: %p\n", seg); 1294235537Sgber TAILQ_FOREACH(bp, &seg->segsum, 1295235537Sgber b_cluster.cluster_entry) 1296235537Sgber db_printf("segbp %p\n", bp); 1297235537Sgber TAILQ_FOREACH(bp, &seg->data, 1298235537Sgber b_cluster.cluster_entry) { 1299235537Sgber vp = bp->b_vp; 1300235537Sgber db_printf("bp:%p bp->b_vp:%p ino:%jx\n", bp, vp, 1301235537Sgber (uintmax_t)(vp ? VTON(vp)->nn_ino : 0)); 1302235537Sgber } 1303235537Sgber } 1304235537Sgber } 1305235537Sgber} 1306235537Sgber#endif 1307