1/*-
2 * Copyright (c) 2010-2012 Semihalf.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD$");
29
30#include "opt_ddb.h"
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/conf.h>
35#include <sys/kernel.h>
36#include <sys/lock.h>
37#include <sys/malloc.h>
38#include <sys/mount.h>
39#include <sys/mutex.h>
40#include <sys/namei.h>
41#include <sys/rwlock.h>
42#include <sys/sysctl.h>
43#include <sys/vnode.h>
44#include <sys/buf.h>
45#include <sys/bio.h>
46#include <sys/libkern.h>
47
48#include <ddb/ddb.h>
49
50#include <vm/vm.h>
51#include <vm/vm_param.h>
52#include <vm/vm_kern.h>
53#include <vm/vm_page.h>
54
55#include <geom/geom.h>
56#include <geom/geom_vfs.h>
57
58#include <fs/nandfs/nandfs_mount.h>
59#include <fs/nandfs/nandfs.h>
60#include <fs/nandfs/nandfs_subr.h>
61
62static int
63nandfs_new_segment(struct nandfs_device *fsdev)
64{
65	int error = 0;
66	uint64_t new;
67
68	error = nandfs_alloc_segment(fsdev, &new);
69	if (!error) {
70		fsdev->nd_seg_num = fsdev->nd_next_seg_num;
71		fsdev->nd_next_seg_num = new;
72	}
73	DPRINTF(SYNC, ("%s: new segment %jx next %jx error %d\n",
74	    __func__, (uintmax_t)fsdev->nd_seg_num, (uintmax_t)new, error));
75	if (error)
76		nandfs_error("%s: cannot create segment error %d\n",
77		    __func__, error);
78
79	return (error);
80}
81
82static int
83create_segment(struct nandfs_seginfo *seginfo)
84{
85	struct nandfs_segment *seg;
86	struct nandfs_device *fsdev;
87	struct nandfs_segment *prev;
88	struct buf *bp;
89	uint64_t start_block, curr;
90	uint32_t blks_per_seg, nblocks;
91	int error;
92
93	fsdev = seginfo->fsdev;
94	prev = seginfo->curseg;
95	blks_per_seg = fsdev->nd_fsdata.f_blocks_per_segment;
96	nblocks = fsdev->nd_last_segsum.ss_nblocks;
97
98	if (!prev) {
99		vfs_timestamp(&fsdev->nd_ts);
100		/* Touch current segment */
101		error = nandfs_touch_segment(fsdev, fsdev->nd_seg_num);
102		if (error) {
103			nandfs_error("%s: cannot preallocate segment %jx\n",
104			    __func__, fsdev->nd_seg_num);
105			return (error);
106		}
107		error = nandfs_touch_segment(fsdev, 0);
108		if (error) {
109			nandfs_error("%s: cannot dirty block with segment 0\n",
110			    __func__);
111			return (error);
112		}
113		start_block = fsdev->nd_last_pseg + (uint64_t)nblocks;
114		/*
115		 * XXX Hack
116		 */
117		if (blks_per_seg - (start_block % blks_per_seg) - 1 == 0)
118			start_block++;
119		curr = nandfs_get_segnum_of_block(fsdev, start_block);
120		/* Allocate new segment if last one is full */
121		if (fsdev->nd_seg_num != curr) {
122			error = nandfs_new_segment(fsdev);
123			if (error) {
124				nandfs_error("%s: cannot create new segment\n",
125				    __func__);
126				return (error);
127			}
128			/*
129			 * XXX Hack
130			 */
131			nandfs_get_segment_range(fsdev, fsdev->nd_seg_num, &start_block, NULL);
132		}
133	} else {
134		nandfs_get_segment_range(fsdev, fsdev->nd_next_seg_num,
135		    &start_block, NULL);
136
137		/* Touch current segment and allocate and touch new one */
138		error = nandfs_new_segment(fsdev);
139		if (error) {
140			nandfs_error("%s: cannot create next segment\n",
141			    __func__);
142			return (error);
143		}
144
145		/* Reiterate in case new buf is dirty */
146		seginfo->reiterate = 1;
147	}
148
149	/* Allocate and initialize nandfs_segment structure */
150	seg = malloc(sizeof(*seg), M_DEVBUF, M_WAITOK|M_ZERO);
151	TAILQ_INIT(&seg->segsum);
152	TAILQ_INIT(&seg->data);
153	seg->fsdev = fsdev;
154	seg->start_block = start_block;
155	seg->num_blocks = blks_per_seg - (start_block % blks_per_seg) - 1;
156	seg->seg_num = fsdev->nd_seg_num;
157	seg->seg_next = fsdev->nd_next_seg_num;
158	seg->segsum_blocks = 1;
159	seg->bytes_left = fsdev->nd_blocksize -
160	    sizeof(struct nandfs_segment_summary);
161	seg->segsum_bytes = sizeof(struct nandfs_segment_summary);
162
163	/* Allocate buffer for segment summary */
164	bp = getblk(fsdev->nd_devvp, nandfs_block_to_dblock(fsdev,
165	    seg->start_block), fsdev->nd_blocksize, 0, 0, 0);
166	bzero(bp->b_data, seginfo->fsdev->nd_blocksize);
167	bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
168	bp->b_flags |= B_MANAGED;
169
170	/* Add buffer to segment */
171	TAILQ_INSERT_TAIL(&seg->segsum, bp, b_cluster.cluster_entry);
172	seg->current_off = bp->b_data + sizeof(struct nandfs_segment_summary);
173
174	DPRINTF(SYNC, ("%s: seg %p : initial settings: start %#jx size :%#x\n",
175	    __func__, seg, (uintmax_t)seg->start_block, seg->num_blocks));
176	DPRINTF(SYNC, ("%s: seg->seg_num %#jx cno %#jx next %#jx\n", __func__,
177	    (uintmax_t)seg->seg_num, (uintmax_t)(fsdev->nd_last_cno + 1),
178	    (uintmax_t)seg->seg_next));
179
180	if (!prev)
181		LIST_INSERT_HEAD(&seginfo->seg_list, seg, seg_link);
182	else
183		LIST_INSERT_AFTER(prev, seg, seg_link);
184
185	seginfo->curseg = seg;
186
187	return (0);
188}
189
190static int
191delete_segment(struct nandfs_seginfo *seginfo)
192{
193	struct nandfs_segment *seg, *tseg;
194	struct buf *bp, *tbp;
195
196	LIST_FOREACH_SAFE(seg, &seginfo->seg_list, seg_link, tseg) {
197		TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry,
198		    tbp) {
199			TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
200			bp->b_flags &= ~B_MANAGED;
201			brelse(bp);
202		}
203
204		LIST_REMOVE(seg, seg_link);
205		free(seg, M_DEVBUF);
206	}
207
208	return (0);
209}
210
211static int
212create_seginfo(struct nandfs_device *fsdev, struct nandfs_seginfo **seginfo)
213{
214	struct nandfs_seginfo *info;
215
216	info = malloc(sizeof(*info), M_DEVBUF, M_WAITOK);
217
218	LIST_INIT(&info->seg_list);
219	info->fsdev = fsdev;
220	info->curseg = NULL;
221	info->blocks = 0;
222	*seginfo = info;
223	fsdev->nd_seginfo = info;
224	return (0);
225}
226
227static int
228delete_seginfo(struct nandfs_seginfo *seginfo)
229{
230	struct nandfs_device *nffsdev;
231
232	nffsdev = seginfo->fsdev;
233	delete_segment(seginfo);
234	nffsdev->nd_seginfo = NULL;
235	free(seginfo, M_DEVBUF);
236
237	return (0);
238}
239
240static int
241nandfs_create_superroot_block(struct nandfs_seginfo *seginfo,
242    struct buf **newbp)
243{
244	struct buf *bp;
245	int error;
246
247	bp = nandfs_geteblk(seginfo->fsdev->nd_blocksize, GB_NOWAIT_BD);
248
249	bzero(bp->b_data, seginfo->fsdev->nd_blocksize);
250	bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
251	bp->b_flags |= B_MANAGED;
252
253	if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
254		error = create_segment(seginfo);
255		if (error) {
256			brelse(bp);
257			nandfs_error("%s: no segment for superroot\n",
258			    __func__);
259			return (error);
260		}
261	}
262
263	TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry);
264
265	seginfo->curseg->nblocks++;
266	seginfo->curseg->num_blocks--;
267	seginfo->blocks++;
268
269	*newbp = bp;
270	return (0);
271}
272
273static int
274nandfs_add_superroot(struct nandfs_seginfo *seginfo)
275{
276	struct nandfs_device *fsdev;
277	struct nandfs_super_root *sr;
278	struct buf *bp = NULL;
279	uint64_t crc_skip;
280	uint32_t crc_calc;
281	int error;
282
283	fsdev = seginfo->fsdev;
284
285	error = nandfs_create_superroot_block(seginfo, &bp);
286	if (error) {
287		nandfs_error("%s: cannot add superroot\n", __func__);
288		return (error);
289	}
290
291	sr = (struct nandfs_super_root *)bp->b_data;
292	/* Save superroot CRC */
293	sr->sr_bytes = NANDFS_SR_BYTES;
294	sr->sr_flags = 0;
295	sr->sr_nongc_ctime = 0;
296
297	memcpy(&sr->sr_dat, &fsdev->nd_dat_node->nn_inode,
298	    sizeof(struct nandfs_inode));
299	memcpy(&sr->sr_cpfile, &fsdev->nd_cp_node->nn_inode,
300	    sizeof(struct nandfs_inode));
301	memcpy(&sr->sr_sufile, &fsdev->nd_su_node->nn_inode,
302	    sizeof(struct nandfs_inode));
303
304	crc_skip = sizeof(sr->sr_sum);
305	crc_calc = crc32((uint8_t *)sr + crc_skip, NANDFS_SR_BYTES - crc_skip);
306
307	sr->sr_sum = crc_calc;
308
309	bp->b_flags |= B_MANAGED;
310	bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
311
312	bp->b_flags &= ~B_INVAL;
313	nandfs_dirty_bufs_increment(fsdev);
314	DPRINTF(SYNC, ("%s: bp:%p\n", __func__, bp));
315
316	return (0);
317}
318
319static int
320nandfs_add_segsum_block(struct nandfs_seginfo *seginfo, struct buf **newbp)
321{
322	struct nandfs_device *fsdev;
323	nandfs_daddr_t blk;
324	struct buf *bp;
325	int error;
326
327	if (!(seginfo->curseg) || seginfo->curseg->num_blocks <= 1) {
328		error = create_segment(seginfo);
329		if (error) {
330			nandfs_error("%s: error:%d when creating segment\n",
331			    __func__, error);
332			return (error);
333		}
334		*newbp = TAILQ_FIRST(&seginfo->curseg->segsum);
335		return (0);
336	}
337
338	fsdev = seginfo->fsdev;
339	blk = nandfs_block_to_dblock(fsdev, seginfo->curseg->start_block +
340	    seginfo->curseg->segsum_blocks);
341
342	bp = getblk(fsdev->nd_devvp, blk, fsdev->nd_blocksize, 0, 0, 0);
343
344	bzero(bp->b_data, seginfo->fsdev->nd_blocksize);
345	bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
346	bp->b_flags |= B_MANAGED;
347
348	TAILQ_INSERT_TAIL(&seginfo->curseg->segsum, bp,
349	    b_cluster.cluster_entry);
350	seginfo->curseg->num_blocks--;
351
352	seginfo->curseg->segsum_blocks++;
353	seginfo->curseg->bytes_left = seginfo->fsdev->nd_blocksize;
354	seginfo->curseg->current_off = bp->b_data;
355	seginfo->blocks++;
356
357	*newbp = bp;
358
359	DPRINTF(SYNC, ("%s: bp %p\n", __func__, bp));
360
361	return (0);
362}
363
364static int
365nandfs_add_blocks(struct nandfs_seginfo *seginfo, struct nandfs_node *node,
366    struct buf *bp)
367{
368	union nandfs_binfo *binfo;
369	struct buf *seg_bp;
370	int error;
371
372	if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
373		error = create_segment(seginfo);
374		if (error) {
375			nandfs_error("%s: error:%d when creating segment\n",
376			    __func__, error);
377			return (error);
378		}
379	}
380
381	if (seginfo->curseg->bytes_left < sizeof(union nandfs_binfo)) {
382		error = nandfs_add_segsum_block(seginfo, &seg_bp);
383		if (error) {
384			nandfs_error("%s: error:%d when adding segsum\n",
385			    __func__, error);
386			return (error);
387		}
388	}
389	binfo = (union nandfs_binfo *)seginfo->curseg->current_off;
390
391	if (node->nn_ino != NANDFS_DAT_INO) {
392		binfo->bi_v.bi_blkoff = bp->b_lblkno;
393		binfo->bi_v.bi_ino = node->nn_ino;
394	} else {
395		binfo->bi_dat.bi_blkoff = bp->b_lblkno;
396		binfo->bi_dat.bi_ino = node->nn_ino;
397		if (NANDFS_IS_INDIRECT(bp))
398			binfo->bi_dat.bi_level = 1;
399		else
400			binfo->bi_dat.bi_level = 0;
401	}
402	binfo++;
403
404	seginfo->curseg->bytes_left -= sizeof(union nandfs_binfo);
405	seginfo->curseg->segsum_bytes += sizeof(union nandfs_binfo);
406	seginfo->curseg->current_off = (char *)binfo;
407
408	TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry);
409
410	seginfo->curseg->nbinfos++;
411	seginfo->curseg->nblocks++;
412	seginfo->curseg->num_blocks--;
413	seginfo->blocks++;
414
415	DPRINTF(SYNC, ("%s: bp (%p) number %x (left %x)\n",
416	    __func__, bp, seginfo->curseg->nblocks,
417	    seginfo->curseg->num_blocks));
418	return (0);
419}
420
421static int
422nandfs_iterate_dirty_buf(struct vnode *vp, struct nandfs_seginfo *seginfo,
423    uint8_t hold)
424{
425	struct buf *bp, *tbd;
426	struct bufobj *bo;
427	struct nandfs_node *node;
428	int error;
429
430	node = VTON(vp);
431	bo = &vp->v_bufobj;
432
433	ASSERT_VOP_ELOCKED(vp, __func__);
434
435	/* Iterate dirty data bufs */
436	TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, tbd) {
437		DPRINTF(SYNC, ("%s: vp (%p): bp (%p) with lblkno %jx ino %jx "
438		    "add buf\n", __func__, vp, bp, bp->b_lblkno, node->nn_ino));
439
440		if (!(NANDFS_ISGATHERED(bp))) {
441			error = nandfs_bmap_update_dat(node,
442			    nandfs_vblk_get(bp), bp);
443			if (error)
444				return (error);
445			NANDFS_GATHER(bp);
446			nandfs_add_blocks(seginfo, node, bp);
447		}
448	}
449
450	return (0);
451}
452
453static int
454nandfs_iterate_system_vnode(struct nandfs_node *node,
455    struct nandfs_seginfo *seginfo)
456{
457	struct vnode *vp;
458	int nblocks;
459	uint8_t hold = 0;
460
461	if (node->nn_ino != NANDFS_IFILE_INO)
462		hold = 1;
463
464	vp = NTOV(node);
465
466	nblocks = vp->v_bufobj.bo_dirty.bv_cnt;
467	DPRINTF(SYNC, ("%s: vp (%p): nblocks %x ino %jx\n",
468	    __func__, vp, nblocks, node->nn_ino));
469
470	if (nblocks)
471		nandfs_iterate_dirty_buf(vp, seginfo, hold);
472
473	return (0);
474}
475
476static int
477nandfs_iterate_dirty_vnodes(struct mount *mp, struct nandfs_seginfo *seginfo)
478{
479	struct nandfs_node *nandfs_node;
480	struct vnode *vp, *mvp;
481	struct thread *td;
482	struct bufobj *bo;
483	int error, update;
484
485	td = curthread;
486
487	MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) {
488		update = 0;
489
490		if (mp->mnt_syncer == vp || VOP_ISLOCKED(vp)) {
491			VI_UNLOCK(vp);
492			continue;
493		}
494		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK | LK_NOWAIT, td) != 0)
495			continue;
496
497		nandfs_node = VTON(vp);
498		if (nandfs_node->nn_flags & IN_MODIFIED) {
499			nandfs_node->nn_flags &= ~(IN_MODIFIED);
500			update = 1;
501		}
502
503		bo = &vp->v_bufobj;
504		BO_LOCK(bo);
505		if (vp->v_bufobj.bo_dirty.bv_cnt) {
506			error = nandfs_iterate_dirty_buf(vp, seginfo, 0);
507			if (error) {
508				nandfs_error("%s: cannot iterate vnode:%p "
509				    "err:%d\n", __func__, vp, error);
510				vput(vp);
511				BO_UNLOCK(bo);
512				return (error);
513			}
514			update = 1;
515		} else
516			vput(vp);
517		BO_UNLOCK(bo);
518
519		if (update)
520			nandfs_node_update(nandfs_node);
521	}
522
523	return (0);
524}
525
526static int
527nandfs_update_phys_block(struct nandfs_device *fsdev, struct buf *bp,
528    uint64_t phys_blknr, union nandfs_binfo *binfo)
529{
530	struct nandfs_node *node, *dat;
531	struct vnode *vp;
532	uint64_t new_blknr;
533	int error;
534
535	vp = bp->b_vp;
536	node = VTON(vp);
537	new_blknr = nandfs_vblk_get(bp);
538	dat = fsdev->nd_dat_node;
539
540	DPRINTF(BMAP, ("%s: ino %#jx lblk %#jx: vblk %#jx -> %#jx\n",
541	    __func__, (uintmax_t)node->nn_ino, (uintmax_t)bp->b_lblkno,
542	    (uintmax_t)new_blknr, (uintmax_t)phys_blknr));
543
544	if (node->nn_ino != NANDFS_DAT_INO) {
545		KASSERT((new_blknr != 0), ("vblk for bp %p is 0", bp));
546
547		nandfs_vblock_assign(fsdev, new_blknr, phys_blknr);
548		binfo->bi_v.bi_vblocknr = new_blknr;
549		binfo->bi_v.bi_blkoff = bp->b_lblkno;
550		binfo->bi_v.bi_ino = node->nn_ino;
551	} else {
552		VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
553		error = nandfs_bmap_update_block(node, bp, phys_blknr);
554		if (error) {
555			nandfs_error("%s: error updating block:%jx for bp:%p\n",
556			    __func__, (uintmax_t)phys_blknr, bp);
557			VOP_UNLOCK(NTOV(dat), 0);
558			return (error);
559		}
560		VOP_UNLOCK(NTOV(dat), 0);
561		binfo->bi_dat.bi_blkoff = bp->b_lblkno;
562		binfo->bi_dat.bi_ino = node->nn_ino;
563		if (NANDFS_IS_INDIRECT(bp))
564			binfo->bi_dat.bi_level = 1;
565		else
566			binfo->bi_dat.bi_level = 0;
567	}
568
569	return (0);
570}
571
572#define	NBINFO(off) ((off) + sizeof(union nandfs_binfo))
573static int
574nandfs_segment_assign_pblk(struct nandfs_segment *nfsseg)
575{
576	struct nandfs_device *fsdev;
577	union nandfs_binfo *binfo;
578	struct buf *bp, *seg_bp;
579	uint64_t blocknr;
580	uint32_t curr_off, blocksize;
581	int error;
582
583	fsdev = nfsseg->fsdev;
584	blocksize = fsdev->nd_blocksize;
585
586	blocknr = nfsseg->start_block + nfsseg->segsum_blocks;
587	seg_bp = TAILQ_FIRST(&nfsseg->segsum);
588	DPRINTF(SYNC, ("%s: seg:%p segsum bp:%p data:%p\n",
589	    __func__, nfsseg, seg_bp, seg_bp->b_data));
590
591	binfo = (union nandfs_binfo *)(seg_bp->b_data +
592	    sizeof(struct nandfs_segment_summary));
593	curr_off = sizeof(struct nandfs_segment_summary);
594
595	TAILQ_FOREACH(bp, &nfsseg->data, b_cluster.cluster_entry) {
596		KASSERT((bp->b_vp), ("bp %p has not vp", bp));
597
598		DPRINTF(BMAP, ("\n\n%s: assign buf %p for ino %#jx next %p\n",
599		    __func__, bp, (uintmax_t)VTON(bp->b_vp)->nn_ino,
600		    TAILQ_NEXT(bp, b_cluster.cluster_entry)));
601
602		if (NBINFO(curr_off) > blocksize) {
603			seg_bp = TAILQ_NEXT(seg_bp, b_cluster.cluster_entry);
604			binfo = (union nandfs_binfo *)seg_bp->b_data;
605			curr_off = 0;
606			DPRINTF(SYNC, ("%s: next segsum %p data %p\n",
607			    __func__, seg_bp, seg_bp->b_data));
608		}
609
610		error = nandfs_update_phys_block(fsdev, bp, blocknr, binfo);
611		if (error) {
612			nandfs_error("%s: err:%d when updatinng phys block:%jx"
613			    " for bp:%p and binfo:%p\n", __func__, error,
614			    (uintmax_t)blocknr, bp, binfo);
615			return (error);
616		}
617		binfo++;
618		curr_off = NBINFO(curr_off);
619
620		blocknr++;
621	}
622
623	return (0);
624}
625
626static int
627nandfs_seginfo_assign_pblk(struct nandfs_seginfo *seginfo)
628{
629	struct nandfs_segment *nfsseg;
630	int error = 0;
631
632	LIST_FOREACH(nfsseg, &seginfo->seg_list, seg_link) {
633		error = nandfs_segment_assign_pblk(nfsseg);
634		if (error)
635			break;
636	}
637
638	return (error);
639}
640
641static struct nandfs_segment_summary *
642nandfs_fill_segsum(struct nandfs_segment *seg, int has_sr)
643{
644	struct nandfs_segment_summary *ss;
645	struct nandfs_device *fsdev;
646	struct buf *bp;
647	uint32_t rest, segsum_size, blocksize, crc_calc;
648	uint16_t flags;
649	uint8_t *crc_area, crc_skip;
650
651	DPRINTF(SYNC, ("%s: seg %#jx nblocks %#x sumbytes %#x\n",
652	    __func__, (uintmax_t) seg->seg_num,
653	    seg->nblocks + seg->segsum_blocks,
654	    seg->segsum_bytes));
655
656	fsdev = seg->fsdev;
657
658	flags = NANDFS_SS_LOGBGN | NANDFS_SS_LOGEND;
659	if (has_sr)
660		flags |= NANDFS_SS_SR;
661
662	bp = TAILQ_FIRST(&seg->segsum);
663	ss = (struct nandfs_segment_summary *) bp->b_data;
664	ss->ss_magic = NANDFS_SEGSUM_MAGIC;
665	ss->ss_bytes = sizeof(struct nandfs_segment_summary);
666	ss->ss_flags = flags;
667	ss->ss_seq = ++(fsdev->nd_seg_sequence);
668	ss->ss_create = fsdev->nd_ts.tv_sec;
669	nandfs_get_segment_range(fsdev, seg->seg_next, &ss->ss_next, NULL);
670	ss->ss_nblocks = seg->nblocks + seg->segsum_blocks;
671	ss->ss_nbinfos = seg->nbinfos;
672	ss->ss_sumbytes = seg->segsum_bytes;
673
674	crc_skip = sizeof(ss->ss_datasum) + sizeof(ss->ss_sumsum);
675	blocksize = seg->fsdev->nd_blocksize;
676
677	segsum_size = seg->segsum_bytes - crc_skip;
678	rest = min(seg->segsum_bytes, blocksize) - crc_skip;
679	crc_area = (uint8_t *)ss + crc_skip;
680	crc_calc = ~0U;
681	while (segsum_size > 0) {
682		crc_calc = crc32_raw(crc_area, rest, crc_calc);
683		segsum_size -= rest;
684		if (!segsum_size)
685			break;
686		bp = TAILQ_NEXT(bp, b_cluster.cluster_entry);
687		crc_area = (uint8_t *)bp->b_data;
688		rest = segsum_size <= blocksize ? segsum_size : blocksize;
689	}
690	ss->ss_sumsum = crc_calc ^ ~0U;
691
692	return (ss);
693
694}
695
696static int
697nandfs_save_buf(struct buf *bp, uint64_t blocknr, struct nandfs_device *fsdev)
698{
699	struct bufobj *bo;
700	int error;
701
702	bo = &fsdev->nd_devvp->v_bufobj;
703
704	bp->b_blkno = nandfs_block_to_dblock(fsdev, blocknr);
705	bp->b_iooffset = dbtob(bp->b_blkno);
706
707	KASSERT(bp->b_bufobj != NULL, ("no bufobj for %p", bp));
708	if (bp->b_bufobj != bo) {
709		BO_LOCK(bp->b_bufobj);
710		BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK,
711		    BO_LOCKPTR(bp->b_bufobj));
712		KASSERT(BUF_ISLOCKED(bp), ("Problem with locking buffer"));
713	}
714
715	DPRINTF(SYNC, ("%s: buf: %p offset %#jx blk %#jx size %#x\n",
716	    __func__, bp, (uintmax_t)bp->b_offset, (uintmax_t)blocknr,
717	    fsdev->nd_blocksize));
718
719	NANDFS_UNGATHER(bp);
720	nandfs_buf_clear(bp, 0xffffffff);
721	bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED);
722	error = bwrite(bp);
723	if (error) {
724		nandfs_error("%s: error:%d when writing buffer:%p\n",
725		    __func__, error, bp);
726		return (error);
727	}
728	return (error);
729}
730
731static void
732nandfs_clean_buf(struct nandfs_device *fsdev, struct buf *bp)
733{
734
735	DPRINTF(SYNC, ("%s: buf: %p\n", __func__, bp));
736
737	NANDFS_UNGATHER(bp);
738	nandfs_buf_clear(bp, 0xffffffff);
739	bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED);
740	nandfs_undirty_buf_fsdev(fsdev, bp);
741}
742
743static void
744nandfs_clean_segblocks(struct nandfs_segment *seg, uint8_t unlock)
745{
746	struct nandfs_device *fsdev = seg->fsdev;
747	struct nandfs_segment *next_seg;
748	struct buf *bp, *tbp, *next_bp;
749	struct vnode *vp, *next_vp;
750
751	VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE);
752	TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) {
753		TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
754		nandfs_clean_buf(fsdev, bp);
755	}
756
757	TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) {
758		TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry);
759
760		/*
761		 * If bp is not super-root and vnode is not currently
762		 * locked lock it.
763		 */
764		vp = bp->b_vp;
765		next_vp = NULL;
766		next_bp = TAILQ_NEXT(bp,  b_cluster.cluster_entry);
767		if (!next_bp) {
768			next_seg = LIST_NEXT(seg, seg_link);
769			if (next_seg)
770				next_bp = TAILQ_FIRST(&next_seg->data);
771		}
772
773		if (next_bp)
774			next_vp = next_bp->b_vp;
775
776		nandfs_clean_buf(fsdev, bp);
777
778		if (unlock && vp != NULL && next_vp != vp &&
779		    !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
780			vput(vp);
781
782		nandfs_dirty_bufs_decrement(fsdev);
783	}
784
785	VOP_UNLOCK(fsdev->nd_devvp, 0);
786}
787
788static int
789nandfs_save_segblocks(struct nandfs_segment *seg, uint8_t unlock)
790{
791	struct nandfs_device *fsdev = seg->fsdev;
792	struct nandfs_segment *next_seg;
793	struct buf *bp, *tbp, *next_bp;
794	struct vnode *vp, *next_vp;
795	uint64_t blocknr;
796	uint32_t i = 0;
797	int error = 0;
798
799	VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE);
800	TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) {
801		TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
802		blocknr = seg->start_block + i;
803		error = nandfs_save_buf(bp, blocknr, fsdev);
804		if (error) {
805			nandfs_error("%s: error saving buf: %p blocknr:%jx\n",
806			    __func__, bp, (uintmax_t)blocknr);
807			goto out;
808		}
809		i++;
810	}
811
812	i = 0;
813	TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) {
814		TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry);
815
816		blocknr = seg->start_block + seg->segsum_blocks + i;
817		/*
818		 * If bp is not super-root and vnode is not currently
819		 * locked lock it.
820		 */
821		vp = bp->b_vp;
822		next_vp = NULL;
823		next_bp = TAILQ_NEXT(bp,  b_cluster.cluster_entry);
824		if (!next_bp) {
825			next_seg = LIST_NEXT(seg, seg_link);
826			if (next_seg)
827				next_bp = TAILQ_FIRST(&next_seg->data);
828		}
829
830		if (next_bp)
831			next_vp = next_bp->b_vp;
832
833		error = nandfs_save_buf(bp, blocknr, fsdev);
834		if (error) {
835			nandfs_error("%s: error saving buf: %p blknr: %jx\n",
836			    __func__, bp, (uintmax_t)blocknr);
837			if (unlock && vp != NULL && next_vp != vp &&
838			    !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
839				vput(vp);
840			goto out;
841		}
842
843		if (unlock && vp != NULL && next_vp != vp &&
844		    !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
845			vput(vp);
846
847		i++;
848		nandfs_dirty_bufs_decrement(fsdev);
849	}
850out:
851	if (error) {
852		nandfs_clean_segblocks(seg, unlock);
853		VOP_UNLOCK(fsdev->nd_devvp, 0);
854		return (error);
855	}
856
857	VOP_UNLOCK(fsdev->nd_devvp, 0);
858	return (error);
859}
860
861
862static void
863clean_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock)
864{
865	struct nandfs_segment *seg;
866
867	DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo));
868
869	LIST_FOREACH(seg, &seginfo->seg_list, seg_link) {
870		nandfs_clean_segblocks(seg, unlock);
871	}
872}
873
874static int
875save_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock)
876{
877	struct nandfs_segment *seg;
878	struct nandfs_device *fsdev;
879	struct nandfs_segment_summary *ss;
880	int error = 0;
881
882	fsdev = seginfo->fsdev;
883
884	DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo));
885
886	LIST_FOREACH(seg, &seginfo->seg_list, seg_link) {
887		if (LIST_NEXT(seg, seg_link)) {
888			nandfs_fill_segsum(seg, 0);
889			error = nandfs_save_segblocks(seg, unlock);
890			if (error) {
891				nandfs_error("%s: error:%d saving seg:%p\n",
892				    __func__, error, seg);
893				goto out;
894			}
895		} else {
896			ss = nandfs_fill_segsum(seg, 1);
897			fsdev->nd_last_segsum = *ss;
898			error = nandfs_save_segblocks(seg, unlock);
899			if (error) {
900				nandfs_error("%s: error:%d saving seg:%p\n",
901				    __func__, error, seg);
902				goto out;
903			}
904			fsdev->nd_last_cno++;
905			fsdev->nd_last_pseg = seg->start_block;
906		}
907	}
908out:
909	if (error)
910		clean_seginfo(seginfo, unlock);
911	return (error);
912}
913
914static void
915nandfs_invalidate_bufs(struct nandfs_device *fsdev, uint64_t segno)
916{
917	uint64_t start, end;
918	struct buf *bp, *tbd;
919	struct bufobj *bo;
920
921	nandfs_get_segment_range(fsdev, segno, &start, &end);
922
923	bo = &NTOV(fsdev->nd_gc_node)->v_bufobj;
924
925	BO_LOCK(bo);
926restart_locked_gc:
927	TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, tbd) {
928		if (!(bp->b_lblkno >= start && bp->b_lblkno <= end))
929			continue;
930
931		if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL))
932			goto restart_locked_gc;
933
934		bremfree(bp);
935		bp->b_flags |= (B_INVAL | B_RELBUF);
936		bp->b_flags &= ~(B_ASYNC | B_MANAGED);
937		BO_UNLOCK(bo);
938		brelse(bp);
939		BO_LOCK(bo);
940	}
941	BO_UNLOCK(bo);
942}
943
944/* Process segments marks to free by cleaner */
945static void
946nandfs_process_segments(struct nandfs_device *fsdev)
947{
948	uint64_t saved_segment;
949	int i;
950
951	if (fsdev->nd_free_base) {
952		saved_segment = nandfs_get_segnum_of_block(fsdev,
953		    fsdev->nd_super.s_last_pseg);
954		for (i = 0; i < fsdev->nd_free_count; i++) {
955			if (fsdev->nd_free_base[i] == NANDFS_NOSEGMENT)
956				continue;
957			/* Update superblock if clearing segment point by it */
958			if (fsdev->nd_free_base[i] == saved_segment) {
959				nandfs_write_superblock(fsdev);
960				saved_segment = nandfs_get_segnum_of_block(
961				    fsdev, fsdev->nd_super.s_last_pseg);
962			}
963			nandfs_invalidate_bufs(fsdev, fsdev->nd_free_base[i]);
964			nandfs_clear_segment(fsdev, fsdev->nd_free_base[i]);
965		}
966
967		free(fsdev->nd_free_base, M_NANDFSTEMP);
968		fsdev->nd_free_base = NULL;
969		fsdev->nd_free_count = 0;
970	}
971}
972
973/* Collect and write dirty buffers */
974int
975nandfs_sync_file(struct vnode *vp)
976{
977	struct nandfs_device *fsdev;
978	struct nandfs_node *nandfs_node;
979	struct nandfsmount *nmp;
980	struct nandfs_node *dat, *su, *ifile, *cp;
981	struct nandfs_seginfo *seginfo = NULL;
982	struct nandfs_segment *seg;
983	int update, error;
984	int cno_changed;
985
986	ASSERT_VOP_LOCKED(vp, __func__);
987	DPRINTF(SYNC, ("%s: START\n", __func__));
988
989	error = 0;
990	nmp = VFSTONANDFS(vp->v_mount);
991	fsdev = nmp->nm_nandfsdev;
992
993	dat = fsdev->nd_dat_node;
994	su = fsdev->nd_su_node;
995	cp = fsdev->nd_cp_node;
996	ifile = nmp->nm_ifile_node;
997
998	NANDFS_WRITEASSERT(fsdev);
999	if (lockmgr(&fsdev->nd_seg_const, LK_UPGRADE, NULL) != 0) {
1000		DPRINTF(SYNC, ("%s: lost shared lock\n", __func__));
1001		if (lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL) != 0)
1002			panic("couldn't lock exclusive");
1003	}
1004	DPRINTF(SYNC, ("%s: got lock\n", __func__));
1005
1006	VOP_LOCK(NTOV(su), LK_EXCLUSIVE);
1007	create_seginfo(fsdev, &seginfo);
1008
1009	update = 0;
1010
1011	nandfs_node = VTON(vp);
1012	if (nandfs_node->nn_flags & IN_MODIFIED) {
1013		nandfs_node->nn_flags &= ~(IN_MODIFIED);
1014		update = 1;
1015	}
1016
1017	if (vp->v_bufobj.bo_dirty.bv_cnt) {
1018		error = nandfs_iterate_dirty_buf(vp, seginfo, 0);
1019		if (error) {
1020			clean_seginfo(seginfo, 0);
1021			delete_seginfo(seginfo);
1022			VOP_UNLOCK(NTOV(su), 0);
1023			lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1024			nandfs_error("%s: err:%d iterating dirty bufs vp:%p",
1025			    __func__, error, vp);
1026			return (error);
1027		}
1028		update = 1;
1029	}
1030
1031	if (update) {
1032		VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE);
1033		error = nandfs_node_update(nandfs_node);
1034		if (error) {
1035			clean_seginfo(seginfo, 0);
1036			delete_seginfo(seginfo);
1037			VOP_UNLOCK(NTOV(ifile), 0);
1038			VOP_UNLOCK(NTOV(su), 0);
1039			lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1040			nandfs_error("%s: err:%d updating vp:%p",
1041			    __func__, error, vp);
1042			return (error);
1043		}
1044		VOP_UNLOCK(NTOV(ifile), 0);
1045	}
1046
1047	cno_changed = 0;
1048	if (seginfo->blocks) {
1049		VOP_LOCK(NTOV(cp), LK_EXCLUSIVE);
1050		cno_changed = 1;
1051		/* Create new checkpoint */
1052		error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1);
1053		if (error) {
1054			clean_seginfo(seginfo, 0);
1055			delete_seginfo(seginfo);
1056			VOP_UNLOCK(NTOV(cp), 0);
1057			VOP_UNLOCK(NTOV(su), 0);
1058			lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1059			nandfs_error("%s: err:%d getting cp:%jx",
1060			    __func__, error, fsdev->nd_last_cno + 1);
1061			return (error);
1062		}
1063
1064		/* Reiterate all blocks and assign physical block number */
1065		nandfs_seginfo_assign_pblk(seginfo);
1066
1067		/* Fill checkpoint data */
1068		error = nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1,
1069		    &ifile->nn_inode, seginfo->blocks);
1070		if (error) {
1071			clean_seginfo(seginfo, 0);
1072			delete_seginfo(seginfo);
1073			VOP_UNLOCK(NTOV(cp), 0);
1074			VOP_UNLOCK(NTOV(su), 0);
1075			lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1076			nandfs_error("%s: err:%d setting cp:%jx",
1077			    __func__, error, fsdev->nd_last_cno + 1);
1078			return (error);
1079		}
1080
1081		VOP_UNLOCK(NTOV(cp), 0);
1082		LIST_FOREACH(seg, &seginfo->seg_list, seg_link)
1083			nandfs_update_segment(fsdev, seg->seg_num,
1084			    seg->nblocks + seg->segsum_blocks);
1085
1086		VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1087		error = save_seginfo(seginfo, 0);
1088		if (error) {
1089			clean_seginfo(seginfo, 0);
1090			delete_seginfo(seginfo);
1091			VOP_UNLOCK(NTOV(dat), 0);
1092			VOP_UNLOCK(NTOV(su), 0);
1093			lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1094			nandfs_error("%s: err:%d updating seg",
1095			    __func__, error);
1096			return (error);
1097		}
1098		VOP_UNLOCK(NTOV(dat), 0);
1099	}
1100
1101	VOP_UNLOCK(NTOV(su), 0);
1102
1103	delete_seginfo(seginfo);
1104	lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1105
1106	if (cno_changed && !error) {
1107		if (nandfs_cps_between_sblocks != 0 &&
1108		    fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0)
1109			nandfs_write_superblock(fsdev);
1110	}
1111
1112	ASSERT_VOP_LOCKED(vp, __func__);
1113	DPRINTF(SYNC, ("%s: END error %d\n", __func__, error));
1114	return (error);
1115}
1116
1117int
1118nandfs_segment_constructor(struct nandfsmount *nmp, int flags)
1119{
1120	struct nandfs_device *fsdev;
1121	struct nandfs_seginfo *seginfo = NULL;
1122	struct nandfs_segment *seg;
1123	struct nandfs_node *dat, *su, *ifile, *cp, *gc;
1124	int cno_changed, error;
1125
1126	DPRINTF(SYNC, ("%s: START\n", __func__));
1127	fsdev = nmp->nm_nandfsdev;
1128
1129	lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL);
1130	DPRINTF(SYNC, ("%s: git lock\n", __func__));
1131again:
1132	create_seginfo(fsdev, &seginfo);
1133
1134	dat = fsdev->nd_dat_node;
1135	su = fsdev->nd_su_node;
1136	cp = fsdev->nd_cp_node;
1137	gc = fsdev->nd_gc_node;
1138	ifile = nmp->nm_ifile_node;
1139
1140	VOP_LOCK(NTOV(su), LK_EXCLUSIVE);
1141	VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE);
1142	VOP_LOCK(NTOV(gc), LK_EXCLUSIVE);
1143	VOP_LOCK(NTOV(cp), LK_EXCLUSIVE);
1144
1145	nandfs_iterate_system_vnode(gc, seginfo);
1146	nandfs_iterate_dirty_vnodes(nmp->nm_vfs_mountp, seginfo);
1147	nandfs_iterate_system_vnode(ifile, seginfo);
1148	nandfs_iterate_system_vnode(su, seginfo);
1149
1150	cno_changed = 0;
1151	if (seginfo->blocks || flags) {
1152		cno_changed = 1;
1153		/* Create new checkpoint */
1154		error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1);
1155		if (error) {
1156			clean_seginfo(seginfo, 0);
1157			delete_seginfo(seginfo);
1158			goto error_locks;
1159		}
1160
1161		/* Collect blocks from system files */
1162		nandfs_iterate_system_vnode(cp, seginfo);
1163		nandfs_iterate_system_vnode(su, seginfo);
1164		VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1165		nandfs_iterate_system_vnode(dat, seginfo);
1166		VOP_UNLOCK(NTOV(dat), 0);
1167reiterate:
1168		seginfo->reiterate = 0;
1169		nandfs_iterate_system_vnode(su, seginfo);
1170		VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1171		nandfs_iterate_system_vnode(dat, seginfo);
1172		VOP_UNLOCK(NTOV(dat), 0);
1173		if (seginfo->reiterate)
1174			goto reiterate;
1175		if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
1176			error = create_segment(seginfo);
1177			if (error) {
1178				clean_seginfo(seginfo, 0);
1179				delete_seginfo(seginfo);
1180				goto error_locks;
1181			}
1182			goto reiterate;
1183		}
1184
1185		/* Reiterate all blocks and assign physical block number */
1186		nandfs_seginfo_assign_pblk(seginfo);
1187
1188		/* Fill superroot */
1189		error = nandfs_add_superroot(seginfo);
1190		if (error) {
1191			clean_seginfo(seginfo, 0);
1192			delete_seginfo(seginfo);
1193			goto error_locks;
1194		}
1195		KASSERT(!(seginfo->reiterate), ("reiteration after superroot"));
1196
1197		/* Fill checkpoint data */
1198		nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1,
1199		    &ifile->nn_inode, seginfo->blocks);
1200
1201		LIST_FOREACH(seg, &seginfo->seg_list, seg_link)
1202			nandfs_update_segment(fsdev, seg->seg_num,
1203			    seg->nblocks + seg->segsum_blocks);
1204
1205		VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1206		error = save_seginfo(seginfo, 1);
1207		if (error) {
1208			clean_seginfo(seginfo, 1);
1209			delete_seginfo(seginfo);
1210			goto error_dat;
1211		}
1212		VOP_UNLOCK(NTOV(dat), 0);
1213	}
1214
1215	VOP_UNLOCK(NTOV(cp), 0);
1216	VOP_UNLOCK(NTOV(gc), 0);
1217	VOP_UNLOCK(NTOV(ifile), 0);
1218
1219	nandfs_process_segments(fsdev);
1220
1221	VOP_UNLOCK(NTOV(su), 0);
1222
1223	delete_seginfo(seginfo);
1224
1225	/*
1226	 * XXX: a hack, will go away soon
1227	 */
1228	if ((NTOV(dat)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1229	    NTOV(cp)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1230	    NTOV(gc)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1231	    NTOV(ifile)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1232	    NTOV(su)->v_bufobj.bo_dirty.bv_cnt != 0) &&
1233	    (flags & NANDFS_UMOUNT)) {
1234		DPRINTF(SYNC, ("%s: RERUN\n", __func__));
1235		goto again;
1236	}
1237
1238	MPASS(fsdev->nd_free_base == NULL);
1239
1240	lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL);
1241
1242	if (cno_changed) {
1243		if ((nandfs_cps_between_sblocks != 0 &&
1244		    fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) ||
1245		    flags & NANDFS_UMOUNT)
1246			nandfs_write_superblock(fsdev);
1247	}
1248
1249	DPRINTF(SYNC, ("%s: END\n", __func__));
1250	return (0);
1251error_dat:
1252	VOP_UNLOCK(NTOV(dat), 0);
1253error_locks:
1254	VOP_UNLOCK(NTOV(cp), 0);
1255	VOP_UNLOCK(NTOV(gc), 0);
1256	VOP_UNLOCK(NTOV(ifile), 0);
1257	VOP_UNLOCK(NTOV(su), 0);
1258	lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL);
1259
1260	return (error);
1261}
1262
1263#ifdef DDB
1264/*
1265 * Show details about the given NANDFS mount point.
1266 */
1267DB_SHOW_COMMAND(nandfs, db_show_nandfs)
1268{
1269	struct mount *mp;
1270	struct nandfs_device *nffsdev;
1271	struct nandfs_segment *seg;
1272	struct nandfsmount *nmp;
1273	struct buf *bp;
1274	struct vnode *vp;
1275
1276	if (!have_addr) {
1277		db_printf("\nUsage: show nandfs <mount_addr>\n");
1278		return;
1279	}
1280
1281	mp = (struct mount *)addr;
1282	db_printf("%p %s on %s (%s)\n", mp, mp->mnt_stat.f_mntfromname,
1283	    mp->mnt_stat.f_mntonname, mp->mnt_stat.f_fstypename);
1284
1285
1286	nmp = (struct nandfsmount *)(mp->mnt_data);
1287	nffsdev = nmp->nm_nandfsdev;
1288	db_printf("dev vnode:%p\n", nffsdev->nd_devvp);
1289	db_printf("blocksize:%jx last cno:%jx last pseg:%jx seg num:%jx\n",
1290	    (uintmax_t)nffsdev->nd_blocksize, (uintmax_t)nffsdev->nd_last_cno,
1291	    (uintmax_t)nffsdev->nd_last_pseg, (uintmax_t)nffsdev->nd_seg_num);
1292	db_printf("system nodes: dat:%p cp:%p su:%p ifile:%p gc:%p\n",
1293	    nffsdev->nd_dat_node, nffsdev->nd_cp_node, nffsdev->nd_su_node,
1294	    nmp->nm_ifile_node, nffsdev->nd_gc_node);
1295
1296	if (nffsdev->nd_seginfo != NULL) {
1297		LIST_FOREACH(seg, &nffsdev->nd_seginfo->seg_list, seg_link) {
1298			db_printf("seg: %p\n", seg);
1299			TAILQ_FOREACH(bp, &seg->segsum,
1300			    b_cluster.cluster_entry)
1301				db_printf("segbp %p\n", bp);
1302			TAILQ_FOREACH(bp, &seg->data,
1303			    b_cluster.cluster_entry) {
1304				vp = bp->b_vp;
1305				db_printf("bp:%p bp->b_vp:%p ino:%jx\n", bp, vp,
1306				    (uintmax_t)(vp ? VTON(vp)->nn_ino : 0));
1307			}
1308		}
1309	}
1310}
1311#endif
1312