1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2010-2012 Semihalf
5  * Copyright (c) 2008, 2009 Reinoud Zandijk
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * From: NetBSD: nilfs_subr.c,v 1.4 2009/07/29 17:06:57 reinoud
29  */
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD: stable/12/sys/fs/nandfs/nandfs_subr.c 371940 2022-04-10 05:02:22Z git2svn $");
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/gsb_crc32.h>
37 #include <sys/namei.h>
38 #include <sys/resourcevar.h>
39 #include <sys/kernel.h>
40 #include <sys/file.h>
41 #include <sys/stat.h>
42 #include <sys/buf.h>
43 #include <sys/bio.h>
44 #include <sys/proc.h>
45 #include <sys/mount.h>
46 #include <sys/vnode.h>
47 #include <sys/signalvar.h>
48 #include <sys/malloc.h>
49 #include <sys/dirent.h>
50 #include <sys/lockf.h>
51 #include <sys/libkern.h>
52 
53 #include <geom/geom.h>
54 #include <geom/geom_vfs.h>
55 
56 #include <vm/vm.h>
57 #include <vm/vm_extern.h>
58 
59 #include <machine/_inttypes.h>
60 #include "nandfs_mount.h"
61 #include "nandfs.h"
62 #include "nandfs_subr.h"
63 
64 MALLOC_DEFINE(M_NANDFSMNT, "nandfs_mount", "NANDFS mount");
65 MALLOC_DEFINE(M_NANDFSTEMP, "nandfs_tmt", "NANDFS tmp");
66 
67 uma_zone_t nandfs_node_zone;
68 
69 void nandfs_bdflush(struct bufobj *bo, struct buf *bp);
70 int nandfs_bufsync(struct bufobj *bo, int waitfor);
71 
72 struct buf_ops buf_ops_nandfs = {
73 	.bop_name	=	"buf_ops_nandfs",
74 	.bop_write	=	bufwrite,
75 	.bop_strategy	=	bufstrategy,
76 	.bop_sync	=	nandfs_bufsync,
77 	.bop_bdflush	=	nandfs_bdflush,
78 };
79 
80 int
nandfs_bufsync(struct bufobj * bo,int waitfor)81 nandfs_bufsync(struct bufobj *bo, int waitfor)
82 {
83 	struct vnode *vp;
84 	int error = 0;
85 
86 	vp = bo2vnode(bo);
87 
88 	ASSERT_VOP_LOCKED(vp, __func__);
89 	error = nandfs_sync_file(vp);
90 	if (error)
91 		nandfs_warning("%s: cannot flush buffers err:%d\n",
92 		    __func__, error);
93 
94 	return (error);
95 }
96 
97 void
nandfs_bdflush(bo,bp)98 nandfs_bdflush(bo, bp)
99 	struct bufobj *bo;
100 	struct buf *bp;
101 {
102 	struct vnode *vp;
103 	int error;
104 
105 	if (bo->bo_dirty.bv_cnt <= ((dirtybufthresh * 8) / 10))
106 		return;
107 
108 	vp = bp->b_vp;
109 	if (NANDFS_SYS_NODE(VTON(vp)->nn_ino))
110 		return;
111 
112 	if (NANDFS_IS_INDIRECT(bp))
113 		return;
114 
115 	error = nandfs_sync_file(vp);
116 	if (error)
117 		nandfs_warning("%s: cannot flush buffers err:%d\n",
118 		    __func__, error);
119 }
120 
121 int
nandfs_init(struct vfsconf * vfsp)122 nandfs_init(struct vfsconf *vfsp)
123 {
124 
125 	nandfs_node_zone = uma_zcreate("nandfs node zone",
126 	    sizeof(struct nandfs_node), NULL, NULL, NULL, NULL, 0, 0);
127 
128 	return (0);
129 }
130 
131 int
nandfs_uninit(struct vfsconf * vfsp)132 nandfs_uninit(struct vfsconf *vfsp)
133 {
134 
135 	uma_zdestroy(nandfs_node_zone);
136 	return (0);
137 }
138 
139 /* Basic calculators */
140 uint64_t
nandfs_get_segnum_of_block(struct nandfs_device * nandfsdev,nandfs_daddr_t blocknr)141 nandfs_get_segnum_of_block(struct nandfs_device *nandfsdev,
142     nandfs_daddr_t blocknr)
143 {
144 	uint64_t segnum, blks_per_seg;
145 
146 	MPASS(blocknr >= nandfsdev->nd_fsdata.f_first_data_block);
147 
148 	blks_per_seg = nandfsdev->nd_fsdata.f_blocks_per_segment;
149 
150 	segnum = blocknr / blks_per_seg;
151 	segnum -= nandfsdev->nd_fsdata.f_first_data_block / blks_per_seg;
152 
153 	DPRINTF(SYNC, ("%s: returning blocknr %jx -> segnum %jx\n", __func__,
154 	    blocknr, segnum));
155 
156 	return (segnum);
157 }
158 
159 void
nandfs_get_segment_range(struct nandfs_device * nandfsdev,uint64_t segnum,uint64_t * seg_start,uint64_t * seg_end)160 nandfs_get_segment_range(struct nandfs_device *nandfsdev, uint64_t segnum,
161     uint64_t *seg_start, uint64_t *seg_end)
162 {
163 	uint64_t blks_per_seg;
164 
165 	blks_per_seg = nandfsdev->nd_fsdata.f_blocks_per_segment;
166 	*seg_start = nandfsdev->nd_fsdata.f_first_data_block +
167 	    blks_per_seg * segnum;
168 	if (seg_end != NULL)
169 		*seg_end = *seg_start + blks_per_seg -1;
170 }
171 
nandfs_calc_mdt_consts(struct nandfs_device * nandfsdev,struct nandfs_mdt * mdt,int entry_size)172 void nandfs_calc_mdt_consts(struct nandfs_device *nandfsdev,
173     struct nandfs_mdt *mdt, int entry_size)
174 {
175 	uint32_t blocksize = nandfsdev->nd_blocksize;
176 
177 	mdt->entries_per_group = blocksize * 8;
178 	mdt->entries_per_block = blocksize / entry_size;
179 
180 	mdt->blocks_per_group =
181 	    (mdt->entries_per_group -1) / mdt->entries_per_block + 1 + 1;
182 	mdt->groups_per_desc_block =
183 	    blocksize / sizeof(struct nandfs_block_group_desc);
184 	mdt->blocks_per_desc_block =
185 	    mdt->groups_per_desc_block * mdt->blocks_per_group + 1;
186 }
187 
188 int
nandfs_dev_bread(struct nandfs_device * nandfsdev,nandfs_lbn_t blocknr,struct ucred * cred,int flags,struct buf ** bpp)189 nandfs_dev_bread(struct nandfs_device *nandfsdev, nandfs_lbn_t blocknr,
190     struct ucred *cred, int flags, struct buf **bpp)
191 {
192 	int blk2dev = nandfsdev->nd_blocksize / DEV_BSIZE;
193 	int error;
194 
195 	DPRINTF(BLOCK, ("%s: read from block %jx vp %p\n", __func__,
196 	    blocknr * blk2dev, nandfsdev->nd_devvp));
197 	error = bread(nandfsdev->nd_devvp, blocknr * blk2dev,
198 	    nandfsdev->nd_blocksize, NOCRED, bpp);
199 	if (error)
200 		nandfs_error("%s: cannot read from device - blk:%jx\n",
201 		    __func__, blocknr);
202 	return (error);
203 }
204 
205 /* Read on a node */
206 int
nandfs_bread(struct nandfs_node * node,nandfs_lbn_t blocknr,struct ucred * cred,int flags,struct buf ** bpp)207 nandfs_bread(struct nandfs_node *node, nandfs_lbn_t blocknr,
208     struct ucred *cred, int flags, struct buf **bpp)
209 {
210 	nandfs_daddr_t vblk;
211 	int error;
212 
213 	DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node),
214 	    blocknr));
215 
216 	error = bread(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize,
217 	    cred, bpp);
218 
219 	KASSERT(error == 0, ("%s: vp:%p lbn:%#jx err:%d\n", __func__,
220 	    NTOV(node), blocknr, error));
221 
222 	if (!nandfs_vblk_get(*bpp) &&
223 	    ((*bpp)->b_flags & B_CACHE) && node->nn_ino != NANDFS_DAT_INO) {
224 		nandfs_bmap_lookup(node, blocknr, &vblk);
225 		nandfs_vblk_set(*bpp, vblk);
226 	}
227 	return (error);
228 }
229 
230 int
nandfs_bread_meta(struct nandfs_node * node,nandfs_lbn_t blocknr,struct ucred * cred,int flags,struct buf ** bpp)231 nandfs_bread_meta(struct nandfs_node *node, nandfs_lbn_t blocknr,
232     struct ucred *cred, int flags, struct buf **bpp)
233 {
234 	nandfs_daddr_t vblk;
235 	int error;
236 
237 	DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node),
238 	    blocknr));
239 
240 	error = bread(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize,
241 	    cred, bpp);
242 
243 	KASSERT(error == 0, ("%s: vp:%p lbn:%#jx err:%d\n", __func__,
244 	    NTOV(node), blocknr, error));
245 
246 	if (!nandfs_vblk_get(*bpp) &&
247 	    ((*bpp)->b_flags & B_CACHE) && node->nn_ino != NANDFS_DAT_INO) {
248 		nandfs_bmap_lookup(node, blocknr, &vblk);
249 		nandfs_vblk_set(*bpp, vblk);
250 	}
251 
252 	return (error);
253 }
254 
255 int
nandfs_bdestroy(struct nandfs_node * node,nandfs_daddr_t vblk)256 nandfs_bdestroy(struct nandfs_node *node, nandfs_daddr_t vblk)
257 {
258 	int error;
259 
260 	if (!NANDFS_SYS_NODE(node->nn_ino))
261 		NANDFS_WRITEASSERT(node->nn_nandfsdev);
262 
263 	error = nandfs_vblock_end(node->nn_nandfsdev, vblk);
264 	if (error) {
265 		nandfs_error("%s: ending vblk: %jx failed\n",
266 		    __func__, (uintmax_t)vblk);
267 		return (error);
268 	}
269 	node->nn_inode.i_blocks--;
270 
271 	return (0);
272 }
273 
274 int
nandfs_bcreate(struct nandfs_node * node,nandfs_lbn_t blocknr,struct ucred * cred,int flags,struct buf ** bpp)275 nandfs_bcreate(struct nandfs_node *node, nandfs_lbn_t blocknr,
276     struct ucred *cred, int flags, struct buf **bpp)
277 {
278 	int error;
279 
280 	ASSERT_VOP_LOCKED(NTOV(node), __func__);
281 	if (!NANDFS_SYS_NODE(node->nn_ino))
282 		NANDFS_WRITEASSERT(node->nn_nandfsdev);
283 
284 	DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node),
285 	    blocknr));
286 
287 	*bpp = getblk(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize,
288 	    0, 0, 0);
289 
290 	KASSERT((*bpp), ("%s: vp:%p lbn:%#jx\n", __func__,
291 	    NTOV(node), blocknr));
292 
293 	if (*bpp) {
294 		vfs_bio_clrbuf(*bpp);
295 		(*bpp)->b_blkno = ~(0); /* To avoid VOP_BMAP in bdwrite */
296 		error = nandfs_bmap_insert_block(node, blocknr, *bpp);
297 		if (error) {
298 			nandfs_warning("%s: failed bmap insert node:%p"
299 			    " blk:%jx\n", __func__, node, blocknr);
300 			brelse(*bpp);
301 			return (error);
302 		}
303 		node->nn_inode.i_blocks++;
304 
305 		return (0);
306 	}
307 
308 	return (-1);
309 }
310 
311 int
nandfs_bcreate_meta(struct nandfs_node * node,nandfs_lbn_t blocknr,struct ucred * cred,int flags,struct buf ** bpp)312 nandfs_bcreate_meta(struct nandfs_node *node, nandfs_lbn_t blocknr,
313     struct ucred *cred, int flags, struct buf **bpp)
314 {
315 	struct nandfs_device *fsdev;
316 	nandfs_daddr_t vblk;
317 	int error;
318 
319 	ASSERT_VOP_LOCKED(NTOV(node), __func__);
320 	NANDFS_WRITEASSERT(node->nn_nandfsdev);
321 
322 	DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node),
323 	    blocknr));
324 
325 	fsdev = node->nn_nandfsdev;
326 
327 	*bpp = getblk(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize,
328 	    0, 0, 0);
329 
330 	KASSERT((*bpp), ("%s: vp:%p lbn:%#jx\n", __func__,
331 	    NTOV(node), blocknr));
332 
333 	memset((*bpp)->b_data, 0, fsdev->nd_blocksize);
334 
335 	vfs_bio_clrbuf(*bpp);
336 	(*bpp)->b_blkno = ~(0); /* To avoid VOP_BMAP in bdwrite */
337 
338 	nandfs_buf_set(*bpp, NANDFS_VBLK_ASSIGNED);
339 
340 	if (node->nn_ino != NANDFS_DAT_INO) {
341 		error = nandfs_vblock_alloc(fsdev, &vblk);
342 		if (error) {
343 			nandfs_buf_clear(*bpp, NANDFS_VBLK_ASSIGNED);
344 			brelse(*bpp);
345 			return (error);
346 		}
347 	} else
348 		vblk = fsdev->nd_fakevblk++;
349 
350 	nandfs_vblk_set(*bpp, vblk);
351 
352 	nandfs_bmap_insert_block(node, blocknr, *bpp);
353 	return (0);
354 }
355 
356 /* Translate index to a file block number and an entry */
357 void
nandfs_mdt_trans(struct nandfs_mdt * mdt,uint64_t index,nandfs_lbn_t * blocknr,uint32_t * entry_in_block)358 nandfs_mdt_trans(struct nandfs_mdt *mdt, uint64_t index,
359     nandfs_lbn_t *blocknr, uint32_t *entry_in_block)
360 {
361 	uint64_t blknr;
362 	uint64_t group, group_offset, blocknr_in_group;
363 	uint64_t desc_block, desc_offset;
364 
365 	/* Calculate our offset in the file */
366 	group = index / mdt->entries_per_group;
367 	group_offset = index % mdt->entries_per_group;
368 	desc_block = group / mdt->groups_per_desc_block;
369 	desc_offset = group % mdt->groups_per_desc_block;
370 	blocknr_in_group = group_offset / mdt->entries_per_block;
371 
372 	/* To descgroup offset */
373 	blknr = 1 + desc_block * mdt->blocks_per_desc_block;
374 
375 	/* To group offset */
376 	blknr += desc_offset * mdt->blocks_per_group;
377 
378 	/* To actual file block */
379 	blknr += 1 + blocknr_in_group;
380 
381 	*blocknr = blknr;
382 	*entry_in_block = group_offset % mdt->entries_per_block;
383 }
384 
385 void
nandfs_mdt_trans_blk(struct nandfs_mdt * mdt,uint64_t index,uint64_t * desc,uint64_t * bitmap,nandfs_lbn_t * blocknr,uint32_t * entry_in_block)386 nandfs_mdt_trans_blk(struct nandfs_mdt *mdt, uint64_t index,
387     uint64_t *desc, uint64_t *bitmap, nandfs_lbn_t *blocknr,
388     uint32_t *entry_in_block)
389 {
390 	uint64_t blknr;
391 	uint64_t group, group_offset, blocknr_in_group;
392 	uint64_t desc_block, desc_offset;
393 
394 	/* Calculate our offset in the file */
395 	group = index / mdt->entries_per_group;
396 	group_offset = index % mdt->entries_per_group;
397 	desc_block = group / mdt->groups_per_desc_block;
398 	desc_offset = group % mdt->groups_per_desc_block;
399 	blocknr_in_group = group_offset / mdt->entries_per_block;
400 
401 	/* To descgroup offset */
402 	*desc = desc_block * mdt->blocks_per_desc_block;
403 	blknr = 1 + desc_block * mdt->blocks_per_desc_block;
404 
405 	/* To group offset */
406 	blknr += desc_offset * mdt->blocks_per_group;
407 	*bitmap = blknr;
408 
409 	/* To actual file block */
410 	blknr += 1 + blocknr_in_group;
411 
412 	*blocknr = blknr;
413 	*entry_in_block = group_offset % mdt->entries_per_block;
414 
415 	DPRINTF(ALLOC,
416 	    ("%s: desc_buf: %jx bitmap_buf: %jx entry_buf: %jx entry: %x\n",
417 	    __func__, (uintmax_t)*desc, (uintmax_t)*bitmap,
418 	    (uintmax_t)*blocknr, *entry_in_block));
419 }
420 
421 int
nandfs_vtop(struct nandfs_node * node,nandfs_daddr_t vblocknr,nandfs_daddr_t * pblocknr)422 nandfs_vtop(struct nandfs_node *node, nandfs_daddr_t vblocknr,
423     nandfs_daddr_t *pblocknr)
424 {
425 	struct nandfs_node *dat_node;
426 	struct nandfs_dat_entry *entry;
427 	struct buf *bp;
428 	nandfs_lbn_t ldatblknr;
429 	uint32_t entry_in_block;
430 	int locked, error;
431 
432 	if (node->nn_ino == NANDFS_DAT_INO || node->nn_ino == NANDFS_GC_INO) {
433 		*pblocknr = vblocknr;
434 		return (0);
435 	}
436 
437 	/* only translate valid vblocknrs */
438 	if (vblocknr == 0)
439 		return (0);
440 
441 	dat_node = node->nn_nandfsdev->nd_dat_node;
442 	nandfs_mdt_trans(&node->nn_nandfsdev->nd_dat_mdt, vblocknr, &ldatblknr,
443 	    &entry_in_block);
444 
445 	locked = NANDFS_VOP_ISLOCKED(NTOV(dat_node));
446 	if (!locked)
447 		VOP_LOCK(NTOV(dat_node), LK_SHARED);
448 	error = nandfs_bread(dat_node, ldatblknr, NOCRED, 0, &bp);
449 	if (error) {
450 		DPRINTF(TRANSLATE, ("vtop: can't read in DAT block %#jx!\n",
451 		    (uintmax_t)ldatblknr));
452 		brelse(bp);
453 		VOP_UNLOCK(NTOV(dat_node), 0);
454 		return (error);
455 	}
456 
457 	/* Get our translation */
458 	entry = ((struct nandfs_dat_entry *) bp->b_data) + entry_in_block;
459 	DPRINTF(TRANSLATE, ("\tentry %p data %p entry_in_block %x\n",
460 	    entry, bp->b_data, entry_in_block))
461 	DPRINTF(TRANSLATE, ("\tvblk %#jx -> %#jx for cp [%#jx-%#jx]\n",
462 	    (uintmax_t)vblocknr, (uintmax_t)entry->de_blocknr,
463 	    (uintmax_t)entry->de_start, (uintmax_t)entry->de_end));
464 
465 	*pblocknr = entry->de_blocknr;
466 	brelse(bp);
467 	if (!locked)
468 		VOP_UNLOCK(NTOV(dat_node), 0);
469 
470 	MPASS(*pblocknr >= node->nn_nandfsdev->nd_fsdata.f_first_data_block ||
471 	    *pblocknr == 0);
472 
473 	return (0);
474 }
475 
476 int
nandfs_segsum_valid(struct nandfs_segment_summary * segsum)477 nandfs_segsum_valid(struct nandfs_segment_summary *segsum)
478 {
479 
480 	return (segsum->ss_magic == NANDFS_SEGSUM_MAGIC);
481 }
482 
483 int
nandfs_load_segsum(struct nandfs_device * fsdev,nandfs_daddr_t blocknr,struct nandfs_segment_summary * segsum)484 nandfs_load_segsum(struct nandfs_device *fsdev, nandfs_daddr_t blocknr,
485     struct nandfs_segment_summary *segsum)
486 {
487 	struct buf *bp;
488 	int error;
489 
490 	DPRINTF(VOLUMES, ("nandfs: try segsum at block %jx\n",
491 	    (uintmax_t)blocknr));
492 
493 	error = nandfs_dev_bread(fsdev, blocknr, NOCRED, 0, &bp);
494 	if (error)
495 		return (error);
496 
497 	memcpy(segsum, bp->b_data, sizeof(struct nandfs_segment_summary));
498 	brelse(bp);
499 
500 	if (!nandfs_segsum_valid(segsum)) {
501 		DPRINTF(VOLUMES, ("%s: bad magic pseg:%jx\n", __func__,
502 		    blocknr));
503 		return (EINVAL);
504 	}
505 
506 	return (error);
507 }
508 
509 static int
nandfs_load_super_root(struct nandfs_device * nandfsdev,struct nandfs_segment_summary * segsum,uint64_t pseg)510 nandfs_load_super_root(struct nandfs_device *nandfsdev,
511     struct nandfs_segment_summary *segsum, uint64_t pseg)
512 {
513 	struct nandfs_super_root super_root;
514 	struct buf *bp;
515 	uint64_t blocknr;
516 	uint32_t super_root_crc, comp_crc;
517 	int off, error;
518 
519 	/* Check if there is a superroot */
520 	if ((segsum->ss_flags & NANDFS_SS_SR) == 0) {
521 		DPRINTF(VOLUMES, ("%s: no super root in pseg:%jx\n", __func__,
522 		    pseg));
523 		return (ENOENT);
524 	}
525 
526 	/* Get our super root, located at the end of the pseg */
527 	blocknr = pseg + segsum->ss_nblocks - 1;
528 	DPRINTF(VOLUMES, ("%s: try at %#jx\n", __func__, (uintmax_t)blocknr));
529 
530 	error = nandfs_dev_bread(nandfsdev, blocknr, NOCRED, 0, &bp);
531 	if (error)
532 		return (error);
533 
534 	memcpy(&super_root, bp->b_data, sizeof(struct nandfs_super_root));
535 	brelse(bp);
536 
537 	/* Check super root CRC */
538 	super_root_crc = super_root.sr_sum;
539 	off = sizeof(super_root.sr_sum);
540 	comp_crc = crc32((uint8_t *)&super_root + off,
541 	    NANDFS_SR_BYTES - off);
542 
543 	if (super_root_crc != comp_crc) {
544 		DPRINTF(VOLUMES, ("%s: invalid crc:%#x [expect:%#x]\n",
545 		    __func__, super_root_crc, comp_crc));
546 		return (EINVAL);
547 	}
548 
549 	nandfsdev->nd_super_root = super_root;
550 	DPRINTF(VOLUMES, ("%s: got valid superroot\n", __func__));
551 
552 	return (0);
553 }
554 
555 /*
556  * Search for the last super root recorded.
557  */
558 int
nandfs_search_super_root(struct nandfs_device * nandfsdev)559 nandfs_search_super_root(struct nandfs_device *nandfsdev)
560 {
561 	struct nandfs_super_block *super;
562 	struct nandfs_segment_summary segsum;
563 	uint64_t seg_start, seg_end, cno, seq, create, pseg;
564 	uint64_t segnum;
565 	int error, found;
566 
567 	error = found = 0;
568 
569 	/* Search for last super root */
570 	pseg = nandfsdev->nd_super.s_last_pseg;
571 	segnum = nandfs_get_segnum_of_block(nandfsdev, pseg);
572 
573 	cno = nandfsdev->nd_super.s_last_cno;
574 	create = seq = 0;
575 	DPRINTF(VOLUMES, ("%s: start in pseg %#jx\n", __func__,
576 	    (uintmax_t)pseg));
577 
578 	for (;;) {
579 		error = nandfs_load_segsum(nandfsdev, pseg, &segsum);
580 		if (error)
581 			break;
582 
583 		if (segsum.ss_seq < seq || segsum.ss_create < create)
584 			break;
585 
586 		/* Try to load super root */
587 		if (segsum.ss_flags & NANDFS_SS_SR) {
588 			error = nandfs_load_super_root(nandfsdev, &segsum, pseg);
589 			if (error)
590 				break;	/* confused */
591 			found = 1;
592 
593 			super = &nandfsdev->nd_super;
594 			nandfsdev->nd_last_segsum = segsum;
595 			super->s_last_pseg = pseg;
596 			super->s_last_cno = cno++;
597 			super->s_last_seq = segsum.ss_seq;
598 			super->s_state = NANDFS_VALID_FS;
599 			seq = segsum.ss_seq;
600 			create = segsum.ss_create;
601 		} else {
602 			seq = segsum.ss_seq;
603 			create = segsum.ss_create;
604 		}
605 
606 		/* Calculate next partial segment location */
607 		pseg += segsum.ss_nblocks;
608 		DPRINTF(VOLUMES, ("%s: next partial seg is %jx\n", __func__,
609 		    (uintmax_t)pseg));
610 
611 		/* Did we reach the end of the segment? if so, go to the next */
612 		nandfs_get_segment_range(nandfsdev, segnum, &seg_start,
613 		    &seg_end);
614 		if (pseg >= seg_end) {
615 			pseg = segsum.ss_next;
616 			DPRINTF(VOLUMES,
617 			    (" partial seg oor next is %jx[%jx - %jx]\n",
618 			    (uintmax_t)pseg, (uintmax_t)seg_start,
619 			    (uintmax_t)seg_end));
620 		}
621 		segnum = nandfs_get_segnum_of_block(nandfsdev, pseg);
622 	}
623 
624 	if (error && !found)
625 		return (error);
626 
627 	return (0);
628 }
629 
630 int
nandfs_get_node_raw(struct nandfs_device * nandfsdev,struct nandfsmount * nmp,uint64_t ino,struct nandfs_inode * inode,struct nandfs_node ** nodep)631 nandfs_get_node_raw(struct nandfs_device *nandfsdev, struct nandfsmount *nmp,
632     uint64_t ino, struct nandfs_inode *inode, struct nandfs_node **nodep)
633 {
634 	struct nandfs_node *node;
635 	struct vnode *nvp;
636 	struct mount *mp;
637 	int error;
638 
639 	*nodep = NULL;
640 
641 	/* Associate with mountpoint if present */
642 	if (nmp) {
643 		mp = nmp->nm_vfs_mountp;
644 		error = getnewvnode("nandfs", mp, &nandfs_vnodeops, &nvp);
645 		if (error)
646 			return (error);
647 	} else {
648 		mp = NULL;
649 		error = getnewvnode("snandfs", mp, &nandfs_system_vnodeops,
650 		    &nvp);
651 		if (error)
652 			return (error);
653 	}
654 
655 	if (mp)
656 		NANDFS_WRITELOCK(nandfsdev);
657 
658 	DPRINTF(IFILE, ("%s: ino: %#jx -> vp: %p\n",
659 	    __func__, (uintmax_t)ino, nvp));
660 	/* Lock node */
661 	lockmgr(nvp->v_vnlock, LK_EXCLUSIVE, NULL);
662 
663 	if (mp) {
664 		error = insmntque(nvp, mp);
665 		if (error != 0) {
666 			*nodep = NULL;
667 			return (error);
668 		}
669 	}
670 
671 	node = uma_zalloc(nandfs_node_zone, M_WAITOK | M_ZERO);
672 
673 	/* Crosslink */
674 	node->nn_vnode = nvp;
675 	nvp->v_bufobj.bo_ops = &buf_ops_nandfs;
676 	node->nn_nmp = nmp;
677 	node->nn_nandfsdev = nandfsdev;
678 	nvp->v_data = node;
679 
680 	/* Initiase NANDFS node */
681 	node->nn_ino = ino;
682 	if (inode != NULL)
683 		node->nn_inode = *inode;
684 
685 	nandfs_vinit(nvp, ino);
686 
687 	/* Return node */
688 	*nodep = node;
689 	DPRINTF(IFILE, ("%s: ino:%#jx vp:%p node:%p\n",
690 	    __func__, (uintmax_t)ino, nvp, *nodep));
691 
692 	return (0);
693 }
694 
695 int
nandfs_get_node(struct nandfsmount * nmp,uint64_t ino,struct nandfs_node ** nodep)696 nandfs_get_node(struct nandfsmount *nmp, uint64_t ino,
697     struct nandfs_node **nodep)
698 {
699 	struct nandfs_device *nandfsdev;
700 	struct nandfs_inode inode, *entry;
701 	struct vnode *nvp, *vpp;
702 	struct thread *td;
703 	struct buf *bp;
704 	uint64_t ivblocknr;
705 	uint32_t entry_in_block;
706 	int error;
707 
708 	/* Look up node in hash table */
709 	td = curthread;
710 	*nodep = NULL;
711 
712 	if ((ino < NANDFS_ATIME_INO) && (ino != NANDFS_ROOT_INO)) {
713 		printf("nandfs_get_node: system ino %"PRIu64" not in mount "
714 		    "point!\n", ino);
715 		return (ENOENT);
716 	}
717 
718 	error = vfs_hash_get(nmp->nm_vfs_mountp, ino, LK_EXCLUSIVE, td, &nvp,
719 	    NULL, NULL);
720 	if (error)
721 		return (error);
722 
723 	if (nvp != NULL) {
724 		*nodep = (struct nandfs_node *)nvp->v_data;
725 		return (0);
726 	}
727 
728 	/* Look up inode structure in mountpoints ifile */
729 	nandfsdev = nmp->nm_nandfsdev;
730 	nandfs_mdt_trans(&nandfsdev->nd_ifile_mdt, ino, &ivblocknr,
731 	    &entry_in_block);
732 
733 	VOP_LOCK(NTOV(nmp->nm_ifile_node), LK_SHARED);
734 	error = nandfs_bread(nmp->nm_ifile_node, ivblocknr, NOCRED, 0, &bp);
735 	if (error) {
736 		brelse(bp);
737 		VOP_UNLOCK(NTOV(nmp->nm_ifile_node), 0);
738 		return (ENOENT);
739 	}
740 
741 	/* Get inode entry */
742 	entry = (struct nandfs_inode *) bp->b_data + entry_in_block;
743 	memcpy(&inode, entry, sizeof(struct nandfs_inode));
744 	brelse(bp);
745 	VOP_UNLOCK(NTOV(nmp->nm_ifile_node), 0);
746 
747 	/* Get node */
748 	error = nandfs_get_node_raw(nmp->nm_nandfsdev, nmp, ino, &inode, nodep);
749 	if (error) {
750 		*nodep = NULL;
751 		return (error);
752 	}
753 
754 	nvp = (*nodep)->nn_vnode;
755 	error = vfs_hash_insert(nvp, ino, 0, td, &vpp, NULL, NULL);
756 	if (error) {
757 		*nodep = NULL;
758 		return (error);
759 	}
760 
761 	return (error);
762 }
763 
764 void
nandfs_dispose_node(struct nandfs_node ** nodep)765 nandfs_dispose_node(struct nandfs_node **nodep)
766 {
767 	struct nandfs_node *node;
768 	struct vnode *vp;
769 
770 	/* Protect against rogue values */
771 	node = *nodep;
772 	if (!node) {
773 		return;
774 	}
775 	DPRINTF(NODE, ("nandfs_dispose_node: %p\n", *nodep));
776 
777 	vp = NTOV(node);
778 	vp->v_data = NULL;
779 
780 	/* Free our associated memory */
781 	uma_zfree(nandfs_node_zone, node);
782 
783 	*nodep = NULL;
784 }
785 
786 int
nandfs_lookup_name_in_dir(struct vnode * dvp,const char * name,int namelen,uint64_t * ino,int * found,uint64_t * off)787 nandfs_lookup_name_in_dir(struct vnode *dvp, const char *name, int namelen,
788     uint64_t *ino, int *found, uint64_t *off)
789 {
790 	struct nandfs_node *dir_node = VTON(dvp);
791 	struct nandfs_dir_entry	*ndirent;
792 	struct buf *bp;
793 	uint64_t file_size, diroffset, blkoff;
794 	uint64_t blocknr;
795 	uint32_t blocksize = dir_node->nn_nandfsdev->nd_blocksize;
796 	uint8_t *pos, name_len;
797 	int error;
798 
799 	*found = 0;
800 
801 	DPRINTF(VNCALL, ("%s: %s file\n", __func__, name));
802 	if (dvp->v_type != VDIR) {
803 		return (ENOTDIR);
804 	}
805 
806 	/* Get directory filesize */
807 	file_size = dir_node->nn_inode.i_size;
808 
809 	/* Walk the directory */
810 	diroffset = 0;
811 	blocknr = 0;
812 	blkoff = 0;
813 	error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp);
814 	if (error) {
815 		brelse(bp);
816 		return (EIO);
817 	}
818 
819 	while (diroffset < file_size) {
820 		if (blkoff >= blocksize) {
821 			blkoff = 0; blocknr++;
822 			brelse(bp);
823 			error = nandfs_bread(dir_node, blocknr, NOCRED, 0,
824 			    &bp);
825 			if (error) {
826 				brelse(bp);
827 				return (EIO);
828 			}
829 		}
830 
831 		/* Read in one dirent */
832 		pos = (uint8_t *) bp->b_data + blkoff;
833 		ndirent = (struct nandfs_dir_entry *) pos;
834 		name_len = ndirent->name_len;
835 
836 		if ((name_len == namelen) &&
837 		    (strncmp(name, ndirent->name, name_len) == 0) &&
838 		    (ndirent->inode != 0)) {
839 			*ino = ndirent->inode;
840 			*off = diroffset;
841 			DPRINTF(LOOKUP, ("found `%.*s` with ino %"PRIx64"\n",
842 			    name_len, ndirent->name, *ino));
843 			*found = 1;
844 			break;
845 		}
846 
847 		/* Advance */
848 		diroffset += ndirent->rec_len;
849 		blkoff += ndirent->rec_len;
850 	}
851 	brelse(bp);
852 
853 	return (error);
854 }
855 
856 int
nandfs_get_fsinfo(struct nandfsmount * nmp,struct nandfs_fsinfo * fsinfo)857 nandfs_get_fsinfo(struct nandfsmount *nmp, struct nandfs_fsinfo *fsinfo)
858 {
859 	struct nandfs_device *fsdev;
860 
861 	fsdev = nmp->nm_nandfsdev;
862 
863 	memcpy(&fsinfo->fs_fsdata, &fsdev->nd_fsdata, sizeof(fsdev->nd_fsdata));
864 	memcpy(&fsinfo->fs_super, &fsdev->nd_super, sizeof(fsdev->nd_super));
865 	snprintf(fsinfo->fs_dev, sizeof(fsinfo->fs_dev),
866 	    "%s", nmp->nm_vfs_mountp->mnt_stat.f_mntfromname);
867 
868 	return (0);
869 }
870 
871 void
nandfs_inode_init(struct nandfs_inode * inode,uint16_t mode)872 nandfs_inode_init(struct nandfs_inode *inode, uint16_t mode)
873 {
874 	struct timespec ts;
875 
876 	vfs_timestamp(&ts);
877 
878 	inode->i_blocks = 0;
879 	inode->i_size = 0;
880 	inode->i_ctime = ts.tv_sec;
881 	inode->i_ctime_nsec = ts.tv_nsec;
882 	inode->i_mtime = ts.tv_sec;
883 	inode->i_mtime_nsec = ts.tv_nsec;
884 	inode->i_mode = mode;
885 	inode->i_links_count = 1;
886 	if (S_ISDIR(mode))
887 		inode->i_links_count = 2;
888 	inode->i_flags = 0;
889 
890 	inode->i_special = 0;
891 	memset(inode->i_db, 0, sizeof(inode->i_db));
892 	memset(inode->i_ib, 0, sizeof(inode->i_ib));
893 }
894 
895 void
nandfs_inode_destroy(struct nandfs_inode * inode)896 nandfs_inode_destroy(struct nandfs_inode *inode)
897 {
898 
899 	MPASS(inode->i_blocks == 0);
900 	bzero(inode, sizeof(*inode));
901 }
902 
903 int
nandfs_fs_full(struct nandfs_device * nffsdev)904 nandfs_fs_full(struct nandfs_device *nffsdev)
905 {
906 	uint64_t space, bps;
907 
908 	bps = nffsdev->nd_fsdata.f_blocks_per_segment;
909 	space = (nffsdev->nd_clean_segs - 1) * bps;
910 
911 	DPRINTF(BUF, ("%s: bufs:%jx space:%jx\n", __func__,
912 	    (uintmax_t)nffsdev->nd_dirty_bufs, (uintmax_t)space));
913 
914 	if (nffsdev->nd_dirty_bufs + (nffsdev->nd_segs_reserved * bps) >= space)
915 		return (1);
916 
917 	return (0);
918 }
919 
920 static int
_nandfs_dirty_buf(struct buf * bp,int dirty_meta,int force)921 _nandfs_dirty_buf(struct buf *bp, int dirty_meta, int force)
922 {
923 	struct nandfs_device *nffsdev;
924 	struct nandfs_node *node;
925 	uint64_t ino, bps;
926 
927 	if (NANDFS_ISGATHERED(bp)) {
928 		bqrelse(bp);
929 		return (0);
930 	}
931 	if ((bp->b_flags & (B_MANAGED | B_DELWRI)) == (B_MANAGED | B_DELWRI)) {
932 		bqrelse(bp);
933 		return (0);
934 	}
935 
936 	node = VTON(bp->b_vp);
937 	nffsdev = node->nn_nandfsdev;
938 	DPRINTF(BUF, ("%s: buf:%p\n", __func__, bp));
939 	ino = node->nn_ino;
940 
941 	if (nandfs_fs_full(nffsdev) && !NANDFS_SYS_NODE(ino) && !force) {
942 		brelse(bp);
943 		return (ENOSPC);
944 	}
945 
946 	bp->b_flags |= B_MANAGED;
947 	bdwrite(bp);
948 
949 	nandfs_dirty_bufs_increment(nffsdev);
950 
951 	KASSERT((bp->b_vp), ("vp missing for bp"));
952 	KASSERT((nandfs_vblk_get(bp) || ino == NANDFS_DAT_INO),
953 	    ("bp vblk is 0"));
954 
955 	/*
956 	 * To maintain consistency of FS we need to force making
957 	 * meta buffers dirty, even if free space is low.
958 	 */
959 	if (dirty_meta && ino != NANDFS_GC_INO)
960 		nandfs_bmap_dirty_blocks(VTON(bp->b_vp), bp, 1);
961 
962 	bps = nffsdev->nd_fsdata.f_blocks_per_segment;
963 
964 	if (nffsdev->nd_dirty_bufs >= (bps * nandfs_max_dirty_segs)) {
965 		mtx_lock(&nffsdev->nd_sync_mtx);
966 		if (nffsdev->nd_syncing == 0) {
967 			DPRINTF(SYNC, ("%s: wakeup gc\n", __func__));
968 			nffsdev->nd_syncing = 1;
969 			wakeup(&nffsdev->nd_syncing);
970 		}
971 		mtx_unlock(&nffsdev->nd_sync_mtx);
972 	}
973 
974 	return (0);
975 }
976 
977 int
nandfs_dirty_buf(struct buf * bp,int force)978 nandfs_dirty_buf(struct buf *bp, int force)
979 {
980 
981 	return (_nandfs_dirty_buf(bp, 1, force));
982 }
983 
984 int
nandfs_dirty_buf_meta(struct buf * bp,int force)985 nandfs_dirty_buf_meta(struct buf *bp, int force)
986 {
987 
988 	return (_nandfs_dirty_buf(bp, 0, force));
989 }
990 
991 void
nandfs_undirty_buf_fsdev(struct nandfs_device * nffsdev,struct buf * bp)992 nandfs_undirty_buf_fsdev(struct nandfs_device *nffsdev, struct buf *bp)
993 {
994 
995 	BUF_ASSERT_HELD(bp);
996 
997 	if (bp->b_flags & B_DELWRI) {
998 		bp->b_flags &= ~(B_DELWRI|B_MANAGED);
999 		nandfs_dirty_bufs_decrement(nffsdev);
1000 	}
1001 	/*
1002 	 * Since it is now being written, we can clear its deferred write flag.
1003 	 */
1004 	bp->b_flags &= ~B_DEFERRED;
1005 
1006 	brelse(bp);
1007 }
1008 
1009 void
nandfs_undirty_buf(struct buf * bp)1010 nandfs_undirty_buf(struct buf *bp)
1011 {
1012 	struct nandfs_node *node;
1013 
1014 	node = VTON(bp->b_vp);
1015 
1016 	nandfs_undirty_buf_fsdev(node->nn_nandfsdev, bp);
1017 }
1018 
1019 void
nandfs_vblk_set(struct buf * bp,nandfs_daddr_t blocknr)1020 nandfs_vblk_set(struct buf *bp, nandfs_daddr_t blocknr)
1021 {
1022 
1023 	nandfs_daddr_t *vblk = (nandfs_daddr_t *)(&bp->b_fsprivate1);
1024 	*vblk = blocknr;
1025 }
1026 
1027 nandfs_daddr_t
nandfs_vblk_get(struct buf * bp)1028 nandfs_vblk_get(struct buf *bp)
1029 {
1030 
1031 	nandfs_daddr_t *vblk = (nandfs_daddr_t *)(&bp->b_fsprivate1);
1032 	return (*vblk);
1033 }
1034 
1035 void
nandfs_buf_set(struct buf * bp,uint32_t bits)1036 nandfs_buf_set(struct buf *bp, uint32_t bits)
1037 {
1038 	uintptr_t flags;
1039 
1040 	flags = (uintptr_t)bp->b_fsprivate3;
1041 	flags |= (uintptr_t)bits;
1042 	bp->b_fsprivate3 = (void *)flags;
1043 }
1044 
1045 void
nandfs_buf_clear(struct buf * bp,uint32_t bits)1046 nandfs_buf_clear(struct buf *bp, uint32_t bits)
1047 {
1048 	uintptr_t flags;
1049 
1050 	flags = (uintptr_t)bp->b_fsprivate3;
1051 	flags &= ~(uintptr_t)bits;
1052 	bp->b_fsprivate3 = (void *)flags;
1053 }
1054 
1055 int
nandfs_buf_check(struct buf * bp,uint32_t bits)1056 nandfs_buf_check(struct buf *bp, uint32_t bits)
1057 {
1058 	uintptr_t flags;
1059 
1060 	flags = (uintptr_t)bp->b_fsprivate3;
1061 	if (flags & bits)
1062 		return (1);
1063 	return (0);
1064 }
1065 
1066 int
nandfs_erase(struct nandfs_device * fsdev,off_t offset,size_t size)1067 nandfs_erase(struct nandfs_device *fsdev, off_t offset, size_t size)
1068 {
1069 	DPRINTF(BLOCK, ("%s: performing erase at offset %jx size %zx\n",
1070 	    __func__, offset, size));
1071 
1072 	MPASS(size % fsdev->nd_erasesize == 0);
1073 
1074 	return (g_delete_data(fsdev->nd_gconsumer, offset, size));
1075 }
1076 
1077 int
nandfs_vop_islocked(struct vnode * vp)1078 nandfs_vop_islocked(struct vnode *vp)
1079 {
1080 	int islocked;
1081 
1082 	islocked = VOP_ISLOCKED(vp);
1083 	return (islocked == LK_EXCLUSIVE || islocked == LK_SHARED);
1084 }
1085 
1086 nandfs_daddr_t
nandfs_block_to_dblock(struct nandfs_device * fsdev,nandfs_lbn_t block)1087 nandfs_block_to_dblock(struct nandfs_device *fsdev, nandfs_lbn_t block)
1088 {
1089 
1090 	return (btodb(block * fsdev->nd_blocksize));
1091 }
1092