The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/nandfs/nandfs_segment.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 506901e218e3a7ca0bed884ac59fbada


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.