1235537Sgber/*-
2235537Sgber * Copyright (c) 2010-2012 Semihalf.
3235537Sgber * All rights reserved.
4235537Sgber *
5235537Sgber * Redistribution and use in source and binary forms, with or without
6235537Sgber * modification, are permitted provided that the following conditions
7235537Sgber * are met:
8235537Sgber * 1. Redistributions of source code must retain the above copyright
9235537Sgber *    notice, this list of conditions and the following disclaimer.
10235537Sgber * 2. Redistributions in binary form must reproduce the above copyright
11235537Sgber *    notice, this list of conditions and the following disclaimer in the
12235537Sgber *    documentation and/or other materials provided with the distribution.
13235537Sgber *
14235537Sgber * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15235537Sgber * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16235537Sgber * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17235537Sgber * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18235537Sgber * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19235537Sgber * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20235537Sgber * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21235537Sgber * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22235537Sgber * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23235537Sgber * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24235537Sgber * SUCH DAMAGE.
25235537Sgber */
26235537Sgber
27235537Sgber#include <sys/cdefs.h>
28235537Sgber__FBSDID("$FreeBSD$");
29235537Sgber
30235537Sgber#include "opt_ddb.h"
31235537Sgber
32235537Sgber#include <sys/param.h>
33235537Sgber#include <sys/systm.h>
34235537Sgber#include <sys/conf.h>
35235537Sgber#include <sys/kernel.h>
36235537Sgber#include <sys/lock.h>
37235537Sgber#include <sys/malloc.h>
38235537Sgber#include <sys/mount.h>
39235537Sgber#include <sys/mutex.h>
40235537Sgber#include <sys/namei.h>
41251171Sjeff#include <sys/rwlock.h>
42235537Sgber#include <sys/sysctl.h>
43235537Sgber#include <sys/vnode.h>
44235537Sgber#include <sys/buf.h>
45235537Sgber#include <sys/bio.h>
46235537Sgber#include <sys/libkern.h>
47235537Sgber
48235537Sgber#include <ddb/ddb.h>
49235537Sgber
50235537Sgber#include <vm/vm.h>
51235537Sgber#include <vm/vm_param.h>
52235537Sgber#include <vm/vm_kern.h>
53235537Sgber#include <vm/vm_page.h>
54235537Sgber
55235537Sgber#include <geom/geom.h>
56235537Sgber#include <geom/geom_vfs.h>
57235537Sgber
58235537Sgber#include <fs/nandfs/nandfs_mount.h>
59235537Sgber#include <fs/nandfs/nandfs.h>
60235537Sgber#include <fs/nandfs/nandfs_subr.h>
61235537Sgber
62235537Sgberstatic int
63235537Sgbernandfs_new_segment(struct nandfs_device *fsdev)
64235537Sgber{
65235537Sgber	int error = 0;
66235537Sgber	uint64_t new;
67235537Sgber
68235537Sgber	error = nandfs_alloc_segment(fsdev, &new);
69235537Sgber	if (!error) {
70235537Sgber		fsdev->nd_seg_num = fsdev->nd_next_seg_num;
71235537Sgber		fsdev->nd_next_seg_num = new;
72235537Sgber	}
73235537Sgber	DPRINTF(SYNC, ("%s: new segment %jx next %jx error %d\n",
74235537Sgber	    __func__, (uintmax_t)fsdev->nd_seg_num, (uintmax_t)new, error));
75235537Sgber	if (error)
76235537Sgber		nandfs_error("%s: cannot create segment error %d\n",
77235537Sgber		    __func__, error);
78235537Sgber
79235537Sgber	return (error);
80235537Sgber}
81235537Sgber
82235537Sgberstatic int
83235537Sgbercreate_segment(struct nandfs_seginfo *seginfo)
84235537Sgber{
85235537Sgber	struct nandfs_segment *seg;
86235537Sgber	struct nandfs_device *fsdev;
87235537Sgber	struct nandfs_segment *prev;
88235537Sgber	struct buf *bp;
89235537Sgber	uint64_t start_block, curr;
90235537Sgber	uint32_t blks_per_seg, nblocks;
91235537Sgber	int error;
92235537Sgber
93235537Sgber	fsdev = seginfo->fsdev;
94235537Sgber	prev = seginfo->curseg;
95235537Sgber	blks_per_seg = fsdev->nd_fsdata.f_blocks_per_segment;
96235537Sgber	nblocks = fsdev->nd_last_segsum.ss_nblocks;
97235537Sgber
98235537Sgber	if (!prev) {
99235537Sgber		vfs_timestamp(&fsdev->nd_ts);
100235537Sgber		/* Touch current segment */
101235537Sgber		error = nandfs_touch_segment(fsdev, fsdev->nd_seg_num);
102235537Sgber		if (error) {
103235537Sgber			nandfs_error("%s: cannot preallocate segment %jx\n",
104235537Sgber			    __func__, fsdev->nd_seg_num);
105235537Sgber			return (error);
106235537Sgber		}
107235537Sgber		error = nandfs_touch_segment(fsdev, 0);
108235537Sgber		if (error) {
109235537Sgber			nandfs_error("%s: cannot dirty block with segment 0\n",
110235537Sgber			    __func__);
111235537Sgber			return (error);
112235537Sgber		}
113235537Sgber		start_block = fsdev->nd_last_pseg + (uint64_t)nblocks;
114235537Sgber		/*
115235537Sgber		 * XXX Hack
116235537Sgber		 */
117235537Sgber		if (blks_per_seg - (start_block % blks_per_seg) - 1 == 0)
118235537Sgber			start_block++;
119235537Sgber		curr = nandfs_get_segnum_of_block(fsdev, start_block);
120235537Sgber		/* Allocate new segment if last one is full */
121235537Sgber		if (fsdev->nd_seg_num != curr) {
122235537Sgber			error = nandfs_new_segment(fsdev);
123235537Sgber			if (error) {
124235537Sgber				nandfs_error("%s: cannot create new segment\n",
125235537Sgber				    __func__);
126235537Sgber				return (error);
127235537Sgber			}
128235537Sgber			/*
129235537Sgber			 * XXX Hack
130235537Sgber			 */
131235537Sgber			nandfs_get_segment_range(fsdev, fsdev->nd_seg_num, &start_block, NULL);
132235537Sgber		}
133235537Sgber	} else {
134235537Sgber		nandfs_get_segment_range(fsdev, fsdev->nd_next_seg_num,
135235537Sgber		    &start_block, NULL);
136235537Sgber
137235537Sgber		/* Touch current segment and allocate and touch new one */
138235537Sgber		error = nandfs_new_segment(fsdev);
139235537Sgber		if (error) {
140235537Sgber			nandfs_error("%s: cannot create next segment\n",
141235537Sgber			    __func__);
142235537Sgber			return (error);
143235537Sgber		}
144235537Sgber
145235537Sgber		/* Reiterate in case new buf is dirty */
146235537Sgber		seginfo->reiterate = 1;
147235537Sgber	}
148235537Sgber
149235537Sgber	/* Allocate and initialize nandfs_segment structure */
150235537Sgber	seg = malloc(sizeof(*seg), M_DEVBUF, M_WAITOK|M_ZERO);
151235537Sgber	TAILQ_INIT(&seg->segsum);
152235537Sgber	TAILQ_INIT(&seg->data);
153235537Sgber	seg->fsdev = fsdev;
154235537Sgber	seg->start_block = start_block;
155235537Sgber	seg->num_blocks = blks_per_seg - (start_block % blks_per_seg) - 1;
156235537Sgber	seg->seg_num = fsdev->nd_seg_num;
157235537Sgber	seg->seg_next = fsdev->nd_next_seg_num;
158235537Sgber	seg->segsum_blocks = 1;
159235537Sgber	seg->bytes_left = fsdev->nd_blocksize -
160235537Sgber	    sizeof(struct nandfs_segment_summary);
161235537Sgber	seg->segsum_bytes = sizeof(struct nandfs_segment_summary);
162235537Sgber
163235537Sgber	/* Allocate buffer for segment summary */
164235537Sgber	bp = getblk(fsdev->nd_devvp, nandfs_block_to_dblock(fsdev,
165235537Sgber	    seg->start_block), fsdev->nd_blocksize, 0, 0, 0);
166235537Sgber	bzero(bp->b_data, seginfo->fsdev->nd_blocksize);
167235537Sgber	bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
168235537Sgber	bp->b_flags |= B_MANAGED;
169235537Sgber
170235537Sgber	/* Add buffer to segment */
171235537Sgber	TAILQ_INSERT_TAIL(&seg->segsum, bp, b_cluster.cluster_entry);
172235537Sgber	seg->current_off = bp->b_data + sizeof(struct nandfs_segment_summary);
173235537Sgber
174235537Sgber	DPRINTF(SYNC, ("%s: seg %p : initial settings: start %#jx size :%#x\n",
175235537Sgber	    __func__, seg, (uintmax_t)seg->start_block, seg->num_blocks));
176235537Sgber	DPRINTF(SYNC, ("%s: seg->seg_num %#jx cno %#jx next %#jx\n", __func__,
177235537Sgber	    (uintmax_t)seg->seg_num, (uintmax_t)(fsdev->nd_last_cno + 1),
178235537Sgber	    (uintmax_t)seg->seg_next));
179235537Sgber
180235537Sgber	if (!prev)
181235537Sgber		LIST_INSERT_HEAD(&seginfo->seg_list, seg, seg_link);
182235537Sgber	else
183235537Sgber		LIST_INSERT_AFTER(prev, seg, seg_link);
184235537Sgber
185235537Sgber	seginfo->curseg = seg;
186235537Sgber
187235537Sgber	return (0);
188235537Sgber}
189235537Sgber
190235537Sgberstatic int
191235537Sgberdelete_segment(struct nandfs_seginfo *seginfo)
192235537Sgber{
193235537Sgber	struct nandfs_segment *seg, *tseg;
194235537Sgber	struct buf *bp, *tbp;
195235537Sgber
196235537Sgber	LIST_FOREACH_SAFE(seg, &seginfo->seg_list, seg_link, tseg) {
197235537Sgber		TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry,
198235537Sgber		    tbp) {
199235537Sgber			TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
200235537Sgber			bp->b_flags &= ~B_MANAGED;
201235537Sgber			brelse(bp);
202235537Sgber		};
203235537Sgber
204235537Sgber		LIST_REMOVE(seg, seg_link);
205235537Sgber		free(seg, M_DEVBUF);
206235537Sgber	}
207235537Sgber
208235537Sgber	return (0);
209235537Sgber}
210235537Sgber
211235537Sgberstatic int
212235537Sgbercreate_seginfo(struct nandfs_device *fsdev, struct nandfs_seginfo **seginfo)
213235537Sgber{
214235537Sgber	struct nandfs_seginfo *info;
215235537Sgber
216235537Sgber	info = malloc(sizeof(*info), M_DEVBUF, M_WAITOK);
217235537Sgber
218235537Sgber	LIST_INIT(&info->seg_list);
219235537Sgber	info->fsdev = fsdev;
220235537Sgber	info->curseg = NULL;
221235537Sgber	info->blocks = 0;
222235537Sgber	*seginfo = info;
223235537Sgber	fsdev->nd_seginfo = info;
224235537Sgber	return (0);
225235537Sgber}
226235537Sgber
227235537Sgberstatic int
228235537Sgberdelete_seginfo(struct nandfs_seginfo *seginfo)
229235537Sgber{
230235537Sgber	struct nandfs_device *nffsdev;
231235537Sgber
232235537Sgber	nffsdev = seginfo->fsdev;
233235537Sgber	delete_segment(seginfo);
234235537Sgber	nffsdev->nd_seginfo = NULL;
235235537Sgber	free(seginfo, M_DEVBUF);
236235537Sgber
237235537Sgber	return (0);
238235537Sgber}
239235537Sgber
240235537Sgberstatic int
241235537Sgbernandfs_create_superroot_block(struct nandfs_seginfo *seginfo,
242235537Sgber    struct buf **newbp)
243235537Sgber{
244235537Sgber	struct buf *bp;
245235537Sgber	int error;
246235537Sgber
247235537Sgber	bp = nandfs_geteblk(seginfo->fsdev->nd_blocksize, GB_NOWAIT_BD);
248235537Sgber
249235537Sgber	bzero(bp->b_data, seginfo->fsdev->nd_blocksize);
250235537Sgber	bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
251235537Sgber	bp->b_flags |= B_MANAGED;
252235537Sgber
253235537Sgber	if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
254235537Sgber		error = create_segment(seginfo);
255235537Sgber		if (error) {
256235537Sgber			brelse(bp);
257235537Sgber			nandfs_error("%s: no segment for superroot\n",
258235537Sgber			    __func__);
259235537Sgber			return (error);
260235537Sgber		}
261235537Sgber	}
262235537Sgber
263235537Sgber	TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry);
264235537Sgber
265235537Sgber	seginfo->curseg->nblocks++;
266235537Sgber	seginfo->curseg->num_blocks--;
267235537Sgber	seginfo->blocks++;
268235537Sgber
269235537Sgber	*newbp = bp;
270235537Sgber	return (0);
271235537Sgber}
272235537Sgber
273235537Sgberstatic int
274235537Sgbernandfs_add_superroot(struct nandfs_seginfo *seginfo)
275235537Sgber{
276235537Sgber	struct nandfs_device *fsdev;
277235537Sgber	struct nandfs_super_root *sr;
278235537Sgber	struct buf *bp = NULL;
279235537Sgber	uint64_t crc_skip;
280235537Sgber	uint32_t crc_calc;
281235537Sgber	int error;
282235537Sgber
283235537Sgber	fsdev = seginfo->fsdev;
284235537Sgber
285235537Sgber	error = nandfs_create_superroot_block(seginfo, &bp);
286235537Sgber	if (error) {
287235537Sgber		nandfs_error("%s: cannot add superroot\n", __func__);
288235537Sgber		return (error);
289235537Sgber	}
290235537Sgber
291235537Sgber	sr = (struct nandfs_super_root *)bp->b_data;
292235537Sgber	/* Save superroot CRC */
293235537Sgber	sr->sr_bytes = NANDFS_SR_BYTES;
294235537Sgber	sr->sr_flags = 0;
295235537Sgber	sr->sr_nongc_ctime = 0;
296235537Sgber
297235537Sgber	memcpy(&sr->sr_dat, &fsdev->nd_dat_node->nn_inode,
298235537Sgber	    sizeof(struct nandfs_inode));
299235537Sgber	memcpy(&sr->sr_cpfile, &fsdev->nd_cp_node->nn_inode,
300235537Sgber	    sizeof(struct nandfs_inode));
301235537Sgber	memcpy(&sr->sr_sufile, &fsdev->nd_su_node->nn_inode,
302235537Sgber	    sizeof(struct nandfs_inode));
303235537Sgber
304235537Sgber	crc_skip = sizeof(sr->sr_sum);
305235537Sgber	crc_calc = crc32((uint8_t *)sr + crc_skip, NANDFS_SR_BYTES - crc_skip);
306235537Sgber
307235537Sgber	sr->sr_sum = crc_calc;
308235537Sgber
309235537Sgber	bp->b_flags |= B_MANAGED;
310235537Sgber	bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
311235537Sgber
312235537Sgber	bp->b_flags &= ~B_INVAL;
313235537Sgber	nandfs_dirty_bufs_increment(fsdev);
314235537Sgber	DPRINTF(SYNC, ("%s: bp:%p\n", __func__, bp));
315235537Sgber
316235537Sgber	return (0);
317235537Sgber}
318235537Sgber
319235537Sgberstatic int
320235537Sgbernandfs_add_segsum_block(struct nandfs_seginfo *seginfo, struct buf **newbp)
321235537Sgber{
322235537Sgber	struct nandfs_device *fsdev;
323235537Sgber	nandfs_daddr_t blk;
324235537Sgber	struct buf *bp;
325235537Sgber	int error;
326235537Sgber
327235537Sgber	if (!(seginfo->curseg) || seginfo->curseg->num_blocks <= 1) {
328235537Sgber		error = create_segment(seginfo);
329235537Sgber		if (error) {
330235537Sgber			nandfs_error("%s: error:%d when creating segment\n",
331235537Sgber			    __func__, error);
332235537Sgber			return (error);
333235537Sgber		}
334235537Sgber		*newbp = TAILQ_FIRST(&seginfo->curseg->segsum);
335235537Sgber		return (0);
336235537Sgber	}
337235537Sgber
338235537Sgber	fsdev = seginfo->fsdev;
339235537Sgber	blk = nandfs_block_to_dblock(fsdev, seginfo->curseg->start_block +
340235537Sgber	    seginfo->curseg->segsum_blocks);
341235537Sgber
342235537Sgber	bp = getblk(fsdev->nd_devvp, blk, fsdev->nd_blocksize, 0, 0, 0);
343235537Sgber
344235537Sgber	bzero(bp->b_data, seginfo->fsdev->nd_blocksize);
345235537Sgber	bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
346235537Sgber	bp->b_flags |= B_MANAGED;
347235537Sgber
348235537Sgber	TAILQ_INSERT_TAIL(&seginfo->curseg->segsum, bp,
349235537Sgber	    b_cluster.cluster_entry);
350235537Sgber	seginfo->curseg->num_blocks--;
351235537Sgber
352235537Sgber	seginfo->curseg->segsum_blocks++;
353235537Sgber	seginfo->curseg->bytes_left = seginfo->fsdev->nd_blocksize;
354235537Sgber	seginfo->curseg->current_off = bp->b_data;
355235537Sgber	seginfo->blocks++;
356235537Sgber
357235537Sgber	*newbp = bp;
358235537Sgber
359235537Sgber	DPRINTF(SYNC, ("%s: bp %p\n", __func__, bp));
360235537Sgber
361235537Sgber	return (0);
362235537Sgber}
363235537Sgber
364235537Sgberstatic int
365235537Sgbernandfs_add_blocks(struct nandfs_seginfo *seginfo, struct nandfs_node *node,
366235537Sgber    struct buf *bp)
367235537Sgber{
368235537Sgber	union nandfs_binfo *binfo;
369235537Sgber	struct buf *seg_bp;
370235537Sgber	int error;
371235537Sgber
372235537Sgber	if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
373235537Sgber		error = create_segment(seginfo);
374235537Sgber		if (error) {
375235537Sgber			nandfs_error("%s: error:%d when creating segment\n",
376235537Sgber			    __func__, error);
377235537Sgber			return (error);
378235537Sgber		}
379235537Sgber	}
380235537Sgber
381235537Sgber	if (seginfo->curseg->bytes_left < sizeof(union nandfs_binfo)) {
382235537Sgber		error = nandfs_add_segsum_block(seginfo, &seg_bp);
383235537Sgber		if (error) {
384235537Sgber			nandfs_error("%s: error:%d when adding segsum\n",
385235537Sgber			    __func__, error);
386235537Sgber			return (error);
387235537Sgber		}
388235537Sgber	}
389235537Sgber	binfo = (union nandfs_binfo *)seginfo->curseg->current_off;
390235537Sgber
391235537Sgber	if (node->nn_ino != NANDFS_DAT_INO) {
392235537Sgber		binfo->bi_v.bi_blkoff = bp->b_lblkno;
393235537Sgber		binfo->bi_v.bi_ino = node->nn_ino;
394235537Sgber	} else {
395235537Sgber		binfo->bi_dat.bi_blkoff = bp->b_lblkno;
396235537Sgber		binfo->bi_dat.bi_ino = node->nn_ino;
397235537Sgber		if (NANDFS_IS_INDIRECT(bp))
398235537Sgber			binfo->bi_dat.bi_level = 1;
399235537Sgber		else
400235537Sgber			binfo->bi_dat.bi_level = 0;
401235537Sgber	}
402235537Sgber	binfo++;
403235537Sgber
404235537Sgber	seginfo->curseg->bytes_left -= sizeof(union nandfs_binfo);
405235537Sgber	seginfo->curseg->segsum_bytes += sizeof(union nandfs_binfo);
406235537Sgber	seginfo->curseg->current_off = (char *)binfo;
407235537Sgber
408235537Sgber	TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry);
409235537Sgber
410235537Sgber	seginfo->curseg->nbinfos++;
411235537Sgber	seginfo->curseg->nblocks++;
412235537Sgber	seginfo->curseg->num_blocks--;
413235537Sgber	seginfo->blocks++;
414235537Sgber
415235537Sgber	DPRINTF(SYNC, ("%s: bp (%p) number %x (left %x)\n",
416235537Sgber	    __func__, bp, seginfo->curseg->nblocks,
417235537Sgber	    seginfo->curseg->num_blocks));
418235537Sgber	return (0);
419235537Sgber}
420235537Sgber
421235537Sgberstatic int
422235537Sgbernandfs_iterate_dirty_buf(struct vnode *vp, struct nandfs_seginfo *seginfo,
423235537Sgber    uint8_t hold)
424235537Sgber{
425235537Sgber	struct buf *bp, *tbd;
426235537Sgber	struct bufobj *bo;
427235537Sgber	struct nandfs_node *node;
428235537Sgber	int error;
429235537Sgber
430235537Sgber	node = VTON(vp);
431235537Sgber	bo = &vp->v_bufobj;
432235537Sgber
433235537Sgber	ASSERT_VOP_ELOCKED(vp, __func__);
434235537Sgber
435235537Sgber	/* Iterate dirty data bufs */
436235537Sgber	TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, tbd) {
437235537Sgber		DPRINTF(SYNC, ("%s: vp (%p): bp (%p) with lblkno %jx ino %jx "
438235537Sgber		    "add buf\n", __func__, vp, bp, bp->b_lblkno, node->nn_ino));
439235537Sgber
440235537Sgber		if (!(NANDFS_ISGATHERED(bp))) {
441235537Sgber			error = nandfs_bmap_update_dat(node,
442235537Sgber			    nandfs_vblk_get(bp), bp);
443235537Sgber			if (error)
444235537Sgber				return (error);
445235537Sgber			NANDFS_GATHER(bp);
446235537Sgber			nandfs_add_blocks(seginfo, node, bp);
447235537Sgber		}
448235537Sgber	}
449235537Sgber
450235537Sgber	return (0);
451235537Sgber}
452235537Sgber
453235537Sgberstatic int
454235537Sgbernandfs_iterate_system_vnode(struct nandfs_node *node,
455235537Sgber    struct nandfs_seginfo *seginfo)
456235537Sgber{
457235537Sgber	struct vnode *vp;
458235537Sgber	int nblocks;
459235537Sgber	uint8_t hold = 0;
460235537Sgber
461235537Sgber	if (node->nn_ino != NANDFS_IFILE_INO)
462235537Sgber		hold = 1;
463235537Sgber
464235537Sgber	vp = NTOV(node);
465235537Sgber
466235537Sgber	nblocks = vp->v_bufobj.bo_dirty.bv_cnt;
467235537Sgber	DPRINTF(SYNC, ("%s: vp (%p): nblocks %x ino %jx\n",
468235537Sgber	    __func__, vp, nblocks, node->nn_ino));
469235537Sgber
470235537Sgber	if (nblocks)
471235537Sgber		nandfs_iterate_dirty_buf(vp, seginfo, hold);
472235537Sgber
473235537Sgber	return (0);
474235537Sgber}
475235537Sgber
476235537Sgberstatic int
477235537Sgbernandfs_iterate_dirty_vnodes(struct mount *mp, struct nandfs_seginfo *seginfo)
478235537Sgber{
479235537Sgber	struct nandfs_node *nandfs_node;
480235537Sgber	struct vnode *vp, *mvp;
481235537Sgber	struct thread *td;
482245000Skib	int error, update;
483235537Sgber
484235537Sgber	td = curthread;
485235537Sgber
486245000Skib	MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) {
487235537Sgber		update = 0;
488235537Sgber
489245000Skib		if (mp->mnt_syncer == vp || VOP_ISLOCKED(vp)) {
490235537Sgber			VI_UNLOCK(vp);
491235537Sgber			continue;
492235537Sgber		}
493245000Skib		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK | LK_NOWAIT, td) != 0)
494235537Sgber			continue;
495235537Sgber
496235537Sgber		nandfs_node = VTON(vp);
497235537Sgber		if (nandfs_node->nn_flags & IN_MODIFIED) {
498235537Sgber			nandfs_node->nn_flags &= ~(IN_MODIFIED);
499235537Sgber			update = 1;
500235537Sgber		}
501235537Sgber
502235537Sgber		if (vp->v_bufobj.bo_dirty.bv_cnt) {
503235537Sgber			error = nandfs_iterate_dirty_buf(vp, seginfo, 0);
504235537Sgber			if (error) {
505235537Sgber				nandfs_error("%s: cannot iterate vnode:%p "
506235537Sgber				    "err:%d\n", __func__, vp, error);
507235537Sgber				vput(vp);
508235537Sgber				return (error);
509235537Sgber			}
510235537Sgber			update = 1;
511235537Sgber		} else
512235537Sgber			vput(vp);
513235537Sgber
514235537Sgber		if (update)
515235537Sgber			nandfs_node_update(nandfs_node);
516235537Sgber	}
517235537Sgber
518235537Sgber	return (0);
519235537Sgber}
520235537Sgber
521235537Sgberstatic int
522235537Sgbernandfs_update_phys_block(struct nandfs_device *fsdev, struct buf *bp,
523235537Sgber    uint64_t phys_blknr, union nandfs_binfo *binfo)
524235537Sgber{
525235537Sgber	struct nandfs_node *node, *dat;
526235537Sgber	struct vnode *vp;
527235537Sgber	uint64_t new_blknr;
528235537Sgber	int error;
529235537Sgber
530235537Sgber	vp = bp->b_vp;
531235537Sgber	node = VTON(vp);
532235537Sgber	new_blknr = nandfs_vblk_get(bp);
533235537Sgber	dat = fsdev->nd_dat_node;
534235537Sgber
535235537Sgber	DPRINTF(BMAP, ("%s: ino %#jx lblk %#jx: vblk %#jx -> %#jx\n",
536235537Sgber	    __func__, (uintmax_t)node->nn_ino, (uintmax_t)bp->b_lblkno,
537235537Sgber	    (uintmax_t)new_blknr, (uintmax_t)phys_blknr));
538235537Sgber
539235537Sgber	if (node->nn_ino != NANDFS_DAT_INO) {
540235537Sgber		KASSERT((new_blknr != 0), ("vblk for bp %p is 0", bp));
541235537Sgber
542235537Sgber		nandfs_vblock_assign(fsdev, new_blknr, phys_blknr);
543235537Sgber		binfo->bi_v.bi_vblocknr = new_blknr;
544235537Sgber		binfo->bi_v.bi_blkoff = bp->b_lblkno;
545235537Sgber		binfo->bi_v.bi_ino = node->nn_ino;
546235537Sgber	} else {
547235537Sgber		VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
548235537Sgber		error = nandfs_bmap_update_block(node, bp, phys_blknr);
549235537Sgber		if (error) {
550235537Sgber			nandfs_error("%s: error updating block:%jx for bp:%p\n",
551235537Sgber			    __func__, (uintmax_t)phys_blknr, bp);
552235537Sgber			VOP_UNLOCK(NTOV(dat), 0);
553235537Sgber			return (error);
554235537Sgber		}
555235537Sgber		VOP_UNLOCK(NTOV(dat), 0);
556235537Sgber		binfo->bi_dat.bi_blkoff = bp->b_lblkno;
557235537Sgber		binfo->bi_dat.bi_ino = node->nn_ino;
558235537Sgber		if (NANDFS_IS_INDIRECT(bp))
559235537Sgber			binfo->bi_dat.bi_level = 1;
560235537Sgber		else
561235537Sgber			binfo->bi_dat.bi_level = 0;
562235537Sgber	}
563235537Sgber
564235537Sgber	return (0);
565235537Sgber}
566235537Sgber
567235537Sgber#define	NBINFO(off) ((off) + sizeof(union nandfs_binfo))
568235537Sgberstatic int
569235537Sgbernandfs_segment_assign_pblk(struct nandfs_segment *nfsseg)
570235537Sgber{
571235537Sgber	struct nandfs_device *fsdev;
572235537Sgber	union nandfs_binfo *binfo;
573235537Sgber	struct buf *bp, *seg_bp;
574235537Sgber	uint64_t blocknr;
575235537Sgber	uint32_t curr_off, blocksize;
576235537Sgber	int error;
577235537Sgber
578235537Sgber	fsdev = nfsseg->fsdev;
579235537Sgber	blocksize = fsdev->nd_blocksize;
580235537Sgber
581235537Sgber	blocknr = nfsseg->start_block + nfsseg->segsum_blocks;
582235537Sgber	seg_bp = TAILQ_FIRST(&nfsseg->segsum);
583235537Sgber	DPRINTF(SYNC, ("%s: seg:%p segsum bp:%p data:%p\n",
584235537Sgber	    __func__, nfsseg, seg_bp, seg_bp->b_data));
585235537Sgber
586235537Sgber	binfo = (union nandfs_binfo *)(seg_bp->b_data +
587235537Sgber	    sizeof(struct nandfs_segment_summary));
588235537Sgber	curr_off = sizeof(struct nandfs_segment_summary);
589235537Sgber
590235537Sgber	TAILQ_FOREACH(bp, &nfsseg->data, b_cluster.cluster_entry) {
591235537Sgber		KASSERT((bp->b_vp), ("bp %p has not vp", bp));
592235537Sgber
593235537Sgber		DPRINTF(BMAP, ("\n\n%s: assign buf %p for ino %#jx next %p\n",
594235537Sgber		    __func__, bp, (uintmax_t)VTON(bp->b_vp)->nn_ino,
595235537Sgber		    TAILQ_NEXT(bp, b_cluster.cluster_entry)));
596235537Sgber
597235537Sgber		if (NBINFO(curr_off) > blocksize) {
598235537Sgber			seg_bp = TAILQ_NEXT(seg_bp, b_cluster.cluster_entry);
599235537Sgber			binfo = (union nandfs_binfo *)seg_bp->b_data;
600235537Sgber			curr_off = 0;
601235537Sgber			DPRINTF(SYNC, ("%s: next segsum %p data %p\n",
602235537Sgber			    __func__, seg_bp, seg_bp->b_data));
603235537Sgber		}
604235537Sgber
605235537Sgber		error = nandfs_update_phys_block(fsdev, bp, blocknr, binfo);
606235537Sgber		if (error) {
607235537Sgber			nandfs_error("%s: err:%d when updatinng phys block:%jx"
608235537Sgber			    " for bp:%p and binfo:%p\n", __func__, error,
609235537Sgber			    (uintmax_t)blocknr, bp, binfo);
610235537Sgber			return (error);
611235537Sgber		}
612235537Sgber		binfo++;
613235537Sgber		curr_off = NBINFO(curr_off);
614235537Sgber
615235537Sgber		blocknr++;
616235537Sgber	}
617235537Sgber
618235537Sgber	return (0);
619235537Sgber}
620235537Sgber
621235537Sgberstatic int
622235537Sgbernandfs_seginfo_assign_pblk(struct nandfs_seginfo *seginfo)
623235537Sgber{
624235537Sgber	struct nandfs_segment *nfsseg;
625235537Sgber	int error = 0;
626235537Sgber
627235537Sgber	LIST_FOREACH(nfsseg, &seginfo->seg_list, seg_link) {
628235537Sgber		error = nandfs_segment_assign_pblk(nfsseg);
629235537Sgber		if (error)
630235537Sgber			break;
631235537Sgber	}
632235537Sgber
633235537Sgber	return (error);
634235537Sgber}
635235537Sgber
636235537Sgberstatic struct nandfs_segment_summary *
637235537Sgbernandfs_fill_segsum(struct nandfs_segment *seg, int has_sr)
638235537Sgber{
639235537Sgber	struct nandfs_segment_summary *ss;
640235537Sgber	struct nandfs_device *fsdev;
641235537Sgber	struct buf *bp;
642235537Sgber	uint32_t rest, segsum_size, blocksize, crc_calc;
643235537Sgber	uint16_t flags;
644235537Sgber	uint8_t *crc_area, crc_skip;
645235537Sgber
646235537Sgber	DPRINTF(SYNC, ("%s: seg %#jx nblocks %#x sumbytes %#x\n",
647235537Sgber	    __func__, (uintmax_t) seg->seg_num,
648235537Sgber	    seg->nblocks + seg->segsum_blocks,
649235537Sgber	    seg->segsum_bytes));
650235537Sgber
651235537Sgber	fsdev = seg->fsdev;
652235537Sgber
653235537Sgber	flags = NANDFS_SS_LOGBGN | NANDFS_SS_LOGEND;
654235537Sgber	if (has_sr)
655235537Sgber		flags |= NANDFS_SS_SR;
656235537Sgber
657235537Sgber	bp = TAILQ_FIRST(&seg->segsum);
658235537Sgber	ss = (struct nandfs_segment_summary *) bp->b_data;
659235537Sgber	ss->ss_magic = NANDFS_SEGSUM_MAGIC;
660235537Sgber	ss->ss_bytes = sizeof(struct nandfs_segment_summary);
661235537Sgber	ss->ss_flags = flags;
662235537Sgber	ss->ss_seq = ++(fsdev->nd_seg_sequence);
663235537Sgber	ss->ss_create = fsdev->nd_ts.tv_sec;
664235537Sgber	nandfs_get_segment_range(fsdev, seg->seg_next, &ss->ss_next, NULL);
665235537Sgber	ss->ss_nblocks = seg->nblocks + seg->segsum_blocks;
666235537Sgber	ss->ss_nbinfos = seg->nbinfos;
667235537Sgber	ss->ss_sumbytes = seg->segsum_bytes;
668235537Sgber
669235537Sgber	crc_skip = sizeof(ss->ss_datasum) + sizeof(ss->ss_sumsum);
670235537Sgber	blocksize = seg->fsdev->nd_blocksize;
671235537Sgber
672235537Sgber	segsum_size = seg->segsum_bytes - crc_skip;
673235537Sgber	rest = min(seg->segsum_bytes, blocksize) - crc_skip;
674235537Sgber	crc_area = (uint8_t *)ss + crc_skip;
675235537Sgber	crc_calc = ~0U;
676235537Sgber	while (segsum_size > 0) {
677235537Sgber		crc_calc = crc32_raw(crc_area, rest, crc_calc);
678235537Sgber		segsum_size -= rest;
679235537Sgber		if (!segsum_size)
680235537Sgber			break;
681235537Sgber		bp = TAILQ_NEXT(bp, b_cluster.cluster_entry);
682235537Sgber		crc_area = (uint8_t *)bp->b_data;
683235537Sgber		rest = segsum_size <= blocksize ? segsum_size : blocksize;
684235537Sgber	}
685235537Sgber	ss->ss_sumsum = crc_calc ^ ~0U;
686235537Sgber
687235537Sgber	return (ss);
688235537Sgber
689235537Sgber}
690235537Sgber
691235537Sgberstatic int
692235537Sgbernandfs_save_buf(struct buf *bp, uint64_t blocknr, struct nandfs_device *fsdev)
693235537Sgber{
694235537Sgber	struct bufobj *bo;
695235537Sgber	int error;
696235537Sgber
697235537Sgber	bo = &fsdev->nd_devvp->v_bufobj;
698235537Sgber
699235537Sgber	bp->b_blkno = nandfs_block_to_dblock(fsdev, blocknr);
700235537Sgber	bp->b_iooffset = dbtob(bp->b_blkno);
701235537Sgber
702235537Sgber	KASSERT(bp->b_bufobj != NULL, ("no bufobj for %p", bp));
703235537Sgber	if (bp->b_bufobj != bo) {
704235537Sgber		BO_LOCK(bp->b_bufobj);
705235537Sgber		BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK,
706251171Sjeff		    BO_LOCKPTR(bp->b_bufobj));
707235537Sgber		KASSERT(BUF_ISLOCKED(bp), ("Problem with locking buffer"));
708235537Sgber	}
709235537Sgber
710235537Sgber	DPRINTF(SYNC, ("%s: buf: %p offset %#jx blk %#jx size %#x\n",
711235537Sgber	    __func__, bp, (uintmax_t)bp->b_offset, (uintmax_t)blocknr,
712235537Sgber	    fsdev->nd_blocksize));
713235537Sgber
714235537Sgber	NANDFS_UNGATHER(bp);
715235537Sgber	nandfs_buf_clear(bp, 0xffffffff);
716235537Sgber	bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED);
717235537Sgber	error = bwrite(bp);
718235537Sgber	if (error) {
719235537Sgber		nandfs_error("%s: error:%d when writing buffer:%p\n",
720235537Sgber		    __func__, error, bp);
721235537Sgber		return (error);
722235537Sgber	}
723235537Sgber	return (error);
724235537Sgber}
725235537Sgber
726235537Sgberstatic void
727235537Sgbernandfs_clean_buf(struct nandfs_device *fsdev, struct buf *bp)
728235537Sgber{
729235537Sgber
730235537Sgber	DPRINTF(SYNC, ("%s: buf: %p\n", __func__, bp));
731235537Sgber
732235537Sgber	NANDFS_UNGATHER(bp);
733235537Sgber	nandfs_buf_clear(bp, 0xffffffff);
734235537Sgber	bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED);
735235537Sgber	nandfs_undirty_buf_fsdev(fsdev, bp);
736235537Sgber}
737235537Sgber
738235537Sgberstatic void
739235537Sgbernandfs_clean_segblocks(struct nandfs_segment *seg, uint8_t unlock)
740235537Sgber{
741235537Sgber	struct nandfs_device *fsdev = seg->fsdev;
742235537Sgber	struct nandfs_segment *next_seg;
743235537Sgber	struct buf *bp, *tbp, *next_bp;
744235537Sgber	struct vnode *vp, *next_vp;
745235537Sgber
746235537Sgber	VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE);
747235537Sgber	TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) {
748235537Sgber		TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
749235537Sgber		nandfs_clean_buf(fsdev, bp);
750235537Sgber	};
751235537Sgber
752235537Sgber	TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) {
753235537Sgber		TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry);
754235537Sgber
755235537Sgber		/*
756235537Sgber		 * If bp is not super-root and vnode is not currently
757235537Sgber		 * locked lock it.
758235537Sgber		 */
759235537Sgber		vp = bp->b_vp;
760235537Sgber		next_vp = NULL;
761235537Sgber		next_bp = TAILQ_NEXT(bp,  b_cluster.cluster_entry);
762235537Sgber		if (!next_bp) {
763235537Sgber			next_seg = LIST_NEXT(seg, seg_link);
764235537Sgber			if (next_seg)
765235537Sgber				next_bp = TAILQ_FIRST(&next_seg->data);
766235537Sgber		}
767235537Sgber
768235537Sgber		if (next_bp)
769235537Sgber			next_vp = next_bp->b_vp;
770235537Sgber
771235537Sgber		nandfs_clean_buf(fsdev, bp);
772235537Sgber
773235537Sgber		if (unlock && vp != NULL && next_vp != vp &&
774235537Sgber		    !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
775235537Sgber			vput(vp);
776235537Sgber
777235537Sgber		nandfs_dirty_bufs_decrement(fsdev);
778235537Sgber	}
779235537Sgber
780235537Sgber	VOP_UNLOCK(fsdev->nd_devvp, 0);
781235537Sgber}
782235537Sgber
783235537Sgberstatic int
784235537Sgbernandfs_save_segblocks(struct nandfs_segment *seg, uint8_t unlock)
785235537Sgber{
786235537Sgber	struct nandfs_device *fsdev = seg->fsdev;
787235537Sgber	struct nandfs_segment *next_seg;
788235537Sgber	struct buf *bp, *tbp, *next_bp;
789235537Sgber	struct vnode *vp, *next_vp;
790235537Sgber	uint64_t blocknr;
791235537Sgber	uint32_t i = 0;
792235537Sgber	int error = 0;
793235537Sgber
794235537Sgber	VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE);
795235537Sgber	TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) {
796235537Sgber		TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
797235537Sgber		blocknr = seg->start_block + i;
798235537Sgber		error = nandfs_save_buf(bp, blocknr, fsdev);
799235537Sgber		if (error) {
800235537Sgber			nandfs_error("%s: error saving buf: %p blocknr:%jx\n",
801235537Sgber			    __func__, bp, (uintmax_t)blocknr);
802235537Sgber			goto out;
803235537Sgber		}
804235537Sgber		i++;
805235537Sgber	};
806235537Sgber
807235537Sgber	i = 0;
808235537Sgber	TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) {
809235537Sgber		TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry);
810235537Sgber
811235537Sgber		blocknr = seg->start_block + seg->segsum_blocks + i;
812235537Sgber		/*
813235537Sgber		 * If bp is not super-root and vnode is not currently
814235537Sgber		 * locked lock it.
815235537Sgber		 */
816235537Sgber		vp = bp->b_vp;
817235537Sgber		next_vp = NULL;
818235537Sgber		next_bp = TAILQ_NEXT(bp,  b_cluster.cluster_entry);
819235537Sgber		if (!next_bp) {
820235537Sgber			next_seg = LIST_NEXT(seg, seg_link);
821235537Sgber			if (next_seg)
822235537Sgber				next_bp = TAILQ_FIRST(&next_seg->data);
823235537Sgber		}
824235537Sgber
825235537Sgber		if (next_bp)
826235537Sgber			next_vp = next_bp->b_vp;
827235537Sgber
828235537Sgber		error = nandfs_save_buf(bp, blocknr, fsdev);
829235537Sgber		if (error) {
830235537Sgber			nandfs_error("%s: error saving buf: %p blknr: %jx\n",
831235537Sgber			    __func__, bp, (uintmax_t)blocknr);
832235537Sgber			if (unlock && vp != NULL && next_vp != vp &&
833235537Sgber			    !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
834235537Sgber				vput(vp);
835235537Sgber			goto out;
836235537Sgber		}
837235537Sgber
838235537Sgber		if (unlock && vp != NULL && next_vp != vp &&
839235537Sgber		    !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
840235537Sgber			vput(vp);
841235537Sgber
842235537Sgber		i++;
843235537Sgber		nandfs_dirty_bufs_decrement(fsdev);
844235537Sgber	}
845235537Sgberout:
846235537Sgber	if (error) {
847235537Sgber		nandfs_clean_segblocks(seg, unlock);
848235537Sgber		VOP_UNLOCK(fsdev->nd_devvp, 0);
849235537Sgber		return (error);
850235537Sgber	}
851235537Sgber
852235537Sgber	VOP_UNLOCK(fsdev->nd_devvp, 0);
853235537Sgber	return (error);
854235537Sgber}
855235537Sgber
856235537Sgber
857235537Sgberstatic void
858235537Sgberclean_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock)
859235537Sgber{
860235537Sgber	struct nandfs_segment *seg;
861235537Sgber
862235537Sgber	DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo));
863235537Sgber
864235537Sgber	LIST_FOREACH(seg, &seginfo->seg_list, seg_link) {
865235537Sgber		nandfs_clean_segblocks(seg, unlock);
866235537Sgber	}
867235537Sgber}
868235537Sgber
869235537Sgberstatic int
870235537Sgbersave_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock)
871235537Sgber{
872235537Sgber	struct nandfs_segment *seg;
873235537Sgber	struct nandfs_device *fsdev;
874235537Sgber	struct nandfs_segment_summary *ss;
875235537Sgber	int error = 0;
876235537Sgber
877235537Sgber	fsdev = seginfo->fsdev;
878235537Sgber
879235537Sgber	DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo));
880235537Sgber
881235537Sgber	LIST_FOREACH(seg, &seginfo->seg_list, seg_link) {
882235537Sgber		if (LIST_NEXT(seg, seg_link)) {
883235537Sgber			nandfs_fill_segsum(seg, 0);
884235537Sgber			error = nandfs_save_segblocks(seg, unlock);
885235537Sgber			if (error) {
886235537Sgber				nandfs_error("%s: error:%d saving seg:%p\n",
887235537Sgber				    __func__, error, seg);
888235537Sgber				goto out;
889235537Sgber			}
890235537Sgber		} else {
891235537Sgber			ss = nandfs_fill_segsum(seg, 1);
892235537Sgber			fsdev->nd_last_segsum = *ss;
893235537Sgber			error = nandfs_save_segblocks(seg, unlock);
894235537Sgber			if (error) {
895235537Sgber				nandfs_error("%s: error:%d saving seg:%p\n",
896235537Sgber				    __func__, error, seg);
897235537Sgber				goto out;
898235537Sgber			}
899235537Sgber			fsdev->nd_last_cno++;
900235537Sgber			fsdev->nd_last_pseg = seg->start_block;
901235537Sgber		}
902235537Sgber	}
903235537Sgberout:
904235537Sgber	if (error)
905235537Sgber		clean_seginfo(seginfo, unlock);
906235537Sgber	return (error);
907235537Sgber}
908235537Sgber
909235537Sgberstatic void
910235537Sgbernandfs_invalidate_bufs(struct nandfs_device *fsdev, uint64_t segno)
911235537Sgber{
912235537Sgber	uint64_t start, end;
913235537Sgber	struct buf *bp, *tbd;
914235537Sgber	struct bufobj *bo;
915235537Sgber
916235537Sgber	nandfs_get_segment_range(fsdev, segno, &start, &end);
917235537Sgber
918235537Sgber	bo = &NTOV(fsdev->nd_gc_node)->v_bufobj;
919235537Sgber
920235537Sgber	BO_LOCK(bo);
921235537Sgberrestart_locked_gc:
922235537Sgber	TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, tbd) {
923235537Sgber		if (!(bp->b_lblkno >= start && bp->b_lblkno <= end))
924235537Sgber			continue;
925235537Sgber
926235537Sgber		if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL))
927235537Sgber			goto restart_locked_gc;
928235537Sgber
929235537Sgber		bremfree(bp);
930235537Sgber		bp->b_flags |= (B_INVAL | B_RELBUF);
931235537Sgber		bp->b_flags &= ~(B_ASYNC | B_MANAGED);
932235537Sgber		BO_UNLOCK(bo);
933235537Sgber		brelse(bp);
934235537Sgber		BO_LOCK(bo);
935235537Sgber	}
936235537Sgber	BO_UNLOCK(bo);
937235537Sgber}
938235537Sgber
939235537Sgber/* Process segments marks to free by cleaner */
940235537Sgberstatic void
941235537Sgbernandfs_process_segments(struct nandfs_device *fsdev)
942235537Sgber{
943235537Sgber	uint64_t saved_segment;
944235537Sgber	int i;
945235537Sgber
946235537Sgber	if (fsdev->nd_free_base) {
947235537Sgber		saved_segment = nandfs_get_segnum_of_block(fsdev,
948235537Sgber		    fsdev->nd_super.s_last_pseg);
949235537Sgber		for (i = 0; i < fsdev->nd_free_count; i++) {
950235537Sgber			if (fsdev->nd_free_base[i] == NANDFS_NOSEGMENT)
951235537Sgber				continue;
952235537Sgber			/* Update superblock if clearing segment point by it */
953235537Sgber			if (fsdev->nd_free_base[i] == saved_segment) {
954235537Sgber				nandfs_write_superblock(fsdev);
955235537Sgber				saved_segment = nandfs_get_segnum_of_block(
956235537Sgber				    fsdev, fsdev->nd_super.s_last_pseg);
957235537Sgber			}
958235537Sgber			nandfs_invalidate_bufs(fsdev, fsdev->nd_free_base[i]);
959235537Sgber			nandfs_clear_segment(fsdev, fsdev->nd_free_base[i]);
960235537Sgber		}
961235537Sgber
962235537Sgber		free(fsdev->nd_free_base, M_NANDFSTEMP);
963235537Sgber		fsdev->nd_free_base = NULL;
964235537Sgber		fsdev->nd_free_count = 0;
965235537Sgber	}
966235537Sgber}
967235537Sgber
968235537Sgber/* Collect and write dirty buffers */
969235537Sgberint
970235537Sgbernandfs_sync_file(struct vnode *vp)
971235537Sgber{
972235537Sgber	struct nandfs_device *fsdev;
973235537Sgber	struct nandfs_node *nandfs_node;
974235537Sgber	struct nandfsmount *nmp;
975235537Sgber	struct nandfs_node *dat, *su, *ifile, *cp;
976235537Sgber	struct nandfs_seginfo *seginfo = NULL;
977235537Sgber	struct nandfs_segment *seg;
978235537Sgber	int update, error;
979235537Sgber	int cno_changed;
980235537Sgber
981235537Sgber	ASSERT_VOP_LOCKED(vp, __func__);
982235537Sgber	DPRINTF(SYNC, ("%s: START\n", __func__));
983235537Sgber
984235537Sgber	error = 0;
985235537Sgber	nmp = VFSTONANDFS(vp->v_mount);
986235537Sgber	fsdev = nmp->nm_nandfsdev;
987235537Sgber
988235537Sgber	dat = fsdev->nd_dat_node;
989235537Sgber	su = fsdev->nd_su_node;
990235537Sgber	cp = fsdev->nd_cp_node;
991235537Sgber	ifile = nmp->nm_ifile_node;
992235537Sgber
993235537Sgber	NANDFS_WRITEASSERT(fsdev);
994235537Sgber	if (lockmgr(&fsdev->nd_seg_const, LK_UPGRADE, NULL) != 0) {
995235537Sgber		DPRINTF(SYNC, ("%s: lost shared lock\n", __func__));
996235537Sgber		if (lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL) != 0)
997235537Sgber			panic("couldn't lock exclusive");
998235537Sgber	}
999235537Sgber	DPRINTF(SYNC, ("%s: got lock\n", __func__));
1000235537Sgber
1001235537Sgber	VOP_LOCK(NTOV(su), LK_EXCLUSIVE);
1002235537Sgber	create_seginfo(fsdev, &seginfo);
1003235537Sgber
1004235537Sgber	update = 0;
1005235537Sgber
1006235537Sgber	nandfs_node = VTON(vp);
1007235537Sgber	if (nandfs_node->nn_flags & IN_MODIFIED) {
1008235537Sgber		nandfs_node->nn_flags &= ~(IN_MODIFIED);
1009235537Sgber		update = 1;
1010235537Sgber	}
1011235537Sgber
1012235537Sgber	if (vp->v_bufobj.bo_dirty.bv_cnt) {
1013235537Sgber		error = nandfs_iterate_dirty_buf(vp, seginfo, 0);
1014235537Sgber		if (error) {
1015235537Sgber			clean_seginfo(seginfo, 0);
1016235537Sgber			delete_seginfo(seginfo);
1017235537Sgber			VOP_UNLOCK(NTOV(su), 0);
1018235537Sgber			lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1019235537Sgber			nandfs_error("%s: err:%d iterating dirty bufs vp:%p",
1020235537Sgber			    __func__, error, vp);
1021235537Sgber			return (error);
1022235537Sgber		}
1023235537Sgber		update = 1;
1024235537Sgber	}
1025235537Sgber
1026235537Sgber	if (update) {
1027235537Sgber		VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE);
1028235537Sgber		error = nandfs_node_update(nandfs_node);
1029235537Sgber		if (error) {
1030235537Sgber			clean_seginfo(seginfo, 0);
1031235537Sgber			delete_seginfo(seginfo);
1032235537Sgber			VOP_UNLOCK(NTOV(ifile), 0);
1033235537Sgber			VOP_UNLOCK(NTOV(su), 0);
1034235537Sgber			lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1035235537Sgber			nandfs_error("%s: err:%d updating vp:%p",
1036235537Sgber			    __func__, error, vp);
1037235537Sgber			return (error);
1038235537Sgber		}
1039235537Sgber		VOP_UNLOCK(NTOV(ifile), 0);
1040235537Sgber	}
1041235537Sgber
1042235537Sgber	cno_changed = 0;
1043235537Sgber	if (seginfo->blocks) {
1044235537Sgber		VOP_LOCK(NTOV(cp), LK_EXCLUSIVE);
1045235537Sgber		cno_changed = 1;
1046235537Sgber		/* Create new checkpoint */
1047235537Sgber		error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1);
1048235537Sgber		if (error) {
1049235537Sgber			clean_seginfo(seginfo, 0);
1050235537Sgber			delete_seginfo(seginfo);
1051235537Sgber			VOP_UNLOCK(NTOV(cp), 0);
1052235537Sgber			VOP_UNLOCK(NTOV(su), 0);
1053235537Sgber			lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1054235537Sgber			nandfs_error("%s: err:%d getting cp:%jx",
1055235537Sgber			    __func__, error, fsdev->nd_last_cno + 1);
1056235537Sgber			return (error);
1057235537Sgber		}
1058235537Sgber
1059235537Sgber		/* Reiterate all blocks and assign physical block number */
1060235537Sgber		nandfs_seginfo_assign_pblk(seginfo);
1061235537Sgber
1062235537Sgber		/* Fill checkpoint data */
1063235537Sgber		error = nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1,
1064235537Sgber		    &ifile->nn_inode, seginfo->blocks);
1065235537Sgber		if (error) {
1066235537Sgber			clean_seginfo(seginfo, 0);
1067235537Sgber			delete_seginfo(seginfo);
1068235537Sgber			VOP_UNLOCK(NTOV(cp), 0);
1069235537Sgber			VOP_UNLOCK(NTOV(su), 0);
1070235537Sgber			lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1071235537Sgber			nandfs_error("%s: err:%d setting cp:%jx",
1072235537Sgber			    __func__, error, fsdev->nd_last_cno + 1);
1073235537Sgber			return (error);
1074235537Sgber		}
1075235537Sgber
1076235537Sgber		VOP_UNLOCK(NTOV(cp), 0);
1077235537Sgber		LIST_FOREACH(seg, &seginfo->seg_list, seg_link)
1078235537Sgber			nandfs_update_segment(fsdev, seg->seg_num,
1079235537Sgber			    seg->nblocks + seg->segsum_blocks);
1080235537Sgber
1081235537Sgber		VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1082235537Sgber		error = save_seginfo(seginfo, 0);
1083235537Sgber		if (error) {
1084235537Sgber			clean_seginfo(seginfo, 0);
1085235537Sgber			delete_seginfo(seginfo);
1086235537Sgber			VOP_UNLOCK(NTOV(dat), 0);
1087235537Sgber			VOP_UNLOCK(NTOV(su), 0);
1088235537Sgber			lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1089235537Sgber			nandfs_error("%s: err:%d updating seg",
1090235537Sgber			    __func__, error);
1091235537Sgber			return (error);
1092235537Sgber		}
1093235537Sgber		VOP_UNLOCK(NTOV(dat), 0);
1094235537Sgber	}
1095235537Sgber
1096235537Sgber	VOP_UNLOCK(NTOV(su), 0);
1097235537Sgber
1098235537Sgber	delete_seginfo(seginfo);
1099235537Sgber	lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1100235537Sgber
1101235537Sgber	if (cno_changed && !error) {
1102235537Sgber		if (nandfs_cps_between_sblocks != 0 &&
1103235537Sgber		    fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0)
1104235537Sgber			nandfs_write_superblock(fsdev);
1105235537Sgber	}
1106235537Sgber
1107235537Sgber	ASSERT_VOP_LOCKED(vp, __func__);
1108235537Sgber	DPRINTF(SYNC, ("%s: END error %d\n", __func__, error));
1109235537Sgber	return (error);
1110235537Sgber}
1111235537Sgber
1112235537Sgberint
1113235537Sgbernandfs_segment_constructor(struct nandfsmount *nmp, int flags)
1114235537Sgber{
1115235537Sgber	struct nandfs_device *fsdev;
1116235537Sgber	struct nandfs_seginfo *seginfo = NULL;
1117235537Sgber	struct nandfs_segment *seg;
1118235537Sgber	struct nandfs_node *dat, *su, *ifile, *cp, *gc;
1119235537Sgber	int cno_changed, error;
1120235537Sgber
1121235537Sgber	DPRINTF(SYNC, ("%s: START\n", __func__));
1122235537Sgber	fsdev = nmp->nm_nandfsdev;
1123235537Sgber
1124235537Sgber	lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL);
1125235537Sgber	DPRINTF(SYNC, ("%s: git lock\n", __func__));
1126235537Sgberagain:
1127235537Sgber	create_seginfo(fsdev, &seginfo);
1128235537Sgber
1129235537Sgber	dat = fsdev->nd_dat_node;
1130235537Sgber	su = fsdev->nd_su_node;
1131235537Sgber	cp = fsdev->nd_cp_node;
1132235537Sgber	gc = fsdev->nd_gc_node;
1133235537Sgber	ifile = nmp->nm_ifile_node;
1134235537Sgber
1135235537Sgber	VOP_LOCK(NTOV(su), LK_EXCLUSIVE);
1136235537Sgber	VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE);
1137235537Sgber	VOP_LOCK(NTOV(gc), LK_EXCLUSIVE);
1138235537Sgber	VOP_LOCK(NTOV(cp), LK_EXCLUSIVE);
1139235537Sgber
1140235537Sgber	nandfs_iterate_system_vnode(gc, seginfo);
1141235537Sgber	nandfs_iterate_dirty_vnodes(nmp->nm_vfs_mountp, seginfo);
1142235537Sgber	nandfs_iterate_system_vnode(ifile, seginfo);
1143235537Sgber	nandfs_iterate_system_vnode(su, seginfo);
1144235537Sgber
1145235537Sgber	cno_changed = 0;
1146235537Sgber	if (seginfo->blocks || flags) {
1147235537Sgber		cno_changed = 1;
1148235537Sgber		/* Create new checkpoint */
1149235537Sgber		error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1);
1150235537Sgber		if (error) {
1151235537Sgber			clean_seginfo(seginfo, 0);
1152235537Sgber			delete_seginfo(seginfo);
1153235537Sgber			goto error_locks;
1154235537Sgber		}
1155235537Sgber
1156235537Sgber		/* Collect blocks from system files */
1157235537Sgber		nandfs_iterate_system_vnode(cp, seginfo);
1158235537Sgber		nandfs_iterate_system_vnode(su, seginfo);
1159235537Sgber		VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1160235537Sgber		nandfs_iterate_system_vnode(dat, seginfo);
1161235537Sgber		VOP_UNLOCK(NTOV(dat), 0);
1162235537Sgberreiterate:
1163235537Sgber		seginfo->reiterate = 0;
1164235537Sgber		nandfs_iterate_system_vnode(su, seginfo);
1165235537Sgber		VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1166235537Sgber		nandfs_iterate_system_vnode(dat, seginfo);
1167235537Sgber		VOP_UNLOCK(NTOV(dat), 0);
1168235537Sgber		if (seginfo->reiterate)
1169235537Sgber			goto reiterate;
1170235537Sgber		if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
1171235537Sgber			error = create_segment(seginfo);
1172235537Sgber			if (error) {
1173235537Sgber				clean_seginfo(seginfo, 0);
1174235537Sgber				delete_seginfo(seginfo);
1175235537Sgber				goto error_locks;
1176235537Sgber			}
1177235537Sgber			goto reiterate;
1178235537Sgber		}
1179235537Sgber
1180235537Sgber		/* Reiterate all blocks and assign physical block number */
1181235537Sgber		nandfs_seginfo_assign_pblk(seginfo);
1182235537Sgber
1183235537Sgber		/* Fill superroot */
1184235537Sgber		error = nandfs_add_superroot(seginfo);
1185235537Sgber		if (error) {
1186235537Sgber			clean_seginfo(seginfo, 0);
1187235537Sgber			delete_seginfo(seginfo);
1188235537Sgber			goto error_locks;
1189235537Sgber		}
1190235537Sgber		KASSERT(!(seginfo->reiterate), ("reiteration after superroot"));
1191235537Sgber
1192235537Sgber		/* Fill checkpoint data */
1193235537Sgber		nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1,
1194235537Sgber		    &ifile->nn_inode, seginfo->blocks);
1195235537Sgber
1196235537Sgber		LIST_FOREACH(seg, &seginfo->seg_list, seg_link)
1197235537Sgber			nandfs_update_segment(fsdev, seg->seg_num,
1198235537Sgber			    seg->nblocks + seg->segsum_blocks);
1199235537Sgber
1200235537Sgber		VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1201235537Sgber		error = save_seginfo(seginfo, 1);
1202235537Sgber		if (error) {
1203235537Sgber			clean_seginfo(seginfo, 1);
1204235537Sgber			delete_seginfo(seginfo);
1205235537Sgber			goto error_dat;
1206235537Sgber		}
1207235537Sgber		VOP_UNLOCK(NTOV(dat), 0);
1208235537Sgber	}
1209235537Sgber
1210235537Sgber	VOP_UNLOCK(NTOV(cp), 0);
1211235537Sgber	VOP_UNLOCK(NTOV(gc), 0);
1212235537Sgber	VOP_UNLOCK(NTOV(ifile), 0);
1213235537Sgber
1214235537Sgber	nandfs_process_segments(fsdev);
1215235537Sgber
1216235537Sgber	VOP_UNLOCK(NTOV(su), 0);
1217235537Sgber
1218235537Sgber	delete_seginfo(seginfo);
1219235537Sgber
1220235537Sgber	/*
1221235537Sgber	 * XXX: a hack, will go away soon
1222235537Sgber	 */
1223235537Sgber	if ((NTOV(dat)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1224235537Sgber	    NTOV(cp)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1225235537Sgber	    NTOV(gc)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1226235537Sgber	    NTOV(ifile)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1227235537Sgber	    NTOV(su)->v_bufobj.bo_dirty.bv_cnt != 0) &&
1228235537Sgber	    (flags & NANDFS_UMOUNT)) {
1229235537Sgber		DPRINTF(SYNC, ("%s: RERUN\n", __func__));
1230235537Sgber		goto again;
1231235537Sgber	}
1232235537Sgber
1233235537Sgber	MPASS(fsdev->nd_free_base == NULL);
1234235537Sgber
1235235537Sgber	lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL);
1236235537Sgber
1237235537Sgber	if (cno_changed) {
1238235537Sgber		if ((nandfs_cps_between_sblocks != 0 &&
1239235537Sgber		    fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) ||
1240235537Sgber		    flags & NANDFS_UMOUNT)
1241235537Sgber			nandfs_write_superblock(fsdev);
1242235537Sgber	}
1243235537Sgber
1244235537Sgber	DPRINTF(SYNC, ("%s: END\n", __func__));
1245235537Sgber	return (0);
1246235537Sgbererror_dat:
1247235537Sgber	VOP_UNLOCK(NTOV(dat), 0);
1248235537Sgbererror_locks:
1249235537Sgber	VOP_UNLOCK(NTOV(cp), 0);
1250235537Sgber	VOP_UNLOCK(NTOV(gc), 0);
1251235537Sgber	VOP_UNLOCK(NTOV(ifile), 0);
1252235537Sgber	VOP_UNLOCK(NTOV(su), 0);
1253235537Sgber	lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL);
1254235537Sgber
1255235537Sgber	return (error);
1256235537Sgber}
1257235537Sgber
1258235537Sgber#ifdef DDB
1259235537Sgber/*
1260235537Sgber * Show details about the given NANDFS mount point.
1261235537Sgber */
1262235537SgberDB_SHOW_COMMAND(nandfs, db_show_nandfs)
1263235537Sgber{
1264235537Sgber	struct mount *mp;
1265235537Sgber	struct nandfs_device *nffsdev;
1266235537Sgber	struct nandfs_segment *seg;
1267235537Sgber	struct nandfsmount *nmp;
1268235537Sgber	struct buf *bp;
1269235537Sgber	struct vnode *vp;
1270235537Sgber
1271235537Sgber	if (!have_addr) {
1272235537Sgber		db_printf("\nUsage: show nandfs <mount_addr>\n");
1273235537Sgber		return;
1274235537Sgber	}
1275235537Sgber
1276235537Sgber	mp = (struct mount *)addr;
1277235537Sgber	db_printf("%p %s on %s (%s)\n", mp, mp->mnt_stat.f_mntfromname,
1278235537Sgber	    mp->mnt_stat.f_mntonname, mp->mnt_stat.f_fstypename);
1279235537Sgber
1280235537Sgber
1281235537Sgber	nmp = (struct nandfsmount *)(mp->mnt_data);
1282235537Sgber	nffsdev = nmp->nm_nandfsdev;
1283235537Sgber	db_printf("dev vnode:%p\n", nffsdev->nd_devvp);
1284235537Sgber	db_printf("blocksize:%jx last cno:%jx last pseg:%jx seg num:%jx\n",
1285235537Sgber	    (uintmax_t)nffsdev->nd_blocksize, (uintmax_t)nffsdev->nd_last_cno,
1286235537Sgber	    (uintmax_t)nffsdev->nd_last_pseg, (uintmax_t)nffsdev->nd_seg_num);
1287235537Sgber	db_printf("system nodes: dat:%p cp:%p su:%p ifile:%p gc:%p\n",
1288235537Sgber	    nffsdev->nd_dat_node, nffsdev->nd_cp_node, nffsdev->nd_su_node,
1289235537Sgber	    nmp->nm_ifile_node, nffsdev->nd_gc_node);
1290235537Sgber
1291235537Sgber	if (nffsdev->nd_seginfo != NULL) {
1292235537Sgber		LIST_FOREACH(seg, &nffsdev->nd_seginfo->seg_list, seg_link) {
1293235537Sgber			db_printf("seg: %p\n", seg);
1294235537Sgber			TAILQ_FOREACH(bp, &seg->segsum,
1295235537Sgber			    b_cluster.cluster_entry)
1296235537Sgber				db_printf("segbp %p\n", bp);
1297235537Sgber			TAILQ_FOREACH(bp, &seg->data,
1298235537Sgber			    b_cluster.cluster_entry) {
1299235537Sgber				vp = bp->b_vp;
1300235537Sgber				db_printf("bp:%p bp->b_vp:%p ino:%jx\n", bp, vp,
1301235537Sgber				    (uintmax_t)(vp ? VTON(vp)->nn_ino : 0));
1302235537Sgber			}
1303235537Sgber		}
1304235537Sgber	}
1305235537Sgber}
1306235537Sgber#endif
1307