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/sysctl.h>
42 #include <sys/vnode.h>
45 #include <sys/libkern.h>
50 #include <vm/vm_param.h>
51 #include <vm/vm_kern.h>
52 #include <vm/vm_page.h>
54 #include <geom/geom.h>
55 #include <geom/geom_vfs.h>
57 #include <fs/nandfs/nandfs_mount.h>
58 #include <fs/nandfs/nandfs.h>
59 #include <fs/nandfs/nandfs_subr.h>
62 nandfs_new_segment(struct nandfs_device *fsdev)
67 error = nandfs_alloc_segment(fsdev, &new);
69 fsdev->nd_seg_num = fsdev->nd_next_seg_num;
70 fsdev->nd_next_seg_num = new;
72 DPRINTF(SYNC, ("%s: new segment %jx next %jx error %d\n",
73 __func__, (uintmax_t)fsdev->nd_seg_num, (uintmax_t)new, error));
75 nandfs_error("%s: cannot create segment error %d\n",
82 create_segment(struct nandfs_seginfo *seginfo)
84 struct nandfs_segment *seg;
85 struct nandfs_device *fsdev;
86 struct nandfs_segment *prev;
88 uint64_t start_block, curr;
89 uint32_t blks_per_seg, nblocks;
92 fsdev = seginfo->fsdev;
93 prev = seginfo->curseg;
94 blks_per_seg = fsdev->nd_fsdata.f_blocks_per_segment;
95 nblocks = fsdev->nd_last_segsum.ss_nblocks;
98 vfs_timestamp(&fsdev->nd_ts);
99 /* Touch current segment */
100 error = nandfs_touch_segment(fsdev, fsdev->nd_seg_num);
102 nandfs_error("%s: cannot preallocate segment %jx\n",
103 __func__, fsdev->nd_seg_num);
106 error = nandfs_touch_segment(fsdev, 0);
108 nandfs_error("%s: cannot dirty block with segment 0\n",
112 start_block = fsdev->nd_last_pseg + (uint64_t)nblocks;
116 if (blks_per_seg - (start_block % blks_per_seg) - 1 == 0)
118 curr = nandfs_get_segnum_of_block(fsdev, start_block);
119 /* Allocate new segment if last one is full */
120 if (fsdev->nd_seg_num != curr) {
121 error = nandfs_new_segment(fsdev);
123 nandfs_error("%s: cannot create new segment\n",
130 nandfs_get_segment_range(fsdev, fsdev->nd_seg_num, &start_block, NULL);
133 nandfs_get_segment_range(fsdev, fsdev->nd_next_seg_num,
136 /* Touch current segment and allocate and touch new one */
137 error = nandfs_new_segment(fsdev);
139 nandfs_error("%s: cannot create next segment\n",
144 /* Reiterate in case new buf is dirty */
145 seginfo->reiterate = 1;
148 /* Allocate and initialize nandfs_segment structure */
149 seg = malloc(sizeof(*seg), M_DEVBUF, M_WAITOK|M_ZERO);
150 TAILQ_INIT(&seg->segsum);
151 TAILQ_INIT(&seg->data);
153 seg->start_block = start_block;
154 seg->num_blocks = blks_per_seg - (start_block % blks_per_seg) - 1;
155 seg->seg_num = fsdev->nd_seg_num;
156 seg->seg_next = fsdev->nd_next_seg_num;
157 seg->segsum_blocks = 1;
158 seg->bytes_left = fsdev->nd_blocksize -
159 sizeof(struct nandfs_segment_summary);
160 seg->segsum_bytes = sizeof(struct nandfs_segment_summary);
162 /* Allocate buffer for segment summary */
163 bp = getblk(fsdev->nd_devvp, nandfs_block_to_dblock(fsdev,
164 seg->start_block), fsdev->nd_blocksize, 0, 0, 0);
165 bzero(bp->b_data, seginfo->fsdev->nd_blocksize);
166 bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
167 bp->b_flags |= B_MANAGED;
169 /* Add buffer to segment */
170 TAILQ_INSERT_TAIL(&seg->segsum, bp, b_cluster.cluster_entry);
171 seg->current_off = bp->b_data + sizeof(struct nandfs_segment_summary);
173 DPRINTF(SYNC, ("%s: seg %p : initial settings: start %#jx size :%#x\n",
174 __func__, seg, (uintmax_t)seg->start_block, seg->num_blocks));
175 DPRINTF(SYNC, ("%s: seg->seg_num %#jx cno %#jx next %#jx\n", __func__,
176 (uintmax_t)seg->seg_num, (uintmax_t)(fsdev->nd_last_cno + 1),
177 (uintmax_t)seg->seg_next));
180 LIST_INSERT_HEAD(&seginfo->seg_list, seg, seg_link);
182 LIST_INSERT_AFTER(prev, seg, seg_link);
184 seginfo->curseg = seg;
190 delete_segment(struct nandfs_seginfo *seginfo)
192 struct nandfs_segment *seg, *tseg;
193 struct buf *bp, *tbp;
195 LIST_FOREACH_SAFE(seg, &seginfo->seg_list, seg_link, tseg) {
196 TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry,
198 TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
199 bp->b_flags &= ~B_MANAGED;
203 LIST_REMOVE(seg, seg_link);
211 create_seginfo(struct nandfs_device *fsdev, struct nandfs_seginfo **seginfo)
213 struct nandfs_seginfo *info;
215 info = malloc(sizeof(*info), M_DEVBUF, M_WAITOK);
217 LIST_INIT(&info->seg_list);
222 fsdev->nd_seginfo = info;
227 delete_seginfo(struct nandfs_seginfo *seginfo)
229 struct nandfs_device *nffsdev;
231 nffsdev = seginfo->fsdev;
232 delete_segment(seginfo);
233 nffsdev->nd_seginfo = NULL;
234 free(seginfo, M_DEVBUF);
240 nandfs_create_superroot_block(struct nandfs_seginfo *seginfo,
246 bp = nandfs_geteblk(seginfo->fsdev->nd_blocksize, GB_NOWAIT_BD);
248 bzero(bp->b_data, seginfo->fsdev->nd_blocksize);
249 bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
250 bp->b_flags |= B_MANAGED;
252 if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
253 error = create_segment(seginfo);
256 nandfs_error("%s: no segment for superroot\n",
262 TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry);
264 seginfo->curseg->nblocks++;
265 seginfo->curseg->num_blocks--;
273 nandfs_add_superroot(struct nandfs_seginfo *seginfo)
275 struct nandfs_device *fsdev;
276 struct nandfs_super_root *sr;
277 struct buf *bp = NULL;
282 fsdev = seginfo->fsdev;
284 error = nandfs_create_superroot_block(seginfo, &bp);
286 nandfs_error("%s: cannot add superroot\n", __func__);
290 sr = (struct nandfs_super_root *)bp->b_data;
291 /* Save superroot CRC */
292 sr->sr_bytes = NANDFS_SR_BYTES;
294 sr->sr_nongc_ctime = 0;
296 memcpy(&sr->sr_dat, &fsdev->nd_dat_node->nn_inode,
297 sizeof(struct nandfs_inode));
298 memcpy(&sr->sr_cpfile, &fsdev->nd_cp_node->nn_inode,
299 sizeof(struct nandfs_inode));
300 memcpy(&sr->sr_sufile, &fsdev->nd_su_node->nn_inode,
301 sizeof(struct nandfs_inode));
303 crc_skip = sizeof(sr->sr_sum);
304 crc_calc = crc32((uint8_t *)sr + crc_skip, NANDFS_SR_BYTES - crc_skip);
306 sr->sr_sum = crc_calc;
308 bp->b_flags |= B_MANAGED;
309 bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
311 bp->b_flags &= ~B_INVAL;
312 nandfs_dirty_bufs_increment(fsdev);
313 DPRINTF(SYNC, ("%s: bp:%p\n", __func__, bp));
319 nandfs_add_segsum_block(struct nandfs_seginfo *seginfo, struct buf **newbp)
321 struct nandfs_device *fsdev;
326 if (!(seginfo->curseg) || seginfo->curseg->num_blocks <= 1) {
327 error = create_segment(seginfo);
329 nandfs_error("%s: error:%d when creating segment\n",
333 *newbp = TAILQ_FIRST(&seginfo->curseg->segsum);
337 fsdev = seginfo->fsdev;
338 blk = nandfs_block_to_dblock(fsdev, seginfo->curseg->start_block +
339 seginfo->curseg->segsum_blocks);
341 bp = getblk(fsdev->nd_devvp, blk, fsdev->nd_blocksize, 0, 0, 0);
343 bzero(bp->b_data, seginfo->fsdev->nd_blocksize);
344 bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
345 bp->b_flags |= B_MANAGED;
347 TAILQ_INSERT_TAIL(&seginfo->curseg->segsum, bp,
348 b_cluster.cluster_entry);
349 seginfo->curseg->num_blocks--;
351 seginfo->curseg->segsum_blocks++;
352 seginfo->curseg->bytes_left = seginfo->fsdev->nd_blocksize;
353 seginfo->curseg->current_off = bp->b_data;
358 DPRINTF(SYNC, ("%s: bp %p\n", __func__, bp));
364 nandfs_add_blocks(struct nandfs_seginfo *seginfo, struct nandfs_node *node,
367 union nandfs_binfo *binfo;
371 if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
372 error = create_segment(seginfo);
374 nandfs_error("%s: error:%d when creating segment\n",
380 if (seginfo->curseg->bytes_left < sizeof(union nandfs_binfo)) {
381 error = nandfs_add_segsum_block(seginfo, &seg_bp);
383 nandfs_error("%s: error:%d when adding segsum\n",
388 binfo = (union nandfs_binfo *)seginfo->curseg->current_off;
390 if (node->nn_ino != NANDFS_DAT_INO) {
391 binfo->bi_v.bi_blkoff = bp->b_lblkno;
392 binfo->bi_v.bi_ino = node->nn_ino;
394 binfo->bi_dat.bi_blkoff = bp->b_lblkno;
395 binfo->bi_dat.bi_ino = node->nn_ino;
396 if (NANDFS_IS_INDIRECT(bp))
397 binfo->bi_dat.bi_level = 1;
399 binfo->bi_dat.bi_level = 0;
403 seginfo->curseg->bytes_left -= sizeof(union nandfs_binfo);
404 seginfo->curseg->segsum_bytes += sizeof(union nandfs_binfo);
405 seginfo->curseg->current_off = (char *)binfo;
407 TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry);
409 seginfo->curseg->nbinfos++;
410 seginfo->curseg->nblocks++;
411 seginfo->curseg->num_blocks--;
414 DPRINTF(SYNC, ("%s: bp (%p) number %x (left %x)\n",
415 __func__, bp, seginfo->curseg->nblocks,
416 seginfo->curseg->num_blocks));
421 nandfs_iterate_dirty_buf(struct vnode *vp, struct nandfs_seginfo *seginfo,
424 struct buf *bp, *tbd;
426 struct nandfs_node *node;
432 ASSERT_VOP_ELOCKED(vp, __func__);
434 /* Iterate dirty data bufs */
435 TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, tbd) {
436 DPRINTF(SYNC, ("%s: vp (%p): bp (%p) with lblkno %jx ino %jx "
437 "add buf\n", __func__, vp, bp, bp->b_lblkno, node->nn_ino));
439 if (!(NANDFS_ISGATHERED(bp))) {
440 error = nandfs_bmap_update_dat(node,
441 nandfs_vblk_get(bp), bp);
445 nandfs_add_blocks(seginfo, node, bp);
453 nandfs_iterate_system_vnode(struct nandfs_node *node,
454 struct nandfs_seginfo *seginfo)
460 if (node->nn_ino != NANDFS_IFILE_INO)
465 nblocks = vp->v_bufobj.bo_dirty.bv_cnt;
466 DPRINTF(SYNC, ("%s: vp (%p): nblocks %x ino %jx\n",
467 __func__, vp, nblocks, node->nn_ino));
470 nandfs_iterate_dirty_buf(vp, seginfo, hold);
476 nandfs_iterate_dirty_vnodes(struct mount *mp, struct nandfs_seginfo *seginfo)
478 struct nandfs_node *nandfs_node;
479 struct vnode *vp, *mvp;
481 int error, lockreq, update;
484 lockreq = LK_EXCLUSIVE | LK_INTERLOCK | LK_RETRY;
488 MNT_VNODE_FOREACH(vp, mp, mvp) {
491 if (mp->mnt_syncer == vp)
493 if (VOP_ISLOCKED(vp))
498 if (vp->v_iflag & VI_DOOMED) {
504 if ((error = vget(vp, lockreq, td)) != 0) {
509 if (vp->v_iflag & VI_DOOMED) {
515 nandfs_node = VTON(vp);
516 if (nandfs_node->nn_flags & IN_MODIFIED) {
517 nandfs_node->nn_flags &= ~(IN_MODIFIED);
521 if (vp->v_bufobj.bo_dirty.bv_cnt) {
522 error = nandfs_iterate_dirty_buf(vp, seginfo, 0);
524 nandfs_error("%s: cannot iterate vnode:%p "
525 "err:%d\n", __func__, vp, error);
534 nandfs_node_update(nandfs_node);
545 nandfs_update_phys_block(struct nandfs_device *fsdev, struct buf *bp,
546 uint64_t phys_blknr, union nandfs_binfo *binfo)
548 struct nandfs_node *node, *dat;
555 new_blknr = nandfs_vblk_get(bp);
556 dat = fsdev->nd_dat_node;
558 DPRINTF(BMAP, ("%s: ino %#jx lblk %#jx: vblk %#jx -> %#jx\n",
559 __func__, (uintmax_t)node->nn_ino, (uintmax_t)bp->b_lblkno,
560 (uintmax_t)new_blknr, (uintmax_t)phys_blknr));
562 if (node->nn_ino != NANDFS_DAT_INO) {
563 KASSERT((new_blknr != 0), ("vblk for bp %p is 0", bp));
565 nandfs_vblock_assign(fsdev, new_blknr, phys_blknr);
566 binfo->bi_v.bi_vblocknr = new_blknr;
567 binfo->bi_v.bi_blkoff = bp->b_lblkno;
568 binfo->bi_v.bi_ino = node->nn_ino;
570 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
571 error = nandfs_bmap_update_block(node, bp, phys_blknr);
573 nandfs_error("%s: error updating block:%jx for bp:%p\n",
574 __func__, (uintmax_t)phys_blknr, bp);
575 VOP_UNLOCK(NTOV(dat), 0);
578 VOP_UNLOCK(NTOV(dat), 0);
579 binfo->bi_dat.bi_blkoff = bp->b_lblkno;
580 binfo->bi_dat.bi_ino = node->nn_ino;
581 if (NANDFS_IS_INDIRECT(bp))
582 binfo->bi_dat.bi_level = 1;
584 binfo->bi_dat.bi_level = 0;
590 #define NBINFO(off) ((off) + sizeof(union nandfs_binfo))
592 nandfs_segment_assign_pblk(struct nandfs_segment *nfsseg)
594 struct nandfs_device *fsdev;
595 union nandfs_binfo *binfo;
596 struct buf *bp, *seg_bp;
598 uint32_t curr_off, blocksize;
601 fsdev = nfsseg->fsdev;
602 blocksize = fsdev->nd_blocksize;
604 blocknr = nfsseg->start_block + nfsseg->segsum_blocks;
605 seg_bp = TAILQ_FIRST(&nfsseg->segsum);
606 DPRINTF(SYNC, ("%s: seg:%p segsum bp:%p data:%p\n",
607 __func__, nfsseg, seg_bp, seg_bp->b_data));
609 binfo = (union nandfs_binfo *)(seg_bp->b_data +
610 sizeof(struct nandfs_segment_summary));
611 curr_off = sizeof(struct nandfs_segment_summary);
613 TAILQ_FOREACH(bp, &nfsseg->data, b_cluster.cluster_entry) {
614 KASSERT((bp->b_vp), ("bp %p has not vp", bp));
616 DPRINTF(BMAP, ("\n\n%s: assign buf %p for ino %#jx next %p\n",
617 __func__, bp, (uintmax_t)VTON(bp->b_vp)->nn_ino,
618 TAILQ_NEXT(bp, b_cluster.cluster_entry)));
620 if (NBINFO(curr_off) > blocksize) {
621 seg_bp = TAILQ_NEXT(seg_bp, b_cluster.cluster_entry);
622 binfo = (union nandfs_binfo *)seg_bp->b_data;
624 DPRINTF(SYNC, ("%s: next segsum %p data %p\n",
625 __func__, seg_bp, seg_bp->b_data));
628 error = nandfs_update_phys_block(fsdev, bp, blocknr, binfo);
630 nandfs_error("%s: err:%d when updatinng phys block:%jx"
631 " for bp:%p and binfo:%p\n", __func__, error,
632 (uintmax_t)blocknr, bp, binfo);
636 curr_off = NBINFO(curr_off);
645 nandfs_seginfo_assign_pblk(struct nandfs_seginfo *seginfo)
647 struct nandfs_segment *nfsseg;
650 LIST_FOREACH(nfsseg, &seginfo->seg_list, seg_link) {
651 error = nandfs_segment_assign_pblk(nfsseg);
659 static struct nandfs_segment_summary *
660 nandfs_fill_segsum(struct nandfs_segment *seg, int has_sr)
662 struct nandfs_segment_summary *ss;
663 struct nandfs_device *fsdev;
665 uint32_t rest, segsum_size, blocksize, crc_calc;
667 uint8_t *crc_area, crc_skip;
669 DPRINTF(SYNC, ("%s: seg %#jx nblocks %#x sumbytes %#x\n",
670 __func__, (uintmax_t) seg->seg_num,
671 seg->nblocks + seg->segsum_blocks,
676 flags = NANDFS_SS_LOGBGN | NANDFS_SS_LOGEND;
678 flags |= NANDFS_SS_SR;
680 bp = TAILQ_FIRST(&seg->segsum);
681 ss = (struct nandfs_segment_summary *) bp->b_data;
682 ss->ss_magic = NANDFS_SEGSUM_MAGIC;
683 ss->ss_bytes = sizeof(struct nandfs_segment_summary);
684 ss->ss_flags = flags;
685 ss->ss_seq = ++(fsdev->nd_seg_sequence);
686 ss->ss_create = fsdev->nd_ts.tv_sec;
687 nandfs_get_segment_range(fsdev, seg->seg_next, &ss->ss_next, NULL);
688 ss->ss_nblocks = seg->nblocks + seg->segsum_blocks;
689 ss->ss_nbinfos = seg->nbinfos;
690 ss->ss_sumbytes = seg->segsum_bytes;
692 crc_skip = sizeof(ss->ss_datasum) + sizeof(ss->ss_sumsum);
693 blocksize = seg->fsdev->nd_blocksize;
695 segsum_size = seg->segsum_bytes - crc_skip;
696 rest = min(seg->segsum_bytes, blocksize) - crc_skip;
697 crc_area = (uint8_t *)ss + crc_skip;
699 while (segsum_size > 0) {
700 crc_calc = crc32_raw(crc_area, rest, crc_calc);
704 bp = TAILQ_NEXT(bp, b_cluster.cluster_entry);
705 crc_area = (uint8_t *)bp->b_data;
706 rest = segsum_size <= blocksize ? segsum_size : blocksize;
708 ss->ss_sumsum = crc_calc ^ ~0U;
715 nandfs_save_buf(struct buf *bp, uint64_t blocknr, struct nandfs_device *fsdev)
720 bo = &fsdev->nd_devvp->v_bufobj;
722 bp->b_blkno = nandfs_block_to_dblock(fsdev, blocknr);
723 bp->b_iooffset = dbtob(bp->b_blkno);
725 KASSERT(bp->b_bufobj != NULL, ("no bufobj for %p", bp));
726 if (bp->b_bufobj != bo) {
727 BO_LOCK(bp->b_bufobj);
728 BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK,
729 BO_MTX(bp->b_bufobj));
730 KASSERT(BUF_ISLOCKED(bp), ("Problem with locking buffer"));
733 DPRINTF(SYNC, ("%s: buf: %p offset %#jx blk %#jx size %#x\n",
734 __func__, bp, (uintmax_t)bp->b_offset, (uintmax_t)blocknr,
735 fsdev->nd_blocksize));
738 nandfs_buf_clear(bp, 0xffffffff);
739 bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED);
742 nandfs_error("%s: error:%d when writing buffer:%p\n",
743 __func__, error, bp);
750 nandfs_clean_buf(struct nandfs_device *fsdev, struct buf *bp)
753 DPRINTF(SYNC, ("%s: buf: %p\n", __func__, bp));
756 nandfs_buf_clear(bp, 0xffffffff);
757 bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED);
758 nandfs_undirty_buf_fsdev(fsdev, bp);
762 nandfs_clean_segblocks(struct nandfs_segment *seg, uint8_t unlock)
764 struct nandfs_device *fsdev = seg->fsdev;
765 struct nandfs_segment *next_seg;
766 struct buf *bp, *tbp, *next_bp;
767 struct vnode *vp, *next_vp;
769 VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE);
770 TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) {
771 TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
772 nandfs_clean_buf(fsdev, bp);
775 TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) {
776 TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry);
779 * If bp is not super-root and vnode is not currently
784 next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry);
786 next_seg = LIST_NEXT(seg, seg_link);
788 next_bp = TAILQ_FIRST(&next_seg->data);
792 next_vp = next_bp->b_vp;
794 nandfs_clean_buf(fsdev, bp);
796 if (unlock && vp != NULL && next_vp != vp &&
797 !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
800 nandfs_dirty_bufs_decrement(fsdev);
803 VOP_UNLOCK(fsdev->nd_devvp, 0);
807 nandfs_save_segblocks(struct nandfs_segment *seg, uint8_t unlock)
809 struct nandfs_device *fsdev = seg->fsdev;
810 struct nandfs_segment *next_seg;
811 struct buf *bp, *tbp, *next_bp;
812 struct vnode *vp, *next_vp;
817 VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE);
818 TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) {
819 TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
820 blocknr = seg->start_block + i;
821 error = nandfs_save_buf(bp, blocknr, fsdev);
823 nandfs_error("%s: error saving buf: %p blocknr:%jx\n",
824 __func__, bp, (uintmax_t)blocknr);
831 TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) {
832 TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry);
834 blocknr = seg->start_block + seg->segsum_blocks + i;
836 * If bp is not super-root and vnode is not currently
841 next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry);
843 next_seg = LIST_NEXT(seg, seg_link);
845 next_bp = TAILQ_FIRST(&next_seg->data);
849 next_vp = next_bp->b_vp;
851 error = nandfs_save_buf(bp, blocknr, fsdev);
853 nandfs_error("%s: error saving buf: %p blknr: %jx\n",
854 __func__, bp, (uintmax_t)blocknr);
855 if (unlock && vp != NULL && next_vp != vp &&
856 !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
861 if (unlock && vp != NULL && next_vp != vp &&
862 !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
866 nandfs_dirty_bufs_decrement(fsdev);
870 nandfs_clean_segblocks(seg, unlock);
871 VOP_UNLOCK(fsdev->nd_devvp, 0);
875 VOP_UNLOCK(fsdev->nd_devvp, 0);
881 clean_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock)
883 struct nandfs_segment *seg;
885 DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo));
887 LIST_FOREACH(seg, &seginfo->seg_list, seg_link) {
888 nandfs_clean_segblocks(seg, unlock);
893 save_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock)
895 struct nandfs_segment *seg;
896 struct nandfs_device *fsdev;
897 struct nandfs_segment_summary *ss;
900 fsdev = seginfo->fsdev;
902 DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo));
904 LIST_FOREACH(seg, &seginfo->seg_list, seg_link) {
905 if (LIST_NEXT(seg, seg_link)) {
906 nandfs_fill_segsum(seg, 0);
907 error = nandfs_save_segblocks(seg, unlock);
909 nandfs_error("%s: error:%d saving seg:%p\n",
910 __func__, error, seg);
914 ss = nandfs_fill_segsum(seg, 1);
915 fsdev->nd_last_segsum = *ss;
916 error = nandfs_save_segblocks(seg, unlock);
918 nandfs_error("%s: error:%d saving seg:%p\n",
919 __func__, error, seg);
922 fsdev->nd_last_cno++;
923 fsdev->nd_last_pseg = seg->start_block;
928 clean_seginfo(seginfo, unlock);
933 nandfs_invalidate_bufs(struct nandfs_device *fsdev, uint64_t segno)
936 struct buf *bp, *tbd;
939 nandfs_get_segment_range(fsdev, segno, &start, &end);
941 bo = &NTOV(fsdev->nd_gc_node)->v_bufobj;
945 TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, tbd) {
946 if (!(bp->b_lblkno >= start && bp->b_lblkno <= end))
949 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL))
950 goto restart_locked_gc;
953 bp->b_flags |= (B_INVAL | B_RELBUF);
954 bp->b_flags &= ~(B_ASYNC | B_MANAGED);
962 /* Process segments marks to free by cleaner */
964 nandfs_process_segments(struct nandfs_device *fsdev)
966 uint64_t saved_segment;
969 if (fsdev->nd_free_base) {
970 saved_segment = nandfs_get_segnum_of_block(fsdev,
971 fsdev->nd_super.s_last_pseg);
972 for (i = 0; i < fsdev->nd_free_count; i++) {
973 if (fsdev->nd_free_base[i] == NANDFS_NOSEGMENT)
975 /* Update superblock if clearing segment point by it */
976 if (fsdev->nd_free_base[i] == saved_segment) {
977 nandfs_write_superblock(fsdev);
978 saved_segment = nandfs_get_segnum_of_block(
979 fsdev, fsdev->nd_super.s_last_pseg);
981 nandfs_invalidate_bufs(fsdev, fsdev->nd_free_base[i]);
982 nandfs_clear_segment(fsdev, fsdev->nd_free_base[i]);
985 free(fsdev->nd_free_base, M_NANDFSTEMP);
986 fsdev->nd_free_base = NULL;
987 fsdev->nd_free_count = 0;
991 /* Collect and write dirty buffers */
993 nandfs_sync_file(struct vnode *vp)
995 struct nandfs_device *fsdev;
996 struct nandfs_node *nandfs_node;
997 struct nandfsmount *nmp;
998 struct nandfs_node *dat, *su, *ifile, *cp;
999 struct nandfs_seginfo *seginfo = NULL;
1000 struct nandfs_segment *seg;
1004 ASSERT_VOP_LOCKED(vp, __func__);
1005 DPRINTF(SYNC, ("%s: START\n", __func__));
1008 nmp = VFSTONANDFS(vp->v_mount);
1009 fsdev = nmp->nm_nandfsdev;
1011 dat = fsdev->nd_dat_node;
1012 su = fsdev->nd_su_node;
1013 cp = fsdev->nd_cp_node;
1014 ifile = nmp->nm_ifile_node;
1016 NANDFS_WRITEASSERT(fsdev);
1017 if (lockmgr(&fsdev->nd_seg_const, LK_UPGRADE, NULL) != 0) {
1018 DPRINTF(SYNC, ("%s: lost shared lock\n", __func__));
1019 if (lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL) != 0)
1020 panic("couldn't lock exclusive");
1022 DPRINTF(SYNC, ("%s: got lock\n", __func__));
1024 VOP_LOCK(NTOV(su), LK_EXCLUSIVE);
1025 create_seginfo(fsdev, &seginfo);
1029 nandfs_node = VTON(vp);
1030 if (nandfs_node->nn_flags & IN_MODIFIED) {
1031 nandfs_node->nn_flags &= ~(IN_MODIFIED);
1035 if (vp->v_bufobj.bo_dirty.bv_cnt) {
1036 error = nandfs_iterate_dirty_buf(vp, seginfo, 0);
1038 clean_seginfo(seginfo, 0);
1039 delete_seginfo(seginfo);
1040 VOP_UNLOCK(NTOV(su), 0);
1041 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1042 nandfs_error("%s: err:%d iterating dirty bufs vp:%p",
1043 __func__, error, vp);
1050 VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE);
1051 error = nandfs_node_update(nandfs_node);
1053 clean_seginfo(seginfo, 0);
1054 delete_seginfo(seginfo);
1055 VOP_UNLOCK(NTOV(ifile), 0);
1056 VOP_UNLOCK(NTOV(su), 0);
1057 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1058 nandfs_error("%s: err:%d updating vp:%p",
1059 __func__, error, vp);
1062 VOP_UNLOCK(NTOV(ifile), 0);
1066 if (seginfo->blocks) {
1067 VOP_LOCK(NTOV(cp), LK_EXCLUSIVE);
1069 /* Create new checkpoint */
1070 error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1);
1072 clean_seginfo(seginfo, 0);
1073 delete_seginfo(seginfo);
1074 VOP_UNLOCK(NTOV(cp), 0);
1075 VOP_UNLOCK(NTOV(su), 0);
1076 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1077 nandfs_error("%s: err:%d getting cp:%jx",
1078 __func__, error, fsdev->nd_last_cno + 1);
1082 /* Reiterate all blocks and assign physical block number */
1083 nandfs_seginfo_assign_pblk(seginfo);
1085 /* Fill checkpoint data */
1086 error = nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1,
1087 &ifile->nn_inode, seginfo->blocks);
1089 clean_seginfo(seginfo, 0);
1090 delete_seginfo(seginfo);
1091 VOP_UNLOCK(NTOV(cp), 0);
1092 VOP_UNLOCK(NTOV(su), 0);
1093 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1094 nandfs_error("%s: err:%d setting cp:%jx",
1095 __func__, error, fsdev->nd_last_cno + 1);
1099 VOP_UNLOCK(NTOV(cp), 0);
1100 LIST_FOREACH(seg, &seginfo->seg_list, seg_link)
1101 nandfs_update_segment(fsdev, seg->seg_num,
1102 seg->nblocks + seg->segsum_blocks);
1104 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1105 error = save_seginfo(seginfo, 0);
1107 clean_seginfo(seginfo, 0);
1108 delete_seginfo(seginfo);
1109 VOP_UNLOCK(NTOV(dat), 0);
1110 VOP_UNLOCK(NTOV(su), 0);
1111 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1112 nandfs_error("%s: err:%d updating seg",
1116 VOP_UNLOCK(NTOV(dat), 0);
1119 VOP_UNLOCK(NTOV(su), 0);
1121 delete_seginfo(seginfo);
1122 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1124 if (cno_changed && !error) {
1125 if (nandfs_cps_between_sblocks != 0 &&
1126 fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0)
1127 nandfs_write_superblock(fsdev);
1130 ASSERT_VOP_LOCKED(vp, __func__);
1131 DPRINTF(SYNC, ("%s: END error %d\n", __func__, error));
1136 nandfs_segment_constructor(struct nandfsmount *nmp, int flags)
1138 struct nandfs_device *fsdev;
1139 struct nandfs_seginfo *seginfo = NULL;
1140 struct nandfs_segment *seg;
1141 struct nandfs_node *dat, *su, *ifile, *cp, *gc;
1142 int cno_changed, error;
1144 DPRINTF(SYNC, ("%s: START\n", __func__));
1145 fsdev = nmp->nm_nandfsdev;
1147 lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL);
1148 DPRINTF(SYNC, ("%s: git lock\n", __func__));
1150 create_seginfo(fsdev, &seginfo);
1152 dat = fsdev->nd_dat_node;
1153 su = fsdev->nd_su_node;
1154 cp = fsdev->nd_cp_node;
1155 gc = fsdev->nd_gc_node;
1156 ifile = nmp->nm_ifile_node;
1158 VOP_LOCK(NTOV(su), LK_EXCLUSIVE);
1159 VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE);
1160 VOP_LOCK(NTOV(gc), LK_EXCLUSIVE);
1161 VOP_LOCK(NTOV(cp), LK_EXCLUSIVE);
1163 nandfs_iterate_system_vnode(gc, seginfo);
1164 nandfs_iterate_dirty_vnodes(nmp->nm_vfs_mountp, seginfo);
1165 nandfs_iterate_system_vnode(ifile, seginfo);
1166 nandfs_iterate_system_vnode(su, seginfo);
1169 if (seginfo->blocks || flags) {
1171 /* Create new checkpoint */
1172 error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1);
1174 clean_seginfo(seginfo, 0);
1175 delete_seginfo(seginfo);
1179 /* Collect blocks from system files */
1180 nandfs_iterate_system_vnode(cp, seginfo);
1181 nandfs_iterate_system_vnode(su, seginfo);
1182 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1183 nandfs_iterate_system_vnode(dat, seginfo);
1184 VOP_UNLOCK(NTOV(dat), 0);
1186 seginfo->reiterate = 0;
1187 nandfs_iterate_system_vnode(su, seginfo);
1188 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1189 nandfs_iterate_system_vnode(dat, seginfo);
1190 VOP_UNLOCK(NTOV(dat), 0);
1191 if (seginfo->reiterate)
1193 if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
1194 error = create_segment(seginfo);
1196 clean_seginfo(seginfo, 0);
1197 delete_seginfo(seginfo);
1203 /* Reiterate all blocks and assign physical block number */
1204 nandfs_seginfo_assign_pblk(seginfo);
1206 /* Fill superroot */
1207 error = nandfs_add_superroot(seginfo);
1209 clean_seginfo(seginfo, 0);
1210 delete_seginfo(seginfo);
1213 KASSERT(!(seginfo->reiterate), ("reiteration after superroot"));
1215 /* Fill checkpoint data */
1216 nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1,
1217 &ifile->nn_inode, seginfo->blocks);
1219 LIST_FOREACH(seg, &seginfo->seg_list, seg_link)
1220 nandfs_update_segment(fsdev, seg->seg_num,
1221 seg->nblocks + seg->segsum_blocks);
1223 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1224 error = save_seginfo(seginfo, 1);
1226 clean_seginfo(seginfo, 1);
1227 delete_seginfo(seginfo);
1230 VOP_UNLOCK(NTOV(dat), 0);
1233 VOP_UNLOCK(NTOV(cp), 0);
1234 VOP_UNLOCK(NTOV(gc), 0);
1235 VOP_UNLOCK(NTOV(ifile), 0);
1237 nandfs_process_segments(fsdev);
1239 VOP_UNLOCK(NTOV(su), 0);
1241 delete_seginfo(seginfo);
1244 * XXX: a hack, will go away soon
1246 if ((NTOV(dat)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1247 NTOV(cp)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1248 NTOV(gc)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1249 NTOV(ifile)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1250 NTOV(su)->v_bufobj.bo_dirty.bv_cnt != 0) &&
1251 (flags & NANDFS_UMOUNT)) {
1252 DPRINTF(SYNC, ("%s: RERUN\n", __func__));
1256 MPASS(fsdev->nd_free_base == NULL);
1258 lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL);
1261 if ((nandfs_cps_between_sblocks != 0 &&
1262 fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) ||
1263 flags & NANDFS_UMOUNT)
1264 nandfs_write_superblock(fsdev);
1267 DPRINTF(SYNC, ("%s: END\n", __func__));
1270 VOP_UNLOCK(NTOV(dat), 0);
1272 VOP_UNLOCK(NTOV(cp), 0);
1273 VOP_UNLOCK(NTOV(gc), 0);
1274 VOP_UNLOCK(NTOV(ifile), 0);
1275 VOP_UNLOCK(NTOV(su), 0);
1276 lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL);
1283 * Show details about the given NANDFS mount point.
1285 DB_SHOW_COMMAND(nandfs, db_show_nandfs)
1288 struct nandfs_device *nffsdev;
1289 struct nandfs_segment *seg;
1290 struct nandfsmount *nmp;
1295 db_printf("\nUsage: show nandfs <mount_addr>\n");
1299 mp = (struct mount *)addr;
1300 db_printf("%p %s on %s (%s)\n", mp, mp->mnt_stat.f_mntfromname,
1301 mp->mnt_stat.f_mntonname, mp->mnt_stat.f_fstypename);
1304 nmp = (struct nandfsmount *)(mp->mnt_data);
1305 nffsdev = nmp->nm_nandfsdev;
1306 db_printf("dev vnode:%p\n", nffsdev->nd_devvp);
1307 db_printf("blocksize:%jx last cno:%jx last pseg:%jx seg num:%jx\n",
1308 (uintmax_t)nffsdev->nd_blocksize, (uintmax_t)nffsdev->nd_last_cno,
1309 (uintmax_t)nffsdev->nd_last_pseg, (uintmax_t)nffsdev->nd_seg_num);
1310 db_printf("system nodes: dat:%p cp:%p su:%p ifile:%p gc:%p\n",
1311 nffsdev->nd_dat_node, nffsdev->nd_cp_node, nffsdev->nd_su_node,
1312 nmp->nm_ifile_node, nffsdev->nd_gc_node);
1314 if (nffsdev->nd_seginfo != NULL) {
1315 LIST_FOREACH(seg, &nffsdev->nd_seginfo->seg_list, seg_link) {
1316 db_printf("seg: %p\n", seg);
1317 TAILQ_FOREACH(bp, &seg->segsum,
1318 b_cluster.cluster_entry)
1319 db_printf("segbp %p\n", bp);
1320 TAILQ_FOREACH(bp, &seg->data,
1321 b_cluster.cluster_entry) {
1323 db_printf("bp:%p bp->b_vp:%p ino:%jx\n", bp, vp,
1324 (uintmax_t)(vp ? VTON(vp)->nn_ino : 0));