1/*- 2 * Copyright (c) 2010-2012 Semihalf. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD$"); 29 30#include "opt_ddb.h" 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/conf.h> 35#include <sys/kernel.h> 36#include <sys/lock.h> 37#include <sys/malloc.h> 38#include <sys/mount.h> 39#include <sys/mutex.h> 40#include <sys/namei.h> 41#include <sys/rwlock.h> 42#include <sys/sysctl.h> 43#include <sys/vnode.h> 44#include <sys/buf.h> 45#include <sys/bio.h> 46#include <sys/libkern.h> 47 48#include <ddb/ddb.h> 49 50#include <vm/vm.h> 51#include <vm/vm_param.h> 52#include <vm/vm_kern.h> 53#include <vm/vm_page.h> 54 55#include <geom/geom.h> 56#include <geom/geom_vfs.h> 57 58#include <fs/nandfs/nandfs_mount.h> 59#include <fs/nandfs/nandfs.h> 60#include <fs/nandfs/nandfs_subr.h> 61 62static int 63nandfs_new_segment(struct nandfs_device *fsdev) 64{ 65 int error = 0; 66 uint64_t new; 67 68 error = nandfs_alloc_segment(fsdev, &new); 69 if (!error) { 70 fsdev->nd_seg_num = fsdev->nd_next_seg_num; 71 fsdev->nd_next_seg_num = new; 72 } 73 DPRINTF(SYNC, ("%s: new segment %jx next %jx error %d\n", 74 __func__, (uintmax_t)fsdev->nd_seg_num, (uintmax_t)new, error)); 75 if (error) 76 nandfs_error("%s: cannot create segment error %d\n", 77 __func__, error); 78 79 return (error); 80} 81 82static int 83create_segment(struct nandfs_seginfo *seginfo) 84{ 85 struct nandfs_segment *seg; 86 struct nandfs_device *fsdev; 87 struct nandfs_segment *prev; 88 struct buf *bp; 89 uint64_t start_block, curr; 90 uint32_t blks_per_seg, nblocks; 91 int error; 92 93 fsdev = seginfo->fsdev; 94 prev = seginfo->curseg; 95 blks_per_seg = fsdev->nd_fsdata.f_blocks_per_segment; 96 nblocks = fsdev->nd_last_segsum.ss_nblocks; 97 98 if (!prev) { 99 vfs_timestamp(&fsdev->nd_ts); 100 /* Touch current segment */ 101 error = nandfs_touch_segment(fsdev, fsdev->nd_seg_num); 102 if (error) { 103 nandfs_error("%s: cannot preallocate segment %jx\n", 104 __func__, fsdev->nd_seg_num); 105 return (error); 106 } 107 error = nandfs_touch_segment(fsdev, 0); 108 if (error) { 109 nandfs_error("%s: cannot dirty block with segment 0\n", 110 __func__); 111 return (error); 112 } 113 start_block = fsdev->nd_last_pseg + (uint64_t)nblocks; 114 /* 115 * XXX Hack 116 */ 117 if (blks_per_seg - (start_block % blks_per_seg) - 1 == 0) 118 start_block++; 119 curr = nandfs_get_segnum_of_block(fsdev, start_block); 120 /* Allocate new segment if last one is full */ 121 if (fsdev->nd_seg_num != curr) { 122 error = nandfs_new_segment(fsdev); 123 if (error) { 124 nandfs_error("%s: cannot create new segment\n", 125 __func__); 126 return (error); 127 } 128 /* 129 * XXX Hack 130 */ 131 nandfs_get_segment_range(fsdev, fsdev->nd_seg_num, &start_block, NULL); 132 } 133 } else { 134 nandfs_get_segment_range(fsdev, fsdev->nd_next_seg_num, 135 &start_block, NULL); 136 137 /* Touch current segment and allocate and touch new one */ 138 error = nandfs_new_segment(fsdev); 139 if (error) { 140 nandfs_error("%s: cannot create next segment\n", 141 __func__); 142 return (error); 143 } 144 145 /* Reiterate in case new buf is dirty */ 146 seginfo->reiterate = 1; 147 } 148 149 /* Allocate and initialize nandfs_segment structure */ 150 seg = malloc(sizeof(*seg), M_DEVBUF, M_WAITOK|M_ZERO); 151 TAILQ_INIT(&seg->segsum); 152 TAILQ_INIT(&seg->data); 153 seg->fsdev = fsdev; 154 seg->start_block = start_block; 155 seg->num_blocks = blks_per_seg - (start_block % blks_per_seg) - 1; 156 seg->seg_num = fsdev->nd_seg_num; 157 seg->seg_next = fsdev->nd_next_seg_num; 158 seg->segsum_blocks = 1; 159 seg->bytes_left = fsdev->nd_blocksize - 160 sizeof(struct nandfs_segment_summary); 161 seg->segsum_bytes = sizeof(struct nandfs_segment_summary); 162 163 /* Allocate buffer for segment summary */ 164 bp = getblk(fsdev->nd_devvp, nandfs_block_to_dblock(fsdev, 165 seg->start_block), fsdev->nd_blocksize, 0, 0, 0); 166 bzero(bp->b_data, seginfo->fsdev->nd_blocksize); 167 bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; 168 bp->b_flags |= B_MANAGED; 169 170 /* Add buffer to segment */ 171 TAILQ_INSERT_TAIL(&seg->segsum, bp, b_cluster.cluster_entry); 172 seg->current_off = bp->b_data + sizeof(struct nandfs_segment_summary); 173 174 DPRINTF(SYNC, ("%s: seg %p : initial settings: start %#jx size :%#x\n", 175 __func__, seg, (uintmax_t)seg->start_block, seg->num_blocks)); 176 DPRINTF(SYNC, ("%s: seg->seg_num %#jx cno %#jx next %#jx\n", __func__, 177 (uintmax_t)seg->seg_num, (uintmax_t)(fsdev->nd_last_cno + 1), 178 (uintmax_t)seg->seg_next)); 179 180 if (!prev) 181 LIST_INSERT_HEAD(&seginfo->seg_list, seg, seg_link); 182 else 183 LIST_INSERT_AFTER(prev, seg, seg_link); 184 185 seginfo->curseg = seg; 186 187 return (0); 188} 189 190static int 191delete_segment(struct nandfs_seginfo *seginfo) 192{ 193 struct nandfs_segment *seg, *tseg; 194 struct buf *bp, *tbp; 195 196 LIST_FOREACH_SAFE(seg, &seginfo->seg_list, seg_link, tseg) { 197 TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, 198 tbp) { 199 TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry); 200 bp->b_flags &= ~B_MANAGED; 201 brelse(bp); 202 } 203 204 LIST_REMOVE(seg, seg_link); 205 free(seg, M_DEVBUF); 206 } 207 208 return (0); 209} 210 211static int 212create_seginfo(struct nandfs_device *fsdev, struct nandfs_seginfo **seginfo) 213{ 214 struct nandfs_seginfo *info; 215 216 info = malloc(sizeof(*info), M_DEVBUF, M_WAITOK); 217 218 LIST_INIT(&info->seg_list); 219 info->fsdev = fsdev; 220 info->curseg = NULL; 221 info->blocks = 0; 222 *seginfo = info; 223 fsdev->nd_seginfo = info; 224 return (0); 225} 226 227static int 228delete_seginfo(struct nandfs_seginfo *seginfo) 229{ 230 struct nandfs_device *nffsdev; 231 232 nffsdev = seginfo->fsdev; 233 delete_segment(seginfo); 234 nffsdev->nd_seginfo = NULL; 235 free(seginfo, M_DEVBUF); 236 237 return (0); 238} 239 240static int 241nandfs_create_superroot_block(struct nandfs_seginfo *seginfo, 242 struct buf **newbp) 243{ 244 struct buf *bp; 245 int error; 246 247 bp = nandfs_geteblk(seginfo->fsdev->nd_blocksize, GB_NOWAIT_BD); 248 249 bzero(bp->b_data, seginfo->fsdev->nd_blocksize); 250 bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; 251 bp->b_flags |= B_MANAGED; 252 253 if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) { 254 error = create_segment(seginfo); 255 if (error) { 256 brelse(bp); 257 nandfs_error("%s: no segment for superroot\n", 258 __func__); 259 return (error); 260 } 261 } 262 263 TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry); 264 265 seginfo->curseg->nblocks++; 266 seginfo->curseg->num_blocks--; 267 seginfo->blocks++; 268 269 *newbp = bp; 270 return (0); 271} 272 273static int 274nandfs_add_superroot(struct nandfs_seginfo *seginfo) 275{ 276 struct nandfs_device *fsdev; 277 struct nandfs_super_root *sr; 278 struct buf *bp = NULL; 279 uint64_t crc_skip; 280 uint32_t crc_calc; 281 int error; 282 283 fsdev = seginfo->fsdev; 284 285 error = nandfs_create_superroot_block(seginfo, &bp); 286 if (error) { 287 nandfs_error("%s: cannot add superroot\n", __func__); 288 return (error); 289 } 290 291 sr = (struct nandfs_super_root *)bp->b_data; 292 /* Save superroot CRC */ 293 sr->sr_bytes = NANDFS_SR_BYTES; 294 sr->sr_flags = 0; 295 sr->sr_nongc_ctime = 0; 296 297 memcpy(&sr->sr_dat, &fsdev->nd_dat_node->nn_inode, 298 sizeof(struct nandfs_inode)); 299 memcpy(&sr->sr_cpfile, &fsdev->nd_cp_node->nn_inode, 300 sizeof(struct nandfs_inode)); 301 memcpy(&sr->sr_sufile, &fsdev->nd_su_node->nn_inode, 302 sizeof(struct nandfs_inode)); 303 304 crc_skip = sizeof(sr->sr_sum); 305 crc_calc = crc32((uint8_t *)sr + crc_skip, NANDFS_SR_BYTES - crc_skip); 306 307 sr->sr_sum = crc_calc; 308 309 bp->b_flags |= B_MANAGED; 310 bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; 311 312 bp->b_flags &= ~B_INVAL; 313 nandfs_dirty_bufs_increment(fsdev); 314 DPRINTF(SYNC, ("%s: bp:%p\n", __func__, bp)); 315 316 return (0); 317} 318 319static int 320nandfs_add_segsum_block(struct nandfs_seginfo *seginfo, struct buf **newbp) 321{ 322 struct nandfs_device *fsdev; 323 nandfs_daddr_t blk; 324 struct buf *bp; 325 int error; 326 327 if (!(seginfo->curseg) || seginfo->curseg->num_blocks <= 1) { 328 error = create_segment(seginfo); 329 if (error) { 330 nandfs_error("%s: error:%d when creating segment\n", 331 __func__, error); 332 return (error); 333 } 334 *newbp = TAILQ_FIRST(&seginfo->curseg->segsum); 335 return (0); 336 } 337 338 fsdev = seginfo->fsdev; 339 blk = nandfs_block_to_dblock(fsdev, seginfo->curseg->start_block + 340 seginfo->curseg->segsum_blocks); 341 342 bp = getblk(fsdev->nd_devvp, blk, fsdev->nd_blocksize, 0, 0, 0); 343 344 bzero(bp->b_data, seginfo->fsdev->nd_blocksize); 345 bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj; 346 bp->b_flags |= B_MANAGED; 347 348 TAILQ_INSERT_TAIL(&seginfo->curseg->segsum, bp, 349 b_cluster.cluster_entry); 350 seginfo->curseg->num_blocks--; 351 352 seginfo->curseg->segsum_blocks++; 353 seginfo->curseg->bytes_left = seginfo->fsdev->nd_blocksize; 354 seginfo->curseg->current_off = bp->b_data; 355 seginfo->blocks++; 356 357 *newbp = bp; 358 359 DPRINTF(SYNC, ("%s: bp %p\n", __func__, bp)); 360 361 return (0); 362} 363 364static int 365nandfs_add_blocks(struct nandfs_seginfo *seginfo, struct nandfs_node *node, 366 struct buf *bp) 367{ 368 union nandfs_binfo *binfo; 369 struct buf *seg_bp; 370 int error; 371 372 if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) { 373 error = create_segment(seginfo); 374 if (error) { 375 nandfs_error("%s: error:%d when creating segment\n", 376 __func__, error); 377 return (error); 378 } 379 } 380 381 if (seginfo->curseg->bytes_left < sizeof(union nandfs_binfo)) { 382 error = nandfs_add_segsum_block(seginfo, &seg_bp); 383 if (error) { 384 nandfs_error("%s: error:%d when adding segsum\n", 385 __func__, error); 386 return (error); 387 } 388 } 389 binfo = (union nandfs_binfo *)seginfo->curseg->current_off; 390 391 if (node->nn_ino != NANDFS_DAT_INO) { 392 binfo->bi_v.bi_blkoff = bp->b_lblkno; 393 binfo->bi_v.bi_ino = node->nn_ino; 394 } else { 395 binfo->bi_dat.bi_blkoff = bp->b_lblkno; 396 binfo->bi_dat.bi_ino = node->nn_ino; 397 if (NANDFS_IS_INDIRECT(bp)) 398 binfo->bi_dat.bi_level = 1; 399 else 400 binfo->bi_dat.bi_level = 0; 401 } 402 binfo++; 403 404 seginfo->curseg->bytes_left -= sizeof(union nandfs_binfo); 405 seginfo->curseg->segsum_bytes += sizeof(union nandfs_binfo); 406 seginfo->curseg->current_off = (char *)binfo; 407 408 TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry); 409 410 seginfo->curseg->nbinfos++; 411 seginfo->curseg->nblocks++; 412 seginfo->curseg->num_blocks--; 413 seginfo->blocks++; 414 415 DPRINTF(SYNC, ("%s: bp (%p) number %x (left %x)\n", 416 __func__, bp, seginfo->curseg->nblocks, 417 seginfo->curseg->num_blocks)); 418 return (0); 419} 420 421static int 422nandfs_iterate_dirty_buf(struct vnode *vp, struct nandfs_seginfo *seginfo, 423 uint8_t hold) 424{ 425 struct buf *bp, *tbd; 426 struct bufobj *bo; 427 struct nandfs_node *node; 428 int error; 429 430 node = VTON(vp); 431 bo = &vp->v_bufobj; 432 433 ASSERT_VOP_ELOCKED(vp, __func__); 434 435 /* Iterate dirty data bufs */ 436 TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, tbd) { 437 DPRINTF(SYNC, ("%s: vp (%p): bp (%p) with lblkno %jx ino %jx " 438 "add buf\n", __func__, vp, bp, bp->b_lblkno, node->nn_ino)); 439 440 if (!(NANDFS_ISGATHERED(bp))) { 441 error = nandfs_bmap_update_dat(node, 442 nandfs_vblk_get(bp), bp); 443 if (error) 444 return (error); 445 NANDFS_GATHER(bp); 446 nandfs_add_blocks(seginfo, node, bp); 447 } 448 } 449 450 return (0); 451} 452 453static int 454nandfs_iterate_system_vnode(struct nandfs_node *node, 455 struct nandfs_seginfo *seginfo) 456{ 457 struct vnode *vp; 458 int nblocks; 459 uint8_t hold = 0; 460 461 if (node->nn_ino != NANDFS_IFILE_INO) 462 hold = 1; 463 464 vp = NTOV(node); 465 466 nblocks = vp->v_bufobj.bo_dirty.bv_cnt; 467 DPRINTF(SYNC, ("%s: vp (%p): nblocks %x ino %jx\n", 468 __func__, vp, nblocks, node->nn_ino)); 469 470 if (nblocks) 471 nandfs_iterate_dirty_buf(vp, seginfo, hold); 472 473 return (0); 474} 475 476static int 477nandfs_iterate_dirty_vnodes(struct mount *mp, struct nandfs_seginfo *seginfo) 478{ 479 struct nandfs_node *nandfs_node; 480 struct vnode *vp, *mvp; 481 struct thread *td; 482 struct bufobj *bo; 483 int error, update; 484 485 td = curthread; 486 487 MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) { 488 update = 0; 489 490 if (mp->mnt_syncer == vp || VOP_ISLOCKED(vp)) { 491 VI_UNLOCK(vp); 492 continue; 493 } 494 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK | LK_NOWAIT, td) != 0) 495 continue; 496 497 nandfs_node = VTON(vp); 498 if (nandfs_node->nn_flags & IN_MODIFIED) { 499 nandfs_node->nn_flags &= ~(IN_MODIFIED); 500 update = 1; 501 } 502 503 bo = &vp->v_bufobj; 504 BO_LOCK(bo); 505 if (vp->v_bufobj.bo_dirty.bv_cnt) { 506 error = nandfs_iterate_dirty_buf(vp, seginfo, 0); 507 if (error) { 508 nandfs_error("%s: cannot iterate vnode:%p " 509 "err:%d\n", __func__, vp, error); 510 vput(vp); 511 BO_UNLOCK(bo); 512 return (error); 513 } 514 update = 1; 515 } else 516 vput(vp); 517 BO_UNLOCK(bo); 518 519 if (update) 520 nandfs_node_update(nandfs_node); 521 } 522 523 return (0); 524} 525 526static int 527nandfs_update_phys_block(struct nandfs_device *fsdev, struct buf *bp, 528 uint64_t phys_blknr, union nandfs_binfo *binfo) 529{ 530 struct nandfs_node *node, *dat; 531 struct vnode *vp; 532 uint64_t new_blknr; 533 int error; 534 535 vp = bp->b_vp; 536 node = VTON(vp); 537 new_blknr = nandfs_vblk_get(bp); 538 dat = fsdev->nd_dat_node; 539 540 DPRINTF(BMAP, ("%s: ino %#jx lblk %#jx: vblk %#jx -> %#jx\n", 541 __func__, (uintmax_t)node->nn_ino, (uintmax_t)bp->b_lblkno, 542 (uintmax_t)new_blknr, (uintmax_t)phys_blknr)); 543 544 if (node->nn_ino != NANDFS_DAT_INO) { 545 KASSERT((new_blknr != 0), ("vblk for bp %p is 0", bp)); 546 547 nandfs_vblock_assign(fsdev, new_blknr, phys_blknr); 548 binfo->bi_v.bi_vblocknr = new_blknr; 549 binfo->bi_v.bi_blkoff = bp->b_lblkno; 550 binfo->bi_v.bi_ino = node->nn_ino; 551 } else { 552 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); 553 error = nandfs_bmap_update_block(node, bp, phys_blknr); 554 if (error) { 555 nandfs_error("%s: error updating block:%jx for bp:%p\n", 556 __func__, (uintmax_t)phys_blknr, bp); 557 VOP_UNLOCK(NTOV(dat), 0); 558 return (error); 559 } 560 VOP_UNLOCK(NTOV(dat), 0); 561 binfo->bi_dat.bi_blkoff = bp->b_lblkno; 562 binfo->bi_dat.bi_ino = node->nn_ino; 563 if (NANDFS_IS_INDIRECT(bp)) 564 binfo->bi_dat.bi_level = 1; 565 else 566 binfo->bi_dat.bi_level = 0; 567 } 568 569 return (0); 570} 571 572#define NBINFO(off) ((off) + sizeof(union nandfs_binfo)) 573static int 574nandfs_segment_assign_pblk(struct nandfs_segment *nfsseg) 575{ 576 struct nandfs_device *fsdev; 577 union nandfs_binfo *binfo; 578 struct buf *bp, *seg_bp; 579 uint64_t blocknr; 580 uint32_t curr_off, blocksize; 581 int error; 582 583 fsdev = nfsseg->fsdev; 584 blocksize = fsdev->nd_blocksize; 585 586 blocknr = nfsseg->start_block + nfsseg->segsum_blocks; 587 seg_bp = TAILQ_FIRST(&nfsseg->segsum); 588 DPRINTF(SYNC, ("%s: seg:%p segsum bp:%p data:%p\n", 589 __func__, nfsseg, seg_bp, seg_bp->b_data)); 590 591 binfo = (union nandfs_binfo *)(seg_bp->b_data + 592 sizeof(struct nandfs_segment_summary)); 593 curr_off = sizeof(struct nandfs_segment_summary); 594 595 TAILQ_FOREACH(bp, &nfsseg->data, b_cluster.cluster_entry) { 596 KASSERT((bp->b_vp), ("bp %p has not vp", bp)); 597 598 DPRINTF(BMAP, ("\n\n%s: assign buf %p for ino %#jx next %p\n", 599 __func__, bp, (uintmax_t)VTON(bp->b_vp)->nn_ino, 600 TAILQ_NEXT(bp, b_cluster.cluster_entry))); 601 602 if (NBINFO(curr_off) > blocksize) { 603 seg_bp = TAILQ_NEXT(seg_bp, b_cluster.cluster_entry); 604 binfo = (union nandfs_binfo *)seg_bp->b_data; 605 curr_off = 0; 606 DPRINTF(SYNC, ("%s: next segsum %p data %p\n", 607 __func__, seg_bp, seg_bp->b_data)); 608 } 609 610 error = nandfs_update_phys_block(fsdev, bp, blocknr, binfo); 611 if (error) { 612 nandfs_error("%s: err:%d when updatinng phys block:%jx" 613 " for bp:%p and binfo:%p\n", __func__, error, 614 (uintmax_t)blocknr, bp, binfo); 615 return (error); 616 } 617 binfo++; 618 curr_off = NBINFO(curr_off); 619 620 blocknr++; 621 } 622 623 return (0); 624} 625 626static int 627nandfs_seginfo_assign_pblk(struct nandfs_seginfo *seginfo) 628{ 629 struct nandfs_segment *nfsseg; 630 int error = 0; 631 632 LIST_FOREACH(nfsseg, &seginfo->seg_list, seg_link) { 633 error = nandfs_segment_assign_pblk(nfsseg); 634 if (error) 635 break; 636 } 637 638 return (error); 639} 640 641static struct nandfs_segment_summary * 642nandfs_fill_segsum(struct nandfs_segment *seg, int has_sr) 643{ 644 struct nandfs_segment_summary *ss; 645 struct nandfs_device *fsdev; 646 struct buf *bp; 647 uint32_t rest, segsum_size, blocksize, crc_calc; 648 uint16_t flags; 649 uint8_t *crc_area, crc_skip; 650 651 DPRINTF(SYNC, ("%s: seg %#jx nblocks %#x sumbytes %#x\n", 652 __func__, (uintmax_t) seg->seg_num, 653 seg->nblocks + seg->segsum_blocks, 654 seg->segsum_bytes)); 655 656 fsdev = seg->fsdev; 657 658 flags = NANDFS_SS_LOGBGN | NANDFS_SS_LOGEND; 659 if (has_sr) 660 flags |= NANDFS_SS_SR; 661 662 bp = TAILQ_FIRST(&seg->segsum); 663 ss = (struct nandfs_segment_summary *) bp->b_data; 664 ss->ss_magic = NANDFS_SEGSUM_MAGIC; 665 ss->ss_bytes = sizeof(struct nandfs_segment_summary); 666 ss->ss_flags = flags; 667 ss->ss_seq = ++(fsdev->nd_seg_sequence); 668 ss->ss_create = fsdev->nd_ts.tv_sec; 669 nandfs_get_segment_range(fsdev, seg->seg_next, &ss->ss_next, NULL); 670 ss->ss_nblocks = seg->nblocks + seg->segsum_blocks; 671 ss->ss_nbinfos = seg->nbinfos; 672 ss->ss_sumbytes = seg->segsum_bytes; 673 674 crc_skip = sizeof(ss->ss_datasum) + sizeof(ss->ss_sumsum); 675 blocksize = seg->fsdev->nd_blocksize; 676 677 segsum_size = seg->segsum_bytes - crc_skip; 678 rest = min(seg->segsum_bytes, blocksize) - crc_skip; 679 crc_area = (uint8_t *)ss + crc_skip; 680 crc_calc = ~0U; 681 while (segsum_size > 0) { 682 crc_calc = crc32_raw(crc_area, rest, crc_calc); 683 segsum_size -= rest; 684 if (!segsum_size) 685 break; 686 bp = TAILQ_NEXT(bp, b_cluster.cluster_entry); 687 crc_area = (uint8_t *)bp->b_data; 688 rest = segsum_size <= blocksize ? segsum_size : blocksize; 689 } 690 ss->ss_sumsum = crc_calc ^ ~0U; 691 692 return (ss); 693 694} 695 696static int 697nandfs_save_buf(struct buf *bp, uint64_t blocknr, struct nandfs_device *fsdev) 698{ 699 struct bufobj *bo; 700 int error; 701 702 bo = &fsdev->nd_devvp->v_bufobj; 703 704 bp->b_blkno = nandfs_block_to_dblock(fsdev, blocknr); 705 bp->b_iooffset = dbtob(bp->b_blkno); 706 707 KASSERT(bp->b_bufobj != NULL, ("no bufobj for %p", bp)); 708 if (bp->b_bufobj != bo) { 709 BO_LOCK(bp->b_bufobj); 710 BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, 711 BO_LOCKPTR(bp->b_bufobj)); 712 KASSERT(BUF_ISLOCKED(bp), ("Problem with locking buffer")); 713 } 714 715 DPRINTF(SYNC, ("%s: buf: %p offset %#jx blk %#jx size %#x\n", 716 __func__, bp, (uintmax_t)bp->b_offset, (uintmax_t)blocknr, 717 fsdev->nd_blocksize)); 718 719 NANDFS_UNGATHER(bp); 720 nandfs_buf_clear(bp, 0xffffffff); 721 bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED); 722 error = bwrite(bp); 723 if (error) { 724 nandfs_error("%s: error:%d when writing buffer:%p\n", 725 __func__, error, bp); 726 return (error); 727 } 728 return (error); 729} 730 731static void 732nandfs_clean_buf(struct nandfs_device *fsdev, struct buf *bp) 733{ 734 735 DPRINTF(SYNC, ("%s: buf: %p\n", __func__, bp)); 736 737 NANDFS_UNGATHER(bp); 738 nandfs_buf_clear(bp, 0xffffffff); 739 bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED); 740 nandfs_undirty_buf_fsdev(fsdev, bp); 741} 742 743static void 744nandfs_clean_segblocks(struct nandfs_segment *seg, uint8_t unlock) 745{ 746 struct nandfs_device *fsdev = seg->fsdev; 747 struct nandfs_segment *next_seg; 748 struct buf *bp, *tbp, *next_bp; 749 struct vnode *vp, *next_vp; 750 751 VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE); 752 TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) { 753 TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry); 754 nandfs_clean_buf(fsdev, bp); 755 } 756 757 TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) { 758 TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry); 759 760 /* 761 * If bp is not super-root and vnode is not currently 762 * locked lock it. 763 */ 764 vp = bp->b_vp; 765 next_vp = NULL; 766 next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry); 767 if (!next_bp) { 768 next_seg = LIST_NEXT(seg, seg_link); 769 if (next_seg) 770 next_bp = TAILQ_FIRST(&next_seg->data); 771 } 772 773 if (next_bp) 774 next_vp = next_bp->b_vp; 775 776 nandfs_clean_buf(fsdev, bp); 777 778 if (unlock && vp != NULL && next_vp != vp && 779 !NANDFS_SYS_NODE(VTON(vp)->nn_ino)) 780 vput(vp); 781 782 nandfs_dirty_bufs_decrement(fsdev); 783 } 784 785 VOP_UNLOCK(fsdev->nd_devvp, 0); 786} 787 788static int 789nandfs_save_segblocks(struct nandfs_segment *seg, uint8_t unlock) 790{ 791 struct nandfs_device *fsdev = seg->fsdev; 792 struct nandfs_segment *next_seg; 793 struct buf *bp, *tbp, *next_bp; 794 struct vnode *vp, *next_vp; 795 uint64_t blocknr; 796 uint32_t i = 0; 797 int error = 0; 798 799 VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE); 800 TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) { 801 TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry); 802 blocknr = seg->start_block + i; 803 error = nandfs_save_buf(bp, blocknr, fsdev); 804 if (error) { 805 nandfs_error("%s: error saving buf: %p blocknr:%jx\n", 806 __func__, bp, (uintmax_t)blocknr); 807 goto out; 808 } 809 i++; 810 } 811 812 i = 0; 813 TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) { 814 TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry); 815 816 blocknr = seg->start_block + seg->segsum_blocks + i; 817 /* 818 * If bp is not super-root and vnode is not currently 819 * locked lock it. 820 */ 821 vp = bp->b_vp; 822 next_vp = NULL; 823 next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry); 824 if (!next_bp) { 825 next_seg = LIST_NEXT(seg, seg_link); 826 if (next_seg) 827 next_bp = TAILQ_FIRST(&next_seg->data); 828 } 829 830 if (next_bp) 831 next_vp = next_bp->b_vp; 832 833 error = nandfs_save_buf(bp, blocknr, fsdev); 834 if (error) { 835 nandfs_error("%s: error saving buf: %p blknr: %jx\n", 836 __func__, bp, (uintmax_t)blocknr); 837 if (unlock && vp != NULL && next_vp != vp && 838 !NANDFS_SYS_NODE(VTON(vp)->nn_ino)) 839 vput(vp); 840 goto out; 841 } 842 843 if (unlock && vp != NULL && next_vp != vp && 844 !NANDFS_SYS_NODE(VTON(vp)->nn_ino)) 845 vput(vp); 846 847 i++; 848 nandfs_dirty_bufs_decrement(fsdev); 849 } 850out: 851 if (error) { 852 nandfs_clean_segblocks(seg, unlock); 853 VOP_UNLOCK(fsdev->nd_devvp, 0); 854 return (error); 855 } 856 857 VOP_UNLOCK(fsdev->nd_devvp, 0); 858 return (error); 859} 860 861 862static void 863clean_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock) 864{ 865 struct nandfs_segment *seg; 866 867 DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo)); 868 869 LIST_FOREACH(seg, &seginfo->seg_list, seg_link) { 870 nandfs_clean_segblocks(seg, unlock); 871 } 872} 873 874static int 875save_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock) 876{ 877 struct nandfs_segment *seg; 878 struct nandfs_device *fsdev; 879 struct nandfs_segment_summary *ss; 880 int error = 0; 881 882 fsdev = seginfo->fsdev; 883 884 DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo)); 885 886 LIST_FOREACH(seg, &seginfo->seg_list, seg_link) { 887 if (LIST_NEXT(seg, seg_link)) { 888 nandfs_fill_segsum(seg, 0); 889 error = nandfs_save_segblocks(seg, unlock); 890 if (error) { 891 nandfs_error("%s: error:%d saving seg:%p\n", 892 __func__, error, seg); 893 goto out; 894 } 895 } else { 896 ss = nandfs_fill_segsum(seg, 1); 897 fsdev->nd_last_segsum = *ss; 898 error = nandfs_save_segblocks(seg, unlock); 899 if (error) { 900 nandfs_error("%s: error:%d saving seg:%p\n", 901 __func__, error, seg); 902 goto out; 903 } 904 fsdev->nd_last_cno++; 905 fsdev->nd_last_pseg = seg->start_block; 906 } 907 } 908out: 909 if (error) 910 clean_seginfo(seginfo, unlock); 911 return (error); 912} 913 914static void 915nandfs_invalidate_bufs(struct nandfs_device *fsdev, uint64_t segno) 916{ 917 uint64_t start, end; 918 struct buf *bp, *tbd; 919 struct bufobj *bo; 920 921 nandfs_get_segment_range(fsdev, segno, &start, &end); 922 923 bo = &NTOV(fsdev->nd_gc_node)->v_bufobj; 924 925 BO_LOCK(bo); 926restart_locked_gc: 927 TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, tbd) { 928 if (!(bp->b_lblkno >= start && bp->b_lblkno <= end)) 929 continue; 930 931 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) 932 goto restart_locked_gc; 933 934 bremfree(bp); 935 bp->b_flags |= (B_INVAL | B_RELBUF); 936 bp->b_flags &= ~(B_ASYNC | B_MANAGED); 937 BO_UNLOCK(bo); 938 brelse(bp); 939 BO_LOCK(bo); 940 } 941 BO_UNLOCK(bo); 942} 943 944/* Process segments marks to free by cleaner */ 945static void 946nandfs_process_segments(struct nandfs_device *fsdev) 947{ 948 uint64_t saved_segment; 949 int i; 950 951 if (fsdev->nd_free_base) { 952 saved_segment = nandfs_get_segnum_of_block(fsdev, 953 fsdev->nd_super.s_last_pseg); 954 for (i = 0; i < fsdev->nd_free_count; i++) { 955 if (fsdev->nd_free_base[i] == NANDFS_NOSEGMENT) 956 continue; 957 /* Update superblock if clearing segment point by it */ 958 if (fsdev->nd_free_base[i] == saved_segment) { 959 nandfs_write_superblock(fsdev); 960 saved_segment = nandfs_get_segnum_of_block( 961 fsdev, fsdev->nd_super.s_last_pseg); 962 } 963 nandfs_invalidate_bufs(fsdev, fsdev->nd_free_base[i]); 964 nandfs_clear_segment(fsdev, fsdev->nd_free_base[i]); 965 } 966 967 free(fsdev->nd_free_base, M_NANDFSTEMP); 968 fsdev->nd_free_base = NULL; 969 fsdev->nd_free_count = 0; 970 } 971} 972 973/* Collect and write dirty buffers */ 974int 975nandfs_sync_file(struct vnode *vp) 976{ 977 struct nandfs_device *fsdev; 978 struct nandfs_node *nandfs_node; 979 struct nandfsmount *nmp; 980 struct nandfs_node *dat, *su, *ifile, *cp; 981 struct nandfs_seginfo *seginfo = NULL; 982 struct nandfs_segment *seg; 983 int update, error; 984 int cno_changed; 985 986 ASSERT_VOP_LOCKED(vp, __func__); 987 DPRINTF(SYNC, ("%s: START\n", __func__)); 988 989 error = 0; 990 nmp = VFSTONANDFS(vp->v_mount); 991 fsdev = nmp->nm_nandfsdev; 992 993 dat = fsdev->nd_dat_node; 994 su = fsdev->nd_su_node; 995 cp = fsdev->nd_cp_node; 996 ifile = nmp->nm_ifile_node; 997 998 NANDFS_WRITEASSERT(fsdev); 999 if (lockmgr(&fsdev->nd_seg_const, LK_UPGRADE, NULL) != 0) { 1000 DPRINTF(SYNC, ("%s: lost shared lock\n", __func__)); 1001 if (lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL) != 0) 1002 panic("couldn't lock exclusive"); 1003 } 1004 DPRINTF(SYNC, ("%s: got lock\n", __func__)); 1005 1006 VOP_LOCK(NTOV(su), LK_EXCLUSIVE); 1007 create_seginfo(fsdev, &seginfo); 1008 1009 update = 0; 1010 1011 nandfs_node = VTON(vp); 1012 if (nandfs_node->nn_flags & IN_MODIFIED) { 1013 nandfs_node->nn_flags &= ~(IN_MODIFIED); 1014 update = 1; 1015 } 1016 1017 if (vp->v_bufobj.bo_dirty.bv_cnt) { 1018 error = nandfs_iterate_dirty_buf(vp, seginfo, 0); 1019 if (error) { 1020 clean_seginfo(seginfo, 0); 1021 delete_seginfo(seginfo); 1022 VOP_UNLOCK(NTOV(su), 0); 1023 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); 1024 nandfs_error("%s: err:%d iterating dirty bufs vp:%p", 1025 __func__, error, vp); 1026 return (error); 1027 } 1028 update = 1; 1029 } 1030 1031 if (update) { 1032 VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE); 1033 error = nandfs_node_update(nandfs_node); 1034 if (error) { 1035 clean_seginfo(seginfo, 0); 1036 delete_seginfo(seginfo); 1037 VOP_UNLOCK(NTOV(ifile), 0); 1038 VOP_UNLOCK(NTOV(su), 0); 1039 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); 1040 nandfs_error("%s: err:%d updating vp:%p", 1041 __func__, error, vp); 1042 return (error); 1043 } 1044 VOP_UNLOCK(NTOV(ifile), 0); 1045 } 1046 1047 cno_changed = 0; 1048 if (seginfo->blocks) { 1049 VOP_LOCK(NTOV(cp), LK_EXCLUSIVE); 1050 cno_changed = 1; 1051 /* Create new checkpoint */ 1052 error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1); 1053 if (error) { 1054 clean_seginfo(seginfo, 0); 1055 delete_seginfo(seginfo); 1056 VOP_UNLOCK(NTOV(cp), 0); 1057 VOP_UNLOCK(NTOV(su), 0); 1058 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); 1059 nandfs_error("%s: err:%d getting cp:%jx", 1060 __func__, error, fsdev->nd_last_cno + 1); 1061 return (error); 1062 } 1063 1064 /* Reiterate all blocks and assign physical block number */ 1065 nandfs_seginfo_assign_pblk(seginfo); 1066 1067 /* Fill checkpoint data */ 1068 error = nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1, 1069 &ifile->nn_inode, seginfo->blocks); 1070 if (error) { 1071 clean_seginfo(seginfo, 0); 1072 delete_seginfo(seginfo); 1073 VOP_UNLOCK(NTOV(cp), 0); 1074 VOP_UNLOCK(NTOV(su), 0); 1075 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); 1076 nandfs_error("%s: err:%d setting cp:%jx", 1077 __func__, error, fsdev->nd_last_cno + 1); 1078 return (error); 1079 } 1080 1081 VOP_UNLOCK(NTOV(cp), 0); 1082 LIST_FOREACH(seg, &seginfo->seg_list, seg_link) 1083 nandfs_update_segment(fsdev, seg->seg_num, 1084 seg->nblocks + seg->segsum_blocks); 1085 1086 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); 1087 error = save_seginfo(seginfo, 0); 1088 if (error) { 1089 clean_seginfo(seginfo, 0); 1090 delete_seginfo(seginfo); 1091 VOP_UNLOCK(NTOV(dat), 0); 1092 VOP_UNLOCK(NTOV(su), 0); 1093 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); 1094 nandfs_error("%s: err:%d updating seg", 1095 __func__, error); 1096 return (error); 1097 } 1098 VOP_UNLOCK(NTOV(dat), 0); 1099 } 1100 1101 VOP_UNLOCK(NTOV(su), 0); 1102 1103 delete_seginfo(seginfo); 1104 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL); 1105 1106 if (cno_changed && !error) { 1107 if (nandfs_cps_between_sblocks != 0 && 1108 fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) 1109 nandfs_write_superblock(fsdev); 1110 } 1111 1112 ASSERT_VOP_LOCKED(vp, __func__); 1113 DPRINTF(SYNC, ("%s: END error %d\n", __func__, error)); 1114 return (error); 1115} 1116 1117int 1118nandfs_segment_constructor(struct nandfsmount *nmp, int flags) 1119{ 1120 struct nandfs_device *fsdev; 1121 struct nandfs_seginfo *seginfo = NULL; 1122 struct nandfs_segment *seg; 1123 struct nandfs_node *dat, *su, *ifile, *cp, *gc; 1124 int cno_changed, error; 1125 1126 DPRINTF(SYNC, ("%s: START\n", __func__)); 1127 fsdev = nmp->nm_nandfsdev; 1128 1129 lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL); 1130 DPRINTF(SYNC, ("%s: git lock\n", __func__)); 1131again: 1132 create_seginfo(fsdev, &seginfo); 1133 1134 dat = fsdev->nd_dat_node; 1135 su = fsdev->nd_su_node; 1136 cp = fsdev->nd_cp_node; 1137 gc = fsdev->nd_gc_node; 1138 ifile = nmp->nm_ifile_node; 1139 1140 VOP_LOCK(NTOV(su), LK_EXCLUSIVE); 1141 VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE); 1142 VOP_LOCK(NTOV(gc), LK_EXCLUSIVE); 1143 VOP_LOCK(NTOV(cp), LK_EXCLUSIVE); 1144 1145 nandfs_iterate_system_vnode(gc, seginfo); 1146 nandfs_iterate_dirty_vnodes(nmp->nm_vfs_mountp, seginfo); 1147 nandfs_iterate_system_vnode(ifile, seginfo); 1148 nandfs_iterate_system_vnode(su, seginfo); 1149 1150 cno_changed = 0; 1151 if (seginfo->blocks || flags) { 1152 cno_changed = 1; 1153 /* Create new checkpoint */ 1154 error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1); 1155 if (error) { 1156 clean_seginfo(seginfo, 0); 1157 delete_seginfo(seginfo); 1158 goto error_locks; 1159 } 1160 1161 /* Collect blocks from system files */ 1162 nandfs_iterate_system_vnode(cp, seginfo); 1163 nandfs_iterate_system_vnode(su, seginfo); 1164 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); 1165 nandfs_iterate_system_vnode(dat, seginfo); 1166 VOP_UNLOCK(NTOV(dat), 0); 1167reiterate: 1168 seginfo->reiterate = 0; 1169 nandfs_iterate_system_vnode(su, seginfo); 1170 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); 1171 nandfs_iterate_system_vnode(dat, seginfo); 1172 VOP_UNLOCK(NTOV(dat), 0); 1173 if (seginfo->reiterate) 1174 goto reiterate; 1175 if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) { 1176 error = create_segment(seginfo); 1177 if (error) { 1178 clean_seginfo(seginfo, 0); 1179 delete_seginfo(seginfo); 1180 goto error_locks; 1181 } 1182 goto reiterate; 1183 } 1184 1185 /* Reiterate all blocks and assign physical block number */ 1186 nandfs_seginfo_assign_pblk(seginfo); 1187 1188 /* Fill superroot */ 1189 error = nandfs_add_superroot(seginfo); 1190 if (error) { 1191 clean_seginfo(seginfo, 0); 1192 delete_seginfo(seginfo); 1193 goto error_locks; 1194 } 1195 KASSERT(!(seginfo->reiterate), ("reiteration after superroot")); 1196 1197 /* Fill checkpoint data */ 1198 nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1, 1199 &ifile->nn_inode, seginfo->blocks); 1200 1201 LIST_FOREACH(seg, &seginfo->seg_list, seg_link) 1202 nandfs_update_segment(fsdev, seg->seg_num, 1203 seg->nblocks + seg->segsum_blocks); 1204 1205 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); 1206 error = save_seginfo(seginfo, 1); 1207 if (error) { 1208 clean_seginfo(seginfo, 1); 1209 delete_seginfo(seginfo); 1210 goto error_dat; 1211 } 1212 VOP_UNLOCK(NTOV(dat), 0); 1213 } 1214 1215 VOP_UNLOCK(NTOV(cp), 0); 1216 VOP_UNLOCK(NTOV(gc), 0); 1217 VOP_UNLOCK(NTOV(ifile), 0); 1218 1219 nandfs_process_segments(fsdev); 1220 1221 VOP_UNLOCK(NTOV(su), 0); 1222 1223 delete_seginfo(seginfo); 1224 1225 /* 1226 * XXX: a hack, will go away soon 1227 */ 1228 if ((NTOV(dat)->v_bufobj.bo_dirty.bv_cnt != 0 || 1229 NTOV(cp)->v_bufobj.bo_dirty.bv_cnt != 0 || 1230 NTOV(gc)->v_bufobj.bo_dirty.bv_cnt != 0 || 1231 NTOV(ifile)->v_bufobj.bo_dirty.bv_cnt != 0 || 1232 NTOV(su)->v_bufobj.bo_dirty.bv_cnt != 0) && 1233 (flags & NANDFS_UMOUNT)) { 1234 DPRINTF(SYNC, ("%s: RERUN\n", __func__)); 1235 goto again; 1236 } 1237 1238 MPASS(fsdev->nd_free_base == NULL); 1239 1240 lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL); 1241 1242 if (cno_changed) { 1243 if ((nandfs_cps_between_sblocks != 0 && 1244 fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) || 1245 flags & NANDFS_UMOUNT) 1246 nandfs_write_superblock(fsdev); 1247 } 1248 1249 DPRINTF(SYNC, ("%s: END\n", __func__)); 1250 return (0); 1251error_dat: 1252 VOP_UNLOCK(NTOV(dat), 0); 1253error_locks: 1254 VOP_UNLOCK(NTOV(cp), 0); 1255 VOP_UNLOCK(NTOV(gc), 0); 1256 VOP_UNLOCK(NTOV(ifile), 0); 1257 VOP_UNLOCK(NTOV(su), 0); 1258 lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL); 1259 1260 return (error); 1261} 1262 1263#ifdef DDB 1264/* 1265 * Show details about the given NANDFS mount point. 1266 */ 1267DB_SHOW_COMMAND(nandfs, db_show_nandfs) 1268{ 1269 struct mount *mp; 1270 struct nandfs_device *nffsdev; 1271 struct nandfs_segment *seg; 1272 struct nandfsmount *nmp; 1273 struct buf *bp; 1274 struct vnode *vp; 1275 1276 if (!have_addr) { 1277 db_printf("\nUsage: show nandfs <mount_addr>\n"); 1278 return; 1279 } 1280 1281 mp = (struct mount *)addr; 1282 db_printf("%p %s on %s (%s)\n", mp, mp->mnt_stat.f_mntfromname, 1283 mp->mnt_stat.f_mntonname, mp->mnt_stat.f_fstypename); 1284 1285 1286 nmp = (struct nandfsmount *)(mp->mnt_data); 1287 nffsdev = nmp->nm_nandfsdev; 1288 db_printf("dev vnode:%p\n", nffsdev->nd_devvp); 1289 db_printf("blocksize:%jx last cno:%jx last pseg:%jx seg num:%jx\n", 1290 (uintmax_t)nffsdev->nd_blocksize, (uintmax_t)nffsdev->nd_last_cno, 1291 (uintmax_t)nffsdev->nd_last_pseg, (uintmax_t)nffsdev->nd_seg_num); 1292 db_printf("system nodes: dat:%p cp:%p su:%p ifile:%p gc:%p\n", 1293 nffsdev->nd_dat_node, nffsdev->nd_cp_node, nffsdev->nd_su_node, 1294 nmp->nm_ifile_node, nffsdev->nd_gc_node); 1295 1296 if (nffsdev->nd_seginfo != NULL) { 1297 LIST_FOREACH(seg, &nffsdev->nd_seginfo->seg_list, seg_link) { 1298 db_printf("seg: %p\n", seg); 1299 TAILQ_FOREACH(bp, &seg->segsum, 1300 b_cluster.cluster_entry) 1301 db_printf("segbp %p\n", bp); 1302 TAILQ_FOREACH(bp, &seg->data, 1303 b_cluster.cluster_entry) { 1304 vp = bp->b_vp; 1305 db_printf("bp:%p bp->b_vp:%p ino:%jx\n", bp, vp, 1306 (uintmax_t)(vp ? VTON(vp)->nn_ino : 0)); 1307 } 1308 } 1309 } 1310} 1311#endif 1312