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