2 * Copyright (c) 2010-2012 Semihalf.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/systm.h>
35 #include <sys/kernel.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>
46 #include <sys/libkern.h>
51 #include <vm/vm_param.h>
52 #include <vm/vm_kern.h>
53 #include <vm/vm_page.h>
55 #include <geom/geom.h>
56 #include <geom/geom_vfs.h>
58 #include <fs/nandfs/nandfs_mount.h>
59 #include <fs/nandfs/nandfs.h>
60 #include <fs/nandfs/nandfs_subr.h>
63 nandfs_new_segment(struct nandfs_device *fsdev)
68 error = nandfs_alloc_segment(fsdev, &new);
70 fsdev->nd_seg_num = fsdev->nd_next_seg_num;
71 fsdev->nd_next_seg_num = new;
73 DPRINTF(SYNC, ("%s: new segment %jx next %jx error %d\n",
74 __func__, (uintmax_t)fsdev->nd_seg_num, (uintmax_t)new, error));
76 nandfs_error("%s: cannot create segment error %d\n",
83 create_segment(struct nandfs_seginfo *seginfo)
85 struct nandfs_segment *seg;
86 struct nandfs_device *fsdev;
87 struct nandfs_segment *prev;
89 uint64_t start_block, curr;
90 uint32_t blks_per_seg, nblocks;
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;
99 vfs_timestamp(&fsdev->nd_ts);
100 /* Touch current segment */
101 error = nandfs_touch_segment(fsdev, fsdev->nd_seg_num);
103 nandfs_error("%s: cannot preallocate segment %jx\n",
104 __func__, fsdev->nd_seg_num);
107 error = nandfs_touch_segment(fsdev, 0);
109 nandfs_error("%s: cannot dirty block with segment 0\n",
113 start_block = fsdev->nd_last_pseg + (uint64_t)nblocks;
117 if (blks_per_seg - (start_block % blks_per_seg) - 1 == 0)
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);
124 nandfs_error("%s: cannot create new segment\n",
131 nandfs_get_segment_range(fsdev, fsdev->nd_seg_num, &start_block, NULL);
134 nandfs_get_segment_range(fsdev, fsdev->nd_next_seg_num,
137 /* Touch current segment and allocate and touch new one */
138 error = nandfs_new_segment(fsdev);
140 nandfs_error("%s: cannot create next segment\n",
145 /* Reiterate in case new buf is dirty */
146 seginfo->reiterate = 1;
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);
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);
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;
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);
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));
181 LIST_INSERT_HEAD(&seginfo->seg_list, seg, seg_link);
183 LIST_INSERT_AFTER(prev, seg, seg_link);
185 seginfo->curseg = seg;
191 delete_segment(struct nandfs_seginfo *seginfo)
193 struct nandfs_segment *seg, *tseg;
194 struct buf *bp, *tbp;
196 LIST_FOREACH_SAFE(seg, &seginfo->seg_list, seg_link, tseg) {
197 TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry,
199 TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
200 bp->b_flags &= ~B_MANAGED;
204 LIST_REMOVE(seg, seg_link);
212 create_seginfo(struct nandfs_device *fsdev, struct nandfs_seginfo **seginfo)
214 struct nandfs_seginfo *info;
216 info = malloc(sizeof(*info), M_DEVBUF, M_WAITOK);
218 LIST_INIT(&info->seg_list);
223 fsdev->nd_seginfo = info;
228 delete_seginfo(struct nandfs_seginfo *seginfo)
230 struct nandfs_device *nffsdev;
232 nffsdev = seginfo->fsdev;
233 delete_segment(seginfo);
234 nffsdev->nd_seginfo = NULL;
235 free(seginfo, M_DEVBUF);
241 nandfs_create_superroot_block(struct nandfs_seginfo *seginfo,
247 bp = nandfs_geteblk(seginfo->fsdev->nd_blocksize, GB_NOWAIT_BD);
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;
253 if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
254 error = create_segment(seginfo);
257 nandfs_error("%s: no segment for superroot\n",
263 TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry);
265 seginfo->curseg->nblocks++;
266 seginfo->curseg->num_blocks--;
274 nandfs_add_superroot(struct nandfs_seginfo *seginfo)
276 struct nandfs_device *fsdev;
277 struct nandfs_super_root *sr;
278 struct buf *bp = NULL;
283 fsdev = seginfo->fsdev;
285 error = nandfs_create_superroot_block(seginfo, &bp);
287 nandfs_error("%s: cannot add superroot\n", __func__);
291 sr = (struct nandfs_super_root *)bp->b_data;
292 /* Save superroot CRC */
293 sr->sr_bytes = NANDFS_SR_BYTES;
295 sr->sr_nongc_ctime = 0;
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));
304 crc_skip = sizeof(sr->sr_sum);
305 crc_calc = crc32((uint8_t *)sr + crc_skip, NANDFS_SR_BYTES - crc_skip);
307 sr->sr_sum = crc_calc;
309 bp->b_flags |= B_MANAGED;
310 bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
312 bp->b_flags &= ~B_INVAL;
313 nandfs_dirty_bufs_increment(fsdev);
314 DPRINTF(SYNC, ("%s: bp:%p\n", __func__, bp));
320 nandfs_add_segsum_block(struct nandfs_seginfo *seginfo, struct buf **newbp)
322 struct nandfs_device *fsdev;
327 if (!(seginfo->curseg) || seginfo->curseg->num_blocks <= 1) {
328 error = create_segment(seginfo);
330 nandfs_error("%s: error:%d when creating segment\n",
334 *newbp = TAILQ_FIRST(&seginfo->curseg->segsum);
338 fsdev = seginfo->fsdev;
339 blk = nandfs_block_to_dblock(fsdev, seginfo->curseg->start_block +
340 seginfo->curseg->segsum_blocks);
342 bp = getblk(fsdev->nd_devvp, blk, fsdev->nd_blocksize, 0, 0, 0);
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;
348 TAILQ_INSERT_TAIL(&seginfo->curseg->segsum, bp,
349 b_cluster.cluster_entry);
350 seginfo->curseg->num_blocks--;
352 seginfo->curseg->segsum_blocks++;
353 seginfo->curseg->bytes_left = seginfo->fsdev->nd_blocksize;
354 seginfo->curseg->current_off = bp->b_data;
359 DPRINTF(SYNC, ("%s: bp %p\n", __func__, bp));
365 nandfs_add_blocks(struct nandfs_seginfo *seginfo, struct nandfs_node *node,
368 union nandfs_binfo *binfo;
372 if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
373 error = create_segment(seginfo);
375 nandfs_error("%s: error:%d when creating segment\n",
381 if (seginfo->curseg->bytes_left < sizeof(union nandfs_binfo)) {
382 error = nandfs_add_segsum_block(seginfo, &seg_bp);
384 nandfs_error("%s: error:%d when adding segsum\n",
389 binfo = (union nandfs_binfo *)seginfo->curseg->current_off;
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;
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;
400 binfo->bi_dat.bi_level = 0;
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;
408 TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry);
410 seginfo->curseg->nbinfos++;
411 seginfo->curseg->nblocks++;
412 seginfo->curseg->num_blocks--;
415 DPRINTF(SYNC, ("%s: bp (%p) number %x (left %x)\n",
416 __func__, bp, seginfo->curseg->nblocks,
417 seginfo->curseg->num_blocks));
422 nandfs_iterate_dirty_buf(struct vnode *vp, struct nandfs_seginfo *seginfo,
425 struct buf *bp, *tbd;
427 struct nandfs_node *node;
433 ASSERT_VOP_ELOCKED(vp, __func__);
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));
440 if (!(NANDFS_ISGATHERED(bp))) {
441 error = nandfs_bmap_update_dat(node,
442 nandfs_vblk_get(bp), bp);
446 nandfs_add_blocks(seginfo, node, bp);
454 nandfs_iterate_system_vnode(struct nandfs_node *node,
455 struct nandfs_seginfo *seginfo)
461 if (node->nn_ino != NANDFS_IFILE_INO)
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));
471 nandfs_iterate_dirty_buf(vp, seginfo, hold);
477 nandfs_iterate_dirty_vnodes(struct mount *mp, struct nandfs_seginfo *seginfo)
479 struct nandfs_node *nandfs_node;
480 struct vnode *vp, *mvp;
486 MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) {
489 if (mp->mnt_syncer == vp || VOP_ISLOCKED(vp)) {
493 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK | LK_NOWAIT, td) != 0)
496 nandfs_node = VTON(vp);
497 if (nandfs_node->nn_flags & IN_MODIFIED) {
498 nandfs_node->nn_flags &= ~(IN_MODIFIED);
502 if (vp->v_bufobj.bo_dirty.bv_cnt) {
503 error = nandfs_iterate_dirty_buf(vp, seginfo, 0);
505 nandfs_error("%s: cannot iterate vnode:%p "
506 "err:%d\n", __func__, vp, error);
515 nandfs_node_update(nandfs_node);
522 nandfs_update_phys_block(struct nandfs_device *fsdev, struct buf *bp,
523 uint64_t phys_blknr, union nandfs_binfo *binfo)
525 struct nandfs_node *node, *dat;
532 new_blknr = nandfs_vblk_get(bp);
533 dat = fsdev->nd_dat_node;
535 DPRINTF(BMAP, ("%s: ino %#jx lblk %#jx: vblk %#jx -> %#jx\n",
536 __func__, (uintmax_t)node->nn_ino, (uintmax_t)bp->b_lblkno,
537 (uintmax_t)new_blknr, (uintmax_t)phys_blknr));
539 if (node->nn_ino != NANDFS_DAT_INO) {
540 KASSERT((new_blknr != 0), ("vblk for bp %p is 0", bp));
542 nandfs_vblock_assign(fsdev, new_blknr, phys_blknr);
543 binfo->bi_v.bi_vblocknr = new_blknr;
544 binfo->bi_v.bi_blkoff = bp->b_lblkno;
545 binfo->bi_v.bi_ino = node->nn_ino;
547 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
548 error = nandfs_bmap_update_block(node, bp, phys_blknr);
550 nandfs_error("%s: error updating block:%jx for bp:%p\n",
551 __func__, (uintmax_t)phys_blknr, bp);
552 VOP_UNLOCK(NTOV(dat), 0);
555 VOP_UNLOCK(NTOV(dat), 0);
556 binfo->bi_dat.bi_blkoff = bp->b_lblkno;
557 binfo->bi_dat.bi_ino = node->nn_ino;
558 if (NANDFS_IS_INDIRECT(bp))
559 binfo->bi_dat.bi_level = 1;
561 binfo->bi_dat.bi_level = 0;
567 #define NBINFO(off) ((off) + sizeof(union nandfs_binfo))
569 nandfs_segment_assign_pblk(struct nandfs_segment *nfsseg)
571 struct nandfs_device *fsdev;
572 union nandfs_binfo *binfo;
573 struct buf *bp, *seg_bp;
575 uint32_t curr_off, blocksize;
578 fsdev = nfsseg->fsdev;
579 blocksize = fsdev->nd_blocksize;
581 blocknr = nfsseg->start_block + nfsseg->segsum_blocks;
582 seg_bp = TAILQ_FIRST(&nfsseg->segsum);
583 DPRINTF(SYNC, ("%s: seg:%p segsum bp:%p data:%p\n",
584 __func__, nfsseg, seg_bp, seg_bp->b_data));
586 binfo = (union nandfs_binfo *)(seg_bp->b_data +
587 sizeof(struct nandfs_segment_summary));
588 curr_off = sizeof(struct nandfs_segment_summary);
590 TAILQ_FOREACH(bp, &nfsseg->data, b_cluster.cluster_entry) {
591 KASSERT((bp->b_vp), ("bp %p has not vp", bp));
593 DPRINTF(BMAP, ("\n\n%s: assign buf %p for ino %#jx next %p\n",
594 __func__, bp, (uintmax_t)VTON(bp->b_vp)->nn_ino,
595 TAILQ_NEXT(bp, b_cluster.cluster_entry)));
597 if (NBINFO(curr_off) > blocksize) {
598 seg_bp = TAILQ_NEXT(seg_bp, b_cluster.cluster_entry);
599 binfo = (union nandfs_binfo *)seg_bp->b_data;
601 DPRINTF(SYNC, ("%s: next segsum %p data %p\n",
602 __func__, seg_bp, seg_bp->b_data));
605 error = nandfs_update_phys_block(fsdev, bp, blocknr, binfo);
607 nandfs_error("%s: err:%d when updatinng phys block:%jx"
608 " for bp:%p and binfo:%p\n", __func__, error,
609 (uintmax_t)blocknr, bp, binfo);
613 curr_off = NBINFO(curr_off);
622 nandfs_seginfo_assign_pblk(struct nandfs_seginfo *seginfo)
624 struct nandfs_segment *nfsseg;
627 LIST_FOREACH(nfsseg, &seginfo->seg_list, seg_link) {
628 error = nandfs_segment_assign_pblk(nfsseg);
636 static struct nandfs_segment_summary *
637 nandfs_fill_segsum(struct nandfs_segment *seg, int has_sr)
639 struct nandfs_segment_summary *ss;
640 struct nandfs_device *fsdev;
642 uint32_t rest, segsum_size, blocksize, crc_calc;
644 uint8_t *crc_area, crc_skip;
646 DPRINTF(SYNC, ("%s: seg %#jx nblocks %#x sumbytes %#x\n",
647 __func__, (uintmax_t) seg->seg_num,
648 seg->nblocks + seg->segsum_blocks,
653 flags = NANDFS_SS_LOGBGN | NANDFS_SS_LOGEND;
655 flags |= NANDFS_SS_SR;
657 bp = TAILQ_FIRST(&seg->segsum);
658 ss = (struct nandfs_segment_summary *) bp->b_data;
659 ss->ss_magic = NANDFS_SEGSUM_MAGIC;
660 ss->ss_bytes = sizeof(struct nandfs_segment_summary);
661 ss->ss_flags = flags;
662 ss->ss_seq = ++(fsdev->nd_seg_sequence);
663 ss->ss_create = fsdev->nd_ts.tv_sec;
664 nandfs_get_segment_range(fsdev, seg->seg_next, &ss->ss_next, NULL);
665 ss->ss_nblocks = seg->nblocks + seg->segsum_blocks;
666 ss->ss_nbinfos = seg->nbinfos;
667 ss->ss_sumbytes = seg->segsum_bytes;
669 crc_skip = sizeof(ss->ss_datasum) + sizeof(ss->ss_sumsum);
670 blocksize = seg->fsdev->nd_blocksize;
672 segsum_size = seg->segsum_bytes - crc_skip;
673 rest = min(seg->segsum_bytes, blocksize) - crc_skip;
674 crc_area = (uint8_t *)ss + crc_skip;
676 while (segsum_size > 0) {
677 crc_calc = crc32_raw(crc_area, rest, crc_calc);
681 bp = TAILQ_NEXT(bp, b_cluster.cluster_entry);
682 crc_area = (uint8_t *)bp->b_data;
683 rest = segsum_size <= blocksize ? segsum_size : blocksize;
685 ss->ss_sumsum = crc_calc ^ ~0U;
692 nandfs_save_buf(struct buf *bp, uint64_t blocknr, struct nandfs_device *fsdev)
697 bo = &fsdev->nd_devvp->v_bufobj;
699 bp->b_blkno = nandfs_block_to_dblock(fsdev, blocknr);
700 bp->b_iooffset = dbtob(bp->b_blkno);
702 KASSERT(bp->b_bufobj != NULL, ("no bufobj for %p", bp));
703 if (bp->b_bufobj != bo) {
704 BO_LOCK(bp->b_bufobj);
705 BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK,
706 BO_LOCKPTR(bp->b_bufobj));
707 KASSERT(BUF_ISLOCKED(bp), ("Problem with locking buffer"));
710 DPRINTF(SYNC, ("%s: buf: %p offset %#jx blk %#jx size %#x\n",
711 __func__, bp, (uintmax_t)bp->b_offset, (uintmax_t)blocknr,
712 fsdev->nd_blocksize));
715 nandfs_buf_clear(bp, 0xffffffff);
716 bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED);
719 nandfs_error("%s: error:%d when writing buffer:%p\n",
720 __func__, error, bp);
727 nandfs_clean_buf(struct nandfs_device *fsdev, struct buf *bp)
730 DPRINTF(SYNC, ("%s: buf: %p\n", __func__, bp));
733 nandfs_buf_clear(bp, 0xffffffff);
734 bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED);
735 nandfs_undirty_buf_fsdev(fsdev, bp);
739 nandfs_clean_segblocks(struct nandfs_segment *seg, uint8_t unlock)
741 struct nandfs_device *fsdev = seg->fsdev;
742 struct nandfs_segment *next_seg;
743 struct buf *bp, *tbp, *next_bp;
744 struct vnode *vp, *next_vp;
746 VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE);
747 TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) {
748 TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
749 nandfs_clean_buf(fsdev, bp);
752 TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) {
753 TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry);
756 * If bp is not super-root and vnode is not currently
761 next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry);
763 next_seg = LIST_NEXT(seg, seg_link);
765 next_bp = TAILQ_FIRST(&next_seg->data);
769 next_vp = next_bp->b_vp;
771 nandfs_clean_buf(fsdev, bp);
773 if (unlock && vp != NULL && next_vp != vp &&
774 !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
777 nandfs_dirty_bufs_decrement(fsdev);
780 VOP_UNLOCK(fsdev->nd_devvp, 0);
784 nandfs_save_segblocks(struct nandfs_segment *seg, uint8_t unlock)
786 struct nandfs_device *fsdev = seg->fsdev;
787 struct nandfs_segment *next_seg;
788 struct buf *bp, *tbp, *next_bp;
789 struct vnode *vp, *next_vp;
794 VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE);
795 TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) {
796 TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
797 blocknr = seg->start_block + i;
798 error = nandfs_save_buf(bp, blocknr, fsdev);
800 nandfs_error("%s: error saving buf: %p blocknr:%jx\n",
801 __func__, bp, (uintmax_t)blocknr);
808 TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) {
809 TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry);
811 blocknr = seg->start_block + seg->segsum_blocks + i;
813 * If bp is not super-root and vnode is not currently
818 next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry);
820 next_seg = LIST_NEXT(seg, seg_link);
822 next_bp = TAILQ_FIRST(&next_seg->data);
826 next_vp = next_bp->b_vp;
828 error = nandfs_save_buf(bp, blocknr, fsdev);
830 nandfs_error("%s: error saving buf: %p blknr: %jx\n",
831 __func__, bp, (uintmax_t)blocknr);
832 if (unlock && vp != NULL && next_vp != vp &&
833 !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
838 if (unlock && vp != NULL && next_vp != vp &&
839 !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
843 nandfs_dirty_bufs_decrement(fsdev);
847 nandfs_clean_segblocks(seg, unlock);
848 VOP_UNLOCK(fsdev->nd_devvp, 0);
852 VOP_UNLOCK(fsdev->nd_devvp, 0);
858 clean_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock)
860 struct nandfs_segment *seg;
862 DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo));
864 LIST_FOREACH(seg, &seginfo->seg_list, seg_link) {
865 nandfs_clean_segblocks(seg, unlock);
870 save_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock)
872 struct nandfs_segment *seg;
873 struct nandfs_device *fsdev;
874 struct nandfs_segment_summary *ss;
877 fsdev = seginfo->fsdev;
879 DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo));
881 LIST_FOREACH(seg, &seginfo->seg_list, seg_link) {
882 if (LIST_NEXT(seg, seg_link)) {
883 nandfs_fill_segsum(seg, 0);
884 error = nandfs_save_segblocks(seg, unlock);
886 nandfs_error("%s: error:%d saving seg:%p\n",
887 __func__, error, seg);
891 ss = nandfs_fill_segsum(seg, 1);
892 fsdev->nd_last_segsum = *ss;
893 error = nandfs_save_segblocks(seg, unlock);
895 nandfs_error("%s: error:%d saving seg:%p\n",
896 __func__, error, seg);
899 fsdev->nd_last_cno++;
900 fsdev->nd_last_pseg = seg->start_block;
905 clean_seginfo(seginfo, unlock);
910 nandfs_invalidate_bufs(struct nandfs_device *fsdev, uint64_t segno)
913 struct buf *bp, *tbd;
916 nandfs_get_segment_range(fsdev, segno, &start, &end);
918 bo = &NTOV(fsdev->nd_gc_node)->v_bufobj;
922 TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, tbd) {
923 if (!(bp->b_lblkno >= start && bp->b_lblkno <= end))
926 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL))
927 goto restart_locked_gc;
930 bp->b_flags |= (B_INVAL | B_RELBUF);
931 bp->b_flags &= ~(B_ASYNC | B_MANAGED);
939 /* Process segments marks to free by cleaner */
941 nandfs_process_segments(struct nandfs_device *fsdev)
943 uint64_t saved_segment;
946 if (fsdev->nd_free_base) {
947 saved_segment = nandfs_get_segnum_of_block(fsdev,
948 fsdev->nd_super.s_last_pseg);
949 for (i = 0; i < fsdev->nd_free_count; i++) {
950 if (fsdev->nd_free_base[i] == NANDFS_NOSEGMENT)
952 /* Update superblock if clearing segment point by it */
953 if (fsdev->nd_free_base[i] == saved_segment) {
954 nandfs_write_superblock(fsdev);
955 saved_segment = nandfs_get_segnum_of_block(
956 fsdev, fsdev->nd_super.s_last_pseg);
958 nandfs_invalidate_bufs(fsdev, fsdev->nd_free_base[i]);
959 nandfs_clear_segment(fsdev, fsdev->nd_free_base[i]);
962 free(fsdev->nd_free_base, M_NANDFSTEMP);
963 fsdev->nd_free_base = NULL;
964 fsdev->nd_free_count = 0;
968 /* Collect and write dirty buffers */
970 nandfs_sync_file(struct vnode *vp)
972 struct nandfs_device *fsdev;
973 struct nandfs_node *nandfs_node;
974 struct nandfsmount *nmp;
975 struct nandfs_node *dat, *su, *ifile, *cp;
976 struct nandfs_seginfo *seginfo = NULL;
977 struct nandfs_segment *seg;
981 ASSERT_VOP_LOCKED(vp, __func__);
982 DPRINTF(SYNC, ("%s: START\n", __func__));
985 nmp = VFSTONANDFS(vp->v_mount);
986 fsdev = nmp->nm_nandfsdev;
988 dat = fsdev->nd_dat_node;
989 su = fsdev->nd_su_node;
990 cp = fsdev->nd_cp_node;
991 ifile = nmp->nm_ifile_node;
993 NANDFS_WRITEASSERT(fsdev);
994 if (lockmgr(&fsdev->nd_seg_const, LK_UPGRADE, NULL) != 0) {
995 DPRINTF(SYNC, ("%s: lost shared lock\n", __func__));
996 if (lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL) != 0)
997 panic("couldn't lock exclusive");
999 DPRINTF(SYNC, ("%s: got lock\n", __func__));
1001 VOP_LOCK(NTOV(su), LK_EXCLUSIVE);
1002 create_seginfo(fsdev, &seginfo);
1006 nandfs_node = VTON(vp);
1007 if (nandfs_node->nn_flags & IN_MODIFIED) {
1008 nandfs_node->nn_flags &= ~(IN_MODIFIED);
1012 if (vp->v_bufobj.bo_dirty.bv_cnt) {
1013 error = nandfs_iterate_dirty_buf(vp, seginfo, 0);
1015 clean_seginfo(seginfo, 0);
1016 delete_seginfo(seginfo);
1017 VOP_UNLOCK(NTOV(su), 0);
1018 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1019 nandfs_error("%s: err:%d iterating dirty bufs vp:%p",
1020 __func__, error, vp);
1027 VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE);
1028 error = nandfs_node_update(nandfs_node);
1030 clean_seginfo(seginfo, 0);
1031 delete_seginfo(seginfo);
1032 VOP_UNLOCK(NTOV(ifile), 0);
1033 VOP_UNLOCK(NTOV(su), 0);
1034 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1035 nandfs_error("%s: err:%d updating vp:%p",
1036 __func__, error, vp);
1039 VOP_UNLOCK(NTOV(ifile), 0);
1043 if (seginfo->blocks) {
1044 VOP_LOCK(NTOV(cp), LK_EXCLUSIVE);
1046 /* Create new checkpoint */
1047 error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1);
1049 clean_seginfo(seginfo, 0);
1050 delete_seginfo(seginfo);
1051 VOP_UNLOCK(NTOV(cp), 0);
1052 VOP_UNLOCK(NTOV(su), 0);
1053 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1054 nandfs_error("%s: err:%d getting cp:%jx",
1055 __func__, error, fsdev->nd_last_cno + 1);
1059 /* Reiterate all blocks and assign physical block number */
1060 nandfs_seginfo_assign_pblk(seginfo);
1062 /* Fill checkpoint data */
1063 error = nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1,
1064 &ifile->nn_inode, seginfo->blocks);
1066 clean_seginfo(seginfo, 0);
1067 delete_seginfo(seginfo);
1068 VOP_UNLOCK(NTOV(cp), 0);
1069 VOP_UNLOCK(NTOV(su), 0);
1070 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1071 nandfs_error("%s: err:%d setting cp:%jx",
1072 __func__, error, fsdev->nd_last_cno + 1);
1076 VOP_UNLOCK(NTOV(cp), 0);
1077 LIST_FOREACH(seg, &seginfo->seg_list, seg_link)
1078 nandfs_update_segment(fsdev, seg->seg_num,
1079 seg->nblocks + seg->segsum_blocks);
1081 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1082 error = save_seginfo(seginfo, 0);
1084 clean_seginfo(seginfo, 0);
1085 delete_seginfo(seginfo);
1086 VOP_UNLOCK(NTOV(dat), 0);
1087 VOP_UNLOCK(NTOV(su), 0);
1088 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1089 nandfs_error("%s: err:%d updating seg",
1093 VOP_UNLOCK(NTOV(dat), 0);
1096 VOP_UNLOCK(NTOV(su), 0);
1098 delete_seginfo(seginfo);
1099 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1101 if (cno_changed && !error) {
1102 if (nandfs_cps_between_sblocks != 0 &&
1103 fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0)
1104 nandfs_write_superblock(fsdev);
1107 ASSERT_VOP_LOCKED(vp, __func__);
1108 DPRINTF(SYNC, ("%s: END error %d\n", __func__, error));
1113 nandfs_segment_constructor(struct nandfsmount *nmp, int flags)
1115 struct nandfs_device *fsdev;
1116 struct nandfs_seginfo *seginfo = NULL;
1117 struct nandfs_segment *seg;
1118 struct nandfs_node *dat, *su, *ifile, *cp, *gc;
1119 int cno_changed, error;
1121 DPRINTF(SYNC, ("%s: START\n", __func__));
1122 fsdev = nmp->nm_nandfsdev;
1124 lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL);
1125 DPRINTF(SYNC, ("%s: git lock\n", __func__));
1127 create_seginfo(fsdev, &seginfo);
1129 dat = fsdev->nd_dat_node;
1130 su = fsdev->nd_su_node;
1131 cp = fsdev->nd_cp_node;
1132 gc = fsdev->nd_gc_node;
1133 ifile = nmp->nm_ifile_node;
1135 VOP_LOCK(NTOV(su), LK_EXCLUSIVE);
1136 VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE);
1137 VOP_LOCK(NTOV(gc), LK_EXCLUSIVE);
1138 VOP_LOCK(NTOV(cp), LK_EXCLUSIVE);
1140 nandfs_iterate_system_vnode(gc, seginfo);
1141 nandfs_iterate_dirty_vnodes(nmp->nm_vfs_mountp, seginfo);
1142 nandfs_iterate_system_vnode(ifile, seginfo);
1143 nandfs_iterate_system_vnode(su, seginfo);
1146 if (seginfo->blocks || flags) {
1148 /* Create new checkpoint */
1149 error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1);
1151 clean_seginfo(seginfo, 0);
1152 delete_seginfo(seginfo);
1156 /* Collect blocks from system files */
1157 nandfs_iterate_system_vnode(cp, seginfo);
1158 nandfs_iterate_system_vnode(su, seginfo);
1159 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1160 nandfs_iterate_system_vnode(dat, seginfo);
1161 VOP_UNLOCK(NTOV(dat), 0);
1163 seginfo->reiterate = 0;
1164 nandfs_iterate_system_vnode(su, seginfo);
1165 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1166 nandfs_iterate_system_vnode(dat, seginfo);
1167 VOP_UNLOCK(NTOV(dat), 0);
1168 if (seginfo->reiterate)
1170 if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
1171 error = create_segment(seginfo);
1173 clean_seginfo(seginfo, 0);
1174 delete_seginfo(seginfo);
1180 /* Reiterate all blocks and assign physical block number */
1181 nandfs_seginfo_assign_pblk(seginfo);
1183 /* Fill superroot */
1184 error = nandfs_add_superroot(seginfo);
1186 clean_seginfo(seginfo, 0);
1187 delete_seginfo(seginfo);
1190 KASSERT(!(seginfo->reiterate), ("reiteration after superroot"));
1192 /* Fill checkpoint data */
1193 nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1,
1194 &ifile->nn_inode, seginfo->blocks);
1196 LIST_FOREACH(seg, &seginfo->seg_list, seg_link)
1197 nandfs_update_segment(fsdev, seg->seg_num,
1198 seg->nblocks + seg->segsum_blocks);
1200 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1201 error = save_seginfo(seginfo, 1);
1203 clean_seginfo(seginfo, 1);
1204 delete_seginfo(seginfo);
1207 VOP_UNLOCK(NTOV(dat), 0);
1210 VOP_UNLOCK(NTOV(cp), 0);
1211 VOP_UNLOCK(NTOV(gc), 0);
1212 VOP_UNLOCK(NTOV(ifile), 0);
1214 nandfs_process_segments(fsdev);
1216 VOP_UNLOCK(NTOV(su), 0);
1218 delete_seginfo(seginfo);
1221 * XXX: a hack, will go away soon
1223 if ((NTOV(dat)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1224 NTOV(cp)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1225 NTOV(gc)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1226 NTOV(ifile)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1227 NTOV(su)->v_bufobj.bo_dirty.bv_cnt != 0) &&
1228 (flags & NANDFS_UMOUNT)) {
1229 DPRINTF(SYNC, ("%s: RERUN\n", __func__));
1233 MPASS(fsdev->nd_free_base == NULL);
1235 lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL);
1238 if ((nandfs_cps_between_sblocks != 0 &&
1239 fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) ||
1240 flags & NANDFS_UMOUNT)
1241 nandfs_write_superblock(fsdev);
1244 DPRINTF(SYNC, ("%s: END\n", __func__));
1247 VOP_UNLOCK(NTOV(dat), 0);
1249 VOP_UNLOCK(NTOV(cp), 0);
1250 VOP_UNLOCK(NTOV(gc), 0);
1251 VOP_UNLOCK(NTOV(ifile), 0);
1252 VOP_UNLOCK(NTOV(su), 0);
1253 lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL);
1260 * Show details about the given NANDFS mount point.
1262 DB_SHOW_COMMAND(nandfs, db_show_nandfs)
1265 struct nandfs_device *nffsdev;
1266 struct nandfs_segment *seg;
1267 struct nandfsmount *nmp;
1272 db_printf("\nUsage: show nandfs <mount_addr>\n");
1276 mp = (struct mount *)addr;
1277 db_printf("%p %s on %s (%s)\n", mp, mp->mnt_stat.f_mntfromname,
1278 mp->mnt_stat.f_mntonname, mp->mnt_stat.f_fstypename);
1281 nmp = (struct nandfsmount *)(mp->mnt_data);
1282 nffsdev = nmp->nm_nandfsdev;
1283 db_printf("dev vnode:%p\n", nffsdev->nd_devvp);
1284 db_printf("blocksize:%jx last cno:%jx last pseg:%jx seg num:%jx\n",
1285 (uintmax_t)nffsdev->nd_blocksize, (uintmax_t)nffsdev->nd_last_cno,
1286 (uintmax_t)nffsdev->nd_last_pseg, (uintmax_t)nffsdev->nd_seg_num);
1287 db_printf("system nodes: dat:%p cp:%p su:%p ifile:%p gc:%p\n",
1288 nffsdev->nd_dat_node, nffsdev->nd_cp_node, nffsdev->nd_su_node,
1289 nmp->nm_ifile_node, nffsdev->nd_gc_node);
1291 if (nffsdev->nd_seginfo != NULL) {
1292 LIST_FOREACH(seg, &nffsdev->nd_seginfo->seg_list, seg_link) {
1293 db_printf("seg: %p\n", seg);
1294 TAILQ_FOREACH(bp, &seg->segsum,
1295 b_cluster.cluster_entry)
1296 db_printf("segbp %p\n", bp);
1297 TAILQ_FOREACH(bp, &seg->data,
1298 b_cluster.cluster_entry) {
1300 db_printf("bp:%p bp->b_vp:%p ino:%jx\n", bp, vp,
1301 (uintmax_t)(vp ? VTON(vp)->nn_ino : 0));