xref: /NextBSD/sys/fs/nandfs/nandfs_vfsops.c (revision 287e3b14e9552995def1802ec9c5034f4adf28ec)
1 /*-
2  * Copyright (c) 2010-2012 Semihalf
3  * Copyright (c) 2008, 2009 Reinoud Zandijk
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * From: NetBSD: nilfs_vfsops.c,v 1.1 2009/07/18 16:31:42 reinoud Exp
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/fcntl.h>
35 #include <sys/kernel.h>
36 #include <sys/lock.h>
37 #include <sys/malloc.h>
38 #include <sys/mount.h>
39 #include <sys/namei.h>
40 #include <sys/proc.h>
41 #include <sys/priv.h>
42 #include <sys/vnode.h>
43 #include <sys/buf.h>
44 #include <sys/sysctl.h>
45 #include <sys/libkern.h>
46 
47 #include <geom/geom.h>
48 #include <geom/geom_vfs.h>
49 
50 #include <machine/_inttypes.h>
51 
52 #include <fs/nandfs/nandfs_mount.h>
53 #include <fs/nandfs/nandfs.h>
54 #include <fs/nandfs/nandfs_subr.h>
55 
56 static MALLOC_DEFINE(M_NANDFSMNT, "nandfs_mount", "NANDFS mount structure");
57 
58 #define	NANDFS_SET_SYSTEMFILE(vp) {	\
59 	(vp)->v_vflag |= VV_SYSTEM;	\
60 	vref(vp);			\
61 	vput(vp); }
62 
63 #define	NANDFS_UNSET_SYSTEMFILE(vp) {	\
64 	VOP_LOCK(vp, LK_EXCLUSIVE);	\
65 	MPASS(vp->v_bufobj.bo_dirty.bv_cnt == 0); \
66 	(vp)->v_vflag &= ~VV_SYSTEM;	\
67 	vgone(vp);			\
68 	vput(vp); }
69 
70 /* Globals */
71 struct _nandfs_devices nandfs_devices;
72 
73 /* Parameters */
74 int nandfs_verbose = 0;
75 
76 static void
nandfs_tunable_init(void * arg)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
nandfs_create_system_nodes(struct nandfs_device * nandfsdev)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
nandfs_release_system_nodes(struct nandfs_device * nandfsdev)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
nandfs_check_fsdata_crc(struct nandfs_fsdata * fsdata)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
nandfs_check_superblock_crc(struct nandfs_fsdata * fsdata,struct nandfs_super_block * super)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
nandfs_calc_superblock_crc(struct nandfs_fsdata * fsdata,struct nandfs_super_block * super)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
nandfs_is_empty(u_char * area,int size)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
nandfs_sblocks_in_esize(struct nandfs_device * fsdev)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
nandfs_max_sblocks(struct nandfs_device * fsdev)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
nandfs_sblocks_in_block(struct nandfs_device * fsdev)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
nandfs_write_superblock_at(struct nandfs_device * fsdev,struct nandfs_fsarea * fstp)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
nandfs_write_superblock(struct nandfs_device * fsdev)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
nandfs_select_fsdata(struct nandfs_device * fsdev,struct nandfs_fsdata * fsdatat,struct nandfs_fsdata ** fsdata,int nfsds)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
nandfs_select_sb(struct nandfs_device * fsdev,struct nandfs_super_block * supert,struct nandfs_super_block ** super,int nsbs)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
nandfs_read_structures_at(struct nandfs_device * fsdev,struct nandfs_fsarea * fstp,struct nandfs_fsdata * fsdata,struct nandfs_super_block * super)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
nandfs_read_structures(struct nandfs_device * fsdev)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
nandfs_unmount_base(struct nandfs_device * nandfsdev)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
nandfs_get_ncleanseg(struct nandfs_device * nandfsdev)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
nandfs_mount_base(struct nandfs_device * nandfsdev,struct mount * mp,struct nandfs_args * args)651 nandfs_mount_base(struct nandfs_device *nandfsdev, struct mount *mp,
652     struct nandfs_args *args)
653 {
654 	uint32_t log_blocksize;
655 	int error;
656 
657 	/* Flush out any old buffers remaining from a previous use. */
658 	if ((error = vinvalbuf(nandfsdev->nd_devvp, V_SAVE, 0, 0)))
659 		return (error);
660 
661 	error = nandfs_read_structures(nandfsdev);
662 	if (error) {
663 		printf("nandfs: could not get valid filesystem structures\n");
664 		return (error);
665 	}
666 
667 	if (nandfsdev->nd_fsdata.f_rev_level != NANDFS_CURRENT_REV) {
668 		printf("nandfs: unsupported file system revision: %d "
669 		    "(supported is %d).\n", nandfsdev->nd_fsdata.f_rev_level,
670 		    NANDFS_CURRENT_REV);
671 		return (EINVAL);
672 	}
673 
674 	if (nandfsdev->nd_fsdata.f_erasesize != nandfsdev->nd_erasesize) {
675 		printf("nandfs: erasesize mismatch (device %#x, fs %#x)\n",
676 		    nandfsdev->nd_erasesize, nandfsdev->nd_fsdata.f_erasesize);
677 		return (EINVAL);
678 	}
679 
680 	/* Get our blocksize */
681 	log_blocksize = nandfsdev->nd_fsdata.f_log_block_size;
682 	nandfsdev->nd_blocksize = (uint64_t) 1 << (log_blocksize + 10);
683 	DPRINTF(VOLUMES, ("%s: blocksize:%x\n", __func__,
684 	    nandfsdev->nd_blocksize));
685 
686 	DPRINTF(VOLUMES, ("%s: accepted super block with cp %#jx\n", __func__,
687 	    (uintmax_t)nandfsdev->nd_super.s_last_cno));
688 
689 	/* Calculate dat structure parameters */
690 	nandfs_calc_mdt_consts(nandfsdev, &nandfsdev->nd_dat_mdt,
691 	    nandfsdev->nd_fsdata.f_dat_entry_size);
692 	nandfs_calc_mdt_consts(nandfsdev, &nandfsdev->nd_ifile_mdt,
693 	    nandfsdev->nd_fsdata.f_inode_size);
694 
695 	/* Search for the super root and roll forward when needed */
696 	if (nandfs_search_super_root(nandfsdev)) {
697 		printf("Cannot find valid SuperRoot\n");
698 		return (EINVAL);
699 	}
700 
701 	nandfsdev->nd_mount_state = nandfsdev->nd_super.s_state;
702 	if (nandfsdev->nd_mount_state != NANDFS_VALID_FS) {
703 		printf("FS is seriously damaged, needs repairing\n");
704 		printf("aborting mount\n");
705 		return (EINVAL);
706 	}
707 
708 	/*
709 	 * FS should be ok now. The superblock and the last segsum could be
710 	 * updated from the repair so extract running values again.
711 	 */
712 	nandfsdev->nd_last_pseg = nandfsdev->nd_super.s_last_pseg;
713 	nandfsdev->nd_seg_sequence = nandfsdev->nd_super.s_last_seq;
714 	nandfsdev->nd_seg_num = nandfs_get_segnum_of_block(nandfsdev,
715 	    nandfsdev->nd_last_pseg);
716 	nandfsdev->nd_next_seg_num = nandfs_get_segnum_of_block(nandfsdev,
717 	    nandfsdev->nd_last_segsum.ss_next);
718 	nandfsdev->nd_ts.tv_sec = nandfsdev->nd_last_segsum.ss_create;
719 	nandfsdev->nd_last_cno = nandfsdev->nd_super.s_last_cno;
720 	nandfsdev->nd_fakevblk = 1;
721 	/*
722 	 * FIXME: bogus calculation. Should use actual number of usable segments
723 	 * instead of total amount.
724 	 */
725 	nandfsdev->nd_segs_reserved =
726 	    nandfsdev->nd_fsdata.f_nsegments *
727 	    nandfsdev->nd_fsdata.f_r_segments_percentage / 100;
728 	nandfsdev->nd_last_ino  = NANDFS_USER_INO;
729 	DPRINTF(VOLUMES, ("%s: last_pseg %#jx last_cno %#jx last_seq %#jx\n"
730 	    "fsdev: last_seg: seq %#jx num %#jx, next_seg_num %#jx "
731 	    "segs_reserved %#jx\n",
732 	    __func__, (uintmax_t)nandfsdev->nd_last_pseg,
733 	    (uintmax_t)nandfsdev->nd_last_cno,
734 	    (uintmax_t)nandfsdev->nd_seg_sequence,
735 	    (uintmax_t)nandfsdev->nd_seg_sequence,
736 	    (uintmax_t)nandfsdev->nd_seg_num,
737 	    (uintmax_t)nandfsdev->nd_next_seg_num,
738 	    (uintmax_t)nandfsdev->nd_segs_reserved));
739 
740 	DPRINTF(VOLUMES, ("nandfs_mount: accepted super root\n"));
741 
742 	/* Create system vnodes for DAT, CP and SEGSUM */
743 	error = nandfs_create_system_nodes(nandfsdev);
744 	if (error)
745 		nandfs_unmount_base(nandfsdev);
746 
747 	nandfs_get_ncleanseg(nandfsdev);
748 
749 	return (error);
750 }
751 
752 static void
nandfs_unmount_device(struct nandfs_device * nandfsdev)753 nandfs_unmount_device(struct nandfs_device *nandfsdev)
754 {
755 
756 	/* Is there anything? */
757 	if (nandfsdev == NULL)
758 		return;
759 
760 	/* Remove the device only if we're the last reference */
761 	nandfsdev->nd_refcnt--;
762 	if (nandfsdev->nd_refcnt >= 1)
763 		return;
764 
765 	MPASS(nandfsdev->nd_syncer == NULL);
766 	MPASS(nandfsdev->nd_cleaner == NULL);
767 	MPASS(nandfsdev->nd_free_base == NULL);
768 
769 	/* Unmount our base */
770 	nandfs_unmount_base(nandfsdev);
771 
772 	/* Remove from our device list */
773 	SLIST_REMOVE(&nandfs_devices, nandfsdev, nandfs_device, nd_next_device);
774 
775 	DROP_GIANT();
776 	g_topology_lock();
777 	g_vfs_close(nandfsdev->nd_gconsumer);
778 	g_topology_unlock();
779 	PICKUP_GIANT();
780 
781 	DPRINTF(VOLUMES, ("closing device\n"));
782 
783 	/* Clear our mount reference and release device node */
784 	vrele(nandfsdev->nd_devvp);
785 
786 	dev_rel(nandfsdev->nd_devvp->v_rdev);
787 
788 	/* Free our device info */
789 	cv_destroy(&nandfsdev->nd_sync_cv);
790 	mtx_destroy(&nandfsdev->nd_sync_mtx);
791 	cv_destroy(&nandfsdev->nd_clean_cv);
792 	mtx_destroy(&nandfsdev->nd_clean_mtx);
793 	mtx_destroy(&nandfsdev->nd_mutex);
794 	lockdestroy(&nandfsdev->nd_seg_const);
795 	free(nandfsdev, M_NANDFSMNT);
796 }
797 
798 static int
nandfs_check_mounts(struct nandfs_device * nandfsdev,struct mount * mp,struct nandfs_args * args)799 nandfs_check_mounts(struct nandfs_device *nandfsdev, struct mount *mp,
800     struct nandfs_args *args)
801 {
802 	struct nandfsmount *nmp;
803 	uint64_t last_cno;
804 
805 	/* no double-mounting of the same checkpoint */
806 	STAILQ_FOREACH(nmp, &nandfsdev->nd_mounts, nm_next_mount) {
807 		if (nmp->nm_mount_args.cpno == args->cpno)
808 			return (EBUSY);
809 	}
810 
811 	/* Allow readonly mounts without questioning here */
812 	if (mp->mnt_flag & MNT_RDONLY)
813 		return (0);
814 
815 	/* Read/write mount */
816 	STAILQ_FOREACH(nmp, &nandfsdev->nd_mounts, nm_next_mount) {
817 		/* Only one RW mount on this device! */
818 		if ((nmp->nm_vfs_mountp->mnt_flag & MNT_RDONLY)==0)
819 			return (EROFS);
820 		/* RDONLY on last mountpoint is device busy */
821 		last_cno = nmp->nm_nandfsdev->nd_super.s_last_cno;
822 		if (nmp->nm_mount_args.cpno == last_cno)
823 			return (EBUSY);
824 	}
825 
826 	/* OK for now */
827 	return (0);
828 }
829 
830 static int
nandfs_mount_device(struct vnode * devvp,struct mount * mp,struct nandfs_args * args,struct nandfs_device ** nandfsdev_p)831 nandfs_mount_device(struct vnode *devvp, struct mount *mp,
832     struct nandfs_args *args, struct nandfs_device **nandfsdev_p)
833 {
834 	struct nandfs_device *nandfsdev;
835 	struct g_provider *pp;
836 	struct g_consumer *cp;
837 	struct cdev *dev;
838 	uint32_t erasesize;
839 	int error, size;
840 	int ronly;
841 
842 	DPRINTF(VOLUMES, ("Mounting NANDFS device\n"));
843 
844 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
845 
846 	/* Look up device in our nandfs_mountpoints */
847 	*nandfsdev_p = NULL;
848 	SLIST_FOREACH(nandfsdev, &nandfs_devices, nd_next_device)
849 		if (nandfsdev->nd_devvp == devvp)
850 			break;
851 
852 	if (nandfsdev) {
853 		DPRINTF(VOLUMES, ("device already mounted\n"));
854 		error = nandfs_check_mounts(nandfsdev, mp, args);
855 		if (error)
856 			return error;
857 		nandfsdev->nd_refcnt++;
858 		*nandfsdev_p = nandfsdev;
859 
860 		if (!ronly) {
861 			DROP_GIANT();
862 			g_topology_lock();
863 			error = g_access(nandfsdev->nd_gconsumer, 0, 1, 0);
864 			g_topology_unlock();
865 			PICKUP_GIANT();
866 		}
867 		return (error);
868 	}
869 
870 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
871 	dev = devvp->v_rdev;
872 	dev_ref(dev);
873 	DROP_GIANT();
874 	g_topology_lock();
875 	error = g_vfs_open(devvp, &cp, "nandfs", ronly ? 0 : 1);
876 	pp = g_dev_getprovider(dev);
877 	g_topology_unlock();
878 	PICKUP_GIANT();
879 	VOP_UNLOCK(devvp, 0);
880 	if (error) {
881 		dev_rel(dev);
882 		return (error);
883 	}
884 
885 	nandfsdev = malloc(sizeof(struct nandfs_device), M_NANDFSMNT, M_WAITOK | M_ZERO);
886 
887 	/* Initialise */
888 	nandfsdev->nd_refcnt = 1;
889 	nandfsdev->nd_devvp = devvp;
890 	nandfsdev->nd_syncing = 0;
891 	nandfsdev->nd_cleaning = 0;
892 	nandfsdev->nd_gconsumer = cp;
893 	cv_init(&nandfsdev->nd_sync_cv, "nandfssync");
894 	mtx_init(&nandfsdev->nd_sync_mtx, "nffssyncmtx", NULL, MTX_DEF);
895 	cv_init(&nandfsdev->nd_clean_cv, "nandfsclean");
896 	mtx_init(&nandfsdev->nd_clean_mtx, "nffscleanmtx", NULL, MTX_DEF);
897 	mtx_init(&nandfsdev->nd_mutex, "nandfsdev lock", NULL, MTX_DEF);
898 	lockinit(&nandfsdev->nd_seg_const, PVFS, "nffssegcon", VLKTIMEOUT,
899 	    LK_CANRECURSE);
900 	STAILQ_INIT(&nandfsdev->nd_mounts);
901 
902 	nandfsdev->nd_devsize = pp->mediasize;
903 	nandfsdev->nd_devblocksize = pp->sectorsize;
904 
905 	size = sizeof(erasesize);
906 	error = g_io_getattr("NAND::blocksize", nandfsdev->nd_gconsumer, &size,
907 	    &erasesize);
908 	if (error) {
909 		DPRINTF(VOLUMES, ("couldn't get erasesize: %d\n", error));
910 
911 		if (error == ENOIOCTL || error == EOPNOTSUPP) {
912 			/*
913 			 * We conclude that this is not NAND storage
914 			 */
915 			erasesize = NANDFS_DEF_ERASESIZE;
916 		} else {
917 			DROP_GIANT();
918 			g_topology_lock();
919 			g_vfs_close(nandfsdev->nd_gconsumer);
920 			g_topology_unlock();
921 			PICKUP_GIANT();
922 			dev_rel(dev);
923 			free(nandfsdev, M_NANDFSMNT);
924 			return (error);
925 		}
926 	}
927 	nandfsdev->nd_erasesize = erasesize;
928 
929 	DPRINTF(VOLUMES, ("%s: erasesize %x\n", __func__,
930 	    nandfsdev->nd_erasesize));
931 
932 	/* Register nandfs_device in list */
933 	SLIST_INSERT_HEAD(&nandfs_devices, nandfsdev, nd_next_device);
934 
935 	error = nandfs_mount_base(nandfsdev, mp, args);
936 	if (error) {
937 		/* Remove all our information */
938 		nandfs_unmount_device(nandfsdev);
939 		return (EINVAL);
940 	}
941 
942 	nandfsdev->nd_maxfilesize = nandfs_get_maxfilesize(nandfsdev);
943 
944 	*nandfsdev_p = nandfsdev;
945 	DPRINTF(VOLUMES, ("NANDFS device mounted ok\n"));
946 
947 	return (0);
948 }
949 
950 static int
nandfs_mount_checkpoint(struct nandfsmount * nmp)951 nandfs_mount_checkpoint(struct nandfsmount *nmp)
952 {
953 	struct nandfs_cpfile_header *cphdr;
954 	struct nandfs_checkpoint *cp;
955 	struct nandfs_inode ifile_inode;
956 	struct nandfs_node *cp_node;
957 	struct buf *bp;
958 	uint64_t ncp, nsn, cpno, fcpno, blocknr, last_cno;
959 	uint32_t off, dlen;
960 	int cp_per_block, error;
961 
962 	cpno = nmp->nm_mount_args.cpno;
963 	if (cpno == 0)
964 		cpno = nmp->nm_nandfsdev->nd_super.s_last_cno;
965 
966 	DPRINTF(VOLUMES, ("%s: trying to mount checkpoint number %"PRIu64"\n",
967 	    __func__, cpno));
968 
969 	cp_node = nmp->nm_nandfsdev->nd_cp_node;
970 
971 	VOP_LOCK(NTOV(cp_node), LK_SHARED);
972 	/* Get cpfile header from 1st block of cp file */
973 	error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
974 	if (error) {
975 		brelse(bp);
976 		VOP_UNLOCK(NTOV(cp_node), 0);
977 		return (error);
978 	}
979 
980 	cphdr = (struct nandfs_cpfile_header *) bp->b_data;
981 	ncp = cphdr->ch_ncheckpoints;
982 	nsn = cphdr->ch_nsnapshots;
983 
984 	brelse(bp);
985 
986 	DPRINTF(VOLUMES, ("mount_nandfs: checkpoint header read in\n"));
987 	DPRINTF(VOLUMES, ("\tNumber of checkpoints %"PRIu64"\n", ncp));
988 	DPRINTF(VOLUMES, ("\tNumber of snapshots %"PRIu64"\n", nsn));
989 
990 	/* Read in our specified checkpoint */
991 	dlen = nmp->nm_nandfsdev->nd_fsdata.f_checkpoint_size;
992 	cp_per_block = nmp->nm_nandfsdev->nd_blocksize / dlen;
993 
994 	fcpno = cpno + NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET - 1;
995 	blocknr = fcpno / cp_per_block;
996 	off = (fcpno % cp_per_block) * dlen;
997 	error = nandfs_bread(cp_node, blocknr, NOCRED, 0, &bp);
998 	if (error) {
999 		brelse(bp);
1000 		VOP_UNLOCK(NTOV(cp_node), 0);
1001 		printf("mount_nandfs: couldn't read cp block %"PRIu64"\n",
1002 		    fcpno);
1003 		return (EINVAL);
1004 	}
1005 
1006 	/* Needs to be a valid checkpoint */
1007 	cp = (struct nandfs_checkpoint *) ((uint8_t *) bp->b_data + off);
1008 	if (cp->cp_flags & NANDFS_CHECKPOINT_INVALID) {
1009 		printf("mount_nandfs: checkpoint marked invalid\n");
1010 		brelse(bp);
1011 		VOP_UNLOCK(NTOV(cp_node), 0);
1012 		return (EINVAL);
1013 	}
1014 
1015 	/* Is this really the checkpoint we want? */
1016 	if (cp->cp_cno != cpno) {
1017 		printf("mount_nandfs: checkpoint file corrupt? "
1018 		    "expected cpno %"PRIu64", found cpno %"PRIu64"\n",
1019 		    cpno, cp->cp_cno);
1020 		brelse(bp);
1021 		VOP_UNLOCK(NTOV(cp_node), 0);
1022 		return (EINVAL);
1023 	}
1024 
1025 	/* Check if it's a snapshot ! */
1026 	last_cno = nmp->nm_nandfsdev->nd_super.s_last_cno;
1027 	if (cpno != last_cno) {
1028 		/* Only allow snapshots if not mounting on the last cp */
1029 		if ((cp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT) == 0) {
1030 			printf( "mount_nandfs: checkpoint %"PRIu64" is not a "
1031 			    "snapshot\n", cpno);
1032 			brelse(bp);
1033 			VOP_UNLOCK(NTOV(cp_node), 0);
1034 			return (EINVAL);
1035 		}
1036 	}
1037 
1038 	ifile_inode = cp->cp_ifile_inode;
1039 	brelse(bp);
1040 
1041 	/* Get ifile inode */
1042 	error = nandfs_get_node_raw(nmp->nm_nandfsdev, NULL, NANDFS_IFILE_INO,
1043 	    &ifile_inode, &nmp->nm_ifile_node);
1044 	if (error) {
1045 		printf("mount_nandfs: can't read ifile node\n");
1046 		VOP_UNLOCK(NTOV(cp_node), 0);
1047 		return (EINVAL);
1048 	}
1049 
1050 	NANDFS_SET_SYSTEMFILE(NTOV(nmp->nm_ifile_node));
1051 	VOP_UNLOCK(NTOV(cp_node), 0);
1052 	/* Get root node? */
1053 
1054 	return (0);
1055 }
1056 
1057 static void
free_nandfs_mountinfo(struct mount * mp)1058 free_nandfs_mountinfo(struct mount *mp)
1059 {
1060 	struct nandfsmount *nmp = VFSTONANDFS(mp);
1061 
1062 	if (nmp == NULL)
1063 		return;
1064 
1065 	free(nmp, M_NANDFSMNT);
1066 }
1067 
1068 void
nandfs_wakeup_wait_sync(struct nandfs_device * nffsdev,int reason)1069 nandfs_wakeup_wait_sync(struct nandfs_device *nffsdev, int reason)
1070 {
1071 	char *reasons[] = {
1072 	    "umount",
1073 	    "vfssync",
1074 	    "bdflush",
1075 	    "fforce",
1076 	    "fsync",
1077 	    "ro_upd"
1078 	};
1079 
1080 	DPRINTF(SYNC, ("%s: %s\n", __func__, reasons[reason]));
1081 	mtx_lock(&nffsdev->nd_sync_mtx);
1082 	if (nffsdev->nd_syncing)
1083 		cv_wait(&nffsdev->nd_sync_cv, &nffsdev->nd_sync_mtx);
1084 	if (reason == SYNCER_UMOUNT)
1085 		nffsdev->nd_syncer_exit = 1;
1086 	nffsdev->nd_syncing = 1;
1087 	wakeup(&nffsdev->nd_syncing);
1088 	cv_wait(&nffsdev->nd_sync_cv, &nffsdev->nd_sync_mtx);
1089 
1090 	mtx_unlock(&nffsdev->nd_sync_mtx);
1091 }
1092 
1093 static void
nandfs_gc_finished(struct nandfs_device * nffsdev,int exit)1094 nandfs_gc_finished(struct nandfs_device *nffsdev, int exit)
1095 {
1096 	int error;
1097 
1098 	mtx_lock(&nffsdev->nd_sync_mtx);
1099 	nffsdev->nd_syncing = 0;
1100 	DPRINTF(SYNC, ("%s: cleaner finish\n", __func__));
1101 	cv_broadcast(&nffsdev->nd_sync_cv);
1102 	mtx_unlock(&nffsdev->nd_sync_mtx);
1103 	if (!exit) {
1104 		error = tsleep(&nffsdev->nd_syncing, PRIBIO, "-",
1105 		    hz * nandfs_sync_interval);
1106 		DPRINTF(SYNC, ("%s: cleaner waked up: %d\n",
1107 		    __func__, error));
1108 	}
1109 }
1110 
1111 static void
nandfs_syncer(struct nandfsmount * nmp)1112 nandfs_syncer(struct nandfsmount *nmp)
1113 {
1114 	struct nandfs_device *nffsdev;
1115 	struct mount *mp;
1116 	int flags, error;
1117 
1118 	mp = nmp->nm_vfs_mountp;
1119 	nffsdev = nmp->nm_nandfsdev;
1120 	tsleep(&nffsdev->nd_syncing, PRIBIO, "-", hz * nandfs_sync_interval);
1121 
1122 	while (!nffsdev->nd_syncer_exit) {
1123 		DPRINTF(SYNC, ("%s: syncer run\n", __func__));
1124 		nffsdev->nd_syncing = 1;
1125 
1126 		flags = (nmp->nm_flags & (NANDFS_FORCE_SYNCER | NANDFS_UMOUNT));
1127 
1128 		error = nandfs_segment_constructor(nmp, flags);
1129 		if (error)
1130 			nandfs_error("%s: error:%d when creating segments\n",
1131 			    __func__, error);
1132 
1133 		nmp->nm_flags &= ~flags;
1134 
1135 		nandfs_gc_finished(nffsdev, 0);
1136 	}
1137 
1138 	MPASS(nffsdev->nd_cleaner == NULL);
1139 	error = nandfs_segment_constructor(nmp,
1140 	    NANDFS_FORCE_SYNCER | NANDFS_UMOUNT);
1141 	if (error)
1142 		nandfs_error("%s: error:%d when creating segments\n",
1143 		    __func__, error);
1144 	nandfs_gc_finished(nffsdev, 1);
1145 	nffsdev->nd_syncer = NULL;
1146 	MPASS(nffsdev->nd_free_base == NULL);
1147 
1148 	DPRINTF(SYNC, ("%s: exiting\n", __func__));
1149 	kthread_exit();
1150 }
1151 
1152 static int
start_syncer(struct nandfsmount * nmp)1153 start_syncer(struct nandfsmount *nmp)
1154 {
1155 	int error;
1156 
1157 	MPASS(nmp->nm_nandfsdev->nd_syncer == NULL);
1158 
1159 	DPRINTF(SYNC, ("%s: start syncer\n", __func__));
1160 
1161 	nmp->nm_nandfsdev->nd_syncer_exit = 0;
1162 
1163 	error = kthread_add((void(*)(void *))nandfs_syncer, nmp, NULL,
1164 	    &nmp->nm_nandfsdev->nd_syncer, 0, 0, "nandfs_syncer");
1165 
1166 	if (error)
1167 		printf("nandfs: could not start syncer: %d\n", error);
1168 
1169 	return (error);
1170 }
1171 
1172 static int
stop_syncer(struct nandfsmount * nmp)1173 stop_syncer(struct nandfsmount *nmp)
1174 {
1175 
1176 	MPASS(nmp->nm_nandfsdev->nd_syncer != NULL);
1177 
1178 	nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_UMOUNT);
1179 
1180 	DPRINTF(SYNC, ("%s: stop syncer\n", __func__));
1181 	return (0);
1182 }
1183 
1184 /*
1185  * Mount null layer
1186  */
1187 static int
nandfs_mount(struct mount * mp)1188 nandfs_mount(struct mount *mp)
1189 {
1190 	struct nandfsmount *nmp;
1191 	struct vnode *devvp;
1192 	struct nameidata nd;
1193 	struct vfsoptlist *opts;
1194 	struct thread *td;
1195 	char *from;
1196 	int error = 0, flags;
1197 
1198 	DPRINTF(VOLUMES, ("%s: mp = %p\n", __func__, (void *)mp));
1199 
1200 	td = curthread;
1201 	opts = mp->mnt_optnew;
1202 
1203 	if (vfs_filteropt(opts, nandfs_opts))
1204 		return (EINVAL);
1205 
1206 	/*
1207 	 * Update is a no-op
1208 	 */
1209 	if (mp->mnt_flag & MNT_UPDATE) {
1210 		nmp = VFSTONANDFS(mp);
1211 		if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) {
1212 			return (error);
1213 		}
1214 		if (!(nmp->nm_ronly) && vfs_flagopt(opts, "ro", NULL, 0)) {
1215 			vn_start_write(NULL, &mp, V_WAIT);
1216 			error = VFS_SYNC(mp, MNT_WAIT);
1217 			if (error)
1218 				return (error);
1219 			vn_finished_write(mp);
1220 
1221 			flags = WRITECLOSE;
1222 			if (mp->mnt_flag & MNT_FORCE)
1223 				flags |= FORCECLOSE;
1224 
1225 			nandfs_wakeup_wait_sync(nmp->nm_nandfsdev,
1226 			    SYNCER_ROUPD);
1227 			error = vflush(mp, 0, flags, td);
1228 			if (error)
1229 				return (error);
1230 
1231 			nandfs_stop_cleaner(nmp->nm_nandfsdev);
1232 			stop_syncer(nmp);
1233 			DROP_GIANT();
1234 			g_topology_lock();
1235 			g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, -1, 0);
1236 			g_topology_unlock();
1237 			PICKUP_GIANT();
1238 			MNT_ILOCK(mp);
1239 			mp->mnt_flag |= MNT_RDONLY;
1240 			MNT_IUNLOCK(mp);
1241 			nmp->nm_ronly = 1;
1242 
1243 		} else if ((nmp->nm_ronly) &&
1244 		    !vfs_flagopt(opts, "ro", NULL, 0)) {
1245 			/*
1246 			 * Don't allow read-write snapshots.
1247 			 */
1248 			if (nmp->nm_mount_args.cpno != 0)
1249 				return (EROFS);
1250 			/*
1251 			 * If upgrade to read-write by non-root, then verify
1252 			 * that user has necessary permissions on the device.
1253 			 */
1254 			devvp = nmp->nm_nandfsdev->nd_devvp;
1255 			vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
1256 			error = VOP_ACCESS(devvp, VREAD | VWRITE,
1257 			    td->td_ucred, td);
1258 			if (error) {
1259 				error = priv_check(td, PRIV_VFS_MOUNT_PERM);
1260 				if (error) {
1261 					VOP_UNLOCK(devvp, 0);
1262 					return (error);
1263 				}
1264 			}
1265 
1266 			VOP_UNLOCK(devvp, 0);
1267 			DROP_GIANT();
1268 			g_topology_lock();
1269 			error = g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, 1,
1270 			    0);
1271 			g_topology_unlock();
1272 			PICKUP_GIANT();
1273 			if (error)
1274 				return (error);
1275 
1276 			MNT_ILOCK(mp);
1277 			mp->mnt_flag &= ~MNT_RDONLY;
1278 			MNT_IUNLOCK(mp);
1279 			error = start_syncer(nmp);
1280 			if (error == 0)
1281 				error = nandfs_start_cleaner(nmp->nm_nandfsdev);
1282 			if (error) {
1283 				DROP_GIANT();
1284 				g_topology_lock();
1285 				g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, -1,
1286 				    0);
1287 				g_topology_unlock();
1288 				PICKUP_GIANT();
1289 				return (error);
1290 			}
1291 
1292 			nmp->nm_ronly = 0;
1293 		}
1294 		return (0);
1295 	}
1296 
1297 	from = vfs_getopts(opts, "from", &error);
1298 	if (error)
1299 		return (error);
1300 
1301 	/*
1302 	 * Find device node
1303 	 */
1304 	NDINIT(&nd, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, from, curthread);
1305 	error = namei(&nd);
1306 	if (error)
1307 		return (error);
1308 	NDFREE(&nd, NDF_ONLY_PNBUF);
1309 
1310 	devvp = nd.ni_vp;
1311 
1312 	if (!vn_isdisk(devvp, &error)) {
1313 		vput(devvp);
1314 		return (error);
1315 	}
1316 
1317 	/* Check the access rights on the mount device */
1318 	error = VOP_ACCESS(devvp, VREAD, curthread->td_ucred, curthread);
1319 	if (error)
1320 		error = priv_check(curthread, PRIV_VFS_MOUNT_PERM);
1321 	if (error) {
1322 		vput(devvp);
1323 		return (error);
1324 	}
1325 
1326 	vfs_getnewfsid(mp);
1327 
1328 	error = nandfs_mountfs(devvp, mp);
1329 	if (error)
1330 		return (error);
1331 	vfs_mountedfrom(mp, from);
1332 
1333 	return (0);
1334 }
1335 
1336 static int
nandfs_mountfs(struct vnode * devvp,struct mount * mp)1337 nandfs_mountfs(struct vnode *devvp, struct mount *mp)
1338 {
1339 	struct nandfsmount *nmp = NULL;
1340 	struct nandfs_args *args = NULL;
1341 	struct nandfs_device *nandfsdev;
1342 	char *from;
1343 	int error, ronly;
1344 	char *cpno;
1345 
1346 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
1347 
1348 	if (devvp->v_rdev->si_iosize_max != 0)
1349 		mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
1350 	VOP_UNLOCK(devvp, 0);
1351 
1352 	if (mp->mnt_iosize_max > MAXPHYS)
1353 		mp->mnt_iosize_max = MAXPHYS;
1354 
1355 	from = vfs_getopts(mp->mnt_optnew, "from", &error);
1356 	if (error)
1357 		goto error;
1358 
1359 	error = vfs_getopt(mp->mnt_optnew, "snap", (void **)&cpno, NULL);
1360 	if (error == ENOENT)
1361 		cpno = NULL;
1362 	else if (error)
1363 		goto error;
1364 
1365 	args = (struct nandfs_args *)malloc(sizeof(struct nandfs_args),
1366 	    M_NANDFSMNT, M_WAITOK | M_ZERO);
1367 
1368 	if (cpno != NULL)
1369 		args->cpno = strtoul(cpno, (char **)NULL, 10);
1370 	else
1371 		args->cpno = 0;
1372 	args->fspec = from;
1373 
1374 	if (args->cpno != 0 && !ronly) {
1375 		error = EROFS;
1376 		goto error;
1377 	}
1378 
1379 	printf("WARNING: NANDFS is considered to be a highly experimental "
1380 	    "feature in FreeBSD.\n");
1381 
1382 	error = nandfs_mount_device(devvp, mp, args, &nandfsdev);
1383 	if (error)
1384 		goto error;
1385 
1386 	nmp = (struct nandfsmount *) malloc(sizeof(struct nandfsmount),
1387 	    M_NANDFSMNT, M_WAITOK | M_ZERO);
1388 
1389 	mp->mnt_data = nmp;
1390 	nmp->nm_vfs_mountp = mp;
1391 	nmp->nm_ronly = ronly;
1392 	MNT_ILOCK(mp);
1393 	mp->mnt_flag |= MNT_LOCAL;
1394 	mp->mnt_kern_flag |= MNTK_USES_BCACHE;
1395 	MNT_IUNLOCK(mp);
1396 	nmp->nm_nandfsdev = nandfsdev;
1397 	/* Add our mountpoint */
1398 	STAILQ_INSERT_TAIL(&nandfsdev->nd_mounts, nmp, nm_next_mount);
1399 
1400 	if (args->cpno > nandfsdev->nd_last_cno) {
1401 		printf("WARNING: supplied checkpoint number (%jd) is greater "
1402 		    "than last known checkpoint on filesystem (%jd). Mounting"
1403 		    " checkpoint %jd\n", (uintmax_t)args->cpno,
1404 		    (uintmax_t)nandfsdev->nd_last_cno,
1405 		    (uintmax_t)nandfsdev->nd_last_cno);
1406 		args->cpno = nandfsdev->nd_last_cno;
1407 	}
1408 
1409 	/* Setting up other parameters */
1410 	nmp->nm_mount_args = *args;
1411 	free(args, M_NANDFSMNT);
1412 	error = nandfs_mount_checkpoint(nmp);
1413 	if (error) {
1414 		nandfs_unmount(mp, MNT_FORCE);
1415 		goto unmounted;
1416 	}
1417 
1418 	if (!ronly) {
1419 		error = start_syncer(nmp);
1420 		if (error == 0)
1421 			error = nandfs_start_cleaner(nmp->nm_nandfsdev);
1422 		if (error)
1423 			nandfs_unmount(mp, MNT_FORCE);
1424 	}
1425 
1426 	return (0);
1427 
1428 error:
1429 	if (args != NULL)
1430 		free(args, M_NANDFSMNT);
1431 
1432 	if (nmp != NULL) {
1433 		free(nmp, M_NANDFSMNT);
1434 		mp->mnt_data = NULL;
1435 	}
1436 unmounted:
1437 	return (error);
1438 }
1439 
1440 static int
nandfs_unmount(struct mount * mp,int mntflags)1441 nandfs_unmount(struct mount *mp, int mntflags)
1442 {
1443 	struct nandfs_device *nandfsdev;
1444 	struct nandfsmount *nmp;
1445 	int error;
1446 	int flags = 0;
1447 
1448 	DPRINTF(VOLUMES, ("%s: mp = %p\n", __func__, (void *)mp));
1449 
1450 	if (mntflags & MNT_FORCE)
1451 		flags |= FORCECLOSE;
1452 
1453 	nmp = mp->mnt_data;
1454 	nandfsdev = nmp->nm_nandfsdev;
1455 
1456 	error = vflush(mp, 0, flags | SKIPSYSTEM, curthread);
1457 	if (error)
1458 		return (error);
1459 
1460 	if (!(nmp->nm_ronly)) {
1461 		nandfs_stop_cleaner(nandfsdev);
1462 		stop_syncer(nmp);
1463 	}
1464 
1465 	if (nmp->nm_ifile_node)
1466 		NANDFS_UNSET_SYSTEMFILE(NTOV(nmp->nm_ifile_node));
1467 
1468 	/* Remove our mount point */
1469 	STAILQ_REMOVE(&nandfsdev->nd_mounts, nmp, nandfsmount, nm_next_mount);
1470 
1471 	/* Unmount the device itself when we're the last one */
1472 	nandfs_unmount_device(nandfsdev);
1473 
1474 	free_nandfs_mountinfo(mp);
1475 
1476 	/*
1477 	 * Finally, throw away the null_mount structure
1478 	 */
1479 	mp->mnt_data = 0;
1480 	MNT_ILOCK(mp);
1481 	mp->mnt_flag &= ~MNT_LOCAL;
1482 	MNT_IUNLOCK(mp);
1483 
1484 	return (0);
1485 }
1486 
1487 static int
nandfs_statfs(struct mount * mp,struct statfs * sbp)1488 nandfs_statfs(struct mount *mp, struct statfs *sbp)
1489 {
1490 	struct nandfsmount *nmp;
1491 	struct nandfs_device *nandfsdev;
1492 	struct nandfs_fsdata *fsdata;
1493 	struct nandfs_super_block *sb;
1494 	struct nandfs_block_group_desc *groups;
1495 	struct nandfs_node *ifile;
1496 	struct nandfs_mdt *mdt;
1497 	struct buf *bp;
1498 	int i, error;
1499 	uint32_t entries_per_group;
1500 	uint64_t files = 0;
1501 
1502 	nmp = mp->mnt_data;
1503 	nandfsdev = nmp->nm_nandfsdev;
1504 	fsdata = &nandfsdev->nd_fsdata;
1505 	sb = &nandfsdev->nd_super;
1506 	ifile = nmp->nm_ifile_node;
1507 	mdt = &nandfsdev->nd_ifile_mdt;
1508 	entries_per_group = mdt->entries_per_group;
1509 
1510 	VOP_LOCK(NTOV(ifile), LK_SHARED);
1511 	error = nandfs_bread(ifile, 0, NOCRED, 0, &bp);
1512 	if (error) {
1513 		brelse(bp);
1514 		VOP_UNLOCK(NTOV(ifile), 0);
1515 		return (error);
1516 	}
1517 
1518 	groups = (struct nandfs_block_group_desc *)bp->b_data;
1519 
1520 	for (i = 0; i < mdt->groups_per_desc_block; i++)
1521 		files += (entries_per_group - groups[i].bg_nfrees);
1522 
1523 	brelse(bp);
1524 	VOP_UNLOCK(NTOV(ifile), 0);
1525 
1526 	sbp->f_bsize = nandfsdev->nd_blocksize;
1527 	sbp->f_iosize = sbp->f_bsize;
1528 	sbp->f_blocks = fsdata->f_blocks_per_segment * fsdata->f_nsegments;
1529 	sbp->f_bfree = sb->s_free_blocks_count;
1530 	sbp->f_bavail = sbp->f_bfree;
1531 	sbp->f_files = files;
1532 	sbp->f_ffree = 0;
1533 	return (0);
1534 }
1535 
1536 static int
nandfs_root(struct mount * mp,int flags,struct vnode ** vpp)1537 nandfs_root(struct mount *mp, int flags, struct vnode **vpp)
1538 {
1539 	struct nandfsmount *nmp = VFSTONANDFS(mp);
1540 	struct nandfs_node *node;
1541 	int error;
1542 
1543 	error = nandfs_get_node(nmp, NANDFS_ROOT_INO, &node);
1544 	if (error)
1545 		return (error);
1546 
1547 	KASSERT(NTOV(node)->v_vflag & VV_ROOT,
1548 	    ("root_vp->v_vflag & VV_ROOT"));
1549 
1550 	*vpp = NTOV(node);
1551 
1552 	return (error);
1553 }
1554 
1555 static int
nandfs_vget(struct mount * mp,ino_t ino,int flags,struct vnode ** vpp)1556 nandfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
1557 {
1558 	struct nandfsmount *nmp = VFSTONANDFS(mp);
1559 	struct nandfs_node *node;
1560 	int error;
1561 
1562 	error = nandfs_get_node(nmp, ino, &node);
1563 	if (node)
1564 		*vpp = NTOV(node);
1565 
1566 	return (error);
1567 }
1568 
1569 static int
nandfs_sync(struct mount * mp,int waitfor)1570 nandfs_sync(struct mount *mp, int waitfor)
1571 {
1572 	struct nandfsmount *nmp = VFSTONANDFS(mp);
1573 
1574 	DPRINTF(SYNC, ("%s: mp %p waitfor %d\n", __func__, mp, waitfor));
1575 
1576 	/*
1577 	 * XXX: A hack to be removed soon
1578 	 */
1579 	if (waitfor == MNT_LAZY)
1580 		return (0);
1581 	if (waitfor == MNT_SUSPEND)
1582 		return (0);
1583 	nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_VFS_SYNC);
1584 	return (0);
1585 }
1586 
1587 static struct vfsops nandfs_vfsops = {
1588 	.vfs_init =		nandfs_init,
1589 	.vfs_mount =		nandfs_mount,
1590 	.vfs_root =		nandfs_root,
1591 	.vfs_statfs =		nandfs_statfs,
1592 	.vfs_uninit =		nandfs_uninit,
1593 	.vfs_unmount =		nandfs_unmount,
1594 	.vfs_vget =		nandfs_vget,
1595 	.vfs_sync =		nandfs_sync,
1596 };
1597 
1598 VFS_SET(nandfs_vfsops, nandfs, VFCF_LOOPBACK);
1599