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