2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2010-2012 Semihalf.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
35 #include <sys/systm.h>
37 #include <sys/kernel.h>
39 #include <sys/malloc.h>
40 #include <sys/mount.h>
41 #include <sys/mutex.h>
42 #include <sys/namei.h>
43 #include <sys/rwlock.h>
44 #include <sys/sysctl.h>
45 #include <sys/vnode.h>
48 #include <sys/libkern.h>
53 #include <vm/vm_param.h>
54 #include <vm/vm_kern.h>
55 #include <vm/vm_page.h>
57 #include <geom/geom.h>
58 #include <geom/geom_vfs.h>
60 #include <fs/nandfs/nandfs_mount.h>
61 #include <fs/nandfs/nandfs.h>
62 #include <fs/nandfs/nandfs_subr.h>
65 nandfs_new_segment(struct nandfs_device *fsdev)
70 error = nandfs_alloc_segment(fsdev, &new);
72 fsdev->nd_seg_num = fsdev->nd_next_seg_num;
73 fsdev->nd_next_seg_num = new;
75 DPRINTF(SYNC, ("%s: new segment %jx next %jx error %d\n",
76 __func__, (uintmax_t)fsdev->nd_seg_num, (uintmax_t)new, error));
78 nandfs_error("%s: cannot create segment error %d\n",
85 create_segment(struct nandfs_seginfo *seginfo)
87 struct nandfs_segment *seg;
88 struct nandfs_device *fsdev;
89 struct nandfs_segment *prev;
91 uint64_t start_block, curr;
92 uint32_t blks_per_seg, nblocks;
95 fsdev = seginfo->fsdev;
96 prev = seginfo->curseg;
97 blks_per_seg = fsdev->nd_fsdata.f_blocks_per_segment;
98 nblocks = fsdev->nd_last_segsum.ss_nblocks;
101 vfs_timestamp(&fsdev->nd_ts);
102 /* Touch current segment */
103 error = nandfs_touch_segment(fsdev, fsdev->nd_seg_num);
105 nandfs_error("%s: cannot preallocate segment %jx\n",
106 __func__, fsdev->nd_seg_num);
109 error = nandfs_touch_segment(fsdev, 0);
111 nandfs_error("%s: cannot dirty block with segment 0\n",
115 start_block = fsdev->nd_last_pseg + (uint64_t)nblocks;
119 if (blks_per_seg - (start_block % blks_per_seg) - 1 == 0)
121 curr = nandfs_get_segnum_of_block(fsdev, start_block);
122 /* Allocate new segment if last one is full */
123 if (fsdev->nd_seg_num != curr) {
124 error = nandfs_new_segment(fsdev);
126 nandfs_error("%s: cannot create new segment\n",
133 nandfs_get_segment_range(fsdev, fsdev->nd_seg_num, &start_block, NULL);
136 nandfs_get_segment_range(fsdev, fsdev->nd_next_seg_num,
139 /* Touch current segment and allocate and touch new one */
140 error = nandfs_new_segment(fsdev);
142 nandfs_error("%s: cannot create next segment\n",
147 /* Reiterate in case new buf is dirty */
148 seginfo->reiterate = 1;
151 /* Allocate and initialize nandfs_segment structure */
152 seg = malloc(sizeof(*seg), M_DEVBUF, M_WAITOK|M_ZERO);
153 TAILQ_INIT(&seg->segsum);
154 TAILQ_INIT(&seg->data);
156 seg->start_block = start_block;
157 seg->num_blocks = blks_per_seg - (start_block % blks_per_seg) - 1;
158 seg->seg_num = fsdev->nd_seg_num;
159 seg->seg_next = fsdev->nd_next_seg_num;
160 seg->segsum_blocks = 1;
161 seg->bytes_left = fsdev->nd_blocksize -
162 sizeof(struct nandfs_segment_summary);
163 seg->segsum_bytes = sizeof(struct nandfs_segment_summary);
165 /* Allocate buffer for segment summary */
166 bp = getblk(fsdev->nd_devvp, nandfs_block_to_dblock(fsdev,
167 seg->start_block), fsdev->nd_blocksize, 0, 0, 0);
168 bzero(bp->b_data, seginfo->fsdev->nd_blocksize);
169 bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
170 bp->b_flags |= B_MANAGED;
172 /* Add buffer to segment */
173 TAILQ_INSERT_TAIL(&seg->segsum, bp, b_cluster.cluster_entry);
174 seg->current_off = bp->b_data + sizeof(struct nandfs_segment_summary);
176 DPRINTF(SYNC, ("%s: seg %p : initial settings: start %#jx size :%#x\n",
177 __func__, seg, (uintmax_t)seg->start_block, seg->num_blocks));
178 DPRINTF(SYNC, ("%s: seg->seg_num %#jx cno %#jx next %#jx\n", __func__,
179 (uintmax_t)seg->seg_num, (uintmax_t)(fsdev->nd_last_cno + 1),
180 (uintmax_t)seg->seg_next));
183 LIST_INSERT_HEAD(&seginfo->seg_list, seg, seg_link);
185 LIST_INSERT_AFTER(prev, seg, seg_link);
187 seginfo->curseg = seg;
193 delete_segment(struct nandfs_seginfo *seginfo)
195 struct nandfs_segment *seg, *tseg;
196 struct buf *bp, *tbp;
198 LIST_FOREACH_SAFE(seg, &seginfo->seg_list, seg_link, tseg) {
199 TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry,
201 TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
202 bp->b_flags &= ~B_MANAGED;
206 LIST_REMOVE(seg, seg_link);
214 create_seginfo(struct nandfs_device *fsdev, struct nandfs_seginfo **seginfo)
216 struct nandfs_seginfo *info;
218 info = malloc(sizeof(*info), M_DEVBUF, M_WAITOK);
220 LIST_INIT(&info->seg_list);
225 fsdev->nd_seginfo = info;
230 delete_seginfo(struct nandfs_seginfo *seginfo)
232 struct nandfs_device *nffsdev;
234 nffsdev = seginfo->fsdev;
235 delete_segment(seginfo);
236 nffsdev->nd_seginfo = NULL;
237 free(seginfo, M_DEVBUF);
243 nandfs_create_superroot_block(struct nandfs_seginfo *seginfo,
249 bp = nandfs_geteblk(seginfo->fsdev->nd_blocksize, GB_NOWAIT_BD);
251 bzero(bp->b_data, seginfo->fsdev->nd_blocksize);
252 bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
253 bp->b_flags |= B_MANAGED;
255 if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
256 error = create_segment(seginfo);
259 nandfs_error("%s: no segment for superroot\n",
265 TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry);
267 seginfo->curseg->nblocks++;
268 seginfo->curseg->num_blocks--;
276 nandfs_add_superroot(struct nandfs_seginfo *seginfo)
278 struct nandfs_device *fsdev;
279 struct nandfs_super_root *sr;
280 struct buf *bp = NULL;
285 fsdev = seginfo->fsdev;
287 error = nandfs_create_superroot_block(seginfo, &bp);
289 nandfs_error("%s: cannot add superroot\n", __func__);
293 sr = (struct nandfs_super_root *)bp->b_data;
294 /* Save superroot CRC */
295 sr->sr_bytes = NANDFS_SR_BYTES;
297 sr->sr_nongc_ctime = 0;
299 memcpy(&sr->sr_dat, &fsdev->nd_dat_node->nn_inode,
300 sizeof(struct nandfs_inode));
301 memcpy(&sr->sr_cpfile, &fsdev->nd_cp_node->nn_inode,
302 sizeof(struct nandfs_inode));
303 memcpy(&sr->sr_sufile, &fsdev->nd_su_node->nn_inode,
304 sizeof(struct nandfs_inode));
306 crc_skip = sizeof(sr->sr_sum);
307 crc_calc = crc32((uint8_t *)sr + crc_skip, NANDFS_SR_BYTES - crc_skip);
309 sr->sr_sum = crc_calc;
311 bp->b_flags |= B_MANAGED;
312 bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
314 bp->b_flags &= ~B_INVAL;
315 nandfs_dirty_bufs_increment(fsdev);
316 DPRINTF(SYNC, ("%s: bp:%p\n", __func__, bp));
322 nandfs_add_segsum_block(struct nandfs_seginfo *seginfo, struct buf **newbp)
324 struct nandfs_device *fsdev;
329 if (!(seginfo->curseg) || seginfo->curseg->num_blocks <= 1) {
330 error = create_segment(seginfo);
332 nandfs_error("%s: error:%d when creating segment\n",
336 *newbp = TAILQ_FIRST(&seginfo->curseg->segsum);
340 fsdev = seginfo->fsdev;
341 blk = nandfs_block_to_dblock(fsdev, seginfo->curseg->start_block +
342 seginfo->curseg->segsum_blocks);
344 bp = getblk(fsdev->nd_devvp, blk, fsdev->nd_blocksize, 0, 0, 0);
346 bzero(bp->b_data, seginfo->fsdev->nd_blocksize);
347 bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
348 bp->b_flags |= B_MANAGED;
350 TAILQ_INSERT_TAIL(&seginfo->curseg->segsum, bp,
351 b_cluster.cluster_entry);
352 seginfo->curseg->num_blocks--;
354 seginfo->curseg->segsum_blocks++;
355 seginfo->curseg->bytes_left = seginfo->fsdev->nd_blocksize;
356 seginfo->curseg->current_off = bp->b_data;
361 DPRINTF(SYNC, ("%s: bp %p\n", __func__, bp));
367 nandfs_add_blocks(struct nandfs_seginfo *seginfo, struct nandfs_node *node,
370 union nandfs_binfo *binfo;
374 if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
375 error = create_segment(seginfo);
377 nandfs_error("%s: error:%d when creating segment\n",
383 if (seginfo->curseg->bytes_left < sizeof(union nandfs_binfo)) {
384 error = nandfs_add_segsum_block(seginfo, &seg_bp);
386 nandfs_error("%s: error:%d when adding segsum\n",
391 binfo = (union nandfs_binfo *)seginfo->curseg->current_off;
393 if (node->nn_ino != NANDFS_DAT_INO) {
394 binfo->bi_v.bi_blkoff = bp->b_lblkno;
395 binfo->bi_v.bi_ino = node->nn_ino;
397 binfo->bi_dat.bi_blkoff = bp->b_lblkno;
398 binfo->bi_dat.bi_ino = node->nn_ino;
399 if (NANDFS_IS_INDIRECT(bp))
400 binfo->bi_dat.bi_level = 1;
402 binfo->bi_dat.bi_level = 0;
406 seginfo->curseg->bytes_left -= sizeof(union nandfs_binfo);
407 seginfo->curseg->segsum_bytes += sizeof(union nandfs_binfo);
408 seginfo->curseg->current_off = (char *)binfo;
410 TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry);
412 seginfo->curseg->nbinfos++;
413 seginfo->curseg->nblocks++;
414 seginfo->curseg->num_blocks--;
417 DPRINTF(SYNC, ("%s: bp (%p) number %x (left %x)\n",
418 __func__, bp, seginfo->curseg->nblocks,
419 seginfo->curseg->num_blocks));
424 nandfs_iterate_dirty_buf(struct vnode *vp, struct nandfs_seginfo *seginfo,
427 struct buf *bp, *tbd;
429 struct nandfs_node *node;
435 ASSERT_VOP_ELOCKED(vp, __func__);
437 /* Iterate dirty data bufs */
438 TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, tbd) {
439 DPRINTF(SYNC, ("%s: vp (%p): bp (%p) with lblkno %jx ino %jx "
440 "add buf\n", __func__, vp, bp, bp->b_lblkno, node->nn_ino));
442 if (!(NANDFS_ISGATHERED(bp))) {
443 error = nandfs_bmap_update_dat(node,
444 nandfs_vblk_get(bp), bp);
448 nandfs_add_blocks(seginfo, node, bp);
456 nandfs_iterate_system_vnode(struct nandfs_node *node,
457 struct nandfs_seginfo *seginfo)
463 if (node->nn_ino != NANDFS_IFILE_INO)
468 nblocks = vp->v_bufobj.bo_dirty.bv_cnt;
469 DPRINTF(SYNC, ("%s: vp (%p): nblocks %x ino %jx\n",
470 __func__, vp, nblocks, node->nn_ino));
473 nandfs_iterate_dirty_buf(vp, seginfo, hold);
479 nandfs_iterate_dirty_vnodes(struct mount *mp, struct nandfs_seginfo *seginfo)
481 struct nandfs_node *nandfs_node;
482 struct vnode *vp, *mvp;
489 MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) {
492 if (mp->mnt_syncer == vp || VOP_ISLOCKED(vp)) {
496 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK | LK_NOWAIT, td) != 0)
499 nandfs_node = VTON(vp);
500 if (nandfs_node->nn_flags & IN_MODIFIED) {
501 nandfs_node->nn_flags &= ~(IN_MODIFIED);
507 if (vp->v_bufobj.bo_dirty.bv_cnt) {
508 error = nandfs_iterate_dirty_buf(vp, seginfo, 0);
510 nandfs_error("%s: cannot iterate vnode:%p "
511 "err:%d\n", __func__, vp, error);
522 nandfs_node_update(nandfs_node);
529 nandfs_update_phys_block(struct nandfs_device *fsdev, struct buf *bp,
530 uint64_t phys_blknr, union nandfs_binfo *binfo)
532 struct nandfs_node *node, *dat;
539 new_blknr = nandfs_vblk_get(bp);
540 dat = fsdev->nd_dat_node;
542 DPRINTF(BMAP, ("%s: ino %#jx lblk %#jx: vblk %#jx -> %#jx\n",
543 __func__, (uintmax_t)node->nn_ino, (uintmax_t)bp->b_lblkno,
544 (uintmax_t)new_blknr, (uintmax_t)phys_blknr));
546 if (node->nn_ino != NANDFS_DAT_INO) {
547 KASSERT((new_blknr != 0), ("vblk for bp %p is 0", bp));
549 nandfs_vblock_assign(fsdev, new_blknr, phys_blknr);
550 binfo->bi_v.bi_vblocknr = new_blknr;
551 binfo->bi_v.bi_blkoff = bp->b_lblkno;
552 binfo->bi_v.bi_ino = node->nn_ino;
554 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
555 error = nandfs_bmap_update_block(node, bp, phys_blknr);
557 nandfs_error("%s: error updating block:%jx for bp:%p\n",
558 __func__, (uintmax_t)phys_blknr, bp);
559 VOP_UNLOCK(NTOV(dat), 0);
562 VOP_UNLOCK(NTOV(dat), 0);
563 binfo->bi_dat.bi_blkoff = bp->b_lblkno;
564 binfo->bi_dat.bi_ino = node->nn_ino;
565 if (NANDFS_IS_INDIRECT(bp))
566 binfo->bi_dat.bi_level = 1;
568 binfo->bi_dat.bi_level = 0;
574 #define NBINFO(off) ((off) + sizeof(union nandfs_binfo))
576 nandfs_segment_assign_pblk(struct nandfs_segment *nfsseg)
578 struct nandfs_device *fsdev;
579 union nandfs_binfo *binfo;
580 struct buf *bp, *seg_bp;
582 uint32_t curr_off, blocksize;
585 fsdev = nfsseg->fsdev;
586 blocksize = fsdev->nd_blocksize;
588 blocknr = nfsseg->start_block + nfsseg->segsum_blocks;
589 seg_bp = TAILQ_FIRST(&nfsseg->segsum);
590 DPRINTF(SYNC, ("%s: seg:%p segsum bp:%p data:%p\n",
591 __func__, nfsseg, seg_bp, seg_bp->b_data));
593 binfo = (union nandfs_binfo *)(seg_bp->b_data +
594 sizeof(struct nandfs_segment_summary));
595 curr_off = sizeof(struct nandfs_segment_summary);
597 TAILQ_FOREACH(bp, &nfsseg->data, b_cluster.cluster_entry) {
598 KASSERT((bp->b_vp), ("bp %p has not vp", bp));
600 DPRINTF(BMAP, ("\n\n%s: assign buf %p for ino %#jx next %p\n",
601 __func__, bp, (uintmax_t)VTON(bp->b_vp)->nn_ino,
602 TAILQ_NEXT(bp, b_cluster.cluster_entry)));
604 if (NBINFO(curr_off) > blocksize) {
605 seg_bp = TAILQ_NEXT(seg_bp, b_cluster.cluster_entry);
606 binfo = (union nandfs_binfo *)seg_bp->b_data;
608 DPRINTF(SYNC, ("%s: next segsum %p data %p\n",
609 __func__, seg_bp, seg_bp->b_data));
612 error = nandfs_update_phys_block(fsdev, bp, blocknr, binfo);
614 nandfs_error("%s: err:%d when updatinng phys block:%jx"
615 " for bp:%p and binfo:%p\n", __func__, error,
616 (uintmax_t)blocknr, bp, binfo);
620 curr_off = NBINFO(curr_off);
629 nandfs_seginfo_assign_pblk(struct nandfs_seginfo *seginfo)
631 struct nandfs_segment *nfsseg;
634 LIST_FOREACH(nfsseg, &seginfo->seg_list, seg_link) {
635 error = nandfs_segment_assign_pblk(nfsseg);
643 static struct nandfs_segment_summary *
644 nandfs_fill_segsum(struct nandfs_segment *seg, int has_sr)
646 struct nandfs_segment_summary *ss;
647 struct nandfs_device *fsdev;
649 uint32_t rest, segsum_size, blocksize, crc_calc;
651 uint8_t *crc_area, crc_skip;
653 DPRINTF(SYNC, ("%s: seg %#jx nblocks %#x sumbytes %#x\n",
654 __func__, (uintmax_t) seg->seg_num,
655 seg->nblocks + seg->segsum_blocks,
660 flags = NANDFS_SS_LOGBGN | NANDFS_SS_LOGEND;
662 flags |= NANDFS_SS_SR;
664 bp = TAILQ_FIRST(&seg->segsum);
665 ss = (struct nandfs_segment_summary *) bp->b_data;
666 ss->ss_magic = NANDFS_SEGSUM_MAGIC;
667 ss->ss_bytes = sizeof(struct nandfs_segment_summary);
668 ss->ss_flags = flags;
669 ss->ss_seq = ++(fsdev->nd_seg_sequence);
670 ss->ss_create = fsdev->nd_ts.tv_sec;
671 nandfs_get_segment_range(fsdev, seg->seg_next, &ss->ss_next, NULL);
672 ss->ss_nblocks = seg->nblocks + seg->segsum_blocks;
673 ss->ss_nbinfos = seg->nbinfos;
674 ss->ss_sumbytes = seg->segsum_bytes;
676 crc_skip = sizeof(ss->ss_datasum) + sizeof(ss->ss_sumsum);
677 blocksize = seg->fsdev->nd_blocksize;
679 segsum_size = seg->segsum_bytes - crc_skip;
680 rest = min(seg->segsum_bytes, blocksize) - crc_skip;
681 crc_area = (uint8_t *)ss + crc_skip;
683 while (segsum_size > 0) {
684 crc_calc = crc32_raw(crc_area, rest, crc_calc);
688 bp = TAILQ_NEXT(bp, b_cluster.cluster_entry);
689 crc_area = (uint8_t *)bp->b_data;
690 rest = segsum_size <= blocksize ? segsum_size : blocksize;
692 ss->ss_sumsum = crc_calc ^ ~0U;
699 nandfs_save_buf(struct buf *bp, uint64_t blocknr, struct nandfs_device *fsdev)
704 bo = &fsdev->nd_devvp->v_bufobj;
706 bp->b_blkno = nandfs_block_to_dblock(fsdev, blocknr);
707 bp->b_iooffset = dbtob(bp->b_blkno);
709 KASSERT(bp->b_bufobj != NULL, ("no bufobj for %p", bp));
710 if (bp->b_bufobj != bo) {
711 BO_LOCK(bp->b_bufobj);
712 BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK,
713 BO_LOCKPTR(bp->b_bufobj));
714 KASSERT(BUF_ISLOCKED(bp), ("Problem with locking buffer"));
717 DPRINTF(SYNC, ("%s: buf: %p offset %#jx blk %#jx size %#x\n",
718 __func__, bp, (uintmax_t)bp->b_offset, (uintmax_t)blocknr,
719 fsdev->nd_blocksize));
722 nandfs_buf_clear(bp, 0xffffffff);
723 bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED);
726 nandfs_error("%s: error:%d when writing buffer:%p\n",
727 __func__, error, bp);
734 nandfs_clean_buf(struct nandfs_device *fsdev, struct buf *bp)
737 DPRINTF(SYNC, ("%s: buf: %p\n", __func__, bp));
740 nandfs_buf_clear(bp, 0xffffffff);
741 bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED);
742 nandfs_undirty_buf_fsdev(fsdev, bp);
746 nandfs_clean_segblocks(struct nandfs_segment *seg, uint8_t unlock)
748 struct nandfs_device *fsdev = seg->fsdev;
749 struct nandfs_segment *next_seg;
750 struct buf *bp, *tbp, *next_bp;
751 struct vnode *vp, *next_vp;
753 VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE);
754 TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) {
755 TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
756 nandfs_clean_buf(fsdev, bp);
759 TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) {
760 TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry);
763 * If bp is not super-root and vnode is not currently
768 next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry);
770 next_seg = LIST_NEXT(seg, seg_link);
772 next_bp = TAILQ_FIRST(&next_seg->data);
776 next_vp = next_bp->b_vp;
778 nandfs_clean_buf(fsdev, bp);
780 if (unlock && vp != NULL && next_vp != vp &&
781 !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
784 nandfs_dirty_bufs_decrement(fsdev);
787 VOP_UNLOCK(fsdev->nd_devvp, 0);
791 nandfs_save_segblocks(struct nandfs_segment *seg, uint8_t unlock)
793 struct nandfs_device *fsdev = seg->fsdev;
794 struct nandfs_segment *next_seg;
795 struct buf *bp, *tbp, *next_bp;
796 struct vnode *vp, *next_vp;
801 VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE);
802 TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) {
803 TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
804 blocknr = seg->start_block + i;
805 error = nandfs_save_buf(bp, blocknr, fsdev);
807 nandfs_error("%s: error saving buf: %p blocknr:%jx\n",
808 __func__, bp, (uintmax_t)blocknr);
815 TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) {
816 TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry);
818 blocknr = seg->start_block + seg->segsum_blocks + i;
820 * If bp is not super-root and vnode is not currently
825 next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry);
827 next_seg = LIST_NEXT(seg, seg_link);
829 next_bp = TAILQ_FIRST(&next_seg->data);
833 next_vp = next_bp->b_vp;
835 error = nandfs_save_buf(bp, blocknr, fsdev);
837 nandfs_error("%s: error saving buf: %p blknr: %jx\n",
838 __func__, bp, (uintmax_t)blocknr);
839 if (unlock && vp != NULL && next_vp != vp &&
840 !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
845 if (unlock && vp != NULL && next_vp != vp &&
846 !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
850 nandfs_dirty_bufs_decrement(fsdev);
854 nandfs_clean_segblocks(seg, unlock);
855 VOP_UNLOCK(fsdev->nd_devvp, 0);
859 VOP_UNLOCK(fsdev->nd_devvp, 0);
865 clean_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock)
867 struct nandfs_segment *seg;
869 DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo));
871 LIST_FOREACH(seg, &seginfo->seg_list, seg_link) {
872 nandfs_clean_segblocks(seg, unlock);
877 save_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock)
879 struct nandfs_segment *seg;
880 struct nandfs_device *fsdev;
881 struct nandfs_segment_summary *ss;
884 fsdev = seginfo->fsdev;
886 DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo));
888 LIST_FOREACH(seg, &seginfo->seg_list, seg_link) {
889 if (LIST_NEXT(seg, seg_link)) {
890 nandfs_fill_segsum(seg, 0);
891 error = nandfs_save_segblocks(seg, unlock);
893 nandfs_error("%s: error:%d saving seg:%p\n",
894 __func__, error, seg);
898 ss = nandfs_fill_segsum(seg, 1);
899 fsdev->nd_last_segsum = *ss;
900 error = nandfs_save_segblocks(seg, unlock);
902 nandfs_error("%s: error:%d saving seg:%p\n",
903 __func__, error, seg);
906 fsdev->nd_last_cno++;
907 fsdev->nd_last_pseg = seg->start_block;
912 clean_seginfo(seginfo, unlock);
917 nandfs_invalidate_bufs(struct nandfs_device *fsdev, uint64_t segno)
920 struct buf *bp, *tbd;
923 nandfs_get_segment_range(fsdev, segno, &start, &end);
925 bo = &NTOV(fsdev->nd_gc_node)->v_bufobj;
929 TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, tbd) {
930 if (!(bp->b_lblkno >= start && bp->b_lblkno <= end))
933 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL))
934 goto restart_locked_gc;
937 bp->b_flags |= (B_INVAL | B_RELBUF);
938 bp->b_flags &= ~(B_ASYNC | B_MANAGED);
946 /* Process segments marks to free by cleaner */
948 nandfs_process_segments(struct nandfs_device *fsdev)
950 uint64_t saved_segment;
953 if (fsdev->nd_free_base) {
954 saved_segment = nandfs_get_segnum_of_block(fsdev,
955 fsdev->nd_super.s_last_pseg);
956 for (i = 0; i < fsdev->nd_free_count; i++) {
957 if (fsdev->nd_free_base[i] == NANDFS_NOSEGMENT)
959 /* Update superblock if clearing segment point by it */
960 if (fsdev->nd_free_base[i] == saved_segment) {
961 nandfs_write_superblock(fsdev);
962 saved_segment = nandfs_get_segnum_of_block(
963 fsdev, fsdev->nd_super.s_last_pseg);
965 nandfs_invalidate_bufs(fsdev, fsdev->nd_free_base[i]);
966 nandfs_clear_segment(fsdev, fsdev->nd_free_base[i]);
969 free(fsdev->nd_free_base, M_NANDFSTEMP);
970 fsdev->nd_free_base = NULL;
971 fsdev->nd_free_count = 0;
975 /* Collect and write dirty buffers */
977 nandfs_sync_file(struct vnode *vp)
979 struct nandfs_device *fsdev;
980 struct nandfs_node *nandfs_node;
981 struct nandfsmount *nmp;
982 struct nandfs_node *dat, *su, *ifile, *cp;
983 struct nandfs_seginfo *seginfo = NULL;
984 struct nandfs_segment *seg;
988 ASSERT_VOP_LOCKED(vp, __func__);
989 DPRINTF(SYNC, ("%s: START\n", __func__));
992 nmp = VFSTONANDFS(vp->v_mount);
993 fsdev = nmp->nm_nandfsdev;
995 dat = fsdev->nd_dat_node;
996 su = fsdev->nd_su_node;
997 cp = fsdev->nd_cp_node;
998 ifile = nmp->nm_ifile_node;
1000 NANDFS_WRITEASSERT(fsdev);
1001 if (lockmgr(&fsdev->nd_seg_const, LK_UPGRADE, NULL) != 0) {
1002 DPRINTF(SYNC, ("%s: lost shared lock\n", __func__));
1003 if (lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL) != 0)
1004 panic("couldn't lock exclusive");
1006 DPRINTF(SYNC, ("%s: got lock\n", __func__));
1008 VOP_LOCK(NTOV(su), LK_EXCLUSIVE);
1009 create_seginfo(fsdev, &seginfo);
1013 nandfs_node = VTON(vp);
1014 if (nandfs_node->nn_flags & IN_MODIFIED) {
1015 nandfs_node->nn_flags &= ~(IN_MODIFIED);
1019 if (vp->v_bufobj.bo_dirty.bv_cnt) {
1020 error = nandfs_iterate_dirty_buf(vp, seginfo, 0);
1022 clean_seginfo(seginfo, 0);
1023 delete_seginfo(seginfo);
1024 VOP_UNLOCK(NTOV(su), 0);
1025 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1026 nandfs_error("%s: err:%d iterating dirty bufs vp:%p",
1027 __func__, error, vp);
1034 VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE);
1035 error = nandfs_node_update(nandfs_node);
1037 clean_seginfo(seginfo, 0);
1038 delete_seginfo(seginfo);
1039 VOP_UNLOCK(NTOV(ifile), 0);
1040 VOP_UNLOCK(NTOV(su), 0);
1041 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1042 nandfs_error("%s: err:%d updating vp:%p",
1043 __func__, error, vp);
1046 VOP_UNLOCK(NTOV(ifile), 0);
1050 if (seginfo->blocks) {
1051 VOP_LOCK(NTOV(cp), LK_EXCLUSIVE);
1053 /* Create new checkpoint */
1054 error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1);
1056 clean_seginfo(seginfo, 0);
1057 delete_seginfo(seginfo);
1058 VOP_UNLOCK(NTOV(cp), 0);
1059 VOP_UNLOCK(NTOV(su), 0);
1060 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1061 nandfs_error("%s: err:%d getting cp:%jx",
1062 __func__, error, fsdev->nd_last_cno + 1);
1066 /* Reiterate all blocks and assign physical block number */
1067 nandfs_seginfo_assign_pblk(seginfo);
1069 /* Fill checkpoint data */
1070 error = nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1,
1071 &ifile->nn_inode, seginfo->blocks);
1073 clean_seginfo(seginfo, 0);
1074 delete_seginfo(seginfo);
1075 VOP_UNLOCK(NTOV(cp), 0);
1076 VOP_UNLOCK(NTOV(su), 0);
1077 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1078 nandfs_error("%s: err:%d setting cp:%jx",
1079 __func__, error, fsdev->nd_last_cno + 1);
1083 VOP_UNLOCK(NTOV(cp), 0);
1084 LIST_FOREACH(seg, &seginfo->seg_list, seg_link)
1085 nandfs_update_segment(fsdev, seg->seg_num,
1086 seg->nblocks + seg->segsum_blocks);
1088 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1089 error = save_seginfo(seginfo, 0);
1091 clean_seginfo(seginfo, 0);
1092 delete_seginfo(seginfo);
1093 VOP_UNLOCK(NTOV(dat), 0);
1094 VOP_UNLOCK(NTOV(su), 0);
1095 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1096 nandfs_error("%s: err:%d updating seg",
1100 VOP_UNLOCK(NTOV(dat), 0);
1103 VOP_UNLOCK(NTOV(su), 0);
1105 delete_seginfo(seginfo);
1106 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1108 if (cno_changed && !error) {
1109 if (nandfs_cps_between_sblocks != 0 &&
1110 fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0)
1111 nandfs_write_superblock(fsdev);
1114 ASSERT_VOP_LOCKED(vp, __func__);
1115 DPRINTF(SYNC, ("%s: END error %d\n", __func__, error));
1120 nandfs_segment_constructor(struct nandfsmount *nmp, int flags)
1122 struct nandfs_device *fsdev;
1123 struct nandfs_seginfo *seginfo = NULL;
1124 struct nandfs_segment *seg;
1125 struct nandfs_node *dat, *su, *ifile, *cp, *gc;
1126 int cno_changed, error;
1128 DPRINTF(SYNC, ("%s: START\n", __func__));
1129 fsdev = nmp->nm_nandfsdev;
1131 lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL);
1132 DPRINTF(SYNC, ("%s: git lock\n", __func__));
1134 create_seginfo(fsdev, &seginfo);
1136 dat = fsdev->nd_dat_node;
1137 su = fsdev->nd_su_node;
1138 cp = fsdev->nd_cp_node;
1139 gc = fsdev->nd_gc_node;
1140 ifile = nmp->nm_ifile_node;
1142 VOP_LOCK(NTOV(su), LK_EXCLUSIVE);
1143 VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE);
1144 VOP_LOCK(NTOV(gc), LK_EXCLUSIVE);
1145 VOP_LOCK(NTOV(cp), LK_EXCLUSIVE);
1147 nandfs_iterate_system_vnode(gc, seginfo);
1148 nandfs_iterate_dirty_vnodes(nmp->nm_vfs_mountp, seginfo);
1149 nandfs_iterate_system_vnode(ifile, seginfo);
1150 nandfs_iterate_system_vnode(su, seginfo);
1153 if (seginfo->blocks || flags) {
1155 /* Create new checkpoint */
1156 error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1);
1158 clean_seginfo(seginfo, 0);
1159 delete_seginfo(seginfo);
1163 /* Collect blocks from system files */
1164 nandfs_iterate_system_vnode(cp, seginfo);
1165 nandfs_iterate_system_vnode(su, seginfo);
1166 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1167 nandfs_iterate_system_vnode(dat, seginfo);
1168 VOP_UNLOCK(NTOV(dat), 0);
1170 seginfo->reiterate = 0;
1171 nandfs_iterate_system_vnode(su, seginfo);
1172 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1173 nandfs_iterate_system_vnode(dat, seginfo);
1174 VOP_UNLOCK(NTOV(dat), 0);
1175 if (seginfo->reiterate)
1177 if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
1178 error = create_segment(seginfo);
1180 clean_seginfo(seginfo, 0);
1181 delete_seginfo(seginfo);
1187 /* Reiterate all blocks and assign physical block number */
1188 nandfs_seginfo_assign_pblk(seginfo);
1190 /* Fill superroot */
1191 error = nandfs_add_superroot(seginfo);
1193 clean_seginfo(seginfo, 0);
1194 delete_seginfo(seginfo);
1197 KASSERT(!(seginfo->reiterate), ("reiteration after superroot"));
1199 /* Fill checkpoint data */
1200 nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1,
1201 &ifile->nn_inode, seginfo->blocks);
1203 LIST_FOREACH(seg, &seginfo->seg_list, seg_link)
1204 nandfs_update_segment(fsdev, seg->seg_num,
1205 seg->nblocks + seg->segsum_blocks);
1207 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1208 error = save_seginfo(seginfo, 1);
1210 clean_seginfo(seginfo, 1);
1211 delete_seginfo(seginfo);
1214 VOP_UNLOCK(NTOV(dat), 0);
1217 VOP_UNLOCK(NTOV(cp), 0);
1218 VOP_UNLOCK(NTOV(gc), 0);
1219 VOP_UNLOCK(NTOV(ifile), 0);
1221 nandfs_process_segments(fsdev);
1223 VOP_UNLOCK(NTOV(su), 0);
1225 delete_seginfo(seginfo);
1228 * XXX: a hack, will go away soon
1230 if ((NTOV(dat)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1231 NTOV(cp)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1232 NTOV(gc)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1233 NTOV(ifile)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1234 NTOV(su)->v_bufobj.bo_dirty.bv_cnt != 0) &&
1235 (flags & NANDFS_UMOUNT)) {
1236 DPRINTF(SYNC, ("%s: RERUN\n", __func__));
1240 MPASS(fsdev->nd_free_base == NULL);
1242 lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL);
1245 if ((nandfs_cps_between_sblocks != 0 &&
1246 fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) ||
1247 flags & NANDFS_UMOUNT)
1248 nandfs_write_superblock(fsdev);
1251 DPRINTF(SYNC, ("%s: END\n", __func__));
1254 VOP_UNLOCK(NTOV(dat), 0);
1256 VOP_UNLOCK(NTOV(cp), 0);
1257 VOP_UNLOCK(NTOV(gc), 0);
1258 VOP_UNLOCK(NTOV(ifile), 0);
1259 VOP_UNLOCK(NTOV(su), 0);
1260 lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL);
1267 * Show details about the given NANDFS mount point.
1269 DB_SHOW_COMMAND(nandfs, db_show_nandfs)
1272 struct nandfs_device *nffsdev;
1273 struct nandfs_segment *seg;
1274 struct nandfsmount *nmp;
1279 db_printf("\nUsage: show nandfs <mount_addr>\n");
1283 mp = (struct mount *)addr;
1284 db_printf("%p %s on %s (%s)\n", mp, mp->mnt_stat.f_mntfromname,
1285 mp->mnt_stat.f_mntonname, mp->mnt_stat.f_fstypename);
1288 nmp = (struct nandfsmount *)(mp->mnt_data);
1289 nffsdev = nmp->nm_nandfsdev;
1290 db_printf("dev vnode:%p\n", nffsdev->nd_devvp);
1291 db_printf("blocksize:%jx last cno:%jx last pseg:%jx seg num:%jx\n",
1292 (uintmax_t)nffsdev->nd_blocksize, (uintmax_t)nffsdev->nd_last_cno,
1293 (uintmax_t)nffsdev->nd_last_pseg, (uintmax_t)nffsdev->nd_seg_num);
1294 db_printf("system nodes: dat:%p cp:%p su:%p ifile:%p gc:%p\n",
1295 nffsdev->nd_dat_node, nffsdev->nd_cp_node, nffsdev->nd_su_node,
1296 nmp->nm_ifile_node, nffsdev->nd_gc_node);
1298 if (nffsdev->nd_seginfo != NULL) {
1299 LIST_FOREACH(seg, &nffsdev->nd_seginfo->seg_list, seg_link) {
1300 db_printf("seg: %p\n", seg);
1301 TAILQ_FOREACH(bp, &seg->segsum,
1302 b_cluster.cluster_entry)
1303 db_printf("segbp %p\n", bp);
1304 TAILQ_FOREACH(bp, &seg->data,
1305 b_cluster.cluster_entry) {
1307 db_printf("bp:%p bp->b_vp:%p ino:%jx\n", bp, vp,
1308 (uintmax_t)(vp ? VTON(vp)->nn_ino : 0));