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_vfsops.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  * Copyright (c) 2008, 2009 Reinoud Zandijk
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  *
   28  * From: NetBSD: nilfs_vfsops.c,v 1.1 2009/07/18 16:31:42 reinoud Exp
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/fcntl.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/namei.h>
   43 #include <sys/proc.h>
   44 #include <sys/priv.h>
   45 #include <sys/vnode.h>
   46 #include <sys/buf.h>
   47 #include <sys/sysctl.h>
   48 #include <sys/libkern.h>
   49 
   50 #include <geom/geom.h>
   51 #include <geom/geom_vfs.h>
   52 
   53 #include <machine/_inttypes.h>
   54 
   55 #include <fs/nandfs/nandfs_mount.h>
   56 #include <fs/nandfs/nandfs.h>
   57 #include <fs/nandfs/nandfs_subr.h>
   58 
   59 static MALLOC_DEFINE(M_NANDFSMNT, "nandfs_mount", "NANDFS mount structure");
   60 
   61 #define NANDFS_SET_SYSTEMFILE(vp) {     \
   62         (vp)->v_vflag |= VV_SYSTEM;     \
   63         vref(vp);                       \
   64         vput(vp); }
   65 
   66 #define NANDFS_UNSET_SYSTEMFILE(vp) {   \
   67         VOP_LOCK(vp, LK_EXCLUSIVE);     \
   68         MPASS(vp->v_bufobj.bo_dirty.bv_cnt == 0); \
   69         (vp)->v_vflag &= ~VV_SYSTEM;    \
   70         vgone(vp);                      \
   71         vput(vp); }
   72 
   73 /* Globals */
   74 struct _nandfs_devices nandfs_devices;
   75 
   76 /* Parameters */
   77 int nandfs_verbose = 0;
   78 
   79 static void
   80 nandfs_tunable_init(void *arg)
   81 {
   82 
   83         TUNABLE_INT_FETCH("vfs.nandfs.verbose", &nandfs_verbose);
   84 }
   85 SYSINIT(nandfs_tunables, SI_SUB_VFS, SI_ORDER_ANY, nandfs_tunable_init, NULL);
   86 
   87 static SYSCTL_NODE(_vfs, OID_AUTO, nandfs, CTLFLAG_RD, 0, "NAND filesystem");
   88 static SYSCTL_NODE(_vfs_nandfs, OID_AUTO, mount, CTLFLAG_RD, 0,
   89     "NANDFS mountpoints");
   90 SYSCTL_INT(_vfs_nandfs, OID_AUTO, verbose, CTLFLAG_RW, &nandfs_verbose, 0, "");
   91 
   92 #define NANDFS_CONSTR_INTERVAL  5
   93 int nandfs_sync_interval = NANDFS_CONSTR_INTERVAL; /* sync every 5 seconds */
   94 SYSCTL_UINT(_vfs_nandfs, OID_AUTO, sync_interval, CTLFLAG_RW,
   95     &nandfs_sync_interval, 0, "");
   96 
   97 #define NANDFS_MAX_DIRTY_SEGS   5
   98 int nandfs_max_dirty_segs = NANDFS_MAX_DIRTY_SEGS; /* sync when 5 dirty seg */
   99 SYSCTL_UINT(_vfs_nandfs, OID_AUTO, max_dirty_segs, CTLFLAG_RW,
  100     &nandfs_max_dirty_segs, 0, "");
  101 
  102 #define NANDFS_CPS_BETWEEN_SBLOCKS 5
  103 int nandfs_cps_between_sblocks = NANDFS_CPS_BETWEEN_SBLOCKS; /* write superblock every 5 checkpoints */
  104 SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cps_between_sblocks, CTLFLAG_RW,
  105     &nandfs_cps_between_sblocks, 0, "");
  106 
  107 #define NANDFS_CLEANER_ENABLE 1
  108 int nandfs_cleaner_enable = NANDFS_CLEANER_ENABLE;
  109 SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cleaner_enable, CTLFLAG_RW,
  110     &nandfs_cleaner_enable, 0, "");
  111 
  112 #define NANDFS_CLEANER_INTERVAL 5
  113 int nandfs_cleaner_interval = NANDFS_CLEANER_INTERVAL;
  114 SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cleaner_interval, CTLFLAG_RW,
  115     &nandfs_cleaner_interval, 0, "");
  116 
  117 #define NANDFS_CLEANER_SEGMENTS 5
  118 int nandfs_cleaner_segments = NANDFS_CLEANER_SEGMENTS;
  119 SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cleaner_segments, CTLFLAG_RW,
  120     &nandfs_cleaner_segments, 0, "");
  121 
  122 static int nandfs_mountfs(struct vnode *devvp, struct mount *mp);
  123 static vfs_mount_t      nandfs_mount;
  124 static vfs_root_t       nandfs_root;
  125 static vfs_statfs_t     nandfs_statfs;
  126 static vfs_unmount_t    nandfs_unmount;
  127 static vfs_vget_t       nandfs_vget;
  128 static vfs_sync_t       nandfs_sync;
  129 static const char *nandfs_opts[] = {
  130         "snap", "from", "noatime", NULL
  131 };
  132 
  133 /* System nodes */
  134 static int
  135 nandfs_create_system_nodes(struct nandfs_device *nandfsdev)
  136 {
  137         int error;
  138 
  139         error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_DAT_INO,
  140             &nandfsdev->nd_super_root.sr_dat, &nandfsdev->nd_dat_node);
  141         if (error)
  142                 goto errorout;
  143 
  144         error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_CPFILE_INO,
  145             &nandfsdev->nd_super_root.sr_cpfile, &nandfsdev->nd_cp_node);
  146         if (error)
  147                 goto errorout;
  148 
  149         error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_SUFILE_INO,
  150             &nandfsdev->nd_super_root.sr_sufile, &nandfsdev->nd_su_node);
  151         if (error)
  152                 goto errorout;
  153 
  154         error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_GC_INO,
  155             NULL, &nandfsdev->nd_gc_node);
  156         if (error)
  157                 goto errorout;
  158 
  159         NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_dat_node));
  160         NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_cp_node));
  161         NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_su_node));
  162         NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_gc_node));
  163 
  164         DPRINTF(VOLUMES, ("System vnodes: dat: %p cp: %p su: %p\n",
  165             NTOV(nandfsdev->nd_dat_node), NTOV(nandfsdev->nd_cp_node),
  166             NTOV(nandfsdev->nd_su_node)));
  167         return (0);
  168 
  169 errorout:
  170         nandfs_dispose_node(&nandfsdev->nd_gc_node);
  171         nandfs_dispose_node(&nandfsdev->nd_dat_node);
  172         nandfs_dispose_node(&nandfsdev->nd_cp_node);
  173         nandfs_dispose_node(&nandfsdev->nd_su_node);
  174 
  175         return (error);
  176 }
  177 
  178 static void
  179 nandfs_release_system_nodes(struct nandfs_device *nandfsdev)
  180 {
  181 
  182         if (!nandfsdev)
  183                 return;
  184         if (nandfsdev->nd_refcnt > 0)
  185                 return;
  186 
  187         if (nandfsdev->nd_gc_node)
  188                 NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_gc_node));
  189         if (nandfsdev->nd_dat_node)
  190                 NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_dat_node));
  191         if (nandfsdev->nd_cp_node)
  192                 NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_cp_node));
  193         if (nandfsdev->nd_su_node)
  194                 NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_su_node));
  195 }
  196 
  197 static int
  198 nandfs_check_fsdata_crc(struct nandfs_fsdata *fsdata)
  199 {
  200         uint32_t fsdata_crc, comp_crc;
  201 
  202         if (fsdata->f_magic != NANDFS_FSDATA_MAGIC)
  203                 return (0);
  204 
  205         /* Preserve CRC */
  206         fsdata_crc = fsdata->f_sum;
  207 
  208         /* Calculate */
  209         fsdata->f_sum = (0);
  210         comp_crc = crc32((uint8_t *)fsdata, fsdata->f_bytes);
  211 
  212         /* Restore */
  213         fsdata->f_sum = fsdata_crc;
  214 
  215         /* Check CRC */
  216         return (fsdata_crc == comp_crc);
  217 }
  218 
  219 static int
  220 nandfs_check_superblock_crc(struct nandfs_fsdata *fsdata,
  221     struct nandfs_super_block *super)
  222 {
  223         uint32_t super_crc, comp_crc;
  224 
  225         /* Check super block magic */
  226         if (super->s_magic != NANDFS_SUPER_MAGIC)
  227                 return (0);
  228 
  229         /* Preserve CRC */
  230         super_crc = super->s_sum;
  231 
  232         /* Calculate */
  233         super->s_sum = (0);
  234         comp_crc = crc32((uint8_t *)super, fsdata->f_sbbytes);
  235 
  236         /* Restore */
  237         super->s_sum = super_crc;
  238 
  239         /* Check CRC */
  240         return (super_crc == comp_crc);
  241 }
  242 
  243 static void
  244 nandfs_calc_superblock_crc(struct nandfs_fsdata *fsdata,
  245     struct nandfs_super_block *super)
  246 {
  247         uint32_t comp_crc;
  248 
  249         /* Calculate */
  250         super->s_sum = 0;
  251         comp_crc = crc32((uint8_t *)super, fsdata->f_sbbytes);
  252 
  253         /* Restore */
  254         super->s_sum = comp_crc;
  255 }
  256 
  257 static int
  258 nandfs_is_empty(u_char *area, int size)
  259 {
  260         int i;
  261 
  262         for (i = 0; i < size; i++)
  263                 if (area[i] != 0xff)
  264                         return (0);
  265 
  266         return (1);
  267 }
  268 
  269 static __inline int
  270 nandfs_sblocks_in_esize(struct nandfs_device *fsdev)
  271 {
  272 
  273         return ((fsdev->nd_erasesize - NANDFS_SBLOCK_OFFSET_BYTES) /
  274             sizeof(struct nandfs_super_block));
  275 }
  276 
  277 static __inline int
  278 nandfs_max_sblocks(struct nandfs_device *fsdev)
  279 {
  280 
  281         return (NANDFS_NFSAREAS * nandfs_sblocks_in_esize(fsdev));
  282 }
  283 
  284 static __inline int
  285 nandfs_sblocks_in_block(struct nandfs_device *fsdev)
  286 {
  287 
  288         return (fsdev->nd_devblocksize / sizeof(struct nandfs_super_block));
  289 }
  290 
  291 #if 0
  292 static __inline int
  293 nandfs_sblocks_in_first_block(struct nandfs_device *fsdev)
  294 {
  295         int n;
  296 
  297         n = nandfs_sblocks_in_block(fsdev) -
  298             NANDFS_SBLOCK_OFFSET_BYTES / sizeof(struct nandfs_super_block);
  299         if (n < 0)
  300                 n = 0;
  301 
  302         return (n);
  303 }
  304 #endif
  305 
  306 static int
  307 nandfs_write_superblock_at(struct nandfs_device *fsdev,
  308     struct nandfs_fsarea *fstp)
  309 {
  310         struct nandfs_super_block *super, *supert;
  311         struct buf *bp;
  312         int sb_per_sector, sbs_in_fsd, read_block;
  313         int index, pos, error;
  314         off_t offset;
  315 
  316         DPRINTF(SYNC, ("%s: last_used %d nandfs_sblocks_in_esize %d\n",
  317             __func__, fstp->last_used, nandfs_sblocks_in_esize(fsdev)));
  318         if (fstp->last_used == nandfs_sblocks_in_esize(fsdev) - 1)
  319                 index = 0;
  320         else
  321                 index = fstp->last_used + 1;
  322 
  323         super = &fsdev->nd_super;
  324         supert = NULL;
  325 
  326         sb_per_sector = nandfs_sblocks_in_block(fsdev);
  327         sbs_in_fsd = sizeof(struct nandfs_fsdata) /
  328             sizeof(struct nandfs_super_block);
  329         index += sbs_in_fsd;
  330         offset = fstp->offset;
  331 
  332         DPRINTF(SYNC, ("%s: offset %#jx s_last_pseg %#jx s_last_cno %#jx "
  333             "s_last_seq %#jx wtime %jd index %d\n", __func__, offset,
  334             super->s_last_pseg, super->s_last_cno, super->s_last_seq,
  335             super->s_wtime, index));
  336 
  337         read_block = btodb(offset + rounddown(index, sb_per_sector) *
  338             sizeof(struct nandfs_super_block));
  339 
  340         DPRINTF(SYNC, ("%s: read_block %#x\n", __func__, read_block));
  341 
  342         if (index == sbs_in_fsd) {
  343                 error = nandfs_erase(fsdev, offset, fsdev->nd_erasesize);
  344                 if (error)
  345                         return (error);
  346 
  347                 error = bread(fsdev->nd_devvp, btodb(offset),
  348                     fsdev->nd_devblocksize, NOCRED, &bp);
  349                 if (error) {
  350                         printf("NANDFS: couldn't read initial data: %d\n",
  351                             error);
  352                         brelse(bp);
  353                         return (error);
  354                 }
  355                 memcpy(bp->b_data, &fsdev->nd_fsdata, sizeof(fsdev->nd_fsdata));
  356                 /*
  357                  * 0xff-out the rest. This bp could be cached, so potentially
  358                  * b_data contains stale super blocks.
  359                  *
  360                  * We don't mind cached bp since most of the time we just add
  361                  * super blocks to already 0xff-out b_data and don't need to
  362                  * perform actual read.
  363                  */
  364                 if (fsdev->nd_devblocksize > sizeof(fsdev->nd_fsdata))
  365                         memset(bp->b_data + sizeof(fsdev->nd_fsdata), 0xff,
  366                             fsdev->nd_devblocksize - sizeof(fsdev->nd_fsdata));
  367                 error = bwrite(bp);
  368                 if (error) {
  369                         printf("NANDFS: cannot rewrite initial data at %jx\n",
  370                             offset);
  371                         return (error);
  372                 }
  373         }
  374 
  375         error = bread(fsdev->nd_devvp, read_block, fsdev->nd_devblocksize,
  376             NOCRED, &bp);
  377         if (error) {
  378                 brelse(bp);
  379                 return (error);
  380         }
  381 
  382         supert = (struct nandfs_super_block *)(bp->b_data);
  383         pos = index % sb_per_sector;
  384 
  385         DPRINTF(SYNC, ("%s: storing at %d\n", __func__, pos));
  386         memcpy(&supert[pos], super, sizeof(struct nandfs_super_block));
  387 
  388         /*
  389          * See comment above in code that performs erase.
  390          */
  391         if (pos == 0)
  392                 memset(&supert[1], 0xff,
  393                     (sb_per_sector - 1) * sizeof(struct nandfs_super_block));
  394 
  395         error = bwrite(bp);
  396         if (error) {
  397                 printf("NANDFS: cannot update superblock at %jx\n", offset);
  398                 return (error);
  399         }
  400 
  401         DPRINTF(SYNC, ("%s: fstp->last_used %d -> %d\n", __func__,
  402             fstp->last_used, index - sbs_in_fsd));
  403         fstp->last_used = index - sbs_in_fsd;
  404 
  405         return (0);
  406 }
  407 
  408 int
  409 nandfs_write_superblock(struct nandfs_device *fsdev)
  410 {
  411         struct nandfs_super_block *super;
  412         struct timespec ts;
  413         int error;
  414         int i, j;
  415 
  416         vfs_timestamp(&ts);
  417 
  418         super = &fsdev->nd_super;
  419 
  420         super->s_last_pseg = fsdev->nd_last_pseg;
  421         super->s_last_cno = fsdev->nd_last_cno;
  422         super->s_last_seq = fsdev->nd_seg_sequence;
  423         super->s_wtime = ts.tv_sec;
  424 
  425         nandfs_calc_superblock_crc(&fsdev->nd_fsdata, super);
  426 
  427         error = 0;
  428         for (i = 0, j = fsdev->nd_last_fsarea; i < NANDFS_NFSAREAS;
  429             i++, j = (j + 1 % NANDFS_NFSAREAS)) {
  430                 if (fsdev->nd_fsarea[j].flags & NANDFS_FSSTOR_FAILED) {
  431                         DPRINTF(SYNC, ("%s: skipping %d\n", __func__, j));
  432                         continue;
  433                 }
  434                 error = nandfs_write_superblock_at(fsdev, &fsdev->nd_fsarea[j]);
  435                 if (error) {
  436                         printf("NANDFS: writing superblock at offset %d failed:"
  437                             "%d\n", j * fsdev->nd_erasesize, error);
  438                         fsdev->nd_fsarea[j].flags |= NANDFS_FSSTOR_FAILED;
  439                 } else
  440                         break;
  441         }
  442 
  443         if (i == NANDFS_NFSAREAS) {
  444                 printf("NANDFS: superblock was not written\n");
  445                 /*
  446                  * TODO: switch to read-only?
  447                  */
  448                 return (error);
  449         } else
  450                 fsdev->nd_last_fsarea = (j + 1) % NANDFS_NFSAREAS;
  451 
  452         return (0);
  453 }
  454 
  455 static int
  456 nandfs_select_fsdata(struct nandfs_device *fsdev,
  457     struct nandfs_fsdata *fsdatat, struct nandfs_fsdata **fsdata, int nfsds)
  458 {
  459         int i;
  460 
  461         *fsdata = NULL;
  462         for (i = 0; i < nfsds; i++) {
  463                 DPRINTF(VOLUMES, ("%s: i %d f_magic %x f_crc %x\n", __func__,
  464                     i, fsdatat[i].f_magic, fsdatat[i].f_sum));
  465                 if (!nandfs_check_fsdata_crc(&fsdatat[i]))
  466                         continue;
  467                 *fsdata = &fsdatat[i];
  468                 break;
  469         }
  470 
  471         return (*fsdata != NULL ? 0 : EINVAL);
  472 }
  473 
  474 static int
  475 nandfs_select_sb(struct nandfs_device *fsdev,
  476     struct nandfs_super_block *supert, struct nandfs_super_block **super,
  477     int nsbs)
  478 {
  479         int i;
  480 
  481         *super = NULL;
  482         for (i = 0; i < nsbs; i++) {
  483                 if (!nandfs_check_superblock_crc(&fsdev->nd_fsdata, &supert[i]))
  484                         continue;
  485                 DPRINTF(SYNC, ("%s: i %d s_last_cno %jx s_magic %x "
  486                     "s_wtime %jd\n", __func__, i, supert[i].s_last_cno,
  487                     supert[i].s_magic, supert[i].s_wtime));
  488                 if (*super == NULL || supert[i].s_last_cno >
  489                     (*super)->s_last_cno)
  490                         *super = &supert[i];
  491         }
  492 
  493         return (*super != NULL ? 0 : EINVAL);
  494 }
  495 
  496 static int
  497 nandfs_read_structures_at(struct nandfs_device *fsdev,
  498     struct nandfs_fsarea *fstp, struct nandfs_fsdata *fsdata,
  499     struct nandfs_super_block *super)
  500 {
  501         struct nandfs_super_block *tsuper, *tsuperd;
  502         struct buf *bp;
  503         int error, read_size;
  504         int i;
  505         int offset;
  506 
  507         offset = fstp->offset;
  508 
  509         if (fsdev->nd_erasesize > MAXBSIZE)
  510                 read_size = MAXBSIZE;
  511         else
  512                 read_size = fsdev->nd_erasesize;
  513 
  514         error = bread(fsdev->nd_devvp, btodb(offset), read_size, NOCRED, &bp);
  515         if (error) {
  516                 printf("couldn't read: %d\n", error);
  517                 brelse(bp);
  518                 fstp->flags |= NANDFS_FSSTOR_FAILED;
  519                 return (error);
  520         }
  521 
  522         tsuper = super;
  523 
  524         memcpy(fsdata, bp->b_data, sizeof(struct nandfs_fsdata));
  525         memcpy(tsuper, (bp->b_data + sizeof(struct nandfs_fsdata)),
  526             read_size - sizeof(struct nandfs_fsdata));
  527         brelse(bp);
  528 
  529         tsuper += (read_size - sizeof(struct nandfs_fsdata)) /
  530             sizeof(struct nandfs_super_block);
  531 
  532         for (i = 1; i < fsdev->nd_erasesize / read_size; i++) {
  533                 error = bread(fsdev->nd_devvp, btodb(offset + i * read_size),
  534                     read_size, NOCRED, &bp);
  535                 if (error) {
  536                         printf("couldn't read: %d\n", error);
  537                         brelse(bp);
  538                         fstp->flags |= NANDFS_FSSTOR_FAILED;
  539                         return (error);
  540                 }
  541                 memcpy(tsuper, bp->b_data, read_size);
  542                 tsuper += read_size / sizeof(struct nandfs_super_block);
  543                 brelse(bp);
  544         }
  545 
  546         tsuper -= 1;
  547         fstp->last_used = nandfs_sblocks_in_esize(fsdev) - 1;
  548         for (tsuperd = super - 1; (tsuper != tsuperd); tsuper -= 1) {
  549                 if (nandfs_is_empty((u_char *)tsuper, sizeof(*tsuper)))
  550                         fstp->last_used--;
  551                 else
  552                         break;
  553         }
  554 
  555         DPRINTF(VOLUMES, ("%s: last_used %d\n", __func__, fstp->last_used));
  556 
  557         return (0);
  558 }
  559 
  560 static int
  561 nandfs_read_structures(struct nandfs_device *fsdev)
  562 {
  563         struct nandfs_fsdata *fsdata, *fsdatat;
  564         struct nandfs_super_block *sblocks, *ssblock;
  565         u_int nsbs, nfsds, i;
  566         int error = 0;
  567         int nrsbs;
  568 
  569         nfsds = NANDFS_NFSAREAS;
  570         nsbs = nandfs_max_sblocks(fsdev);
  571 
  572         fsdatat = malloc(sizeof(struct nandfs_fsdata) * nfsds, M_NANDFSTEMP,
  573             M_WAITOK | M_ZERO);
  574         sblocks = malloc(sizeof(struct nandfs_super_block) * nsbs, M_NANDFSTEMP,
  575             M_WAITOK | M_ZERO);
  576 
  577         nrsbs = 0;
  578         for (i = 0; i < NANDFS_NFSAREAS; i++) {
  579                 fsdev->nd_fsarea[i].offset = i * fsdev->nd_erasesize;
  580                 error = nandfs_read_structures_at(fsdev, &fsdev->nd_fsarea[i],
  581                     &fsdatat[i], sblocks + nrsbs);
  582                 if (error)
  583                         continue;
  584                 nrsbs += (fsdev->nd_fsarea[i].last_used + 1);
  585                 if (fsdev->nd_fsarea[fsdev->nd_last_fsarea].last_used >
  586                     fsdev->nd_fsarea[i].last_used)
  587                         fsdev->nd_last_fsarea = i;
  588         }
  589 
  590         if (nrsbs == 0) {
  591                 printf("nandfs: no valid superblocks found\n");
  592                 error = EINVAL;
  593                 goto out;
  594         }
  595 
  596         error = nandfs_select_fsdata(fsdev, fsdatat, &fsdata, nfsds);
  597         if (error)
  598                 goto out;
  599         memcpy(&fsdev->nd_fsdata, fsdata, sizeof(struct nandfs_fsdata));
  600 
  601         error = nandfs_select_sb(fsdev, sblocks, &ssblock, nsbs);
  602         if (error)
  603                 goto out;
  604 
  605         memcpy(&fsdev->nd_super, ssblock, sizeof(struct nandfs_super_block));
  606 out:
  607         free(fsdatat, M_NANDFSTEMP);
  608         free(sblocks, M_NANDFSTEMP);
  609 
  610         if (error == 0)
  611                 DPRINTF(VOLUMES, ("%s: selected sb with w_time %jd "
  612                     "last_pseg %#jx\n", __func__, fsdev->nd_super.s_wtime,
  613                     fsdev->nd_super.s_last_pseg));
  614 
  615         return (error);
  616 }
  617 
  618 static void
  619 nandfs_unmount_base(struct nandfs_device *nandfsdev)
  620 {
  621         int error;
  622 
  623         if (!nandfsdev)
  624                 return;
  625 
  626         /* Remove all our information */
  627         error = vinvalbuf(nandfsdev->nd_devvp, V_SAVE, 0, 0);
  628         if (error) {
  629                 /*
  630                  * Flushing buffers failed when fs was umounting, can't do
  631                  * much now, just printf error and continue with umount.
  632                  */
  633                 nandfs_error("%s(): error:%d when umounting FS\n",
  634                     __func__, error);
  635         }
  636 
  637         /* Release the device's system nodes */
  638         nandfs_release_system_nodes(nandfsdev);
  639 }
  640 
  641 static void
  642 nandfs_get_ncleanseg(struct nandfs_device *nandfsdev)
  643 {
  644         struct nandfs_seg_stat nss;
  645 
  646         nandfs_get_seg_stat(nandfsdev, &nss);
  647         nandfsdev->nd_clean_segs = nss.nss_ncleansegs;
  648         DPRINTF(VOLUMES, ("nandfs_mount: clean segs: %jx\n",
  649             (uintmax_t)nandfsdev->nd_clean_segs));
  650 }
  651 
  652 
  653 static int
  654 nandfs_mount_base(struct nandfs_device *nandfsdev, struct mount *mp,
  655     struct nandfs_args *args)
  656 {
  657         uint32_t log_blocksize;
  658         int error;
  659 
  660         /* Flush out any old buffers remaining from a previous use. */
  661         if ((error = vinvalbuf(nandfsdev->nd_devvp, V_SAVE, 0, 0)))
  662                 return (error);
  663 
  664         error = nandfs_read_structures(nandfsdev);
  665         if (error) {
  666                 printf("nandfs: could not get valid filesystem structures\n");
  667                 return (error);
  668         }
  669 
  670         if (nandfsdev->nd_fsdata.f_rev_level != NANDFS_CURRENT_REV) {
  671                 printf("nandfs: unsupported file system revision: %d "
  672                     "(supported is %d).\n", nandfsdev->nd_fsdata.f_rev_level,
  673                     NANDFS_CURRENT_REV);
  674                 return (EINVAL);
  675         }
  676 
  677         if (nandfsdev->nd_fsdata.f_erasesize != nandfsdev->nd_erasesize) {
  678                 printf("nandfs: erasesize mismatch (device %#x, fs %#x)\n",
  679                     nandfsdev->nd_erasesize, nandfsdev->nd_fsdata.f_erasesize);
  680                 return (EINVAL);
  681         }
  682 
  683         /* Get our blocksize */
  684         log_blocksize = nandfsdev->nd_fsdata.f_log_block_size;
  685         nandfsdev->nd_blocksize = (uint64_t) 1 << (log_blocksize + 10);
  686         DPRINTF(VOLUMES, ("%s: blocksize:%x\n", __func__,
  687             nandfsdev->nd_blocksize));
  688 
  689         DPRINTF(VOLUMES, ("%s: accepted super block with cp %#jx\n", __func__,
  690             (uintmax_t)nandfsdev->nd_super.s_last_cno));
  691 
  692         /* Calculate dat structure parameters */
  693         nandfs_calc_mdt_consts(nandfsdev, &nandfsdev->nd_dat_mdt,
  694             nandfsdev->nd_fsdata.f_dat_entry_size);
  695         nandfs_calc_mdt_consts(nandfsdev, &nandfsdev->nd_ifile_mdt,
  696             nandfsdev->nd_fsdata.f_inode_size);
  697 
  698         /* Search for the super root and roll forward when needed */
  699         if (nandfs_search_super_root(nandfsdev)) {
  700                 printf("Cannot find valid SuperRoot\n");
  701                 return (EINVAL);
  702         }
  703 
  704         nandfsdev->nd_mount_state = nandfsdev->nd_super.s_state;
  705         if (nandfsdev->nd_mount_state != NANDFS_VALID_FS) {
  706                 printf("FS is seriously damaged, needs repairing\n");
  707                 printf("aborting mount\n");
  708                 return (EINVAL);
  709         }
  710 
  711         /*
  712          * FS should be ok now. The superblock and the last segsum could be
  713          * updated from the repair so extract running values again.
  714          */
  715         nandfsdev->nd_last_pseg = nandfsdev->nd_super.s_last_pseg;
  716         nandfsdev->nd_seg_sequence = nandfsdev->nd_super.s_last_seq;
  717         nandfsdev->nd_seg_num = nandfs_get_segnum_of_block(nandfsdev,
  718             nandfsdev->nd_last_pseg);
  719         nandfsdev->nd_next_seg_num = nandfs_get_segnum_of_block(nandfsdev,
  720             nandfsdev->nd_last_segsum.ss_next);
  721         nandfsdev->nd_ts.tv_sec = nandfsdev->nd_last_segsum.ss_create;
  722         nandfsdev->nd_last_cno = nandfsdev->nd_super.s_last_cno;
  723         nandfsdev->nd_fakevblk = 1;
  724         /*
  725          * FIXME: bogus calculation. Should use actual number of usable segments
  726          * instead of total amount.
  727          */
  728         nandfsdev->nd_segs_reserved =
  729             nandfsdev->nd_fsdata.f_nsegments *
  730             nandfsdev->nd_fsdata.f_r_segments_percentage / 100;
  731         nandfsdev->nd_last_ino  = NANDFS_USER_INO;
  732         DPRINTF(VOLUMES, ("%s: last_pseg %#jx last_cno %#jx last_seq %#jx\n"
  733             "fsdev: last_seg: seq %#jx num %#jx, next_seg_num %#jx "
  734             "segs_reserved %#jx\n",
  735             __func__, (uintmax_t)nandfsdev->nd_last_pseg,
  736             (uintmax_t)nandfsdev->nd_last_cno,
  737             (uintmax_t)nandfsdev->nd_seg_sequence,
  738             (uintmax_t)nandfsdev->nd_seg_sequence,
  739             (uintmax_t)nandfsdev->nd_seg_num,
  740             (uintmax_t)nandfsdev->nd_next_seg_num,
  741             (uintmax_t)nandfsdev->nd_segs_reserved));
  742 
  743         DPRINTF(VOLUMES, ("nandfs_mount: accepted super root\n"));
  744 
  745         /* Create system vnodes for DAT, CP and SEGSUM */
  746         error = nandfs_create_system_nodes(nandfsdev);
  747         if (error)
  748                 nandfs_unmount_base(nandfsdev);
  749 
  750         nandfs_get_ncleanseg(nandfsdev);
  751 
  752         return (error);
  753 }
  754 
  755 static void
  756 nandfs_unmount_device(struct nandfs_device *nandfsdev)
  757 {
  758 
  759         /* Is there anything? */
  760         if (nandfsdev == NULL)
  761                 return;
  762 
  763         /* Remove the device only if we're the last reference */
  764         nandfsdev->nd_refcnt--;
  765         if (nandfsdev->nd_refcnt >= 1)
  766                 return;
  767 
  768         MPASS(nandfsdev->nd_syncer == NULL);
  769         MPASS(nandfsdev->nd_cleaner == NULL);
  770         MPASS(nandfsdev->nd_free_base == NULL);
  771 
  772         /* Unmount our base */
  773         nandfs_unmount_base(nandfsdev);
  774 
  775         /* Remove from our device list */
  776         SLIST_REMOVE(&nandfs_devices, nandfsdev, nandfs_device, nd_next_device);
  777 
  778         DROP_GIANT();
  779         g_topology_lock();
  780         g_vfs_close(nandfsdev->nd_gconsumer);
  781         g_topology_unlock();
  782         PICKUP_GIANT();
  783 
  784         DPRINTF(VOLUMES, ("closing device\n"));
  785 
  786         /* Clear our mount reference and release device node */
  787         vrele(nandfsdev->nd_devvp);
  788 
  789         dev_rel(nandfsdev->nd_devvp->v_rdev);
  790 
  791         /* Free our device info */
  792         cv_destroy(&nandfsdev->nd_sync_cv);
  793         mtx_destroy(&nandfsdev->nd_sync_mtx);
  794         cv_destroy(&nandfsdev->nd_clean_cv);
  795         mtx_destroy(&nandfsdev->nd_clean_mtx);
  796         mtx_destroy(&nandfsdev->nd_mutex);
  797         lockdestroy(&nandfsdev->nd_seg_const);
  798         free(nandfsdev, M_NANDFSMNT);
  799 }
  800 
  801 static int
  802 nandfs_check_mounts(struct nandfs_device *nandfsdev, struct mount *mp,
  803     struct nandfs_args *args)
  804 {
  805         struct nandfsmount *nmp;
  806         uint64_t last_cno;
  807 
  808         /* no double-mounting of the same checkpoint */
  809         STAILQ_FOREACH(nmp, &nandfsdev->nd_mounts, nm_next_mount) {
  810                 if (nmp->nm_mount_args.cpno == args->cpno)
  811                         return (EBUSY);
  812         }
  813 
  814         /* Allow readonly mounts without questioning here */
  815         if (mp->mnt_flag & MNT_RDONLY)
  816                 return (0);
  817 
  818         /* Read/write mount */
  819         STAILQ_FOREACH(nmp, &nandfsdev->nd_mounts, nm_next_mount) {
  820                 /* Only one RW mount on this device! */
  821                 if ((nmp->nm_vfs_mountp->mnt_flag & MNT_RDONLY)==0)
  822                         return (EROFS);
  823                 /* RDONLY on last mountpoint is device busy */
  824                 last_cno = nmp->nm_nandfsdev->nd_super.s_last_cno;
  825                 if (nmp->nm_mount_args.cpno == last_cno)
  826                         return (EBUSY);
  827         }
  828 
  829         /* OK for now */
  830         return (0);
  831 }
  832 
  833 static int
  834 nandfs_mount_device(struct vnode *devvp, struct mount *mp,
  835     struct nandfs_args *args, struct nandfs_device **nandfsdev_p)
  836 {
  837         struct nandfs_device *nandfsdev;
  838         struct g_provider *pp;
  839         struct g_consumer *cp;
  840         struct cdev *dev;
  841         uint32_t erasesize;
  842         int error, size;
  843         int ronly;
  844 
  845         DPRINTF(VOLUMES, ("Mounting NANDFS device\n"));
  846 
  847         ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
  848 
  849         /* Look up device in our nandfs_mountpoints */
  850         *nandfsdev_p = NULL;
  851         SLIST_FOREACH(nandfsdev, &nandfs_devices, nd_next_device)
  852                 if (nandfsdev->nd_devvp == devvp)
  853                         break;
  854 
  855         if (nandfsdev) {
  856                 DPRINTF(VOLUMES, ("device already mounted\n"));
  857                 error = nandfs_check_mounts(nandfsdev, mp, args);
  858                 if (error)
  859                         return error;
  860                 nandfsdev->nd_refcnt++;
  861                 *nandfsdev_p = nandfsdev;
  862 
  863                 if (!ronly) {
  864                         DROP_GIANT();
  865                         g_topology_lock();
  866                         error = g_access(nandfsdev->nd_gconsumer, 0, 1, 0);
  867                         g_topology_unlock();
  868                         PICKUP_GIANT();
  869                 }
  870                 return (error);
  871         }
  872 
  873         vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
  874         dev = devvp->v_rdev;
  875         dev_ref(dev);
  876         DROP_GIANT();
  877         g_topology_lock();
  878         error = g_vfs_open(devvp, &cp, "nandfs", ronly ? 0 : 1);
  879         pp = g_dev_getprovider(dev);
  880         g_topology_unlock();
  881         PICKUP_GIANT();
  882         VOP_UNLOCK(devvp, 0);
  883         if (error) {
  884                 dev_rel(dev);
  885                 return (error);
  886         }
  887 
  888         nandfsdev = malloc(sizeof(struct nandfs_device), M_NANDFSMNT, M_WAITOK | M_ZERO);
  889 
  890         /* Initialise */
  891         nandfsdev->nd_refcnt = 1;
  892         nandfsdev->nd_devvp = devvp;
  893         nandfsdev->nd_syncing = 0;
  894         nandfsdev->nd_cleaning = 0;
  895         nandfsdev->nd_gconsumer = cp;
  896         cv_init(&nandfsdev->nd_sync_cv, "nandfssync");
  897         mtx_init(&nandfsdev->nd_sync_mtx, "nffssyncmtx", NULL, MTX_DEF);
  898         cv_init(&nandfsdev->nd_clean_cv, "nandfsclean");
  899         mtx_init(&nandfsdev->nd_clean_mtx, "nffscleanmtx", NULL, MTX_DEF);
  900         mtx_init(&nandfsdev->nd_mutex, "nandfsdev lock", NULL, MTX_DEF);
  901         lockinit(&nandfsdev->nd_seg_const, PVFS, "nffssegcon", VLKTIMEOUT,
  902             LK_CANRECURSE);
  903         STAILQ_INIT(&nandfsdev->nd_mounts);
  904 
  905         nandfsdev->nd_devsize = pp->mediasize;
  906         nandfsdev->nd_devblocksize = pp->sectorsize;
  907 
  908         size = sizeof(erasesize);
  909         error = g_io_getattr("NAND::blocksize", nandfsdev->nd_gconsumer, &size,
  910             &erasesize);
  911         if (error) {
  912                 DPRINTF(VOLUMES, ("couldn't get erasesize: %d\n", error));
  913 
  914                 if (error == ENOIOCTL || error == EOPNOTSUPP) {
  915                         /*
  916                          * We conclude that this is not NAND storage
  917                          */
  918                         erasesize = NANDFS_DEF_ERASESIZE;
  919                 } else {
  920                         DROP_GIANT();
  921                         g_topology_lock();
  922                         g_vfs_close(nandfsdev->nd_gconsumer);
  923                         g_topology_unlock();
  924                         PICKUP_GIANT();
  925                         dev_rel(dev);
  926                         free(nandfsdev, M_NANDFSMNT);
  927                         return (error);
  928                 }
  929         }
  930         nandfsdev->nd_erasesize = erasesize;
  931 
  932         DPRINTF(VOLUMES, ("%s: erasesize %x\n", __func__,
  933             nandfsdev->nd_erasesize));
  934 
  935         /* Register nandfs_device in list */
  936         SLIST_INSERT_HEAD(&nandfs_devices, nandfsdev, nd_next_device);
  937 
  938         error = nandfs_mount_base(nandfsdev, mp, args);
  939         if (error) {
  940                 /* Remove all our information */
  941                 nandfs_unmount_device(nandfsdev);
  942                 return (EINVAL);
  943         }
  944 
  945         nandfsdev->nd_maxfilesize = nandfs_get_maxfilesize(nandfsdev);
  946 
  947         *nandfsdev_p = nandfsdev;
  948         DPRINTF(VOLUMES, ("NANDFS device mounted ok\n"));
  949 
  950         return (0);
  951 }
  952 
  953 static int
  954 nandfs_mount_checkpoint(struct nandfsmount *nmp)
  955 {
  956         struct nandfs_cpfile_header *cphdr;
  957         struct nandfs_checkpoint *cp;
  958         struct nandfs_inode ifile_inode;
  959         struct nandfs_node *cp_node;
  960         struct buf *bp;
  961         uint64_t ncp, nsn, cpno, fcpno, blocknr, last_cno;
  962         uint32_t off, dlen;
  963         int cp_per_block, error;
  964 
  965         cpno = nmp->nm_mount_args.cpno;
  966         if (cpno == 0)
  967                 cpno = nmp->nm_nandfsdev->nd_super.s_last_cno;
  968 
  969         DPRINTF(VOLUMES, ("%s: trying to mount checkpoint number %"PRIu64"\n",
  970             __func__, cpno));
  971 
  972         cp_node = nmp->nm_nandfsdev->nd_cp_node;
  973 
  974         VOP_LOCK(NTOV(cp_node), LK_SHARED);
  975         /* Get cpfile header from 1st block of cp file */
  976         error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
  977         if (error) {
  978                 brelse(bp);
  979                 VOP_UNLOCK(NTOV(cp_node), 0);
  980                 return (error);
  981         }
  982 
  983         cphdr = (struct nandfs_cpfile_header *) bp->b_data;
  984         ncp = cphdr->ch_ncheckpoints;
  985         nsn = cphdr->ch_nsnapshots;
  986 
  987         brelse(bp);
  988 
  989         DPRINTF(VOLUMES, ("mount_nandfs: checkpoint header read in\n"));
  990         DPRINTF(VOLUMES, ("\tNumber of checkpoints %"PRIu64"\n", ncp));
  991         DPRINTF(VOLUMES, ("\tNumber of snapshots %"PRIu64"\n", nsn));
  992 
  993         /* Read in our specified checkpoint */
  994         dlen = nmp->nm_nandfsdev->nd_fsdata.f_checkpoint_size;
  995         cp_per_block = nmp->nm_nandfsdev->nd_blocksize / dlen;
  996 
  997         fcpno = cpno + NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET - 1;
  998         blocknr = fcpno / cp_per_block;
  999         off = (fcpno % cp_per_block) * dlen;
 1000         error = nandfs_bread(cp_node, blocknr, NOCRED, 0, &bp);
 1001         if (error) {
 1002                 brelse(bp);
 1003                 VOP_UNLOCK(NTOV(cp_node), 0);
 1004                 printf("mount_nandfs: couldn't read cp block %"PRIu64"\n",
 1005                     fcpno);
 1006                 return (EINVAL);
 1007         }
 1008 
 1009         /* Needs to be a valid checkpoint */
 1010         cp = (struct nandfs_checkpoint *) ((uint8_t *) bp->b_data + off);
 1011         if (cp->cp_flags & NANDFS_CHECKPOINT_INVALID) {
 1012                 printf("mount_nandfs: checkpoint marked invalid\n");
 1013                 brelse(bp);
 1014                 VOP_UNLOCK(NTOV(cp_node), 0);
 1015                 return (EINVAL);
 1016         }
 1017 
 1018         /* Is this really the checkpoint we want? */
 1019         if (cp->cp_cno != cpno) {
 1020                 printf("mount_nandfs: checkpoint file corrupt? "
 1021                     "expected cpno %"PRIu64", found cpno %"PRIu64"\n",
 1022                     cpno, cp->cp_cno);
 1023                 brelse(bp);
 1024                 VOP_UNLOCK(NTOV(cp_node), 0);
 1025                 return (EINVAL);
 1026         }
 1027 
 1028         /* Check if it's a snapshot ! */
 1029         last_cno = nmp->nm_nandfsdev->nd_super.s_last_cno;
 1030         if (cpno != last_cno) {
 1031                 /* Only allow snapshots if not mounting on the last cp */
 1032                 if ((cp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT) == 0) {
 1033                         printf( "mount_nandfs: checkpoint %"PRIu64" is not a "
 1034                             "snapshot\n", cpno);
 1035                         brelse(bp);
 1036                         VOP_UNLOCK(NTOV(cp_node), 0);
 1037                         return (EINVAL);
 1038                 }
 1039         }
 1040 
 1041         ifile_inode = cp->cp_ifile_inode;
 1042         brelse(bp);
 1043 
 1044         /* Get ifile inode */
 1045         error = nandfs_get_node_raw(nmp->nm_nandfsdev, NULL, NANDFS_IFILE_INO,
 1046             &ifile_inode, &nmp->nm_ifile_node);
 1047         if (error) {
 1048                 printf("mount_nandfs: can't read ifile node\n");
 1049                 VOP_UNLOCK(NTOV(cp_node), 0);
 1050                 return (EINVAL);
 1051         }
 1052 
 1053         NANDFS_SET_SYSTEMFILE(NTOV(nmp->nm_ifile_node));
 1054         VOP_UNLOCK(NTOV(cp_node), 0);
 1055         /* Get root node? */
 1056 
 1057         return (0);
 1058 }
 1059 
 1060 static void
 1061 free_nandfs_mountinfo(struct mount *mp)
 1062 {
 1063         struct nandfsmount *nmp = VFSTONANDFS(mp);
 1064 
 1065         if (nmp == NULL)
 1066                 return;
 1067 
 1068         free(nmp, M_NANDFSMNT);
 1069 }
 1070 
 1071 void
 1072 nandfs_wakeup_wait_sync(struct nandfs_device *nffsdev, int reason)
 1073 {
 1074         char *reasons[] = {
 1075             "umount",
 1076             "vfssync",
 1077             "bdflush",
 1078             "fforce",
 1079             "fsync",
 1080             "ro_upd"
 1081         };
 1082 
 1083         DPRINTF(SYNC, ("%s: %s\n", __func__, reasons[reason]));
 1084         mtx_lock(&nffsdev->nd_sync_mtx);
 1085         if (nffsdev->nd_syncing)
 1086                 cv_wait(&nffsdev->nd_sync_cv, &nffsdev->nd_sync_mtx);
 1087         if (reason == SYNCER_UMOUNT)
 1088                 nffsdev->nd_syncer_exit = 1;
 1089         nffsdev->nd_syncing = 1;
 1090         wakeup(&nffsdev->nd_syncing);
 1091         cv_wait(&nffsdev->nd_sync_cv, &nffsdev->nd_sync_mtx);
 1092 
 1093         mtx_unlock(&nffsdev->nd_sync_mtx);
 1094 }
 1095 
 1096 static void
 1097 nandfs_gc_finished(struct nandfs_device *nffsdev, int exit)
 1098 {
 1099         int error;
 1100 
 1101         mtx_lock(&nffsdev->nd_sync_mtx);
 1102         nffsdev->nd_syncing = 0;
 1103         DPRINTF(SYNC, ("%s: cleaner finish\n", __func__));
 1104         cv_broadcast(&nffsdev->nd_sync_cv);
 1105         mtx_unlock(&nffsdev->nd_sync_mtx);
 1106         if (!exit) {
 1107                 error = tsleep(&nffsdev->nd_syncing, PRIBIO, "-",
 1108                     hz * nandfs_sync_interval);
 1109                 DPRINTF(SYNC, ("%s: cleaner waked up: %d\n",
 1110                     __func__, error));
 1111         }
 1112 }
 1113 
 1114 static void
 1115 nandfs_syncer(struct nandfsmount *nmp)
 1116 {
 1117         struct nandfs_device *nffsdev;
 1118         struct mount *mp;
 1119         int flags, error;
 1120 
 1121         mp = nmp->nm_vfs_mountp;
 1122         nffsdev = nmp->nm_nandfsdev;
 1123         tsleep(&nffsdev->nd_syncing, PRIBIO, "-", hz * nandfs_sync_interval);
 1124 
 1125         while (!nffsdev->nd_syncer_exit) {
 1126                 DPRINTF(SYNC, ("%s: syncer run\n", __func__));
 1127                 nffsdev->nd_syncing = 1;
 1128 
 1129                 flags = (nmp->nm_flags & (NANDFS_FORCE_SYNCER | NANDFS_UMOUNT));
 1130 
 1131                 error = nandfs_segment_constructor(nmp, flags);
 1132                 if (error)
 1133                         nandfs_error("%s: error:%d when creating segments\n",
 1134                             __func__, error);
 1135 
 1136                 nmp->nm_flags &= ~flags;
 1137 
 1138                 nandfs_gc_finished(nffsdev, 0);
 1139         }
 1140 
 1141         MPASS(nffsdev->nd_cleaner == NULL);
 1142         error = nandfs_segment_constructor(nmp,
 1143             NANDFS_FORCE_SYNCER | NANDFS_UMOUNT);
 1144         if (error)
 1145                 nandfs_error("%s: error:%d when creating segments\n",
 1146                     __func__, error);
 1147         nandfs_gc_finished(nffsdev, 1);
 1148         nffsdev->nd_syncer = NULL;
 1149         MPASS(nffsdev->nd_free_base == NULL);
 1150 
 1151         DPRINTF(SYNC, ("%s: exiting\n", __func__));
 1152         kthread_exit();
 1153 }
 1154 
 1155 static int
 1156 start_syncer(struct nandfsmount *nmp)
 1157 {
 1158         int error;
 1159 
 1160         MPASS(nmp->nm_nandfsdev->nd_syncer == NULL);
 1161 
 1162         DPRINTF(SYNC, ("%s: start syncer\n", __func__));
 1163 
 1164         nmp->nm_nandfsdev->nd_syncer_exit = 0;
 1165 
 1166         error = kthread_add((void(*)(void *))nandfs_syncer, nmp, NULL,
 1167             &nmp->nm_nandfsdev->nd_syncer, 0, 0, "nandfs_syncer");
 1168 
 1169         if (error)
 1170                 printf("nandfs: could not start syncer: %d\n", error);
 1171 
 1172         return (error);
 1173 }
 1174 
 1175 static int
 1176 stop_syncer(struct nandfsmount *nmp)
 1177 {
 1178 
 1179         MPASS(nmp->nm_nandfsdev->nd_syncer != NULL);
 1180 
 1181         nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_UMOUNT);
 1182 
 1183         DPRINTF(SYNC, ("%s: stop syncer\n", __func__));
 1184         return (0);
 1185 }
 1186 
 1187 /*
 1188  * Mount null layer
 1189  */
 1190 static int
 1191 nandfs_mount(struct mount *mp)
 1192 {
 1193         struct nandfsmount *nmp;
 1194         struct vnode *devvp;
 1195         struct nameidata nd;
 1196         struct vfsoptlist *opts;
 1197         struct thread *td;
 1198         char *from;
 1199         int error = 0, flags;
 1200 
 1201         DPRINTF(VOLUMES, ("%s: mp = %p\n", __func__, (void *)mp));
 1202 
 1203         td = curthread;
 1204         opts = mp->mnt_optnew;
 1205 
 1206         if (vfs_filteropt(opts, nandfs_opts))
 1207                 return (EINVAL);
 1208 
 1209         /*
 1210          * Update is a no-op
 1211          */
 1212         if (mp->mnt_flag & MNT_UPDATE) {
 1213                 nmp = VFSTONANDFS(mp);
 1214                 if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) {
 1215                         return (error);
 1216                 }
 1217                 if (!(nmp->nm_ronly) && vfs_flagopt(opts, "ro", NULL, 0)) {
 1218                         vn_start_write(NULL, &mp, V_WAIT);
 1219                         error = VFS_SYNC(mp, MNT_WAIT);
 1220                         if (error)
 1221                                 return (error);
 1222                         vn_finished_write(mp);
 1223 
 1224                         flags = WRITECLOSE;
 1225                         if (mp->mnt_flag & MNT_FORCE)
 1226                                 flags |= FORCECLOSE;
 1227 
 1228                         nandfs_wakeup_wait_sync(nmp->nm_nandfsdev,
 1229                             SYNCER_ROUPD);
 1230                         error = vflush(mp, 0, flags, td);
 1231                         if (error)
 1232                                 return (error);
 1233 
 1234                         nandfs_stop_cleaner(nmp->nm_nandfsdev);
 1235                         stop_syncer(nmp);
 1236                         DROP_GIANT();
 1237                         g_topology_lock();
 1238                         g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, -1, 0);
 1239                         g_topology_unlock();
 1240                         PICKUP_GIANT();
 1241                         MNT_ILOCK(mp);
 1242                         mp->mnt_flag |= MNT_RDONLY;
 1243                         MNT_IUNLOCK(mp);
 1244                         nmp->nm_ronly = 1;
 1245 
 1246                 } else if ((nmp->nm_ronly) &&
 1247                     !vfs_flagopt(opts, "ro", NULL, 0)) {
 1248                         /*
 1249                          * Don't allow read-write snapshots.
 1250                          */
 1251                         if (nmp->nm_mount_args.cpno != 0)
 1252                                 return (EROFS);
 1253                         /*
 1254                          * If upgrade to read-write by non-root, then verify
 1255                          * that user has necessary permissions on the device.
 1256                          */
 1257                         devvp = nmp->nm_nandfsdev->nd_devvp;
 1258                         vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
 1259                         error = VOP_ACCESS(devvp, VREAD | VWRITE,
 1260                             td->td_ucred, td);
 1261                         if (error) {
 1262                                 error = priv_check(td, PRIV_VFS_MOUNT_PERM);
 1263                                 if (error) {
 1264                                         VOP_UNLOCK(devvp, 0);
 1265                                         return (error);
 1266                                 }
 1267                         }
 1268 
 1269                         VOP_UNLOCK(devvp, 0);
 1270                         DROP_GIANT();
 1271                         g_topology_lock();
 1272                         error = g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, 1,
 1273                             0);
 1274                         g_topology_unlock();
 1275                         PICKUP_GIANT();
 1276                         if (error)
 1277                                 return (error);
 1278 
 1279                         MNT_ILOCK(mp);
 1280                         mp->mnt_flag &= ~MNT_RDONLY;
 1281                         MNT_IUNLOCK(mp);
 1282                         error = start_syncer(nmp);
 1283                         if (error == 0)
 1284                                 error = nandfs_start_cleaner(nmp->nm_nandfsdev);
 1285                         if (error) {
 1286                                 DROP_GIANT();
 1287                                 g_topology_lock();
 1288                                 g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, -1,
 1289                                     0);
 1290                                 g_topology_unlock();
 1291                                 PICKUP_GIANT();
 1292                                 return (error);
 1293                         }
 1294 
 1295                         nmp->nm_ronly = 0;
 1296                 }
 1297                 return (0);
 1298         }
 1299 
 1300         from = vfs_getopts(opts, "from", &error);
 1301         if (error)
 1302                 return (error);
 1303 
 1304         /*
 1305          * Find device node
 1306          */
 1307         NDINIT(&nd, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, from, curthread);
 1308         error = namei(&nd);
 1309         if (error)
 1310                 return (error);
 1311         NDFREE(&nd, NDF_ONLY_PNBUF);
 1312 
 1313         devvp = nd.ni_vp;
 1314 
 1315         if (!vn_isdisk(devvp, &error)) {
 1316                 vput(devvp);
 1317                 return (error);
 1318         }
 1319 
 1320         /* Check the access rights on the mount device */
 1321         error = VOP_ACCESS(devvp, VREAD, curthread->td_ucred, curthread);
 1322         if (error)
 1323                 error = priv_check(curthread, PRIV_VFS_MOUNT_PERM);
 1324         if (error) {
 1325                 vput(devvp);
 1326                 return (error);
 1327         }
 1328 
 1329         vfs_getnewfsid(mp);
 1330 
 1331         error = nandfs_mountfs(devvp, mp);
 1332         if (error)
 1333                 return (error);
 1334         vfs_mountedfrom(mp, from);
 1335 
 1336         return (0);
 1337 }
 1338 
 1339 static int
 1340 nandfs_mountfs(struct vnode *devvp, struct mount *mp)
 1341 {
 1342         struct nandfsmount *nmp = NULL;
 1343         struct nandfs_args *args = NULL;
 1344         struct nandfs_device *nandfsdev;
 1345         char *from;
 1346         int error, ronly;
 1347         char *cpno;
 1348 
 1349         ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
 1350 
 1351         if (devvp->v_rdev->si_iosize_max != 0)
 1352                 mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
 1353         VOP_UNLOCK(devvp, 0);
 1354 
 1355         if (mp->mnt_iosize_max > MAXPHYS)
 1356                 mp->mnt_iosize_max = MAXPHYS;
 1357 
 1358         from = vfs_getopts(mp->mnt_optnew, "from", &error);
 1359         if (error)
 1360                 goto error;
 1361 
 1362         error = vfs_getopt(mp->mnt_optnew, "snap", (void **)&cpno, NULL);
 1363         if (error == ENOENT)
 1364                 cpno = NULL;
 1365         else if (error)
 1366                 goto error;
 1367 
 1368         args = (struct nandfs_args *)malloc(sizeof(struct nandfs_args),
 1369             M_NANDFSMNT, M_WAITOK | M_ZERO);
 1370 
 1371         if (cpno != NULL)
 1372                 args->cpno = strtoul(cpno, (char **)NULL, 10);
 1373         else
 1374                 args->cpno = 0;
 1375         args->fspec = from;
 1376 
 1377         if (args->cpno != 0 && !ronly) {
 1378                 error = EROFS;
 1379                 goto error;
 1380         }
 1381 
 1382         printf("WARNING: NANDFS is considered to be a highly experimental "
 1383             "feature in FreeBSD.\n");
 1384 
 1385         error = nandfs_mount_device(devvp, mp, args, &nandfsdev);
 1386         if (error)
 1387                 goto error;
 1388 
 1389         nmp = (struct nandfsmount *) malloc(sizeof(struct nandfsmount),
 1390             M_NANDFSMNT, M_WAITOK | M_ZERO);
 1391 
 1392         mp->mnt_data = nmp;
 1393         nmp->nm_vfs_mountp = mp;
 1394         nmp->nm_ronly = ronly;
 1395         MNT_ILOCK(mp);
 1396         mp->mnt_flag |= MNT_LOCAL;
 1397         mp->mnt_kern_flag |= MNTK_USES_BCACHE;
 1398         MNT_IUNLOCK(mp);
 1399         nmp->nm_nandfsdev = nandfsdev;
 1400         /* Add our mountpoint */
 1401         STAILQ_INSERT_TAIL(&nandfsdev->nd_mounts, nmp, nm_next_mount);
 1402 
 1403         if (args->cpno > nandfsdev->nd_last_cno) {
 1404                 printf("WARNING: supplied checkpoint number (%jd) is greater "
 1405                     "than last known checkpoint on filesystem (%jd). Mounting"
 1406                     " checkpoint %jd\n", (uintmax_t)args->cpno,
 1407                     (uintmax_t)nandfsdev->nd_last_cno,
 1408                     (uintmax_t)nandfsdev->nd_last_cno);
 1409                 args->cpno = nandfsdev->nd_last_cno;
 1410         }
 1411 
 1412         /* Setting up other parameters */
 1413         nmp->nm_mount_args = *args;
 1414         free(args, M_NANDFSMNT);
 1415         error = nandfs_mount_checkpoint(nmp);
 1416         if (error) {
 1417                 nandfs_unmount(mp, MNT_FORCE);
 1418                 goto unmounted;
 1419         }
 1420 
 1421         if (!ronly) {
 1422                 error = start_syncer(nmp);
 1423                 if (error == 0)
 1424                         error = nandfs_start_cleaner(nmp->nm_nandfsdev);
 1425                 if (error)
 1426                         nandfs_unmount(mp, MNT_FORCE);
 1427         }
 1428 
 1429         return (0);
 1430 
 1431 error:
 1432         if (args != NULL)
 1433                 free(args, M_NANDFSMNT);
 1434 
 1435         if (nmp != NULL) {
 1436                 free(nmp, M_NANDFSMNT);
 1437                 mp->mnt_data = NULL;
 1438         }
 1439 unmounted:
 1440         return (error);
 1441 }
 1442 
 1443 static int
 1444 nandfs_unmount(struct mount *mp, int mntflags)
 1445 {
 1446         struct nandfs_device *nandfsdev;
 1447         struct nandfsmount *nmp;
 1448         int error;
 1449         int flags = 0;
 1450 
 1451         DPRINTF(VOLUMES, ("%s: mp = %p\n", __func__, (void *)mp));
 1452 
 1453         if (mntflags & MNT_FORCE)
 1454                 flags |= FORCECLOSE;
 1455 
 1456         nmp = mp->mnt_data;
 1457         nandfsdev = nmp->nm_nandfsdev;
 1458 
 1459         error = vflush(mp, 0, flags | SKIPSYSTEM, curthread);
 1460         if (error)
 1461                 return (error);
 1462 
 1463         if (!(nmp->nm_ronly)) {
 1464                 nandfs_stop_cleaner(nandfsdev);
 1465                 stop_syncer(nmp);
 1466         }
 1467 
 1468         if (nmp->nm_ifile_node)
 1469                 NANDFS_UNSET_SYSTEMFILE(NTOV(nmp->nm_ifile_node));
 1470 
 1471         /* Remove our mount point */
 1472         STAILQ_REMOVE(&nandfsdev->nd_mounts, nmp, nandfsmount, nm_next_mount);
 1473 
 1474         /* Unmount the device itself when we're the last one */
 1475         nandfs_unmount_device(nandfsdev);
 1476 
 1477         free_nandfs_mountinfo(mp);
 1478 
 1479         /*
 1480          * Finally, throw away the null_mount structure
 1481          */
 1482         mp->mnt_data = 0;
 1483         MNT_ILOCK(mp);
 1484         mp->mnt_flag &= ~MNT_LOCAL;
 1485         MNT_IUNLOCK(mp);
 1486 
 1487         return (0);
 1488 }
 1489 
 1490 static int
 1491 nandfs_statfs(struct mount *mp, struct statfs *sbp)
 1492 {
 1493         struct nandfsmount *nmp;
 1494         struct nandfs_device *nandfsdev;
 1495         struct nandfs_fsdata *fsdata;
 1496         struct nandfs_super_block *sb;
 1497         struct nandfs_block_group_desc *groups;
 1498         struct nandfs_node *ifile;
 1499         struct nandfs_mdt *mdt;
 1500         struct buf *bp;
 1501         int i, error;
 1502         uint32_t entries_per_group;
 1503         uint64_t files = 0;
 1504 
 1505         nmp = mp->mnt_data;
 1506         nandfsdev = nmp->nm_nandfsdev;
 1507         fsdata = &nandfsdev->nd_fsdata;
 1508         sb = &nandfsdev->nd_super;
 1509         ifile = nmp->nm_ifile_node;
 1510         mdt = &nandfsdev->nd_ifile_mdt;
 1511         entries_per_group = mdt->entries_per_group;
 1512 
 1513         VOP_LOCK(NTOV(ifile), LK_SHARED);
 1514         error = nandfs_bread(ifile, 0, NOCRED, 0, &bp);
 1515         if (error) {
 1516                 brelse(bp);
 1517                 VOP_UNLOCK(NTOV(ifile), 0);
 1518                 return (error);
 1519         }
 1520 
 1521         groups = (struct nandfs_block_group_desc *)bp->b_data;
 1522 
 1523         for (i = 0; i < mdt->groups_per_desc_block; i++)
 1524                 files += (entries_per_group - groups[i].bg_nfrees);
 1525 
 1526         brelse(bp);
 1527         VOP_UNLOCK(NTOV(ifile), 0);
 1528 
 1529         sbp->f_bsize = nandfsdev->nd_blocksize;
 1530         sbp->f_iosize = sbp->f_bsize;
 1531         sbp->f_blocks = fsdata->f_blocks_per_segment * fsdata->f_nsegments;
 1532         sbp->f_bfree = sb->s_free_blocks_count;
 1533         sbp->f_bavail = sbp->f_bfree;
 1534         sbp->f_files = files;
 1535         sbp->f_ffree = 0;
 1536         return (0);
 1537 }
 1538 
 1539 static int
 1540 nandfs_root(struct mount *mp, int flags, struct vnode **vpp)
 1541 {
 1542         struct nandfsmount *nmp = VFSTONANDFS(mp);
 1543         struct nandfs_node *node;
 1544         int error;
 1545 
 1546         error = nandfs_get_node(nmp, NANDFS_ROOT_INO, &node);
 1547         if (error)
 1548                 return (error);
 1549 
 1550         KASSERT(NTOV(node)->v_vflag & VV_ROOT,
 1551             ("root_vp->v_vflag & VV_ROOT"));
 1552 
 1553         *vpp = NTOV(node);
 1554 
 1555         return (error);
 1556 }
 1557 
 1558 static int
 1559 nandfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
 1560 {
 1561         struct nandfsmount *nmp = VFSTONANDFS(mp);
 1562         struct nandfs_node *node;
 1563         int error;
 1564 
 1565         error = nandfs_get_node(nmp, ino, &node);
 1566         if (node)
 1567                 *vpp = NTOV(node);
 1568 
 1569         return (error);
 1570 }
 1571 
 1572 static int
 1573 nandfs_sync(struct mount *mp, int waitfor)
 1574 {
 1575         struct nandfsmount *nmp = VFSTONANDFS(mp);
 1576 
 1577         DPRINTF(SYNC, ("%s: mp %p waitfor %d\n", __func__, mp, waitfor));
 1578 
 1579         /*
 1580          * XXX: A hack to be removed soon
 1581          */
 1582         if (waitfor == MNT_LAZY)
 1583                 return (0);
 1584         if (waitfor == MNT_SUSPEND)
 1585                 return (0);
 1586         nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_VFS_SYNC);
 1587         return (0);
 1588 }
 1589 
 1590 static struct vfsops nandfs_vfsops = {
 1591         .vfs_init =             nandfs_init,
 1592         .vfs_mount =            nandfs_mount,
 1593         .vfs_root =             nandfs_root,
 1594         .vfs_statfs =           nandfs_statfs,
 1595         .vfs_uninit =           nandfs_uninit,
 1596         .vfs_unmount =          nandfs_unmount,
 1597         .vfs_vget =             nandfs_vget,
 1598         .vfs_sync =             nandfs_sync,
 1599 };
 1600 
 1601 VFS_SET(nandfs_vfsops, nandfs, VFCF_LOOPBACK);

Cache object: 2074b452c9ceed6772f7ac6121c46d90


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