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

Cache object: 0b57c573304024f319eb2bd21f92f5dc


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