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);
202297793Spfg		}
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;
482294200Srpokala	struct bufobj *bo;
483245000Skib	int error, update;
484235537Sgber
485235537Sgber	td = curthread;
486235537Sgber
487245000Skib	MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) {
488235537Sgber		update = 0;
489235537Sgber
490245000Skib		if (mp->mnt_syncer == vp || VOP_ISLOCKED(vp)) {
491235537Sgber			VI_UNLOCK(vp);
492235537Sgber			continue;
493235537Sgber		}
494245000Skib		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK | LK_NOWAIT, td) != 0)
495235537Sgber			continue;
496235537Sgber
497235537Sgber		nandfs_node = VTON(vp);
498235537Sgber		if (nandfs_node->nn_flags & IN_MODIFIED) {
499235537Sgber			nandfs_node->nn_flags &= ~(IN_MODIFIED);
500235537Sgber			update = 1;
501235537Sgber		}
502235537Sgber
503294200Srpokala		bo = &vp->v_bufobj;
504294200Srpokala		BO_LOCK(bo);
505235537Sgber		if (vp->v_bufobj.bo_dirty.bv_cnt) {
506235537Sgber			error = nandfs_iterate_dirty_buf(vp, seginfo, 0);
507235537Sgber			if (error) {
508235537Sgber				nandfs_error("%s: cannot iterate vnode:%p "
509235537Sgber				    "err:%d\n", __func__, vp, error);
510235537Sgber				vput(vp);
511294200Srpokala				BO_UNLOCK(bo);
512235537Sgber				return (error);
513235537Sgber			}
514235537Sgber			update = 1;
515235537Sgber		} else
516235537Sgber			vput(vp);
517294200Srpokala		BO_UNLOCK(bo);
518235537Sgber
519235537Sgber		if (update)
520235537Sgber			nandfs_node_update(nandfs_node);
521235537Sgber	}
522235537Sgber
523235537Sgber	return (0);
524235537Sgber}
525235537Sgber
526235537Sgberstatic int
527235537Sgbernandfs_update_phys_block(struct nandfs_device *fsdev, struct buf *bp,
528235537Sgber    uint64_t phys_blknr, union nandfs_binfo *binfo)
529235537Sgber{
530235537Sgber	struct nandfs_node *node, *dat;
531235537Sgber	struct vnode *vp;
532235537Sgber	uint64_t new_blknr;
533235537Sgber	int error;
534235537Sgber
535235537Sgber	vp = bp->b_vp;
536235537Sgber	node = VTON(vp);
537235537Sgber	new_blknr = nandfs_vblk_get(bp);
538235537Sgber	dat = fsdev->nd_dat_node;
539235537Sgber
540235537Sgber	DPRINTF(BMAP, ("%s: ino %#jx lblk %#jx: vblk %#jx -> %#jx\n",
541235537Sgber	    __func__, (uintmax_t)node->nn_ino, (uintmax_t)bp->b_lblkno,
542235537Sgber	    (uintmax_t)new_blknr, (uintmax_t)phys_blknr));
543235537Sgber
544235537Sgber	if (node->nn_ino != NANDFS_DAT_INO) {
545235537Sgber		KASSERT((new_blknr != 0), ("vblk for bp %p is 0", bp));
546235537Sgber
547235537Sgber		nandfs_vblock_assign(fsdev, new_blknr, phys_blknr);
548235537Sgber		binfo->bi_v.bi_vblocknr = new_blknr;
549235537Sgber		binfo->bi_v.bi_blkoff = bp->b_lblkno;
550235537Sgber		binfo->bi_v.bi_ino = node->nn_ino;
551235537Sgber	} else {
552235537Sgber		VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
553235537Sgber		error = nandfs_bmap_update_block(node, bp, phys_blknr);
554235537Sgber		if (error) {
555235537Sgber			nandfs_error("%s: error updating block:%jx for bp:%p\n",
556235537Sgber			    __func__, (uintmax_t)phys_blknr, bp);
557235537Sgber			VOP_UNLOCK(NTOV(dat), 0);
558235537Sgber			return (error);
559235537Sgber		}
560235537Sgber		VOP_UNLOCK(NTOV(dat), 0);
561235537Sgber		binfo->bi_dat.bi_blkoff = bp->b_lblkno;
562235537Sgber		binfo->bi_dat.bi_ino = node->nn_ino;
563235537Sgber		if (NANDFS_IS_INDIRECT(bp))
564235537Sgber			binfo->bi_dat.bi_level = 1;
565235537Sgber		else
566235537Sgber			binfo->bi_dat.bi_level = 0;
567235537Sgber	}
568235537Sgber
569235537Sgber	return (0);
570235537Sgber}
571235537Sgber
572235537Sgber#define	NBINFO(off) ((off) + sizeof(union nandfs_binfo))
573235537Sgberstatic int
574235537Sgbernandfs_segment_assign_pblk(struct nandfs_segment *nfsseg)
575235537Sgber{
576235537Sgber	struct nandfs_device *fsdev;
577235537Sgber	union nandfs_binfo *binfo;
578235537Sgber	struct buf *bp, *seg_bp;
579235537Sgber	uint64_t blocknr;
580235537Sgber	uint32_t curr_off, blocksize;
581235537Sgber	int error;
582235537Sgber
583235537Sgber	fsdev = nfsseg->fsdev;
584235537Sgber	blocksize = fsdev->nd_blocksize;
585235537Sgber
586235537Sgber	blocknr = nfsseg->start_block + nfsseg->segsum_blocks;
587235537Sgber	seg_bp = TAILQ_FIRST(&nfsseg->segsum);
588235537Sgber	DPRINTF(SYNC, ("%s: seg:%p segsum bp:%p data:%p\n",
589235537Sgber	    __func__, nfsseg, seg_bp, seg_bp->b_data));
590235537Sgber
591235537Sgber	binfo = (union nandfs_binfo *)(seg_bp->b_data +
592235537Sgber	    sizeof(struct nandfs_segment_summary));
593235537Sgber	curr_off = sizeof(struct nandfs_segment_summary);
594235537Sgber
595235537Sgber	TAILQ_FOREACH(bp, &nfsseg->data, b_cluster.cluster_entry) {
596235537Sgber		KASSERT((bp->b_vp), ("bp %p has not vp", bp));
597235537Sgber
598235537Sgber		DPRINTF(BMAP, ("\n\n%s: assign buf %p for ino %#jx next %p\n",
599235537Sgber		    __func__, bp, (uintmax_t)VTON(bp->b_vp)->nn_ino,
600235537Sgber		    TAILQ_NEXT(bp, b_cluster.cluster_entry)));
601235537Sgber
602235537Sgber		if (NBINFO(curr_off) > blocksize) {
603235537Sgber			seg_bp = TAILQ_NEXT(seg_bp, b_cluster.cluster_entry);
604235537Sgber			binfo = (union nandfs_binfo *)seg_bp->b_data;
605235537Sgber			curr_off = 0;
606235537Sgber			DPRINTF(SYNC, ("%s: next segsum %p data %p\n",
607235537Sgber			    __func__, seg_bp, seg_bp->b_data));
608235537Sgber		}
609235537Sgber
610235537Sgber		error = nandfs_update_phys_block(fsdev, bp, blocknr, binfo);
611235537Sgber		if (error) {
612235537Sgber			nandfs_error("%s: err:%d when updatinng phys block:%jx"
613235537Sgber			    " for bp:%p and binfo:%p\n", __func__, error,
614235537Sgber			    (uintmax_t)blocknr, bp, binfo);
615235537Sgber			return (error);
616235537Sgber		}
617235537Sgber		binfo++;
618235537Sgber		curr_off = NBINFO(curr_off);
619235537Sgber
620235537Sgber		blocknr++;
621235537Sgber	}
622235537Sgber
623235537Sgber	return (0);
624235537Sgber}
625235537Sgber
626235537Sgberstatic int
627235537Sgbernandfs_seginfo_assign_pblk(struct nandfs_seginfo *seginfo)
628235537Sgber{
629235537Sgber	struct nandfs_segment *nfsseg;
630235537Sgber	int error = 0;
631235537Sgber
632235537Sgber	LIST_FOREACH(nfsseg, &seginfo->seg_list, seg_link) {
633235537Sgber		error = nandfs_segment_assign_pblk(nfsseg);
634235537Sgber		if (error)
635235537Sgber			break;
636235537Sgber	}
637235537Sgber
638235537Sgber	return (error);
639235537Sgber}
640235537Sgber
641235537Sgberstatic struct nandfs_segment_summary *
642235537Sgbernandfs_fill_segsum(struct nandfs_segment *seg, int has_sr)
643235537Sgber{
644235537Sgber	struct nandfs_segment_summary *ss;
645235537Sgber	struct nandfs_device *fsdev;
646235537Sgber	struct buf *bp;
647235537Sgber	uint32_t rest, segsum_size, blocksize, crc_calc;
648235537Sgber	uint16_t flags;
649235537Sgber	uint8_t *crc_area, crc_skip;
650235537Sgber
651235537Sgber	DPRINTF(SYNC, ("%s: seg %#jx nblocks %#x sumbytes %#x\n",
652235537Sgber	    __func__, (uintmax_t) seg->seg_num,
653235537Sgber	    seg->nblocks + seg->segsum_blocks,
654235537Sgber	    seg->segsum_bytes));
655235537Sgber
656235537Sgber	fsdev = seg->fsdev;
657235537Sgber
658235537Sgber	flags = NANDFS_SS_LOGBGN | NANDFS_SS_LOGEND;
659235537Sgber	if (has_sr)
660235537Sgber		flags |= NANDFS_SS_SR;
661235537Sgber
662235537Sgber	bp = TAILQ_FIRST(&seg->segsum);
663235537Sgber	ss = (struct nandfs_segment_summary *) bp->b_data;
664235537Sgber	ss->ss_magic = NANDFS_SEGSUM_MAGIC;
665235537Sgber	ss->ss_bytes = sizeof(struct nandfs_segment_summary);
666235537Sgber	ss->ss_flags = flags;
667235537Sgber	ss->ss_seq = ++(fsdev->nd_seg_sequence);
668235537Sgber	ss->ss_create = fsdev->nd_ts.tv_sec;
669235537Sgber	nandfs_get_segment_range(fsdev, seg->seg_next, &ss->ss_next, NULL);
670235537Sgber	ss->ss_nblocks = seg->nblocks + seg->segsum_blocks;
671235537Sgber	ss->ss_nbinfos = seg->nbinfos;
672235537Sgber	ss->ss_sumbytes = seg->segsum_bytes;
673235537Sgber
674235537Sgber	crc_skip = sizeof(ss->ss_datasum) + sizeof(ss->ss_sumsum);
675235537Sgber	blocksize = seg->fsdev->nd_blocksize;
676235537Sgber
677235537Sgber	segsum_size = seg->segsum_bytes - crc_skip;
678235537Sgber	rest = min(seg->segsum_bytes, blocksize) - crc_skip;
679235537Sgber	crc_area = (uint8_t *)ss + crc_skip;
680235537Sgber	crc_calc = ~0U;
681235537Sgber	while (segsum_size > 0) {
682235537Sgber		crc_calc = crc32_raw(crc_area, rest, crc_calc);
683235537Sgber		segsum_size -= rest;
684235537Sgber		if (!segsum_size)
685235537Sgber			break;
686235537Sgber		bp = TAILQ_NEXT(bp, b_cluster.cluster_entry);
687235537Sgber		crc_area = (uint8_t *)bp->b_data;
688235537Sgber		rest = segsum_size <= blocksize ? segsum_size : blocksize;
689235537Sgber	}
690235537Sgber	ss->ss_sumsum = crc_calc ^ ~0U;
691235537Sgber
692235537Sgber	return (ss);
693235537Sgber
694235537Sgber}
695235537Sgber
696235537Sgberstatic int
697235537Sgbernandfs_save_buf(struct buf *bp, uint64_t blocknr, struct nandfs_device *fsdev)
698235537Sgber{
699235537Sgber	struct bufobj *bo;
700235537Sgber	int error;
701235537Sgber
702235537Sgber	bo = &fsdev->nd_devvp->v_bufobj;
703235537Sgber
704235537Sgber	bp->b_blkno = nandfs_block_to_dblock(fsdev, blocknr);
705235537Sgber	bp->b_iooffset = dbtob(bp->b_blkno);
706235537Sgber
707235537Sgber	KASSERT(bp->b_bufobj != NULL, ("no bufobj for %p", bp));
708235537Sgber	if (bp->b_bufobj != bo) {
709235537Sgber		BO_LOCK(bp->b_bufobj);
710235537Sgber		BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK,
711251171Sjeff		    BO_LOCKPTR(bp->b_bufobj));
712235537Sgber		KASSERT(BUF_ISLOCKED(bp), ("Problem with locking buffer"));
713235537Sgber	}
714235537Sgber
715235537Sgber	DPRINTF(SYNC, ("%s: buf: %p offset %#jx blk %#jx size %#x\n",
716235537Sgber	    __func__, bp, (uintmax_t)bp->b_offset, (uintmax_t)blocknr,
717235537Sgber	    fsdev->nd_blocksize));
718235537Sgber
719235537Sgber	NANDFS_UNGATHER(bp);
720235537Sgber	nandfs_buf_clear(bp, 0xffffffff);
721235537Sgber	bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED);
722235537Sgber	error = bwrite(bp);
723235537Sgber	if (error) {
724235537Sgber		nandfs_error("%s: error:%d when writing buffer:%p\n",
725235537Sgber		    __func__, error, bp);
726235537Sgber		return (error);
727235537Sgber	}
728235537Sgber	return (error);
729235537Sgber}
730235537Sgber
731235537Sgberstatic void
732235537Sgbernandfs_clean_buf(struct nandfs_device *fsdev, struct buf *bp)
733235537Sgber{
734235537Sgber
735235537Sgber	DPRINTF(SYNC, ("%s: buf: %p\n", __func__, bp));
736235537Sgber
737235537Sgber	NANDFS_UNGATHER(bp);
738235537Sgber	nandfs_buf_clear(bp, 0xffffffff);
739235537Sgber	bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED);
740235537Sgber	nandfs_undirty_buf_fsdev(fsdev, bp);
741235537Sgber}
742235537Sgber
743235537Sgberstatic void
744235537Sgbernandfs_clean_segblocks(struct nandfs_segment *seg, uint8_t unlock)
745235537Sgber{
746235537Sgber	struct nandfs_device *fsdev = seg->fsdev;
747235537Sgber	struct nandfs_segment *next_seg;
748235537Sgber	struct buf *bp, *tbp, *next_bp;
749235537Sgber	struct vnode *vp, *next_vp;
750235537Sgber
751235537Sgber	VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE);
752235537Sgber	TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) {
753235537Sgber		TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
754235537Sgber		nandfs_clean_buf(fsdev, bp);
755297793Spfg	}
756235537Sgber
757235537Sgber	TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) {
758235537Sgber		TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry);
759235537Sgber
760235537Sgber		/*
761235537Sgber		 * If bp is not super-root and vnode is not currently
762235537Sgber		 * locked lock it.
763235537Sgber		 */
764235537Sgber		vp = bp->b_vp;
765235537Sgber		next_vp = NULL;
766235537Sgber		next_bp = TAILQ_NEXT(bp,  b_cluster.cluster_entry);
767235537Sgber		if (!next_bp) {
768235537Sgber			next_seg = LIST_NEXT(seg, seg_link);
769235537Sgber			if (next_seg)
770235537Sgber				next_bp = TAILQ_FIRST(&next_seg->data);
771235537Sgber		}
772235537Sgber
773235537Sgber		if (next_bp)
774235537Sgber			next_vp = next_bp->b_vp;
775235537Sgber
776235537Sgber		nandfs_clean_buf(fsdev, bp);
777235537Sgber
778235537Sgber		if (unlock && vp != NULL && next_vp != vp &&
779235537Sgber		    !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
780235537Sgber			vput(vp);
781235537Sgber
782235537Sgber		nandfs_dirty_bufs_decrement(fsdev);
783235537Sgber	}
784235537Sgber
785235537Sgber	VOP_UNLOCK(fsdev->nd_devvp, 0);
786235537Sgber}
787235537Sgber
788235537Sgberstatic int
789235537Sgbernandfs_save_segblocks(struct nandfs_segment *seg, uint8_t unlock)
790235537Sgber{
791235537Sgber	struct nandfs_device *fsdev = seg->fsdev;
792235537Sgber	struct nandfs_segment *next_seg;
793235537Sgber	struct buf *bp, *tbp, *next_bp;
794235537Sgber	struct vnode *vp, *next_vp;
795235537Sgber	uint64_t blocknr;
796235537Sgber	uint32_t i = 0;
797235537Sgber	int error = 0;
798235537Sgber
799235537Sgber	VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE);
800235537Sgber	TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) {
801235537Sgber		TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
802235537Sgber		blocknr = seg->start_block + i;
803235537Sgber		error = nandfs_save_buf(bp, blocknr, fsdev);
804235537Sgber		if (error) {
805235537Sgber			nandfs_error("%s: error saving buf: %p blocknr:%jx\n",
806235537Sgber			    __func__, bp, (uintmax_t)blocknr);
807235537Sgber			goto out;
808235537Sgber		}
809235537Sgber		i++;
810297793Spfg	}
811235537Sgber
812235537Sgber	i = 0;
813235537Sgber	TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) {
814235537Sgber		TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry);
815235537Sgber
816235537Sgber		blocknr = seg->start_block + seg->segsum_blocks + i;
817235537Sgber		/*
818235537Sgber		 * If bp is not super-root and vnode is not currently
819235537Sgber		 * locked lock it.
820235537Sgber		 */
821235537Sgber		vp = bp->b_vp;
822235537Sgber		next_vp = NULL;
823235537Sgber		next_bp = TAILQ_NEXT(bp,  b_cluster.cluster_entry);
824235537Sgber		if (!next_bp) {
825235537Sgber			next_seg = LIST_NEXT(seg, seg_link);
826235537Sgber			if (next_seg)
827235537Sgber				next_bp = TAILQ_FIRST(&next_seg->data);
828235537Sgber		}
829235537Sgber
830235537Sgber		if (next_bp)
831235537Sgber			next_vp = next_bp->b_vp;
832235537Sgber
833235537Sgber		error = nandfs_save_buf(bp, blocknr, fsdev);
834235537Sgber		if (error) {
835235537Sgber			nandfs_error("%s: error saving buf: %p blknr: %jx\n",
836235537Sgber			    __func__, bp, (uintmax_t)blocknr);
837235537Sgber			if (unlock && vp != NULL && next_vp != vp &&
838235537Sgber			    !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
839235537Sgber				vput(vp);
840235537Sgber			goto out;
841235537Sgber		}
842235537Sgber
843235537Sgber		if (unlock && vp != NULL && next_vp != vp &&
844235537Sgber		    !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
845235537Sgber			vput(vp);
846235537Sgber
847235537Sgber		i++;
848235537Sgber		nandfs_dirty_bufs_decrement(fsdev);
849235537Sgber	}
850235537Sgberout:
851235537Sgber	if (error) {
852235537Sgber		nandfs_clean_segblocks(seg, unlock);
853235537Sgber		VOP_UNLOCK(fsdev->nd_devvp, 0);
854235537Sgber		return (error);
855235537Sgber	}
856235537Sgber
857235537Sgber	VOP_UNLOCK(fsdev->nd_devvp, 0);
858235537Sgber	return (error);
859235537Sgber}
860235537Sgber
861235537Sgber
862235537Sgberstatic void
863235537Sgberclean_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock)
864235537Sgber{
865235537Sgber	struct nandfs_segment *seg;
866235537Sgber
867235537Sgber	DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo));
868235537Sgber
869235537Sgber	LIST_FOREACH(seg, &seginfo->seg_list, seg_link) {
870235537Sgber		nandfs_clean_segblocks(seg, unlock);
871235537Sgber	}
872235537Sgber}
873235537Sgber
874235537Sgberstatic int
875235537Sgbersave_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock)
876235537Sgber{
877235537Sgber	struct nandfs_segment *seg;
878235537Sgber	struct nandfs_device *fsdev;
879235537Sgber	struct nandfs_segment_summary *ss;
880235537Sgber	int error = 0;
881235537Sgber
882235537Sgber	fsdev = seginfo->fsdev;
883235537Sgber
884235537Sgber	DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo));
885235537Sgber
886235537Sgber	LIST_FOREACH(seg, &seginfo->seg_list, seg_link) {
887235537Sgber		if (LIST_NEXT(seg, seg_link)) {
888235537Sgber			nandfs_fill_segsum(seg, 0);
889235537Sgber			error = nandfs_save_segblocks(seg, unlock);
890235537Sgber			if (error) {
891235537Sgber				nandfs_error("%s: error:%d saving seg:%p\n",
892235537Sgber				    __func__, error, seg);
893235537Sgber				goto out;
894235537Sgber			}
895235537Sgber		} else {
896235537Sgber			ss = nandfs_fill_segsum(seg, 1);
897235537Sgber			fsdev->nd_last_segsum = *ss;
898235537Sgber			error = nandfs_save_segblocks(seg, unlock);
899235537Sgber			if (error) {
900235537Sgber				nandfs_error("%s: error:%d saving seg:%p\n",
901235537Sgber				    __func__, error, seg);
902235537Sgber				goto out;
903235537Sgber			}
904235537Sgber			fsdev->nd_last_cno++;
905235537Sgber			fsdev->nd_last_pseg = seg->start_block;
906235537Sgber		}
907235537Sgber	}
908235537Sgberout:
909235537Sgber	if (error)
910235537Sgber		clean_seginfo(seginfo, unlock);
911235537Sgber	return (error);
912235537Sgber}
913235537Sgber
914235537Sgberstatic void
915235537Sgbernandfs_invalidate_bufs(struct nandfs_device *fsdev, uint64_t segno)
916235537Sgber{
917235537Sgber	uint64_t start, end;
918235537Sgber	struct buf *bp, *tbd;
919235537Sgber	struct bufobj *bo;
920235537Sgber
921235537Sgber	nandfs_get_segment_range(fsdev, segno, &start, &end);
922235537Sgber
923235537Sgber	bo = &NTOV(fsdev->nd_gc_node)->v_bufobj;
924235537Sgber
925235537Sgber	BO_LOCK(bo);
926235537Sgberrestart_locked_gc:
927235537Sgber	TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, tbd) {
928235537Sgber		if (!(bp->b_lblkno >= start && bp->b_lblkno <= end))
929235537Sgber			continue;
930235537Sgber
931235537Sgber		if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL))
932235537Sgber			goto restart_locked_gc;
933235537Sgber
934235537Sgber		bremfree(bp);
935235537Sgber		bp->b_flags |= (B_INVAL | B_RELBUF);
936235537Sgber		bp->b_flags &= ~(B_ASYNC | B_MANAGED);
937235537Sgber		BO_UNLOCK(bo);
938235537Sgber		brelse(bp);
939235537Sgber		BO_LOCK(bo);
940235537Sgber	}
941235537Sgber	BO_UNLOCK(bo);
942235537Sgber}
943235537Sgber
944235537Sgber/* Process segments marks to free by cleaner */
945235537Sgberstatic void
946235537Sgbernandfs_process_segments(struct nandfs_device *fsdev)
947235537Sgber{
948235537Sgber	uint64_t saved_segment;
949235537Sgber	int i;
950235537Sgber
951235537Sgber	if (fsdev->nd_free_base) {
952235537Sgber		saved_segment = nandfs_get_segnum_of_block(fsdev,
953235537Sgber		    fsdev->nd_super.s_last_pseg);
954235537Sgber		for (i = 0; i < fsdev->nd_free_count; i++) {
955235537Sgber			if (fsdev->nd_free_base[i] == NANDFS_NOSEGMENT)
956235537Sgber				continue;
957235537Sgber			/* Update superblock if clearing segment point by it */
958235537Sgber			if (fsdev->nd_free_base[i] == saved_segment) {
959235537Sgber				nandfs_write_superblock(fsdev);
960235537Sgber				saved_segment = nandfs_get_segnum_of_block(
961235537Sgber				    fsdev, fsdev->nd_super.s_last_pseg);
962235537Sgber			}
963235537Sgber			nandfs_invalidate_bufs(fsdev, fsdev->nd_free_base[i]);
964235537Sgber			nandfs_clear_segment(fsdev, fsdev->nd_free_base[i]);
965235537Sgber		}
966235537Sgber
967235537Sgber		free(fsdev->nd_free_base, M_NANDFSTEMP);
968235537Sgber		fsdev->nd_free_base = NULL;
969235537Sgber		fsdev->nd_free_count = 0;
970235537Sgber	}
971235537Sgber}
972235537Sgber
973235537Sgber/* Collect and write dirty buffers */
974235537Sgberint
975235537Sgbernandfs_sync_file(struct vnode *vp)
976235537Sgber{
977235537Sgber	struct nandfs_device *fsdev;
978235537Sgber	struct nandfs_node *nandfs_node;
979235537Sgber	struct nandfsmount *nmp;
980235537Sgber	struct nandfs_node *dat, *su, *ifile, *cp;
981235537Sgber	struct nandfs_seginfo *seginfo = NULL;
982235537Sgber	struct nandfs_segment *seg;
983235537Sgber	int update, error;
984235537Sgber	int cno_changed;
985235537Sgber
986235537Sgber	ASSERT_VOP_LOCKED(vp, __func__);
987235537Sgber	DPRINTF(SYNC, ("%s: START\n", __func__));
988235537Sgber
989235537Sgber	error = 0;
990235537Sgber	nmp = VFSTONANDFS(vp->v_mount);
991235537Sgber	fsdev = nmp->nm_nandfsdev;
992235537Sgber
993235537Sgber	dat = fsdev->nd_dat_node;
994235537Sgber	su = fsdev->nd_su_node;
995235537Sgber	cp = fsdev->nd_cp_node;
996235537Sgber	ifile = nmp->nm_ifile_node;
997235537Sgber
998235537Sgber	NANDFS_WRITEASSERT(fsdev);
999235537Sgber	if (lockmgr(&fsdev->nd_seg_const, LK_UPGRADE, NULL) != 0) {
1000235537Sgber		DPRINTF(SYNC, ("%s: lost shared lock\n", __func__));
1001235537Sgber		if (lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL) != 0)
1002235537Sgber			panic("couldn't lock exclusive");
1003235537Sgber	}
1004235537Sgber	DPRINTF(SYNC, ("%s: got lock\n", __func__));
1005235537Sgber
1006235537Sgber	VOP_LOCK(NTOV(su), LK_EXCLUSIVE);
1007235537Sgber	create_seginfo(fsdev, &seginfo);
1008235537Sgber
1009235537Sgber	update = 0;
1010235537Sgber
1011235537Sgber	nandfs_node = VTON(vp);
1012235537Sgber	if (nandfs_node->nn_flags & IN_MODIFIED) {
1013235537Sgber		nandfs_node->nn_flags &= ~(IN_MODIFIED);
1014235537Sgber		update = 1;
1015235537Sgber	}
1016235537Sgber
1017235537Sgber	if (vp->v_bufobj.bo_dirty.bv_cnt) {
1018235537Sgber		error = nandfs_iterate_dirty_buf(vp, seginfo, 0);
1019235537Sgber		if (error) {
1020235537Sgber			clean_seginfo(seginfo, 0);
1021235537Sgber			delete_seginfo(seginfo);
1022235537Sgber			VOP_UNLOCK(NTOV(su), 0);
1023235537Sgber			lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1024235537Sgber			nandfs_error("%s: err:%d iterating dirty bufs vp:%p",
1025235537Sgber			    __func__, error, vp);
1026235537Sgber			return (error);
1027235537Sgber		}
1028235537Sgber		update = 1;
1029235537Sgber	}
1030235537Sgber
1031235537Sgber	if (update) {
1032235537Sgber		VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE);
1033235537Sgber		error = nandfs_node_update(nandfs_node);
1034235537Sgber		if (error) {
1035235537Sgber			clean_seginfo(seginfo, 0);
1036235537Sgber			delete_seginfo(seginfo);
1037235537Sgber			VOP_UNLOCK(NTOV(ifile), 0);
1038235537Sgber			VOP_UNLOCK(NTOV(su), 0);
1039235537Sgber			lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1040235537Sgber			nandfs_error("%s: err:%d updating vp:%p",
1041235537Sgber			    __func__, error, vp);
1042235537Sgber			return (error);
1043235537Sgber		}
1044235537Sgber		VOP_UNLOCK(NTOV(ifile), 0);
1045235537Sgber	}
1046235537Sgber
1047235537Sgber	cno_changed = 0;
1048235537Sgber	if (seginfo->blocks) {
1049235537Sgber		VOP_LOCK(NTOV(cp), LK_EXCLUSIVE);
1050235537Sgber		cno_changed = 1;
1051235537Sgber		/* Create new checkpoint */
1052235537Sgber		error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1);
1053235537Sgber		if (error) {
1054235537Sgber			clean_seginfo(seginfo, 0);
1055235537Sgber			delete_seginfo(seginfo);
1056235537Sgber			VOP_UNLOCK(NTOV(cp), 0);
1057235537Sgber			VOP_UNLOCK(NTOV(su), 0);
1058235537Sgber			lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1059235537Sgber			nandfs_error("%s: err:%d getting cp:%jx",
1060235537Sgber			    __func__, error, fsdev->nd_last_cno + 1);
1061235537Sgber			return (error);
1062235537Sgber		}
1063235537Sgber
1064235537Sgber		/* Reiterate all blocks and assign physical block number */
1065235537Sgber		nandfs_seginfo_assign_pblk(seginfo);
1066235537Sgber
1067235537Sgber		/* Fill checkpoint data */
1068235537Sgber		error = nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1,
1069235537Sgber		    &ifile->nn_inode, seginfo->blocks);
1070235537Sgber		if (error) {
1071235537Sgber			clean_seginfo(seginfo, 0);
1072235537Sgber			delete_seginfo(seginfo);
1073235537Sgber			VOP_UNLOCK(NTOV(cp), 0);
1074235537Sgber			VOP_UNLOCK(NTOV(su), 0);
1075235537Sgber			lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1076235537Sgber			nandfs_error("%s: err:%d setting cp:%jx",
1077235537Sgber			    __func__, error, fsdev->nd_last_cno + 1);
1078235537Sgber			return (error);
1079235537Sgber		}
1080235537Sgber
1081235537Sgber		VOP_UNLOCK(NTOV(cp), 0);
1082235537Sgber		LIST_FOREACH(seg, &seginfo->seg_list, seg_link)
1083235537Sgber			nandfs_update_segment(fsdev, seg->seg_num,
1084235537Sgber			    seg->nblocks + seg->segsum_blocks);
1085235537Sgber
1086235537Sgber		VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1087235537Sgber		error = save_seginfo(seginfo, 0);
1088235537Sgber		if (error) {
1089235537Sgber			clean_seginfo(seginfo, 0);
1090235537Sgber			delete_seginfo(seginfo);
1091235537Sgber			VOP_UNLOCK(NTOV(dat), 0);
1092235537Sgber			VOP_UNLOCK(NTOV(su), 0);
1093235537Sgber			lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1094235537Sgber			nandfs_error("%s: err:%d updating seg",
1095235537Sgber			    __func__, error);
1096235537Sgber			return (error);
1097235537Sgber		}
1098235537Sgber		VOP_UNLOCK(NTOV(dat), 0);
1099235537Sgber	}
1100235537Sgber
1101235537Sgber	VOP_UNLOCK(NTOV(su), 0);
1102235537Sgber
1103235537Sgber	delete_seginfo(seginfo);
1104235537Sgber	lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1105235537Sgber
1106235537Sgber	if (cno_changed && !error) {
1107235537Sgber		if (nandfs_cps_between_sblocks != 0 &&
1108235537Sgber		    fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0)
1109235537Sgber			nandfs_write_superblock(fsdev);
1110235537Sgber	}
1111235537Sgber
1112235537Sgber	ASSERT_VOP_LOCKED(vp, __func__);
1113235537Sgber	DPRINTF(SYNC, ("%s: END error %d\n", __func__, error));
1114235537Sgber	return (error);
1115235537Sgber}
1116235537Sgber
1117235537Sgberint
1118235537Sgbernandfs_segment_constructor(struct nandfsmount *nmp, int flags)
1119235537Sgber{
1120235537Sgber	struct nandfs_device *fsdev;
1121235537Sgber	struct nandfs_seginfo *seginfo = NULL;
1122235537Sgber	struct nandfs_segment *seg;
1123235537Sgber	struct nandfs_node *dat, *su, *ifile, *cp, *gc;
1124235537Sgber	int cno_changed, error;
1125235537Sgber
1126235537Sgber	DPRINTF(SYNC, ("%s: START\n", __func__));
1127235537Sgber	fsdev = nmp->nm_nandfsdev;
1128235537Sgber
1129235537Sgber	lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL);
1130235537Sgber	DPRINTF(SYNC, ("%s: git lock\n", __func__));
1131235537Sgberagain:
1132235537Sgber	create_seginfo(fsdev, &seginfo);
1133235537Sgber
1134235537Sgber	dat = fsdev->nd_dat_node;
1135235537Sgber	su = fsdev->nd_su_node;
1136235537Sgber	cp = fsdev->nd_cp_node;
1137235537Sgber	gc = fsdev->nd_gc_node;
1138235537Sgber	ifile = nmp->nm_ifile_node;
1139235537Sgber
1140235537Sgber	VOP_LOCK(NTOV(su), LK_EXCLUSIVE);
1141235537Sgber	VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE);
1142235537Sgber	VOP_LOCK(NTOV(gc), LK_EXCLUSIVE);
1143235537Sgber	VOP_LOCK(NTOV(cp), LK_EXCLUSIVE);
1144235537Sgber
1145235537Sgber	nandfs_iterate_system_vnode(gc, seginfo);
1146235537Sgber	nandfs_iterate_dirty_vnodes(nmp->nm_vfs_mountp, seginfo);
1147235537Sgber	nandfs_iterate_system_vnode(ifile, seginfo);
1148235537Sgber	nandfs_iterate_system_vnode(su, seginfo);
1149235537Sgber
1150235537Sgber	cno_changed = 0;
1151235537Sgber	if (seginfo->blocks || flags) {
1152235537Sgber		cno_changed = 1;
1153235537Sgber		/* Create new checkpoint */
1154235537Sgber		error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1);
1155235537Sgber		if (error) {
1156235537Sgber			clean_seginfo(seginfo, 0);
1157235537Sgber			delete_seginfo(seginfo);
1158235537Sgber			goto error_locks;
1159235537Sgber		}
1160235537Sgber
1161235537Sgber		/* Collect blocks from system files */
1162235537Sgber		nandfs_iterate_system_vnode(cp, seginfo);
1163235537Sgber		nandfs_iterate_system_vnode(su, seginfo);
1164235537Sgber		VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1165235537Sgber		nandfs_iterate_system_vnode(dat, seginfo);
1166235537Sgber		VOP_UNLOCK(NTOV(dat), 0);
1167235537Sgberreiterate:
1168235537Sgber		seginfo->reiterate = 0;
1169235537Sgber		nandfs_iterate_system_vnode(su, seginfo);
1170235537Sgber		VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1171235537Sgber		nandfs_iterate_system_vnode(dat, seginfo);
1172235537Sgber		VOP_UNLOCK(NTOV(dat), 0);
1173235537Sgber		if (seginfo->reiterate)
1174235537Sgber			goto reiterate;
1175235537Sgber		if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
1176235537Sgber			error = create_segment(seginfo);
1177235537Sgber			if (error) {
1178235537Sgber				clean_seginfo(seginfo, 0);
1179235537Sgber				delete_seginfo(seginfo);
1180235537Sgber				goto error_locks;
1181235537Sgber			}
1182235537Sgber			goto reiterate;
1183235537Sgber		}
1184235537Sgber
1185235537Sgber		/* Reiterate all blocks and assign physical block number */
1186235537Sgber		nandfs_seginfo_assign_pblk(seginfo);
1187235537Sgber
1188235537Sgber		/* Fill superroot */
1189235537Sgber		error = nandfs_add_superroot(seginfo);
1190235537Sgber		if (error) {
1191235537Sgber			clean_seginfo(seginfo, 0);
1192235537Sgber			delete_seginfo(seginfo);
1193235537Sgber			goto error_locks;
1194235537Sgber		}
1195235537Sgber		KASSERT(!(seginfo->reiterate), ("reiteration after superroot"));
1196235537Sgber
1197235537Sgber		/* Fill checkpoint data */
1198235537Sgber		nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1,
1199235537Sgber		    &ifile->nn_inode, seginfo->blocks);
1200235537Sgber
1201235537Sgber		LIST_FOREACH(seg, &seginfo->seg_list, seg_link)
1202235537Sgber			nandfs_update_segment(fsdev, seg->seg_num,
1203235537Sgber			    seg->nblocks + seg->segsum_blocks);
1204235537Sgber
1205235537Sgber		VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1206235537Sgber		error = save_seginfo(seginfo, 1);
1207235537Sgber		if (error) {
1208235537Sgber			clean_seginfo(seginfo, 1);
1209235537Sgber			delete_seginfo(seginfo);
1210235537Sgber			goto error_dat;
1211235537Sgber		}
1212235537Sgber		VOP_UNLOCK(NTOV(dat), 0);
1213235537Sgber	}
1214235537Sgber
1215235537Sgber	VOP_UNLOCK(NTOV(cp), 0);
1216235537Sgber	VOP_UNLOCK(NTOV(gc), 0);
1217235537Sgber	VOP_UNLOCK(NTOV(ifile), 0);
1218235537Sgber
1219235537Sgber	nandfs_process_segments(fsdev);
1220235537Sgber
1221235537Sgber	VOP_UNLOCK(NTOV(su), 0);
1222235537Sgber
1223235537Sgber	delete_seginfo(seginfo);
1224235537Sgber
1225235537Sgber	/*
1226235537Sgber	 * XXX: a hack, will go away soon
1227235537Sgber	 */
1228235537Sgber	if ((NTOV(dat)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1229235537Sgber	    NTOV(cp)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1230235537Sgber	    NTOV(gc)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1231235537Sgber	    NTOV(ifile)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1232235537Sgber	    NTOV(su)->v_bufobj.bo_dirty.bv_cnt != 0) &&
1233235537Sgber	    (flags & NANDFS_UMOUNT)) {
1234235537Sgber		DPRINTF(SYNC, ("%s: RERUN\n", __func__));
1235235537Sgber		goto again;
1236235537Sgber	}
1237235537Sgber
1238235537Sgber	MPASS(fsdev->nd_free_base == NULL);
1239235537Sgber
1240235537Sgber	lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL);
1241235537Sgber
1242235537Sgber	if (cno_changed) {
1243235537Sgber		if ((nandfs_cps_between_sblocks != 0 &&
1244235537Sgber		    fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) ||
1245235537Sgber		    flags & NANDFS_UMOUNT)
1246235537Sgber			nandfs_write_superblock(fsdev);
1247235537Sgber	}
1248235537Sgber
1249235537Sgber	DPRINTF(SYNC, ("%s: END\n", __func__));
1250235537Sgber	return (0);
1251235537Sgbererror_dat:
1252235537Sgber	VOP_UNLOCK(NTOV(dat), 0);
1253235537Sgbererror_locks:
1254235537Sgber	VOP_UNLOCK(NTOV(cp), 0);
1255235537Sgber	VOP_UNLOCK(NTOV(gc), 0);
1256235537Sgber	VOP_UNLOCK(NTOV(ifile), 0);
1257235537Sgber	VOP_UNLOCK(NTOV(su), 0);
1258235537Sgber	lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL);
1259235537Sgber
1260235537Sgber	return (error);
1261235537Sgber}
1262235537Sgber
1263235537Sgber#ifdef DDB
1264235537Sgber/*
1265235537Sgber * Show details about the given NANDFS mount point.
1266235537Sgber */
1267235537SgberDB_SHOW_COMMAND(nandfs, db_show_nandfs)
1268235537Sgber{
1269235537Sgber	struct mount *mp;
1270235537Sgber	struct nandfs_device *nffsdev;
1271235537Sgber	struct nandfs_segment *seg;
1272235537Sgber	struct nandfsmount *nmp;
1273235537Sgber	struct buf *bp;
1274235537Sgber	struct vnode *vp;
1275235537Sgber
1276235537Sgber	if (!have_addr) {
1277235537Sgber		db_printf("\nUsage: show nandfs <mount_addr>\n");
1278235537Sgber		return;
1279235537Sgber	}
1280235537Sgber
1281235537Sgber	mp = (struct mount *)addr;
1282235537Sgber	db_printf("%p %s on %s (%s)\n", mp, mp->mnt_stat.f_mntfromname,
1283235537Sgber	    mp->mnt_stat.f_mntonname, mp->mnt_stat.f_fstypename);
1284235537Sgber
1285235537Sgber
1286235537Sgber	nmp = (struct nandfsmount *)(mp->mnt_data);
1287235537Sgber	nffsdev = nmp->nm_nandfsdev;
1288235537Sgber	db_printf("dev vnode:%p\n", nffsdev->nd_devvp);
1289235537Sgber	db_printf("blocksize:%jx last cno:%jx last pseg:%jx seg num:%jx\n",
1290235537Sgber	    (uintmax_t)nffsdev->nd_blocksize, (uintmax_t)nffsdev->nd_last_cno,
1291235537Sgber	    (uintmax_t)nffsdev->nd_last_pseg, (uintmax_t)nffsdev->nd_seg_num);
1292235537Sgber	db_printf("system nodes: dat:%p cp:%p su:%p ifile:%p gc:%p\n",
1293235537Sgber	    nffsdev->nd_dat_node, nffsdev->nd_cp_node, nffsdev->nd_su_node,
1294235537Sgber	    nmp->nm_ifile_node, nffsdev->nd_gc_node);
1295235537Sgber
1296235537Sgber	if (nffsdev->nd_seginfo != NULL) {
1297235537Sgber		LIST_FOREACH(seg, &nffsdev->nd_seginfo->seg_list, seg_link) {
1298235537Sgber			db_printf("seg: %p\n", seg);
1299235537Sgber			TAILQ_FOREACH(bp, &seg->segsum,
1300235537Sgber			    b_cluster.cluster_entry)
1301235537Sgber				db_printf("segbp %p\n", bp);
1302235537Sgber			TAILQ_FOREACH(bp, &seg->data,
1303235537Sgber			    b_cluster.cluster_entry) {
1304235537Sgber				vp = bp->b_vp;
1305235537Sgber				db_printf("bp:%p bp->b_vp:%p ino:%jx\n", bp, vp,
1306235537Sgber				    (uintmax_t)(vp ? VTON(vp)->nn_ino : 0));
1307235537Sgber			}
1308235537Sgber		}
1309235537Sgber	}
1310235537Sgber}
1311235537Sgber#endif
1312