2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2010-2012 Semihalf
5 * Copyright (c) 2008, 2009 Reinoud Zandijk
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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.
28 * From: NetBSD: nilfs_vfsops.c,v 1.1 2009/07/18 16:31:42 reinoud Exp
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/fcntl.h>
37 #include <sys/kernel.h>
39 #include <sys/malloc.h>
40 #include <sys/mount.h>
41 #include <sys/namei.h>
44 #include <sys/vnode.h>
46 #include <sys/sysctl.h>
47 #include <sys/libkern.h>
49 #include <geom/geom.h>
50 #include <geom/geom_vfs.h>
52 #include <machine/_inttypes.h>
54 #include <fs/nandfs/nandfs_mount.h>
55 #include <fs/nandfs/nandfs.h>
56 #include <fs/nandfs/nandfs_subr.h>
58 static MALLOC_DEFINE(M_NANDFSMNT, "nandfs_mount", "NANDFS mount structure");
60 #define NANDFS_SET_SYSTEMFILE(vp) { \
61 (vp)->v_vflag |= VV_SYSTEM; \
65 #define NANDFS_UNSET_SYSTEMFILE(vp) { \
66 VOP_LOCK(vp, LK_EXCLUSIVE); \
67 MPASS(vp->v_bufobj.bo_dirty.bv_cnt == 0); \
68 (vp)->v_vflag &= ~VV_SYSTEM; \
73 struct _nandfs_devices nandfs_devices;
76 int nandfs_verbose = 0;
79 nandfs_tunable_init(void *arg)
82 TUNABLE_INT_FETCH("vfs.nandfs.verbose", &nandfs_verbose);
84 SYSINIT(nandfs_tunables, SI_SUB_VFS, SI_ORDER_ANY, nandfs_tunable_init, NULL);
86 static SYSCTL_NODE(_vfs, OID_AUTO, nandfs, CTLFLAG_RD, 0, "NAND filesystem");
87 static SYSCTL_NODE(_vfs_nandfs, OID_AUTO, mount, CTLFLAG_RD, 0,
88 "NANDFS mountpoints");
89 SYSCTL_INT(_vfs_nandfs, OID_AUTO, verbose, CTLFLAG_RW, &nandfs_verbose, 0, "");
91 #define NANDFS_CONSTR_INTERVAL 5
92 int nandfs_sync_interval = NANDFS_CONSTR_INTERVAL; /* sync every 5 seconds */
93 SYSCTL_UINT(_vfs_nandfs, OID_AUTO, sync_interval, CTLFLAG_RW,
94 &nandfs_sync_interval, 0, "");
96 #define NANDFS_MAX_DIRTY_SEGS 5
97 int nandfs_max_dirty_segs = NANDFS_MAX_DIRTY_SEGS; /* sync when 5 dirty seg */
98 SYSCTL_UINT(_vfs_nandfs, OID_AUTO, max_dirty_segs, CTLFLAG_RW,
99 &nandfs_max_dirty_segs, 0, "");
101 #define NANDFS_CPS_BETWEEN_SBLOCKS 5
102 int nandfs_cps_between_sblocks = NANDFS_CPS_BETWEEN_SBLOCKS; /* write superblock every 5 checkpoints */
103 SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cps_between_sblocks, CTLFLAG_RW,
104 &nandfs_cps_between_sblocks, 0, "");
106 #define NANDFS_CLEANER_ENABLE 1
107 int nandfs_cleaner_enable = NANDFS_CLEANER_ENABLE;
108 SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cleaner_enable, CTLFLAG_RW,
109 &nandfs_cleaner_enable, 0, "");
111 #define NANDFS_CLEANER_INTERVAL 5
112 int nandfs_cleaner_interval = NANDFS_CLEANER_INTERVAL;
113 SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cleaner_interval, CTLFLAG_RW,
114 &nandfs_cleaner_interval, 0, "");
116 #define NANDFS_CLEANER_SEGMENTS 5
117 int nandfs_cleaner_segments = NANDFS_CLEANER_SEGMENTS;
118 SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cleaner_segments, CTLFLAG_RW,
119 &nandfs_cleaner_segments, 0, "");
121 static int nandfs_mountfs(struct vnode *devvp, struct mount *mp);
122 static vfs_mount_t nandfs_mount;
123 static vfs_root_t nandfs_root;
124 static vfs_statfs_t nandfs_statfs;
125 static vfs_unmount_t nandfs_unmount;
126 static vfs_vget_t nandfs_vget;
127 static vfs_sync_t nandfs_sync;
128 static const char *nandfs_opts[] = {
129 "snap", "from", "noatime", NULL
134 nandfs_create_system_nodes(struct nandfs_device *nandfsdev)
138 error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_DAT_INO,
139 &nandfsdev->nd_super_root.sr_dat, &nandfsdev->nd_dat_node);
143 error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_CPFILE_INO,
144 &nandfsdev->nd_super_root.sr_cpfile, &nandfsdev->nd_cp_node);
148 error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_SUFILE_INO,
149 &nandfsdev->nd_super_root.sr_sufile, &nandfsdev->nd_su_node);
153 error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_GC_INO,
154 NULL, &nandfsdev->nd_gc_node);
158 NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_dat_node));
159 NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_cp_node));
160 NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_su_node));
161 NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_gc_node));
163 DPRINTF(VOLUMES, ("System vnodes: dat: %p cp: %p su: %p\n",
164 NTOV(nandfsdev->nd_dat_node), NTOV(nandfsdev->nd_cp_node),
165 NTOV(nandfsdev->nd_su_node)));
169 nandfs_dispose_node(&nandfsdev->nd_gc_node);
170 nandfs_dispose_node(&nandfsdev->nd_dat_node);
171 nandfs_dispose_node(&nandfsdev->nd_cp_node);
172 nandfs_dispose_node(&nandfsdev->nd_su_node);
178 nandfs_release_system_nodes(struct nandfs_device *nandfsdev)
183 if (nandfsdev->nd_refcnt > 0)
186 if (nandfsdev->nd_gc_node)
187 NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_gc_node));
188 if (nandfsdev->nd_dat_node)
189 NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_dat_node));
190 if (nandfsdev->nd_cp_node)
191 NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_cp_node));
192 if (nandfsdev->nd_su_node)
193 NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_su_node));
197 nandfs_check_fsdata_crc(struct nandfs_fsdata *fsdata)
199 uint32_t fsdata_crc, comp_crc;
201 if (fsdata->f_magic != NANDFS_FSDATA_MAGIC)
205 fsdata_crc = fsdata->f_sum;
209 comp_crc = crc32((uint8_t *)fsdata, fsdata->f_bytes);
212 fsdata->f_sum = fsdata_crc;
215 return (fsdata_crc == comp_crc);
219 nandfs_check_superblock_crc(struct nandfs_fsdata *fsdata,
220 struct nandfs_super_block *super)
222 uint32_t super_crc, comp_crc;
224 /* Check super block magic */
225 if (super->s_magic != NANDFS_SUPER_MAGIC)
229 super_crc = super->s_sum;
233 comp_crc = crc32((uint8_t *)super, fsdata->f_sbbytes);
236 super->s_sum = super_crc;
239 return (super_crc == comp_crc);
243 nandfs_calc_superblock_crc(struct nandfs_fsdata *fsdata,
244 struct nandfs_super_block *super)
250 comp_crc = crc32((uint8_t *)super, fsdata->f_sbbytes);
253 super->s_sum = comp_crc;
257 nandfs_is_empty(u_char *area, int size)
261 for (i = 0; i < size; i++)
269 nandfs_sblocks_in_esize(struct nandfs_device *fsdev)
272 return ((fsdev->nd_erasesize - NANDFS_SBLOCK_OFFSET_BYTES) /
273 sizeof(struct nandfs_super_block));
277 nandfs_max_sblocks(struct nandfs_device *fsdev)
280 return (NANDFS_NFSAREAS * nandfs_sblocks_in_esize(fsdev));
284 nandfs_sblocks_in_block(struct nandfs_device *fsdev)
287 return (fsdev->nd_devblocksize / sizeof(struct nandfs_super_block));
292 nandfs_sblocks_in_first_block(struct nandfs_device *fsdev)
296 n = nandfs_sblocks_in_block(fsdev) -
297 NANDFS_SBLOCK_OFFSET_BYTES / sizeof(struct nandfs_super_block);
306 nandfs_write_superblock_at(struct nandfs_device *fsdev,
307 struct nandfs_fsarea *fstp)
309 struct nandfs_super_block *super, *supert;
311 int sb_per_sector, sbs_in_fsd, read_block;
312 int index, pos, error;
315 DPRINTF(SYNC, ("%s: last_used %d nandfs_sblocks_in_esize %d\n",
316 __func__, fstp->last_used, nandfs_sblocks_in_esize(fsdev)));
317 if (fstp->last_used == nandfs_sblocks_in_esize(fsdev) - 1)
320 index = fstp->last_used + 1;
322 super = &fsdev->nd_super;
325 sb_per_sector = nandfs_sblocks_in_block(fsdev);
326 sbs_in_fsd = sizeof(struct nandfs_fsdata) /
327 sizeof(struct nandfs_super_block);
329 offset = fstp->offset;
331 DPRINTF(SYNC, ("%s: offset %#jx s_last_pseg %#jx s_last_cno %#jx "
332 "s_last_seq %#jx wtime %jd index %d\n", __func__, offset,
333 super->s_last_pseg, super->s_last_cno, super->s_last_seq,
334 super->s_wtime, index));
336 read_block = btodb(offset + rounddown(index, sb_per_sector) *
337 sizeof(struct nandfs_super_block));
339 DPRINTF(SYNC, ("%s: read_block %#x\n", __func__, read_block));
341 if (index == sbs_in_fsd) {
342 error = nandfs_erase(fsdev, offset, fsdev->nd_erasesize);
346 error = bread(fsdev->nd_devvp, btodb(offset),
347 fsdev->nd_devblocksize, NOCRED, &bp);
349 printf("NANDFS: couldn't read initial data: %d\n",
354 memcpy(bp->b_data, &fsdev->nd_fsdata, sizeof(fsdev->nd_fsdata));
356 * 0xff-out the rest. This bp could be cached, so potentially
357 * b_data contains stale super blocks.
359 * We don't mind cached bp since most of the time we just add
360 * super blocks to already 0xff-out b_data and don't need to
361 * perform actual read.
363 if (fsdev->nd_devblocksize > sizeof(fsdev->nd_fsdata))
364 memset(bp->b_data + sizeof(fsdev->nd_fsdata), 0xff,
365 fsdev->nd_devblocksize - sizeof(fsdev->nd_fsdata));
368 printf("NANDFS: cannot rewrite initial data at %jx\n",
374 error = bread(fsdev->nd_devvp, read_block, fsdev->nd_devblocksize,
381 supert = (struct nandfs_super_block *)(bp->b_data);
382 pos = index % sb_per_sector;
384 DPRINTF(SYNC, ("%s: storing at %d\n", __func__, pos));
385 memcpy(&supert[pos], super, sizeof(struct nandfs_super_block));
388 * See comment above in code that performs erase.
391 memset(&supert[1], 0xff,
392 (sb_per_sector - 1) * sizeof(struct nandfs_super_block));
396 printf("NANDFS: cannot update superblock at %jx\n", offset);
400 DPRINTF(SYNC, ("%s: fstp->last_used %d -> %d\n", __func__,
401 fstp->last_used, index - sbs_in_fsd));
402 fstp->last_used = index - sbs_in_fsd;
408 nandfs_write_superblock(struct nandfs_device *fsdev)
410 struct nandfs_super_block *super;
417 super = &fsdev->nd_super;
419 super->s_last_pseg = fsdev->nd_last_pseg;
420 super->s_last_cno = fsdev->nd_last_cno;
421 super->s_last_seq = fsdev->nd_seg_sequence;
422 super->s_wtime = ts.tv_sec;
424 nandfs_calc_superblock_crc(&fsdev->nd_fsdata, super);
427 for (i = 0, j = fsdev->nd_last_fsarea; i < NANDFS_NFSAREAS;
428 i++, j = (j + 1 % NANDFS_NFSAREAS)) {
429 if (fsdev->nd_fsarea[j].flags & NANDFS_FSSTOR_FAILED) {
430 DPRINTF(SYNC, ("%s: skipping %d\n", __func__, j));
433 error = nandfs_write_superblock_at(fsdev, &fsdev->nd_fsarea[j]);
435 printf("NANDFS: writing superblock at offset %d failed:"
436 "%d\n", j * fsdev->nd_erasesize, error);
437 fsdev->nd_fsarea[j].flags |= NANDFS_FSSTOR_FAILED;
442 if (i == NANDFS_NFSAREAS) {
443 printf("NANDFS: superblock was not written\n");
445 * TODO: switch to read-only?
449 fsdev->nd_last_fsarea = (j + 1) % NANDFS_NFSAREAS;
455 nandfs_select_fsdata(struct nandfs_device *fsdev,
456 struct nandfs_fsdata *fsdatat, struct nandfs_fsdata **fsdata, int nfsds)
461 for (i = 0; i < nfsds; i++) {
462 DPRINTF(VOLUMES, ("%s: i %d f_magic %x f_crc %x\n", __func__,
463 i, fsdatat[i].f_magic, fsdatat[i].f_sum));
464 if (!nandfs_check_fsdata_crc(&fsdatat[i]))
466 *fsdata = &fsdatat[i];
470 return (*fsdata != NULL ? 0 : EINVAL);
474 nandfs_select_sb(struct nandfs_device *fsdev,
475 struct nandfs_super_block *supert, struct nandfs_super_block **super,
481 for (i = 0; i < nsbs; i++) {
482 if (!nandfs_check_superblock_crc(&fsdev->nd_fsdata, &supert[i]))
484 DPRINTF(SYNC, ("%s: i %d s_last_cno %jx s_magic %x "
485 "s_wtime %jd\n", __func__, i, supert[i].s_last_cno,
486 supert[i].s_magic, supert[i].s_wtime));
487 if (*super == NULL || supert[i].s_last_cno >
488 (*super)->s_last_cno)
492 return (*super != NULL ? 0 : EINVAL);
496 nandfs_read_structures_at(struct nandfs_device *fsdev,
497 struct nandfs_fsarea *fstp, struct nandfs_fsdata *fsdata,
498 struct nandfs_super_block *super)
500 struct nandfs_super_block *tsuper, *tsuperd;
502 int error, read_size;
506 offset = fstp->offset;
508 if (fsdev->nd_erasesize > MAXBSIZE)
509 read_size = MAXBSIZE;
511 read_size = fsdev->nd_erasesize;
513 error = bread(fsdev->nd_devvp, btodb(offset), read_size, NOCRED, &bp);
515 printf("couldn't read: %d\n", error);
517 fstp->flags |= NANDFS_FSSTOR_FAILED;
523 memcpy(fsdata, bp->b_data, sizeof(struct nandfs_fsdata));
524 memcpy(tsuper, (bp->b_data + sizeof(struct nandfs_fsdata)),
525 read_size - sizeof(struct nandfs_fsdata));
528 tsuper += (read_size - sizeof(struct nandfs_fsdata)) /
529 sizeof(struct nandfs_super_block);
531 for (i = 1; i < fsdev->nd_erasesize / read_size; i++) {
532 error = bread(fsdev->nd_devvp, btodb(offset + i * read_size),
533 read_size, NOCRED, &bp);
535 printf("couldn't read: %d\n", error);
537 fstp->flags |= NANDFS_FSSTOR_FAILED;
540 memcpy(tsuper, bp->b_data, read_size);
541 tsuper += read_size / sizeof(struct nandfs_super_block);
546 fstp->last_used = nandfs_sblocks_in_esize(fsdev) - 1;
547 for (tsuperd = super - 1; (tsuper != tsuperd); tsuper -= 1) {
548 if (nandfs_is_empty((u_char *)tsuper, sizeof(*tsuper)))
554 DPRINTF(VOLUMES, ("%s: last_used %d\n", __func__, fstp->last_used));
560 nandfs_read_structures(struct nandfs_device *fsdev)
562 struct nandfs_fsdata *fsdata, *fsdatat;
563 struct nandfs_super_block *sblocks, *ssblock;
568 nfsds = NANDFS_NFSAREAS;
569 nsbs = nandfs_max_sblocks(fsdev);
571 fsdatat = malloc(sizeof(struct nandfs_fsdata) * nfsds, M_NANDFSTEMP,
573 sblocks = malloc(sizeof(struct nandfs_super_block) * nsbs, M_NANDFSTEMP,
577 for (i = 0; i < NANDFS_NFSAREAS; i++) {
578 fsdev->nd_fsarea[i].offset = i * fsdev->nd_erasesize;
579 error = nandfs_read_structures_at(fsdev, &fsdev->nd_fsarea[i],
580 &fsdatat[i], sblocks + nrsbs);
583 nrsbs += (fsdev->nd_fsarea[i].last_used + 1);
584 if (fsdev->nd_fsarea[fsdev->nd_last_fsarea].last_used >
585 fsdev->nd_fsarea[i].last_used)
586 fsdev->nd_last_fsarea = i;
590 printf("nandfs: no valid superblocks found\n");
595 error = nandfs_select_fsdata(fsdev, fsdatat, &fsdata, nfsds);
598 memcpy(&fsdev->nd_fsdata, fsdata, sizeof(struct nandfs_fsdata));
600 error = nandfs_select_sb(fsdev, sblocks, &ssblock, nsbs);
604 memcpy(&fsdev->nd_super, ssblock, sizeof(struct nandfs_super_block));
606 free(fsdatat, M_NANDFSTEMP);
607 free(sblocks, M_NANDFSTEMP);
610 DPRINTF(VOLUMES, ("%s: selected sb with w_time %jd "
611 "last_pseg %#jx\n", __func__, fsdev->nd_super.s_wtime,
612 fsdev->nd_super.s_last_pseg));
618 nandfs_unmount_base(struct nandfs_device *nandfsdev)
625 /* Remove all our information */
626 error = vinvalbuf(nandfsdev->nd_devvp, V_SAVE, 0, 0);
629 * Flushing buffers failed when fs was umounting, can't do
630 * much now, just printf error and continue with umount.
632 nandfs_error("%s(): error:%d when umounting FS\n",
636 /* Release the device's system nodes */
637 nandfs_release_system_nodes(nandfsdev);
641 nandfs_get_ncleanseg(struct nandfs_device *nandfsdev)
643 struct nandfs_seg_stat nss;
645 nandfs_get_seg_stat(nandfsdev, &nss);
646 nandfsdev->nd_clean_segs = nss.nss_ncleansegs;
647 DPRINTF(VOLUMES, ("nandfs_mount: clean segs: %jx\n",
648 (uintmax_t)nandfsdev->nd_clean_segs));
653 nandfs_mount_base(struct nandfs_device *nandfsdev, struct mount *mp,
654 struct nandfs_args *args)
656 uint32_t log_blocksize;
659 /* Flush out any old buffers remaining from a previous use. */
660 if ((error = vinvalbuf(nandfsdev->nd_devvp, V_SAVE, 0, 0)))
663 error = nandfs_read_structures(nandfsdev);
665 printf("nandfs: could not get valid filesystem structures\n");
669 if (nandfsdev->nd_fsdata.f_rev_level != NANDFS_CURRENT_REV) {
670 printf("nandfs: unsupported file system revision: %d "
671 "(supported is %d).\n", nandfsdev->nd_fsdata.f_rev_level,
676 if (nandfsdev->nd_fsdata.f_erasesize != nandfsdev->nd_erasesize) {
677 printf("nandfs: erasesize mismatch (device %#x, fs %#x)\n",
678 nandfsdev->nd_erasesize, nandfsdev->nd_fsdata.f_erasesize);
682 /* Get our blocksize */
683 log_blocksize = nandfsdev->nd_fsdata.f_log_block_size;
684 nandfsdev->nd_blocksize = (uint64_t) 1 << (log_blocksize + 10);
685 DPRINTF(VOLUMES, ("%s: blocksize:%x\n", __func__,
686 nandfsdev->nd_blocksize));
688 DPRINTF(VOLUMES, ("%s: accepted super block with cp %#jx\n", __func__,
689 (uintmax_t)nandfsdev->nd_super.s_last_cno));
691 /* Calculate dat structure parameters */
692 nandfs_calc_mdt_consts(nandfsdev, &nandfsdev->nd_dat_mdt,
693 nandfsdev->nd_fsdata.f_dat_entry_size);
694 nandfs_calc_mdt_consts(nandfsdev, &nandfsdev->nd_ifile_mdt,
695 nandfsdev->nd_fsdata.f_inode_size);
697 /* Search for the super root and roll forward when needed */
698 if (nandfs_search_super_root(nandfsdev)) {
699 printf("Cannot find valid SuperRoot\n");
703 nandfsdev->nd_mount_state = nandfsdev->nd_super.s_state;
704 if (nandfsdev->nd_mount_state != NANDFS_VALID_FS) {
705 printf("FS is seriously damaged, needs repairing\n");
706 printf("aborting mount\n");
711 * FS should be ok now. The superblock and the last segsum could be
712 * updated from the repair so extract running values again.
714 nandfsdev->nd_last_pseg = nandfsdev->nd_super.s_last_pseg;
715 nandfsdev->nd_seg_sequence = nandfsdev->nd_super.s_last_seq;
716 nandfsdev->nd_seg_num = nandfs_get_segnum_of_block(nandfsdev,
717 nandfsdev->nd_last_pseg);
718 nandfsdev->nd_next_seg_num = nandfs_get_segnum_of_block(nandfsdev,
719 nandfsdev->nd_last_segsum.ss_next);
720 nandfsdev->nd_ts.tv_sec = nandfsdev->nd_last_segsum.ss_create;
721 nandfsdev->nd_last_cno = nandfsdev->nd_super.s_last_cno;
722 nandfsdev->nd_fakevblk = 1;
724 * FIXME: bogus calculation. Should use actual number of usable segments
725 * instead of total amount.
727 nandfsdev->nd_segs_reserved =
728 nandfsdev->nd_fsdata.f_nsegments *
729 nandfsdev->nd_fsdata.f_r_segments_percentage / 100;
730 nandfsdev->nd_last_ino = NANDFS_USER_INO;
731 DPRINTF(VOLUMES, ("%s: last_pseg %#jx last_cno %#jx last_seq %#jx\n"
732 "fsdev: last_seg: seq %#jx num %#jx, next_seg_num %#jx "
733 "segs_reserved %#jx\n",
734 __func__, (uintmax_t)nandfsdev->nd_last_pseg,
735 (uintmax_t)nandfsdev->nd_last_cno,
736 (uintmax_t)nandfsdev->nd_seg_sequence,
737 (uintmax_t)nandfsdev->nd_seg_sequence,
738 (uintmax_t)nandfsdev->nd_seg_num,
739 (uintmax_t)nandfsdev->nd_next_seg_num,
740 (uintmax_t)nandfsdev->nd_segs_reserved));
742 DPRINTF(VOLUMES, ("nandfs_mount: accepted super root\n"));
744 /* Create system vnodes for DAT, CP and SEGSUM */
745 error = nandfs_create_system_nodes(nandfsdev);
747 nandfs_unmount_base(nandfsdev);
749 nandfs_get_ncleanseg(nandfsdev);
755 nandfs_unmount_device(struct nandfs_device *nandfsdev)
758 /* Is there anything? */
759 if (nandfsdev == NULL)
762 /* Remove the device only if we're the last reference */
763 nandfsdev->nd_refcnt--;
764 if (nandfsdev->nd_refcnt >= 1)
767 MPASS(nandfsdev->nd_syncer == NULL);
768 MPASS(nandfsdev->nd_cleaner == NULL);
769 MPASS(nandfsdev->nd_free_base == NULL);
771 /* Unmount our base */
772 nandfs_unmount_base(nandfsdev);
774 /* Remove from our device list */
775 SLIST_REMOVE(&nandfs_devices, nandfsdev, nandfs_device, nd_next_device);
779 g_vfs_close(nandfsdev->nd_gconsumer);
783 DPRINTF(VOLUMES, ("closing device\n"));
785 /* Clear our mount reference and release device node */
786 vrele(nandfsdev->nd_devvp);
788 dev_rel(nandfsdev->nd_devvp->v_rdev);
790 /* Free our device info */
791 cv_destroy(&nandfsdev->nd_sync_cv);
792 mtx_destroy(&nandfsdev->nd_sync_mtx);
793 cv_destroy(&nandfsdev->nd_clean_cv);
794 mtx_destroy(&nandfsdev->nd_clean_mtx);
795 mtx_destroy(&nandfsdev->nd_mutex);
796 lockdestroy(&nandfsdev->nd_seg_const);
797 free(nandfsdev, M_NANDFSMNT);
801 nandfs_check_mounts(struct nandfs_device *nandfsdev, struct mount *mp,
802 struct nandfs_args *args)
804 struct nandfsmount *nmp;
807 /* no double-mounting of the same checkpoint */
808 STAILQ_FOREACH(nmp, &nandfsdev->nd_mounts, nm_next_mount) {
809 if (nmp->nm_mount_args.cpno == args->cpno)
813 /* Allow readonly mounts without questioning here */
814 if (mp->mnt_flag & MNT_RDONLY)
817 /* Read/write mount */
818 STAILQ_FOREACH(nmp, &nandfsdev->nd_mounts, nm_next_mount) {
819 /* Only one RW mount on this device! */
820 if ((nmp->nm_vfs_mountp->mnt_flag & MNT_RDONLY)==0)
822 /* RDONLY on last mountpoint is device busy */
823 last_cno = nmp->nm_nandfsdev->nd_super.s_last_cno;
824 if (nmp->nm_mount_args.cpno == last_cno)
833 nandfs_mount_device(struct vnode *devvp, struct mount *mp,
834 struct nandfs_args *args, struct nandfs_device **nandfsdev_p)
836 struct nandfs_device *nandfsdev;
837 struct g_provider *pp;
838 struct g_consumer *cp;
844 DPRINTF(VOLUMES, ("Mounting NANDFS device\n"));
846 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
848 /* Look up device in our nandfs_mountpoints */
850 SLIST_FOREACH(nandfsdev, &nandfs_devices, nd_next_device)
851 if (nandfsdev->nd_devvp == devvp)
855 DPRINTF(VOLUMES, ("device already mounted\n"));
856 error = nandfs_check_mounts(nandfsdev, mp, args);
859 nandfsdev->nd_refcnt++;
860 *nandfsdev_p = nandfsdev;
865 error = g_access(nandfsdev->nd_gconsumer, 0, 1, 0);
872 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
877 error = g_vfs_open(devvp, &cp, "nandfs", ronly ? 0 : 1);
878 pp = g_dev_getprovider(dev);
881 VOP_UNLOCK(devvp, 0);
887 nandfsdev = malloc(sizeof(struct nandfs_device), M_NANDFSMNT, M_WAITOK | M_ZERO);
890 nandfsdev->nd_refcnt = 1;
891 nandfsdev->nd_devvp = devvp;
892 nandfsdev->nd_syncing = 0;
893 nandfsdev->nd_cleaning = 0;
894 nandfsdev->nd_gconsumer = cp;
895 cv_init(&nandfsdev->nd_sync_cv, "nandfssync");
896 mtx_init(&nandfsdev->nd_sync_mtx, "nffssyncmtx", NULL, MTX_DEF);
897 cv_init(&nandfsdev->nd_clean_cv, "nandfsclean");
898 mtx_init(&nandfsdev->nd_clean_mtx, "nffscleanmtx", NULL, MTX_DEF);
899 mtx_init(&nandfsdev->nd_mutex, "nandfsdev lock", NULL, MTX_DEF);
900 lockinit(&nandfsdev->nd_seg_const, PVFS, "nffssegcon", VLKTIMEOUT,
902 STAILQ_INIT(&nandfsdev->nd_mounts);
904 nandfsdev->nd_devsize = pp->mediasize;
905 nandfsdev->nd_devblocksize = pp->sectorsize;
907 size = sizeof(erasesize);
908 error = g_io_getattr("NAND::blocksize", nandfsdev->nd_gconsumer, &size,
911 DPRINTF(VOLUMES, ("couldn't get erasesize: %d\n", error));
913 if (error == ENOIOCTL || error == EOPNOTSUPP) {
915 * We conclude that this is not NAND storage
917 erasesize = NANDFS_DEF_ERASESIZE;
921 g_vfs_close(nandfsdev->nd_gconsumer);
925 free(nandfsdev, M_NANDFSMNT);
929 nandfsdev->nd_erasesize = erasesize;
931 DPRINTF(VOLUMES, ("%s: erasesize %x\n", __func__,
932 nandfsdev->nd_erasesize));
934 /* Register nandfs_device in list */
935 SLIST_INSERT_HEAD(&nandfs_devices, nandfsdev, nd_next_device);
937 error = nandfs_mount_base(nandfsdev, mp, args);
939 /* Remove all our information */
940 nandfs_unmount_device(nandfsdev);
944 nandfsdev->nd_maxfilesize = nandfs_get_maxfilesize(nandfsdev);
946 *nandfsdev_p = nandfsdev;
947 DPRINTF(VOLUMES, ("NANDFS device mounted ok\n"));
953 nandfs_mount_checkpoint(struct nandfsmount *nmp)
955 struct nandfs_cpfile_header *cphdr;
956 struct nandfs_checkpoint *cp;
957 struct nandfs_inode ifile_inode;
958 struct nandfs_node *cp_node;
960 uint64_t ncp, nsn, cpno, fcpno, blocknr, last_cno;
962 int cp_per_block, error;
964 cpno = nmp->nm_mount_args.cpno;
966 cpno = nmp->nm_nandfsdev->nd_super.s_last_cno;
968 DPRINTF(VOLUMES, ("%s: trying to mount checkpoint number %"PRIu64"\n",
971 cp_node = nmp->nm_nandfsdev->nd_cp_node;
973 VOP_LOCK(NTOV(cp_node), LK_SHARED);
974 /* Get cpfile header from 1st block of cp file */
975 error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
978 VOP_UNLOCK(NTOV(cp_node), 0);
982 cphdr = (struct nandfs_cpfile_header *) bp->b_data;
983 ncp = cphdr->ch_ncheckpoints;
984 nsn = cphdr->ch_nsnapshots;
988 DPRINTF(VOLUMES, ("mount_nandfs: checkpoint header read in\n"));
989 DPRINTF(VOLUMES, ("\tNumber of checkpoints %"PRIu64"\n", ncp));
990 DPRINTF(VOLUMES, ("\tNumber of snapshots %"PRIu64"\n", nsn));
992 /* Read in our specified checkpoint */
993 dlen = nmp->nm_nandfsdev->nd_fsdata.f_checkpoint_size;
994 cp_per_block = nmp->nm_nandfsdev->nd_blocksize / dlen;
996 fcpno = cpno + NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET - 1;
997 blocknr = fcpno / cp_per_block;
998 off = (fcpno % cp_per_block) * dlen;
999 error = nandfs_bread(cp_node, blocknr, NOCRED, 0, &bp);
1002 VOP_UNLOCK(NTOV(cp_node), 0);
1003 printf("mount_nandfs: couldn't read cp block %"PRIu64"\n",
1008 /* Needs to be a valid checkpoint */
1009 cp = (struct nandfs_checkpoint *) ((uint8_t *) bp->b_data + off);
1010 if (cp->cp_flags & NANDFS_CHECKPOINT_INVALID) {
1011 printf("mount_nandfs: checkpoint marked invalid\n");
1013 VOP_UNLOCK(NTOV(cp_node), 0);
1017 /* Is this really the checkpoint we want? */
1018 if (cp->cp_cno != cpno) {
1019 printf("mount_nandfs: checkpoint file corrupt? "
1020 "expected cpno %"PRIu64", found cpno %"PRIu64"\n",
1023 VOP_UNLOCK(NTOV(cp_node), 0);
1027 /* Check if it's a snapshot ! */
1028 last_cno = nmp->nm_nandfsdev->nd_super.s_last_cno;
1029 if (cpno != last_cno) {
1030 /* Only allow snapshots if not mounting on the last cp */
1031 if ((cp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT) == 0) {
1032 printf( "mount_nandfs: checkpoint %"PRIu64" is not a "
1033 "snapshot\n", cpno);
1035 VOP_UNLOCK(NTOV(cp_node), 0);
1040 ifile_inode = cp->cp_ifile_inode;
1043 /* Get ifile inode */
1044 error = nandfs_get_node_raw(nmp->nm_nandfsdev, NULL, NANDFS_IFILE_INO,
1045 &ifile_inode, &nmp->nm_ifile_node);
1047 printf("mount_nandfs: can't read ifile node\n");
1048 VOP_UNLOCK(NTOV(cp_node), 0);
1052 NANDFS_SET_SYSTEMFILE(NTOV(nmp->nm_ifile_node));
1053 VOP_UNLOCK(NTOV(cp_node), 0);
1054 /* Get root node? */
1060 free_nandfs_mountinfo(struct mount *mp)
1062 struct nandfsmount *nmp = VFSTONANDFS(mp);
1067 free(nmp, M_NANDFSMNT);
1071 nandfs_wakeup_wait_sync(struct nandfs_device *nffsdev, int reason)
1082 DPRINTF(SYNC, ("%s: %s\n", __func__, reasons[reason]));
1083 mtx_lock(&nffsdev->nd_sync_mtx);
1084 if (nffsdev->nd_syncing)
1085 cv_wait(&nffsdev->nd_sync_cv, &nffsdev->nd_sync_mtx);
1086 if (reason == SYNCER_UMOUNT)
1087 nffsdev->nd_syncer_exit = 1;
1088 nffsdev->nd_syncing = 1;
1089 wakeup(&nffsdev->nd_syncing);
1090 cv_wait(&nffsdev->nd_sync_cv, &nffsdev->nd_sync_mtx);
1092 mtx_unlock(&nffsdev->nd_sync_mtx);
1096 nandfs_gc_finished(struct nandfs_device *nffsdev, int exit)
1100 mtx_lock(&nffsdev->nd_sync_mtx);
1101 nffsdev->nd_syncing = 0;
1102 DPRINTF(SYNC, ("%s: cleaner finish\n", __func__));
1103 cv_broadcast(&nffsdev->nd_sync_cv);
1104 mtx_unlock(&nffsdev->nd_sync_mtx);
1106 error = tsleep(&nffsdev->nd_syncing, PRIBIO, "-",
1107 hz * nandfs_sync_interval);
1108 DPRINTF(SYNC, ("%s: cleaner waked up: %d\n",
1114 nandfs_syncer(struct nandfsmount *nmp)
1116 struct nandfs_device *nffsdev;
1120 mp = nmp->nm_vfs_mountp;
1121 nffsdev = nmp->nm_nandfsdev;
1122 tsleep(&nffsdev->nd_syncing, PRIBIO, "-", hz * nandfs_sync_interval);
1124 while (!nffsdev->nd_syncer_exit) {
1125 DPRINTF(SYNC, ("%s: syncer run\n", __func__));
1126 nffsdev->nd_syncing = 1;
1128 flags = (nmp->nm_flags & (NANDFS_FORCE_SYNCER | NANDFS_UMOUNT));
1130 error = nandfs_segment_constructor(nmp, flags);
1132 nandfs_error("%s: error:%d when creating segments\n",
1135 nmp->nm_flags &= ~flags;
1137 nandfs_gc_finished(nffsdev, 0);
1140 MPASS(nffsdev->nd_cleaner == NULL);
1141 error = nandfs_segment_constructor(nmp,
1142 NANDFS_FORCE_SYNCER | NANDFS_UMOUNT);
1144 nandfs_error("%s: error:%d when creating segments\n",
1146 nandfs_gc_finished(nffsdev, 1);
1147 nffsdev->nd_syncer = NULL;
1148 MPASS(nffsdev->nd_free_base == NULL);
1150 DPRINTF(SYNC, ("%s: exiting\n", __func__));
1155 start_syncer(struct nandfsmount *nmp)
1159 MPASS(nmp->nm_nandfsdev->nd_syncer == NULL);
1161 DPRINTF(SYNC, ("%s: start syncer\n", __func__));
1163 nmp->nm_nandfsdev->nd_syncer_exit = 0;
1165 error = kthread_add((void(*)(void *))nandfs_syncer, nmp, NULL,
1166 &nmp->nm_nandfsdev->nd_syncer, 0, 0, "nandfs_syncer");
1169 printf("nandfs: could not start syncer: %d\n", error);
1175 stop_syncer(struct nandfsmount *nmp)
1178 MPASS(nmp->nm_nandfsdev->nd_syncer != NULL);
1180 nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_UMOUNT);
1182 DPRINTF(SYNC, ("%s: stop syncer\n", __func__));
1190 nandfs_mount(struct mount *mp)
1192 struct nandfsmount *nmp;
1193 struct vnode *devvp;
1194 struct nameidata nd;
1195 struct vfsoptlist *opts;
1198 int error = 0, flags;
1200 DPRINTF(VOLUMES, ("%s: mp = %p\n", __func__, (void *)mp));
1203 opts = mp->mnt_optnew;
1205 if (vfs_filteropt(opts, nandfs_opts))
1211 if (mp->mnt_flag & MNT_UPDATE) {
1212 nmp = VFSTONANDFS(mp);
1213 if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) {
1216 if (!(nmp->nm_ronly) && vfs_flagopt(opts, "ro", NULL, 0)) {
1217 vn_start_write(NULL, &mp, V_WAIT);
1218 error = VFS_SYNC(mp, MNT_WAIT);
1221 vn_finished_write(mp);
1224 if (mp->mnt_flag & MNT_FORCE)
1225 flags |= FORCECLOSE;
1227 nandfs_wakeup_wait_sync(nmp->nm_nandfsdev,
1229 error = vflush(mp, 0, flags, td);
1233 nandfs_stop_cleaner(nmp->nm_nandfsdev);
1237 g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, -1, 0);
1238 g_topology_unlock();
1241 mp->mnt_flag |= MNT_RDONLY;
1245 } else if ((nmp->nm_ronly) &&
1246 !vfs_flagopt(opts, "ro", NULL, 0)) {
1248 * Don't allow read-write snapshots.
1250 if (nmp->nm_mount_args.cpno != 0)
1253 * If upgrade to read-write by non-root, then verify
1254 * that user has necessary permissions on the device.
1256 devvp = nmp->nm_nandfsdev->nd_devvp;
1257 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
1258 error = VOP_ACCESS(devvp, VREAD | VWRITE,
1261 error = priv_check(td, PRIV_VFS_MOUNT_PERM);
1263 VOP_UNLOCK(devvp, 0);
1268 VOP_UNLOCK(devvp, 0);
1271 error = g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, 1,
1273 g_topology_unlock();
1279 mp->mnt_flag &= ~MNT_RDONLY;
1281 error = start_syncer(nmp);
1283 error = nandfs_start_cleaner(nmp->nm_nandfsdev);
1287 g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, -1,
1289 g_topology_unlock();
1299 from = vfs_getopts(opts, "from", &error);
1306 NDINIT(&nd, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, from, curthread);
1310 NDFREE(&nd, NDF_ONLY_PNBUF);
1314 if (!vn_isdisk(devvp, &error)) {
1319 /* Check the access rights on the mount device */
1320 error = VOP_ACCESS(devvp, VREAD, curthread->td_ucred, curthread);
1322 error = priv_check(curthread, PRIV_VFS_MOUNT_PERM);
1330 error = nandfs_mountfs(devvp, mp);
1333 vfs_mountedfrom(mp, from);
1339 nandfs_mountfs(struct vnode *devvp, struct mount *mp)
1341 struct nandfsmount *nmp = NULL;
1342 struct nandfs_args *args = NULL;
1343 struct nandfs_device *nandfsdev;
1348 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
1350 if (devvp->v_rdev->si_iosize_max != 0)
1351 mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
1352 VOP_UNLOCK(devvp, 0);
1354 if (mp->mnt_iosize_max > MAXPHYS)
1355 mp->mnt_iosize_max = MAXPHYS;
1357 from = vfs_getopts(mp->mnt_optnew, "from", &error);
1361 error = vfs_getopt(mp->mnt_optnew, "snap", (void **)&cpno, NULL);
1362 if (error == ENOENT)
1367 args = (struct nandfs_args *)malloc(sizeof(struct nandfs_args),
1368 M_NANDFSMNT, M_WAITOK | M_ZERO);
1371 args->cpno = strtoul(cpno, (char **)NULL, 10);
1376 if (args->cpno != 0 && !ronly) {
1381 printf("WARNING: NANDFS is considered to be a highly experimental "
1382 "feature in FreeBSD.\n");
1384 error = nandfs_mount_device(devvp, mp, args, &nandfsdev);
1388 nmp = (struct nandfsmount *) malloc(sizeof(struct nandfsmount),
1389 M_NANDFSMNT, M_WAITOK | M_ZERO);
1392 nmp->nm_vfs_mountp = mp;
1393 nmp->nm_ronly = ronly;
1395 mp->mnt_flag |= MNT_LOCAL;
1396 mp->mnt_kern_flag |= MNTK_USES_BCACHE;
1398 nmp->nm_nandfsdev = nandfsdev;
1399 /* Add our mountpoint */
1400 STAILQ_INSERT_TAIL(&nandfsdev->nd_mounts, nmp, nm_next_mount);
1402 if (args->cpno > nandfsdev->nd_last_cno) {
1403 printf("WARNING: supplied checkpoint number (%jd) is greater "
1404 "than last known checkpoint on filesystem (%jd). Mounting"
1405 " checkpoint %jd\n", (uintmax_t)args->cpno,
1406 (uintmax_t)nandfsdev->nd_last_cno,
1407 (uintmax_t)nandfsdev->nd_last_cno);
1408 args->cpno = nandfsdev->nd_last_cno;
1411 /* Setting up other parameters */
1412 nmp->nm_mount_args = *args;
1413 free(args, M_NANDFSMNT);
1414 error = nandfs_mount_checkpoint(nmp);
1416 nandfs_unmount(mp, MNT_FORCE);
1421 error = start_syncer(nmp);
1423 error = nandfs_start_cleaner(nmp->nm_nandfsdev);
1425 nandfs_unmount(mp, MNT_FORCE);
1432 free(args, M_NANDFSMNT);
1435 free(nmp, M_NANDFSMNT);
1436 mp->mnt_data = NULL;
1443 nandfs_unmount(struct mount *mp, int mntflags)
1445 struct nandfs_device *nandfsdev;
1446 struct nandfsmount *nmp;
1450 DPRINTF(VOLUMES, ("%s: mp = %p\n", __func__, (void *)mp));
1452 if (mntflags & MNT_FORCE)
1453 flags |= FORCECLOSE;
1456 nandfsdev = nmp->nm_nandfsdev;
1458 error = vflush(mp, 0, flags | SKIPSYSTEM, curthread);
1462 if (!(nmp->nm_ronly)) {
1463 nandfs_stop_cleaner(nandfsdev);
1467 if (nmp->nm_ifile_node)
1468 NANDFS_UNSET_SYSTEMFILE(NTOV(nmp->nm_ifile_node));
1470 /* Remove our mount point */
1471 STAILQ_REMOVE(&nandfsdev->nd_mounts, nmp, nandfsmount, nm_next_mount);
1473 /* Unmount the device itself when we're the last one */
1474 nandfs_unmount_device(nandfsdev);
1476 free_nandfs_mountinfo(mp);
1479 * Finally, throw away the null_mount structure
1483 mp->mnt_flag &= ~MNT_LOCAL;
1490 nandfs_statfs(struct mount *mp, struct statfs *sbp)
1492 struct nandfsmount *nmp;
1493 struct nandfs_device *nandfsdev;
1494 struct nandfs_fsdata *fsdata;
1495 struct nandfs_super_block *sb;
1496 struct nandfs_block_group_desc *groups;
1497 struct nandfs_node *ifile;
1498 struct nandfs_mdt *mdt;
1501 uint32_t entries_per_group;
1505 nandfsdev = nmp->nm_nandfsdev;
1506 fsdata = &nandfsdev->nd_fsdata;
1507 sb = &nandfsdev->nd_super;
1508 ifile = nmp->nm_ifile_node;
1509 mdt = &nandfsdev->nd_ifile_mdt;
1510 entries_per_group = mdt->entries_per_group;
1512 VOP_LOCK(NTOV(ifile), LK_SHARED);
1513 error = nandfs_bread(ifile, 0, NOCRED, 0, &bp);
1516 VOP_UNLOCK(NTOV(ifile), 0);
1520 groups = (struct nandfs_block_group_desc *)bp->b_data;
1522 for (i = 0; i < mdt->groups_per_desc_block; i++)
1523 files += (entries_per_group - groups[i].bg_nfrees);
1526 VOP_UNLOCK(NTOV(ifile), 0);
1528 sbp->f_bsize = nandfsdev->nd_blocksize;
1529 sbp->f_iosize = sbp->f_bsize;
1530 sbp->f_blocks = fsdata->f_blocks_per_segment * fsdata->f_nsegments;
1531 sbp->f_bfree = sb->s_free_blocks_count;
1532 sbp->f_bavail = sbp->f_bfree;
1533 sbp->f_files = files;
1539 nandfs_root(struct mount *mp, int flags, struct vnode **vpp)
1541 struct nandfsmount *nmp = VFSTONANDFS(mp);
1542 struct nandfs_node *node;
1545 error = nandfs_get_node(nmp, NANDFS_ROOT_INO, &node);
1549 KASSERT(NTOV(node)->v_vflag & VV_ROOT,
1550 ("root_vp->v_vflag & VV_ROOT"));
1558 nandfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
1560 struct nandfsmount *nmp = VFSTONANDFS(mp);
1561 struct nandfs_node *node;
1564 error = nandfs_get_node(nmp, ino, &node);
1572 nandfs_sync(struct mount *mp, int waitfor)
1574 struct nandfsmount *nmp = VFSTONANDFS(mp);
1576 DPRINTF(SYNC, ("%s: mp %p waitfor %d\n", __func__, mp, waitfor));
1579 * XXX: A hack to be removed soon
1581 if (waitfor == MNT_LAZY)
1583 if (waitfor == MNT_SUSPEND)
1585 nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_VFS_SYNC);
1589 static struct vfsops nandfs_vfsops = {
1590 .vfs_init = nandfs_init,
1591 .vfs_mount = nandfs_mount,
1592 .vfs_root = nandfs_root,
1593 .vfs_statfs = nandfs_statfs,
1594 .vfs_uninit = nandfs_uninit,
1595 .vfs_unmount = nandfs_unmount,
1596 .vfs_vget = nandfs_vget,
1597 .vfs_sync = nandfs_sync,
1600 VFS_SET(nandfs_vfsops, nandfs, VFCF_LOOPBACK);