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  * 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: releng/10.4/sys/fs/nandfs/nandfs_segment.c 294853 2016-01-26 22:14:55Z rpokala $");
   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 
   62 static int
   63 nandfs_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 
   82 static int
   83 create_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 
  190 static int
  191 delete_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 
  211 static int
  212 create_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 
  227 static int
  228 delete_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 
  240 static int
  241 nandfs_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 
  273 static int
  274 nandfs_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 
  319 static int
  320 nandfs_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 
  364 static int
  365 nandfs_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 
  421 static int
  422 nandfs_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 
  453 static int
  454 nandfs_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 
  476 static int
  477 nandfs_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 
  526 static int
  527 nandfs_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))
  573 static int
  574 nandfs_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 
  626 static int
  627 nandfs_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 
  641 static struct nandfs_segment_summary *
  642 nandfs_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 
  696 static int
  697 nandfs_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 
  731 static void
  732 nandfs_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 
  743 static void
  744 nandfs_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 
  788 static int
  789 nandfs_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         }
  850 out:
  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 
  862 static void
  863 clean_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 
  874 static int
  875 save_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         }
  908 out:
  909         if (error)
  910                 clean_seginfo(seginfo, unlock);
  911         return (error);
  912 }
  913 
  914 static void
  915 nandfs_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);
  926 restart_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 */
  945 static void
  946 nandfs_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 */
  974 int
  975 nandfs_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 
 1117 int
 1118 nandfs_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__));
 1131 again:
 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);
 1167 reiterate:
 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);
 1251 error_dat:
 1252         VOP_UNLOCK(NTOV(dat), 0);
 1253 error_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  */
 1267 DB_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

Cache object: 51b353bc5c40fb64618ab5e04a4b93a9


[ 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.