1235537Sgber/*-
2235537Sgber * Copyright (c) 2010-2012 Semihalf
3235537Sgber * Copyright (c) 2008, 2009 Reinoud Zandijk
4235537Sgber * All rights reserved.
5235537Sgber *
6235537Sgber * Redistribution and use in source and binary forms, with or without
7235537Sgber * modification, are permitted provided that the following conditions
8235537Sgber * are met:
9235537Sgber * 1. Redistributions of source code must retain the above copyright
10235537Sgber *    notice, this list of conditions and the following disclaimer.
11235537Sgber * 2. Redistributions in binary form must reproduce the above copyright
12235537Sgber *    notice, this list of conditions and the following disclaimer in the
13235537Sgber *    documentation and/or other materials provided with the distribution.
14235537Sgber *
15235537Sgber * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16235537Sgber * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17235537Sgber * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18235537Sgber * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19235537Sgber * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20235537Sgber * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21235537Sgber * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22235537Sgber * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23235537Sgber * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24235537Sgber * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25235537Sgber *
26235537Sgber * From: NetBSD: nilfs_subr.c,v 1.4 2009/07/29 17:06:57 reinoud
27235537Sgber */
28235537Sgber
29235537Sgber#include <sys/cdefs.h>
30235537Sgber__FBSDID("$FreeBSD$");
31235537Sgber
32235537Sgber#include <sys/param.h>
33235537Sgber#include <sys/systm.h>
34235537Sgber#include <sys/namei.h>
35235537Sgber#include <sys/resourcevar.h>
36235537Sgber#include <sys/kernel.h>
37235537Sgber#include <sys/file.h>
38235537Sgber#include <sys/stat.h>
39235537Sgber#include <sys/buf.h>
40235537Sgber#include <sys/bio.h>
41235537Sgber#include <sys/proc.h>
42235537Sgber#include <sys/mount.h>
43235537Sgber#include <sys/vnode.h>
44235537Sgber#include <sys/signalvar.h>
45235537Sgber#include <sys/malloc.h>
46235537Sgber#include <sys/dirent.h>
47235537Sgber#include <sys/lockf.h>
48235537Sgber#include <sys/libkern.h>
49235537Sgber
50235537Sgber#include <geom/geom.h>
51235537Sgber#include <geom/geom_vfs.h>
52235537Sgber
53235537Sgber#include <vm/vm.h>
54235537Sgber#include <vm/vm_extern.h>
55235537Sgber
56235537Sgber#include <machine/_inttypes.h>
57235537Sgber#include "nandfs_mount.h"
58235537Sgber#include "nandfs.h"
59235537Sgber#include "nandfs_subr.h"
60235537Sgber
61241844SeadlerMALLOC_DEFINE(M_NANDFSMNT, "nandfs_mount", "NANDFS mount");
62235537SgberMALLOC_DEFINE(M_NANDFSTEMP, "nandfs_tmt", "NANDFS tmp");
63235537Sgber
64235537Sgberuma_zone_t nandfs_node_zone;
65235537Sgber
66235537Sgbervoid nandfs_bdflush(struct bufobj *bo, struct buf *bp);
67235537Sgberint nandfs_bufsync(struct bufobj *bo, int waitfor);
68235537Sgber
69235537Sgberstruct buf_ops buf_ops_nandfs = {
70235537Sgber	.bop_name	=	"buf_ops_nandfs",
71235537Sgber	.bop_write	=	bufwrite,
72235537Sgber	.bop_strategy	=	bufstrategy,
73235537Sgber	.bop_sync	=	nandfs_bufsync,
74235537Sgber	.bop_bdflush	=	nandfs_bdflush,
75235537Sgber};
76235537Sgber
77235537Sgberint
78235537Sgbernandfs_bufsync(struct bufobj *bo, int waitfor)
79235537Sgber{
80235537Sgber	struct vnode *vp;
81235537Sgber	int error = 0;
82235537Sgber
83235537Sgber	vp = bo->__bo_vnode;
84235537Sgber
85235537Sgber	ASSERT_VOP_LOCKED(vp, __func__);
86235537Sgber	error = nandfs_sync_file(vp);
87235537Sgber	if (error)
88235537Sgber		nandfs_warning("%s: cannot flush buffers err:%d\n",
89235537Sgber		    __func__, error);
90235537Sgber
91235537Sgber	return (error);
92235537Sgber}
93235537Sgber
94235537Sgbervoid
95235537Sgbernandfs_bdflush(bo, bp)
96235537Sgber	struct bufobj *bo;
97235537Sgber	struct buf *bp;
98235537Sgber{
99235537Sgber	struct vnode *vp;
100235537Sgber	int error;
101235537Sgber
102235537Sgber	if (bo->bo_dirty.bv_cnt <= ((dirtybufthresh * 8) / 10))
103235537Sgber		return;
104235537Sgber
105235537Sgber	vp = bp->b_vp;
106235537Sgber	if (NANDFS_SYS_NODE(VTON(vp)->nn_ino))
107235537Sgber		return;
108235537Sgber
109235537Sgber	if (NANDFS_IS_INDIRECT(bp))
110235537Sgber		return;
111235537Sgber
112235537Sgber	error = nandfs_sync_file(vp);
113235537Sgber	if (error)
114235537Sgber		nandfs_warning("%s: cannot flush buffers err:%d\n",
115235537Sgber		    __func__, error);
116235537Sgber}
117235537Sgber
118235537Sgberint
119235537Sgbernandfs_init(struct vfsconf *vfsp)
120235537Sgber{
121235537Sgber
122235537Sgber	nandfs_node_zone = uma_zcreate("nandfs node zone",
123235537Sgber	    sizeof(struct nandfs_node), NULL, NULL, NULL, NULL, 0, 0);
124235537Sgber
125235537Sgber	return (0);
126235537Sgber}
127235537Sgber
128235537Sgberint
129235537Sgbernandfs_uninit(struct vfsconf *vfsp)
130235537Sgber{
131235537Sgber
132235537Sgber	uma_zdestroy(nandfs_node_zone);
133235537Sgber	return (0);
134235537Sgber}
135235537Sgber
136235537Sgber/* Basic calculators */
137235537Sgberuint64_t
138235537Sgbernandfs_get_segnum_of_block(struct nandfs_device *nandfsdev,
139235537Sgber    nandfs_daddr_t blocknr)
140235537Sgber{
141235537Sgber	uint64_t segnum, blks_per_seg;
142235537Sgber
143235537Sgber	MPASS(blocknr >= nandfsdev->nd_fsdata.f_first_data_block);
144235537Sgber
145235537Sgber	blks_per_seg = nandfsdev->nd_fsdata.f_blocks_per_segment;
146235537Sgber
147235537Sgber	segnum = blocknr / blks_per_seg;
148235537Sgber	segnum -= nandfsdev->nd_fsdata.f_first_data_block / blks_per_seg;
149235537Sgber
150235537Sgber	DPRINTF(SYNC, ("%s: returning blocknr %jx -> segnum %jx\n", __func__,
151235537Sgber	    blocknr, segnum));
152235537Sgber
153235537Sgber	return (segnum);
154235537Sgber}
155235537Sgber
156235537Sgbervoid
157235537Sgbernandfs_get_segment_range(struct nandfs_device *nandfsdev, uint64_t segnum,
158235537Sgber    uint64_t *seg_start, uint64_t *seg_end)
159235537Sgber{
160235537Sgber	uint64_t blks_per_seg;
161235537Sgber
162235537Sgber	blks_per_seg = nandfsdev->nd_fsdata.f_blocks_per_segment;
163235537Sgber	*seg_start = nandfsdev->nd_fsdata.f_first_data_block +
164235537Sgber	    blks_per_seg * segnum;
165235537Sgber	if (seg_end != NULL)
166235537Sgber		*seg_end = *seg_start + blks_per_seg -1;
167235537Sgber}
168235537Sgber
169235537Sgbervoid nandfs_calc_mdt_consts(struct nandfs_device *nandfsdev,
170235537Sgber    struct nandfs_mdt *mdt, int entry_size)
171235537Sgber{
172235537Sgber	uint32_t blocksize = nandfsdev->nd_blocksize;
173235537Sgber
174235537Sgber	mdt->entries_per_group = blocksize * 8;
175235537Sgber	mdt->entries_per_block = blocksize / entry_size;
176235537Sgber
177235537Sgber	mdt->blocks_per_group =
178235537Sgber	    (mdt->entries_per_group -1) / mdt->entries_per_block + 1 + 1;
179235537Sgber	mdt->groups_per_desc_block =
180235537Sgber	    blocksize / sizeof(struct nandfs_block_group_desc);
181235537Sgber	mdt->blocks_per_desc_block =
182235537Sgber	    mdt->groups_per_desc_block * mdt->blocks_per_group + 1;
183235537Sgber}
184235537Sgber
185235537Sgberint
186235537Sgbernandfs_dev_bread(struct nandfs_device *nandfsdev, nandfs_lbn_t blocknr,
187235537Sgber    struct ucred *cred, int flags, struct buf **bpp)
188235537Sgber{
189235537Sgber	int blk2dev = nandfsdev->nd_blocksize / DEV_BSIZE;
190235537Sgber	int error;
191235537Sgber
192235537Sgber	DPRINTF(BLOCK, ("%s: read from block %jx vp %p\n", __func__,
193235537Sgber	    blocknr * blk2dev, nandfsdev->nd_devvp));
194235537Sgber	error = bread(nandfsdev->nd_devvp, blocknr * blk2dev,
195235537Sgber	    nandfsdev->nd_blocksize, NOCRED, bpp);
196235537Sgber	if (error)
197235537Sgber		nandfs_error("%s: cannot read from device - blk:%jx\n",
198235537Sgber		    __func__, blocknr);
199235537Sgber	return (error);
200235537Sgber}
201235537Sgber
202235537Sgber/* Read on a node */
203235537Sgberint
204235537Sgbernandfs_bread(struct nandfs_node *node, nandfs_lbn_t blocknr,
205235537Sgber    struct ucred *cred, int flags, struct buf **bpp)
206235537Sgber{
207235537Sgber	nandfs_daddr_t vblk;
208235537Sgber	int error;
209235537Sgber
210235537Sgber	DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node),
211235537Sgber	    blocknr));
212235537Sgber
213235537Sgber	error = bread(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize,
214235537Sgber	    cred, bpp);
215235537Sgber
216235537Sgber	KASSERT(error == 0, ("%s: vp:%p lbn:%#jx err:%d\n", __func__,
217235537Sgber	    NTOV(node), blocknr, error));
218235537Sgber
219235537Sgber	if (!nandfs_vblk_get(*bpp) &&
220235537Sgber	    ((*bpp)->b_flags & B_CACHE) && node->nn_ino != NANDFS_DAT_INO) {
221235537Sgber		nandfs_bmap_lookup(node, blocknr, &vblk);
222235537Sgber		nandfs_vblk_set(*bpp, vblk);
223235537Sgber	}
224235537Sgber	return (error);
225235537Sgber}
226235537Sgber
227235537Sgberint
228235537Sgbernandfs_bread_meta(struct nandfs_node *node, nandfs_lbn_t blocknr,
229235537Sgber    struct ucred *cred, int flags, struct buf **bpp)
230235537Sgber{
231235537Sgber	nandfs_daddr_t vblk;
232235537Sgber	int error;
233235537Sgber
234235537Sgber	DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node),
235235537Sgber	    blocknr));
236235537Sgber
237235537Sgber	error = bread(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize,
238235537Sgber	    cred, bpp);
239235537Sgber
240235537Sgber	KASSERT(error == 0, ("%s: vp:%p lbn:%#jx err:%d\n", __func__,
241235537Sgber	    NTOV(node), blocknr, error));
242235537Sgber
243235537Sgber	if (!nandfs_vblk_get(*bpp) &&
244235537Sgber	    ((*bpp)->b_flags & B_CACHE) && node->nn_ino != NANDFS_DAT_INO) {
245235537Sgber		nandfs_bmap_lookup(node, blocknr, &vblk);
246235537Sgber		nandfs_vblk_set(*bpp, vblk);
247235537Sgber	}
248235537Sgber
249235537Sgber	return (error);
250235537Sgber}
251235537Sgber
252235537Sgberint
253235537Sgbernandfs_bdestroy(struct nandfs_node *node, nandfs_daddr_t vblk)
254235537Sgber{
255235537Sgber	int error;
256235537Sgber
257235537Sgber	if (!NANDFS_SYS_NODE(node->nn_ino))
258235537Sgber		NANDFS_WRITEASSERT(node->nn_nandfsdev);
259235537Sgber
260235537Sgber	error = nandfs_vblock_end(node->nn_nandfsdev, vblk);
261235537Sgber	if (error) {
262235537Sgber		nandfs_error("%s: ending vblk: %jx failed\n",
263235537Sgber		    __func__, (uintmax_t)vblk);
264235537Sgber		return (error);
265235537Sgber	}
266235537Sgber	node->nn_inode.i_blocks--;
267235537Sgber
268235537Sgber	return (0);
269235537Sgber}
270235537Sgber
271235537Sgberint
272235537Sgbernandfs_bcreate(struct nandfs_node *node, nandfs_lbn_t blocknr,
273235537Sgber    struct ucred *cred, int flags, struct buf **bpp)
274235537Sgber{
275235537Sgber	int error;
276235537Sgber
277235537Sgber	ASSERT_VOP_LOCKED(NTOV(node), __func__);
278235537Sgber	if (!NANDFS_SYS_NODE(node->nn_ino))
279235537Sgber		NANDFS_WRITEASSERT(node->nn_nandfsdev);
280235537Sgber
281235537Sgber	DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node),
282235537Sgber	    blocknr));
283235537Sgber
284235537Sgber	*bpp = getblk(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize,
285235537Sgber	    0, 0, 0);
286235537Sgber
287235537Sgber	KASSERT((*bpp), ("%s: vp:%p lbn:%#jx\n", __func__,
288235537Sgber	    NTOV(node), blocknr));
289235537Sgber
290235537Sgber	if (*bpp) {
291235537Sgber		vfs_bio_clrbuf(*bpp);
292235537Sgber		(*bpp)->b_blkno = ~(0); /* To avoid VOP_BMAP in bdwrite */
293235537Sgber		error = nandfs_bmap_insert_block(node, blocknr, *bpp);
294235537Sgber		if (error) {
295235537Sgber			nandfs_warning("%s: failed bmap insert node:%p"
296235537Sgber			    " blk:%jx\n", __func__, node, blocknr);
297235537Sgber			brelse(*bpp);
298235537Sgber			return (error);
299235537Sgber		}
300235537Sgber		node->nn_inode.i_blocks++;
301235537Sgber
302235537Sgber		return (0);
303235537Sgber	}
304235537Sgber
305235537Sgber	return (-1);
306235537Sgber}
307235537Sgber
308235537Sgberint
309235537Sgbernandfs_bcreate_meta(struct nandfs_node *node, nandfs_lbn_t blocknr,
310235537Sgber    struct ucred *cred, int flags, struct buf **bpp)
311235537Sgber{
312235537Sgber	struct nandfs_device *fsdev;
313235537Sgber	nandfs_daddr_t vblk;
314235537Sgber	int error;
315235537Sgber
316235537Sgber	ASSERT_VOP_LOCKED(NTOV(node), __func__);
317235537Sgber	NANDFS_WRITEASSERT(node->nn_nandfsdev);
318235537Sgber
319235537Sgber	DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node),
320235537Sgber	    blocknr));
321235537Sgber
322235537Sgber	fsdev = node->nn_nandfsdev;
323235537Sgber
324235537Sgber	*bpp = getblk(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize,
325235537Sgber	    0, 0, 0);
326235537Sgber
327235537Sgber	KASSERT((*bpp), ("%s: vp:%p lbn:%#jx\n", __func__,
328235537Sgber	    NTOV(node), blocknr));
329235537Sgber
330235537Sgber	memset((*bpp)->b_data, 0, fsdev->nd_blocksize);
331235537Sgber
332235537Sgber	vfs_bio_clrbuf(*bpp);
333235537Sgber	(*bpp)->b_blkno = ~(0); /* To avoid VOP_BMAP in bdwrite */
334235537Sgber
335235537Sgber	nandfs_buf_set(*bpp, NANDFS_VBLK_ASSIGNED);
336235537Sgber
337235537Sgber	if (node->nn_ino != NANDFS_DAT_INO) {
338235537Sgber		error = nandfs_vblock_alloc(fsdev, &vblk);
339235537Sgber		if (error) {
340235537Sgber			nandfs_buf_clear(*bpp, NANDFS_VBLK_ASSIGNED);
341235537Sgber			brelse(*bpp);
342235537Sgber			return (error);
343235537Sgber		}
344235537Sgber	} else
345235537Sgber		vblk = fsdev->nd_fakevblk++;
346235537Sgber
347235537Sgber	nandfs_vblk_set(*bpp, vblk);
348235537Sgber
349235537Sgber	nandfs_bmap_insert_block(node, blocknr, *bpp);
350235537Sgber	return (0);
351235537Sgber}
352235537Sgber
353235537Sgber/* Translate index to a file block number and an entry */
354235537Sgbervoid
355235537Sgbernandfs_mdt_trans(struct nandfs_mdt *mdt, uint64_t index,
356235537Sgber    nandfs_lbn_t *blocknr, uint32_t *entry_in_block)
357235537Sgber{
358235537Sgber	uint64_t blknr;
359235537Sgber	uint64_t group, group_offset, blocknr_in_group;
360235537Sgber	uint64_t desc_block, desc_offset;
361235537Sgber
362235537Sgber	/* Calculate our offset in the file */
363235537Sgber	group = index / mdt->entries_per_group;
364235537Sgber	group_offset = index % mdt->entries_per_group;
365235537Sgber	desc_block = group / mdt->groups_per_desc_block;
366235537Sgber	desc_offset = group % mdt->groups_per_desc_block;
367235537Sgber	blocknr_in_group = group_offset / mdt->entries_per_block;
368235537Sgber
369235537Sgber	/* To descgroup offset */
370235537Sgber	blknr = 1 + desc_block * mdt->blocks_per_desc_block;
371235537Sgber
372235537Sgber	/* To group offset */
373235537Sgber	blknr += desc_offset * mdt->blocks_per_group;
374235537Sgber
375235537Sgber	/* To actual file block */
376235537Sgber	blknr += 1 + blocknr_in_group;
377235537Sgber
378235537Sgber	*blocknr = blknr;
379235537Sgber	*entry_in_block = group_offset % mdt->entries_per_block;
380235537Sgber}
381235537Sgber
382235537Sgbervoid
383235537Sgbernandfs_mdt_trans_blk(struct nandfs_mdt *mdt, uint64_t index,
384235537Sgber    uint64_t *desc, uint64_t *bitmap, nandfs_lbn_t *blocknr,
385235537Sgber    uint32_t *entry_in_block)
386235537Sgber{
387235537Sgber	uint64_t blknr;
388235537Sgber	uint64_t group, group_offset, blocknr_in_group;
389235537Sgber	uint64_t desc_block, desc_offset;
390235537Sgber
391235537Sgber	/* Calculate our offset in the file */
392235537Sgber	group = index / mdt->entries_per_group;
393235537Sgber	group_offset = index % mdt->entries_per_group;
394235537Sgber	desc_block = group / mdt->groups_per_desc_block;
395235537Sgber	desc_offset = group % mdt->groups_per_desc_block;
396235537Sgber	blocknr_in_group = group_offset / mdt->entries_per_block;
397235537Sgber
398235537Sgber	/* To descgroup offset */
399235537Sgber	*desc = desc_block * mdt->blocks_per_desc_block;
400235537Sgber	blknr = 1 + desc_block * mdt->blocks_per_desc_block;
401235537Sgber
402235537Sgber	/* To group offset */
403235537Sgber	blknr += desc_offset * mdt->blocks_per_group;
404235537Sgber	*bitmap = blknr;
405235537Sgber
406235537Sgber	/* To actual file block */
407235537Sgber	blknr += 1 + blocknr_in_group;
408235537Sgber
409235537Sgber	*blocknr = blknr;
410235537Sgber	*entry_in_block = group_offset % mdt->entries_per_block;
411235537Sgber
412235537Sgber	DPRINTF(ALLOC,
413235537Sgber	    ("%s: desc_buf: %jx bitmap_buf: %jx entry_buf: %jx entry: %x\n",
414235537Sgber	    __func__, (uintmax_t)*desc, (uintmax_t)*bitmap,
415235537Sgber	    (uintmax_t)*blocknr, *entry_in_block));
416235537Sgber}
417235537Sgber
418235537Sgberint
419235537Sgbernandfs_vtop(struct nandfs_node *node, nandfs_daddr_t vblocknr,
420235537Sgber    nandfs_daddr_t *pblocknr)
421235537Sgber{
422235537Sgber	struct nandfs_node *dat_node;
423235537Sgber	struct nandfs_dat_entry *entry;
424235537Sgber	struct buf *bp;
425235537Sgber	nandfs_lbn_t ldatblknr;
426235537Sgber	uint32_t entry_in_block;
427235537Sgber	int locked, error;
428235537Sgber
429235537Sgber	if (node->nn_ino == NANDFS_DAT_INO || node->nn_ino == NANDFS_GC_INO) {
430235537Sgber		*pblocknr = vblocknr;
431235537Sgber		return (0);
432235537Sgber	}
433235537Sgber
434235537Sgber	/* only translate valid vblocknrs */
435235537Sgber	if (vblocknr == 0)
436235537Sgber		return (0);
437235537Sgber
438235537Sgber	dat_node = node->nn_nandfsdev->nd_dat_node;
439235537Sgber	nandfs_mdt_trans(&node->nn_nandfsdev->nd_dat_mdt, vblocknr, &ldatblknr,
440235537Sgber	    &entry_in_block);
441235537Sgber
442235537Sgber	locked = NANDFS_VOP_ISLOCKED(NTOV(dat_node));
443235537Sgber	if (!locked)
444235537Sgber		VOP_LOCK(NTOV(dat_node), LK_SHARED);
445235537Sgber	error = nandfs_bread(dat_node, ldatblknr, NOCRED, 0, &bp);
446235537Sgber	if (error) {
447235537Sgber		DPRINTF(TRANSLATE, ("vtop: can't read in DAT block %#jx!\n",
448235537Sgber		    (uintmax_t)ldatblknr));
449235537Sgber		brelse(bp);
450235537Sgber		VOP_UNLOCK(NTOV(dat_node), 0);
451235537Sgber		return (error);
452235537Sgber	}
453235537Sgber
454235537Sgber	/* Get our translation */
455235537Sgber	entry = ((struct nandfs_dat_entry *) bp->b_data) + entry_in_block;
456235537Sgber	DPRINTF(TRANSLATE, ("\tentry %p data %p entry_in_block %x\n",
457235537Sgber	    entry, bp->b_data, entry_in_block))
458235537Sgber	DPRINTF(TRANSLATE, ("\tvblk %#jx -> %#jx for cp [%#jx-%#jx]\n",
459235537Sgber	    (uintmax_t)vblocknr, (uintmax_t)entry->de_blocknr,
460235537Sgber	    (uintmax_t)entry->de_start, (uintmax_t)entry->de_end));
461235537Sgber
462235537Sgber	*pblocknr = entry->de_blocknr;
463235537Sgber	brelse(bp);
464235537Sgber	if (!locked)
465235537Sgber		VOP_UNLOCK(NTOV(dat_node), 0);
466235537Sgber
467235537Sgber	MPASS(*pblocknr >= node->nn_nandfsdev->nd_fsdata.f_first_data_block ||
468235537Sgber	    *pblocknr == 0);
469235537Sgber
470235537Sgber	return (0);
471235537Sgber}
472235537Sgber
473235537Sgberint
474235537Sgbernandfs_segsum_valid(struct nandfs_segment_summary *segsum)
475235537Sgber{
476235537Sgber
477235537Sgber	return (segsum->ss_magic == NANDFS_SEGSUM_MAGIC);
478235537Sgber}
479235537Sgber
480235537Sgberint
481235537Sgbernandfs_load_segsum(struct nandfs_device *fsdev, nandfs_daddr_t blocknr,
482235537Sgber    struct nandfs_segment_summary *segsum)
483235537Sgber{
484235537Sgber	struct buf *bp;
485235537Sgber	int error;
486235537Sgber
487235537Sgber	DPRINTF(VOLUMES, ("nandfs: try segsum at block %jx\n",
488235537Sgber	    (uintmax_t)blocknr));
489235537Sgber
490235537Sgber	error = nandfs_dev_bread(fsdev, blocknr, NOCRED, 0, &bp);
491235537Sgber	if (error)
492235537Sgber		return (error);
493235537Sgber
494235537Sgber	memcpy(segsum, bp->b_data, sizeof(struct nandfs_segment_summary));
495235537Sgber	brelse(bp);
496235537Sgber
497235537Sgber	if (!nandfs_segsum_valid(segsum)) {
498235537Sgber		DPRINTF(VOLUMES, ("%s: bad magic pseg:%jx\n", __func__,
499235537Sgber		    blocknr));
500235537Sgber		return (EINVAL);
501235537Sgber	}
502235537Sgber
503235537Sgber	return (error);
504235537Sgber}
505235537Sgber
506235537Sgberstatic int
507235537Sgbernandfs_load_super_root(struct nandfs_device *nandfsdev,
508235537Sgber    struct nandfs_segment_summary *segsum, uint64_t pseg)
509235537Sgber{
510235537Sgber	struct nandfs_super_root super_root;
511235537Sgber	struct buf *bp;
512235537Sgber	uint64_t blocknr;
513235537Sgber	uint32_t super_root_crc, comp_crc;
514235537Sgber	int off, error;
515235537Sgber
516235537Sgber	/* Check if there is a superroot */
517235537Sgber	if ((segsum->ss_flags & NANDFS_SS_SR) == 0) {
518235537Sgber		DPRINTF(VOLUMES, ("%s: no super root in pseg:%jx\n", __func__,
519235537Sgber		    pseg));
520235537Sgber		return (ENOENT);
521235537Sgber	}
522235537Sgber
523235537Sgber	/* Get our super root, located at the end of the pseg */
524235537Sgber	blocknr = pseg + segsum->ss_nblocks - 1;
525235537Sgber	DPRINTF(VOLUMES, ("%s: try at %#jx\n", __func__, (uintmax_t)blocknr));
526235537Sgber
527235537Sgber	error = nandfs_dev_bread(nandfsdev, blocknr, NOCRED, 0, &bp);
528235537Sgber	if (error)
529235537Sgber		return (error);
530235537Sgber
531235537Sgber	memcpy(&super_root, bp->b_data, sizeof(struct nandfs_super_root));
532235537Sgber	brelse(bp);
533235537Sgber
534235537Sgber	/* Check super root CRC */
535235537Sgber	super_root_crc = super_root.sr_sum;
536235537Sgber	off = sizeof(super_root.sr_sum);
537235537Sgber	comp_crc = crc32((uint8_t *)&super_root + off,
538235537Sgber	    NANDFS_SR_BYTES - off);
539235537Sgber
540235537Sgber	if (super_root_crc != comp_crc) {
541235537Sgber		DPRINTF(VOLUMES, ("%s: invalid crc:%#x [expect:%#x]\n",
542235537Sgber		    __func__, super_root_crc, comp_crc));
543235537Sgber		return (EINVAL);
544235537Sgber	}
545235537Sgber
546235537Sgber	nandfsdev->nd_super_root = super_root;
547235537Sgber	DPRINTF(VOLUMES, ("%s: got valid superroot\n", __func__));
548235537Sgber
549235537Sgber	return (0);
550235537Sgber}
551235537Sgber
552235537Sgber/*
553235537Sgber * Search for the last super root recorded.
554235537Sgber */
555235537Sgberint
556235537Sgbernandfs_search_super_root(struct nandfs_device *nandfsdev)
557235537Sgber{
558235537Sgber	struct nandfs_super_block *super;
559235537Sgber	struct nandfs_segment_summary segsum;
560235537Sgber	uint64_t seg_start, seg_end, cno, seq, create, pseg;
561235537Sgber	uint64_t segnum;
562235537Sgber	int error, found;
563235537Sgber
564235537Sgber	error = found = 0;
565235537Sgber
566235537Sgber	/* Search for last super root */
567235537Sgber	pseg = nandfsdev->nd_super.s_last_pseg;
568235537Sgber	segnum = nandfs_get_segnum_of_block(nandfsdev, pseg);
569235537Sgber
570235537Sgber	cno = nandfsdev->nd_super.s_last_cno;
571235537Sgber	create = seq = 0;
572235537Sgber	DPRINTF(VOLUMES, ("%s: start in pseg %#jx\n", __func__,
573235537Sgber	    (uintmax_t)pseg));
574235537Sgber
575235537Sgber	for (;;) {
576235537Sgber		error = nandfs_load_segsum(nandfsdev, pseg, &segsum);
577235537Sgber		if (error)
578235537Sgber			break;
579235537Sgber
580235537Sgber		if (segsum.ss_seq < seq || segsum.ss_create < create)
581235537Sgber			break;
582235537Sgber
583235537Sgber		/* Try to load super root */
584235537Sgber		if (segsum.ss_flags & NANDFS_SS_SR) {
585235537Sgber			error = nandfs_load_super_root(nandfsdev, &segsum, pseg);
586235537Sgber			if (error)
587235537Sgber				break;	/* confused */
588235537Sgber			found = 1;
589235537Sgber
590235537Sgber			super = &nandfsdev->nd_super;
591235537Sgber			nandfsdev->nd_last_segsum = segsum;
592235537Sgber			super->s_last_pseg = pseg;
593235537Sgber			super->s_last_cno = cno++;
594235537Sgber			super->s_last_seq = segsum.ss_seq;
595235537Sgber			super->s_state = NANDFS_VALID_FS;
596235537Sgber			seq = segsum.ss_seq;
597235537Sgber			create = segsum.ss_create;
598235537Sgber		} else {
599235537Sgber			seq = segsum.ss_seq;
600235537Sgber			create = segsum.ss_create;
601235537Sgber		}
602235537Sgber
603235537Sgber		/* Calculate next partial segment location */
604235537Sgber		pseg += segsum.ss_nblocks;
605235537Sgber		DPRINTF(VOLUMES, ("%s: next partial seg is %jx\n", __func__,
606235537Sgber		    (uintmax_t)pseg));
607235537Sgber
608235537Sgber		/* Did we reach the end of the segment? if so, go to the next */
609235537Sgber		nandfs_get_segment_range(nandfsdev, segnum, &seg_start,
610235537Sgber		    &seg_end);
611235537Sgber		if (pseg >= seg_end) {
612235537Sgber			pseg = segsum.ss_next;
613235537Sgber			DPRINTF(VOLUMES,
614235537Sgber			    (" partial seg oor next is %jx[%jx - %jx]\n",
615235537Sgber			    (uintmax_t)pseg, (uintmax_t)seg_start,
616235537Sgber			    (uintmax_t)seg_end));
617235537Sgber		}
618235537Sgber		segnum = nandfs_get_segnum_of_block(nandfsdev, pseg);
619235537Sgber	}
620235537Sgber
621235537Sgber	if (error && !found)
622235537Sgber		return (error);
623235537Sgber
624235537Sgber	return (0);
625235537Sgber}
626235537Sgber
627235537Sgberint
628235537Sgbernandfs_get_node_raw(struct nandfs_device *nandfsdev, struct nandfsmount *nmp,
629235537Sgber    uint64_t ino, struct nandfs_inode *inode, struct nandfs_node **nodep)
630235537Sgber{
631235537Sgber	struct nandfs_node *node;
632235537Sgber	struct vnode *nvp;
633235537Sgber	struct mount *mp;
634235537Sgber	int error;
635235537Sgber
636235537Sgber	*nodep = NULL;
637235537Sgber
638235537Sgber	/* Associate with mountpoint if present */
639235537Sgber	if (nmp) {
640235537Sgber		mp = nmp->nm_vfs_mountp;
641235537Sgber		error = getnewvnode("nandfs", mp, &nandfs_vnodeops, &nvp);
642269420Simp		if (error)
643235537Sgber			return (error);
644235537Sgber	} else {
645235537Sgber		mp = NULL;
646235537Sgber		error = getnewvnode("snandfs", mp, &nandfs_system_vnodeops,
647235537Sgber		    &nvp);
648269420Simp		if (error)
649235537Sgber			return (error);
650235537Sgber	}
651235537Sgber
652235537Sgber	if (mp)
653235537Sgber		NANDFS_WRITELOCK(nandfsdev);
654235537Sgber
655235537Sgber	DPRINTF(IFILE, ("%s: ino: %#jx -> vp: %p\n",
656235537Sgber	    __func__, (uintmax_t)ino, nvp));
657235537Sgber	/* Lock node */
658235537Sgber	lockmgr(nvp->v_vnlock, LK_EXCLUSIVE, NULL);
659235537Sgber
660235537Sgber	if (mp) {
661235537Sgber		error = insmntque(nvp, mp);
662235537Sgber		if (error != 0) {
663235537Sgber			*nodep = NULL;
664235537Sgber			return (error);
665235537Sgber		}
666235537Sgber	}
667235537Sgber
668235537Sgber	node = uma_zalloc(nandfs_node_zone, M_WAITOK | M_ZERO);
669235537Sgber
670235537Sgber	/* Crosslink */
671235537Sgber	node->nn_vnode = nvp;
672235537Sgber	nvp->v_bufobj.bo_ops = &buf_ops_nandfs;
673235537Sgber	node->nn_nmp = nmp;
674235537Sgber	node->nn_nandfsdev = nandfsdev;
675235537Sgber	nvp->v_data = node;
676235537Sgber
677235537Sgber	/* Initiase NANDFS node */
678235537Sgber	node->nn_ino = ino;
679235537Sgber	if (inode != NULL)
680235537Sgber		node->nn_inode = *inode;
681235537Sgber
682235537Sgber	nandfs_vinit(nvp, ino);
683235537Sgber
684235537Sgber	/* Return node */
685235537Sgber	*nodep = node;
686235537Sgber	DPRINTF(IFILE, ("%s: ino:%#jx vp:%p node:%p\n",
687235537Sgber	    __func__, (uintmax_t)ino, nvp, *nodep));
688235537Sgber
689235537Sgber	return (0);
690235537Sgber}
691235537Sgber
692235537Sgberint
693235537Sgbernandfs_get_node(struct nandfsmount *nmp, uint64_t ino,
694235537Sgber    struct nandfs_node **nodep)
695235537Sgber{
696235537Sgber	struct nandfs_device *nandfsdev;
697235537Sgber	struct nandfs_inode inode, *entry;
698235537Sgber	struct vnode *nvp, *vpp;
699235537Sgber	struct thread *td;
700235537Sgber	struct buf *bp;
701235537Sgber	uint64_t ivblocknr;
702235537Sgber	uint32_t entry_in_block;
703235537Sgber	int error;
704235537Sgber
705235537Sgber	/* Look up node in hash table */
706235537Sgber	td = curthread;
707235537Sgber	*nodep = NULL;
708235537Sgber
709235537Sgber	if ((ino < NANDFS_ATIME_INO) && (ino != NANDFS_ROOT_INO)) {
710235537Sgber		printf("nandfs_get_node: system ino %"PRIu64" not in mount "
711235537Sgber		    "point!\n", ino);
712235537Sgber		return (ENOENT);
713235537Sgber	}
714235537Sgber
715235537Sgber	error = vfs_hash_get(nmp->nm_vfs_mountp, ino, LK_EXCLUSIVE, td, &nvp,
716235537Sgber	    NULL, NULL);
717235537Sgber	if (error)
718235537Sgber		return (error);
719235537Sgber
720235537Sgber	if (nvp != NULL) {
721235537Sgber		*nodep = (struct nandfs_node *)nvp->v_data;
722235537Sgber		return (0);
723235537Sgber	}
724235537Sgber
725235537Sgber	/* Look up inode structure in mountpoints ifile */
726235537Sgber	nandfsdev = nmp->nm_nandfsdev;
727235537Sgber	nandfs_mdt_trans(&nandfsdev->nd_ifile_mdt, ino, &ivblocknr,
728235537Sgber	    &entry_in_block);
729235537Sgber
730235537Sgber	VOP_LOCK(NTOV(nmp->nm_ifile_node), LK_SHARED);
731235537Sgber	error = nandfs_bread(nmp->nm_ifile_node, ivblocknr, NOCRED, 0, &bp);
732235537Sgber	if (error) {
733235537Sgber		brelse(bp);
734235537Sgber		VOP_UNLOCK(NTOV(nmp->nm_ifile_node), 0);
735235537Sgber		return (ENOENT);
736235537Sgber	}
737235537Sgber
738235537Sgber	/* Get inode entry */
739235537Sgber	entry = (struct nandfs_inode *) bp->b_data + entry_in_block;
740235537Sgber	memcpy(&inode, entry, sizeof(struct nandfs_inode));
741235537Sgber	brelse(bp);
742235537Sgber	VOP_UNLOCK(NTOV(nmp->nm_ifile_node), 0);
743235537Sgber
744235537Sgber	/* Get node */
745235537Sgber	error = nandfs_get_node_raw(nmp->nm_nandfsdev, nmp, ino, &inode, nodep);
746235537Sgber	if (error) {
747235537Sgber		*nodep = NULL;
748235537Sgber		return (error);
749235537Sgber	}
750235537Sgber
751235537Sgber	nvp = (*nodep)->nn_vnode;
752235537Sgber	error = vfs_hash_insert(nvp, ino, 0, td, &vpp, NULL, NULL);
753235537Sgber	if (error) {
754235537Sgber		*nodep = NULL;
755235537Sgber		return (error);
756235537Sgber	}
757235537Sgber
758235537Sgber	return (error);
759235537Sgber}
760235537Sgber
761235537Sgbervoid
762235537Sgbernandfs_dispose_node(struct nandfs_node **nodep)
763235537Sgber{
764235537Sgber	struct nandfs_node *node;
765235537Sgber	struct vnode *vp;
766235537Sgber
767235537Sgber	/* Protect against rogue values */
768235537Sgber	node = *nodep;
769235537Sgber	if (!node) {
770235537Sgber		return;
771235537Sgber	}
772235537Sgber	DPRINTF(NODE, ("nandfs_dispose_node: %p\n", *nodep));
773235537Sgber
774235537Sgber	vp = NTOV(node);
775235537Sgber	vp->v_data = NULL;
776235537Sgber
777235537Sgber	/* Free our associated memory */
778235537Sgber	uma_zfree(nandfs_node_zone, node);
779235537Sgber
780235537Sgber	*nodep = NULL;
781235537Sgber}
782235537Sgber
783235537Sgberint
784235537Sgbernandfs_lookup_name_in_dir(struct vnode *dvp, const char *name, int namelen,
785235537Sgber    uint64_t *ino, int *found, uint64_t *off)
786235537Sgber{
787235537Sgber	struct nandfs_node *dir_node = VTON(dvp);
788235537Sgber	struct nandfs_dir_entry	*ndirent;
789235537Sgber	struct buf *bp;
790235537Sgber	uint64_t file_size, diroffset, blkoff;
791235537Sgber	uint64_t blocknr;
792235537Sgber	uint32_t blocksize = dir_node->nn_nandfsdev->nd_blocksize;
793235537Sgber	uint8_t *pos, name_len;
794235537Sgber	int error;
795235537Sgber
796235537Sgber	*found = 0;
797235537Sgber
798235537Sgber	DPRINTF(VNCALL, ("%s: %s file\n", __func__, name));
799235537Sgber	if (dvp->v_type != VDIR) {
800235537Sgber		return (ENOTDIR);
801235537Sgber	}
802235537Sgber
803235537Sgber	/* Get directory filesize */
804235537Sgber	file_size = dir_node->nn_inode.i_size;
805235537Sgber
806235537Sgber	/* Walk the directory */
807235537Sgber	diroffset = 0;
808235537Sgber	blocknr = 0;
809235537Sgber	blkoff = 0;
810235537Sgber	error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp);
811235537Sgber	if (error) {
812235537Sgber		brelse(bp);
813235537Sgber		return (EIO);
814235537Sgber	}
815235537Sgber
816235537Sgber	while (diroffset < file_size) {
817235537Sgber		if (blkoff >= blocksize) {
818235537Sgber			blkoff = 0; blocknr++;
819235537Sgber			brelse(bp);
820235537Sgber			error = nandfs_bread(dir_node, blocknr, NOCRED, 0,
821235537Sgber			    &bp);
822235537Sgber			if (error) {
823235537Sgber				brelse(bp);
824235537Sgber				return (EIO);
825235537Sgber			}
826235537Sgber		}
827235537Sgber
828235537Sgber		/* Read in one dirent */
829235537Sgber		pos = (uint8_t *) bp->b_data + blkoff;
830235537Sgber		ndirent = (struct nandfs_dir_entry *) pos;
831235537Sgber		name_len = ndirent->name_len;
832235537Sgber
833235537Sgber		if ((name_len == namelen) &&
834235537Sgber		    (strncmp(name, ndirent->name, name_len) == 0) &&
835235537Sgber		    (ndirent->inode != 0)) {
836235537Sgber			*ino = ndirent->inode;
837235537Sgber			*off = diroffset;
838235537Sgber			DPRINTF(LOOKUP, ("found `%.*s` with ino %"PRIx64"\n",
839235537Sgber			    name_len, ndirent->name, *ino));
840235537Sgber			*found = 1;
841235537Sgber			break;
842235537Sgber		}
843235537Sgber
844235537Sgber		/* Advance */
845235537Sgber		diroffset += ndirent->rec_len;
846235537Sgber		blkoff += ndirent->rec_len;
847235537Sgber	}
848235537Sgber	brelse(bp);
849235537Sgber
850235537Sgber	return (error);
851235537Sgber}
852235537Sgber
853235537Sgberint
854235537Sgbernandfs_get_fsinfo(struct nandfsmount *nmp, struct nandfs_fsinfo *fsinfo)
855235537Sgber{
856235537Sgber	struct nandfs_device *fsdev;
857235537Sgber
858235537Sgber	fsdev = nmp->nm_nandfsdev;
859235537Sgber
860235537Sgber	memcpy(&fsinfo->fs_fsdata, &fsdev->nd_fsdata, sizeof(fsdev->nd_fsdata));
861235537Sgber	memcpy(&fsinfo->fs_super, &fsdev->nd_super, sizeof(fsdev->nd_super));
862235537Sgber	snprintf(fsinfo->fs_dev, sizeof(fsinfo->fs_dev),
863235537Sgber	    "%s", nmp->nm_vfs_mountp->mnt_stat.f_mntfromname);
864235537Sgber
865235537Sgber	return (0);
866235537Sgber}
867235537Sgber
868235537Sgbervoid
869235537Sgbernandfs_inode_init(struct nandfs_inode *inode, uint16_t mode)
870235537Sgber{
871235537Sgber	struct timespec ts;
872235537Sgber
873235537Sgber	vfs_timestamp(&ts);
874235537Sgber
875235537Sgber	inode->i_blocks = 0;
876235537Sgber	inode->i_size = 0;
877235537Sgber	inode->i_ctime = ts.tv_sec;
878235537Sgber	inode->i_ctime_nsec = ts.tv_nsec;
879235537Sgber	inode->i_mtime = ts.tv_sec;
880235537Sgber	inode->i_mtime_nsec = ts.tv_nsec;
881235537Sgber	inode->i_mode = mode;
882235537Sgber	inode->i_links_count = 1;
883235537Sgber	if (S_ISDIR(mode))
884235537Sgber		inode->i_links_count = 2;
885235537Sgber	inode->i_flags = 0;
886235537Sgber
887235537Sgber	inode->i_special = 0;
888235537Sgber	memset(inode->i_db, 0, sizeof(inode->i_db));
889235537Sgber	memset(inode->i_ib, 0, sizeof(inode->i_ib));
890235537Sgber}
891235537Sgber
892235537Sgbervoid
893235537Sgbernandfs_inode_destroy(struct nandfs_inode *inode)
894235537Sgber{
895235537Sgber
896235537Sgber	MPASS(inode->i_blocks == 0);
897235537Sgber	bzero(inode, sizeof(*inode));
898235537Sgber}
899235537Sgber
900235537Sgberint
901235537Sgbernandfs_fs_full(struct nandfs_device *nffsdev)
902235537Sgber{
903235537Sgber	uint64_t space, bps;
904235537Sgber
905235537Sgber	bps = nffsdev->nd_fsdata.f_blocks_per_segment;
906235537Sgber	space = (nffsdev->nd_clean_segs - 1) * bps;
907235537Sgber
908235537Sgber	DPRINTF(BUF, ("%s: bufs:%jx space:%jx\n", __func__,
909235537Sgber	    (uintmax_t)nffsdev->nd_dirty_bufs, (uintmax_t)space));
910235537Sgber
911264657Simp	if (nffsdev->nd_dirty_bufs + (nffsdev->nd_segs_reserved * bps) >= space)
912235537Sgber		return (1);
913235537Sgber
914235537Sgber	return (0);
915235537Sgber}
916235537Sgber
917235537Sgberstatic int
918235537Sgber_nandfs_dirty_buf(struct buf *bp, int dirty_meta, int force)
919235537Sgber{
920235537Sgber	struct nandfs_device *nffsdev;
921235537Sgber	struct nandfs_node *node;
922235537Sgber	uint64_t ino, bps;
923235537Sgber
924235537Sgber	if (NANDFS_ISGATHERED(bp)) {
925235537Sgber		bqrelse(bp);
926235537Sgber		return (0);
927235537Sgber	}
928235537Sgber	if ((bp->b_flags & (B_MANAGED | B_DELWRI)) == (B_MANAGED | B_DELWRI)) {
929235537Sgber		bqrelse(bp);
930235537Sgber		return (0);
931235537Sgber	}
932235537Sgber
933235537Sgber	node = VTON(bp->b_vp);
934235537Sgber	nffsdev = node->nn_nandfsdev;
935235537Sgber	DPRINTF(BUF, ("%s: buf:%p\n", __func__, bp));
936235537Sgber	ino = node->nn_ino;
937235537Sgber
938235537Sgber	if (nandfs_fs_full(nffsdev) && !NANDFS_SYS_NODE(ino) && !force) {
939235537Sgber		brelse(bp);
940235537Sgber		return (ENOSPC);
941235537Sgber	}
942235537Sgber
943235537Sgber	bp->b_flags |= B_MANAGED;
944235537Sgber	bdwrite(bp);
945235537Sgber
946235537Sgber	nandfs_dirty_bufs_increment(nffsdev);
947235537Sgber
948235537Sgber	KASSERT((bp->b_vp), ("vp missing for bp"));
949235537Sgber	KASSERT((nandfs_vblk_get(bp) || ino == NANDFS_DAT_INO),
950235537Sgber	    ("bp vblk is 0"));
951235537Sgber
952235537Sgber	/*
953235537Sgber	 * To maintain consistency of FS we need to force making
954235537Sgber	 * meta buffers dirty, even if free space is low.
955235537Sgber	 */
956235537Sgber	if (dirty_meta && ino != NANDFS_GC_INO)
957235537Sgber		nandfs_bmap_dirty_blocks(VTON(bp->b_vp), bp, 1);
958235537Sgber
959235537Sgber	bps = nffsdev->nd_fsdata.f_blocks_per_segment;
960235537Sgber
961235537Sgber	if (nffsdev->nd_dirty_bufs >= (bps * nandfs_max_dirty_segs)) {
962235537Sgber		mtx_lock(&nffsdev->nd_sync_mtx);
963235537Sgber		if (nffsdev->nd_syncing == 0) {
964235537Sgber			DPRINTF(SYNC, ("%s: wakeup gc\n", __func__));
965235537Sgber			nffsdev->nd_syncing = 1;
966235537Sgber			wakeup(&nffsdev->nd_syncing);
967235537Sgber		}
968235537Sgber		mtx_unlock(&nffsdev->nd_sync_mtx);
969235537Sgber	}
970235537Sgber
971235537Sgber	return (0);
972235537Sgber}
973235537Sgber
974235537Sgberint
975235537Sgbernandfs_dirty_buf(struct buf *bp, int force)
976235537Sgber{
977235537Sgber
978235537Sgber	return (_nandfs_dirty_buf(bp, 1, force));
979235537Sgber}
980235537Sgber
981235537Sgberint
982235537Sgbernandfs_dirty_buf_meta(struct buf *bp, int force)
983235537Sgber{
984235537Sgber
985235537Sgber	return (_nandfs_dirty_buf(bp, 0, force));
986235537Sgber}
987235537Sgber
988235537Sgbervoid
989235537Sgbernandfs_undirty_buf_fsdev(struct nandfs_device *nffsdev, struct buf *bp)
990235537Sgber{
991235537Sgber
992235537Sgber	BUF_ASSERT_HELD(bp);
993235537Sgber
994235537Sgber	if (bp->b_flags & B_DELWRI) {
995235537Sgber		bp->b_flags &= ~(B_DELWRI|B_MANAGED);
996235537Sgber		nandfs_dirty_bufs_decrement(nffsdev);
997235537Sgber	}
998235537Sgber	/*
999235537Sgber	 * Since it is now being written, we can clear its deferred write flag.
1000235537Sgber	 */
1001235537Sgber	bp->b_flags &= ~B_DEFERRED;
1002235537Sgber
1003235537Sgber	brelse(bp);
1004235537Sgber}
1005235537Sgber
1006235537Sgbervoid
1007235537Sgbernandfs_undirty_buf(struct buf *bp)
1008235537Sgber{
1009235537Sgber	struct nandfs_node *node;
1010235537Sgber
1011235537Sgber	node = VTON(bp->b_vp);
1012235537Sgber
1013235537Sgber	nandfs_undirty_buf_fsdev(node->nn_nandfsdev, bp);
1014235537Sgber}
1015235537Sgber
1016235537Sgbervoid
1017235537Sgbernandfs_vblk_set(struct buf *bp, nandfs_daddr_t blocknr)
1018235537Sgber{
1019235537Sgber
1020235537Sgber	nandfs_daddr_t *vblk = (nandfs_daddr_t *)(&bp->b_fsprivate1);
1021235537Sgber	*vblk = blocknr;
1022235537Sgber}
1023235537Sgber
1024235537Sgbernandfs_daddr_t
1025235537Sgbernandfs_vblk_get(struct buf *bp)
1026235537Sgber{
1027235537Sgber
1028235537Sgber	nandfs_daddr_t *vblk = (nandfs_daddr_t *)(&bp->b_fsprivate1);
1029235537Sgber	return (*vblk);
1030235537Sgber}
1031235537Sgber
1032235537Sgbervoid
1033235537Sgbernandfs_buf_set(struct buf *bp, uint32_t bits)
1034235537Sgber{
1035235537Sgber	uintptr_t flags;
1036235537Sgber
1037235537Sgber	flags = (uintptr_t)bp->b_fsprivate3;
1038235537Sgber	flags |= (uintptr_t)bits;
1039235537Sgber	bp->b_fsprivate3 = (void *)flags;
1040235537Sgber}
1041235537Sgber
1042235537Sgbervoid
1043235537Sgbernandfs_buf_clear(struct buf *bp, uint32_t bits)
1044235537Sgber{
1045235537Sgber	uintptr_t flags;
1046235537Sgber
1047235537Sgber	flags = (uintptr_t)bp->b_fsprivate3;
1048235537Sgber	flags &= ~(uintptr_t)bits;
1049235537Sgber	bp->b_fsprivate3 = (void *)flags;
1050235537Sgber}
1051235537Sgber
1052235537Sgberint
1053235537Sgbernandfs_buf_check(struct buf *bp, uint32_t bits)
1054235537Sgber{
1055235537Sgber	uintptr_t flags;
1056235537Sgber
1057235537Sgber	flags = (uintptr_t)bp->b_fsprivate3;
1058235537Sgber	if (flags & bits)
1059235537Sgber		return (1);
1060235537Sgber	return (0);
1061235537Sgber}
1062235537Sgber
1063235537Sgberint
1064235537Sgbernandfs_erase(struct nandfs_device *fsdev, off_t offset, size_t size)
1065235537Sgber{
1066235537Sgber	DPRINTF(BLOCK, ("%s: performing erase at offset %jx size %zx\n",
1067235537Sgber	    __func__, offset, size));
1068235537Sgber
1069235537Sgber	MPASS(size % fsdev->nd_erasesize == 0);
1070235537Sgber
1071264658Simp	return (g_delete_data(fsdev->nd_gconsumer, offset, size));
1072235537Sgber}
1073235537Sgber
1074235537Sgberint
1075235537Sgbernandfs_vop_islocked(struct vnode *vp)
1076235537Sgber{
1077235537Sgber	int islocked;
1078235537Sgber
1079235537Sgber	islocked = VOP_ISLOCKED(vp);
1080235537Sgber	return (islocked == LK_EXCLUSIVE || islocked == LK_SHARED);
1081235537Sgber}
1082235537Sgber
1083235537Sgbernandfs_daddr_t
1084235537Sgbernandfs_block_to_dblock(struct nandfs_device *fsdev, nandfs_lbn_t block)
1085235537Sgber{
1086235537Sgber
1087235537Sgber	return (btodb(block * fsdev->nd_blocksize));
1088235537Sgber}
1089