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