static int nandfs_cleaner_iterate_segment(struct nandfs_device *fsdev, uint64_t segno, struct nandfs_vinfo **vipp, struct nandfs_bdesc **bdpp, int *select) { struct nandfs_segment_summary *segsum; union nandfs_binfo *binfo; struct buf *bp; uint32_t nblocks; nandfs_daddr_t curr, start, end; int error = 0; nandfs_get_segment_range(fsdev, segno, &start, &end); DPRINTF(CLEAN, ("%s: segno %jx start %jx end %jx\n", __func__, segno, start, end)); *select = 0; for (curr = start; curr < end; curr += nblocks) { error = nandfs_dev_bread(fsdev, curr, NOCRED, 0, &bp); if (error) { brelse(bp); nandfs_error("%s: couldn't load segment summary of %jx: %d\n", __func__, segno, error); return (error); } segsum = (struct nandfs_segment_summary *)bp->b_data; binfo = (union nandfs_binfo *)(bp->b_data + segsum->ss_bytes); if (!nandfs_segsum_valid(segsum)) { brelse(bp); nandfs_error("nandfs: invalid summary of segment %jx\n", segno); return (error); } DPRINTF(CLEAN, ("%s: %jx magic %x bytes %x nblocks %x nbinfos " "%x\n", __func__, segno, segsum->ss_magic, segsum->ss_bytes, segsum->ss_nblocks, segsum->ss_nbinfos)); nandfs_cleaner_iterate_psegment(fsdev, segsum, binfo, curr, vipp, bdpp); nblocks = segsum->ss_nblocks; brelse(bp); } if (error == 0) *select = 1; return (error); }
static int nandfs_process_bdesc(struct nandfs_device *nffsdev, struct nandfs_bdesc *bd, uint64_t nmembs) { struct nandfs_node *dat_node; struct buf *bp; uint64_t i; int error; dat_node = nffsdev->nd_dat_node; VOP_LOCK(NTOV(dat_node), LK_EXCLUSIVE); for (i = 0; i < nmembs; i++) { if (!bd[i].bd_alive) continue; DPRINTF(CLEAN, ("%s: idx %jx offset %jx\n", __func__, i, bd[i].bd_offset)); if (bd[i].bd_level) { error = nandfs_bread_meta(dat_node, bd[i].bd_offset, NULL, 0, &bp); if (error) { nandfs_error("%s: cannot read dat node " "level:%d\n", __func__, bd[i].bd_level); brelse(bp); VOP_UNLOCK(NTOV(dat_node), 0); return (error); } nandfs_dirty_buf_meta(bp, 1); nandfs_bmap_dirty_blocks(VTON(bp->b_vp), bp, 1); } else { error = nandfs_bread(dat_node, bd[i].bd_offset, NULL, 0, &bp); if (error) { nandfs_error("%s: cannot read dat node\n", __func__); brelse(bp); VOP_UNLOCK(NTOV(dat_node), 0); return (error); } nandfs_dirty_buf(bp, 1); } DPRINTF(CLEAN, ("%s: bp: %p\n", __func__, bp)); } VOP_UNLOCK(NTOV(dat_node), 0); return (0); }
/* Update block count of segment */ int nandfs_update_segment(struct nandfs_device *fsdev, uint64_t seg, uint32_t nblks) { struct nandfs_node *su_node; struct nandfs_segment_usage *su_usage; struct buf *bp; uint64_t blk, offset; int error; su_node = fsdev->nd_su_node; ASSERT_VOP_LOCKED(NTOV(su_node), __func__); nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); if (error) { nandfs_error("%s: read block:%jx to update\n", __func__, blk); brelse(bp); return (error); } su_usage = SU_USAGE_OFF(bp, offset); su_usage->su_lastmod = fsdev->nd_ts.tv_sec; su_usage->su_flags = NANDFS_SEGMENT_USAGE_DIRTY; su_usage->su_nblocks += nblks; DPRINTF(SEG, ("%s: seg:%#jx inc:%#x cur:%#x\n", __func__, (uintmax_t)seg, nblks, su_usage->su_nblocks)); nandfs_dirty_buf(bp, 1); return (0); }
int nandfs_node_destroy(struct nandfs_node *node) { struct nandfs_alloc_request req; struct nandfsmount *nmp; struct nandfs_mdt *mdt; struct nandfs_node *ifile; struct vnode *vp; int error = 0; nmp = node->nn_nmp; req.entrynum = node->nn_ino; mdt = &nmp->nm_nandfsdev->nd_ifile_mdt; ifile = nmp->nm_ifile_node; vp = NTOV(ifile); DPRINTF(IFILE, ("%s: destroy node: %p ino: %#jx\n", __func__, node, (uintmax_t)node->nn_ino)); VOP_LOCK(vp, LK_EXCLUSIVE); error = nandfs_find_entry(mdt, ifile, &req); if (error) { nandfs_error("%s: finding entry error:%d node %p(%jx)", __func__, error, node, node->nn_ino); VOP_UNLOCK(vp, 0); return (error); } nandfs_inode_destroy(&node->nn_inode); error = nandfs_free_entry(mdt, &req); if (error) { nandfs_error("%s: freing entry error:%d node %p(%jx)", __func__, error, node, node->nn_ino); VOP_UNLOCK(vp, 0); return (error); } VOP_UNLOCK(vp, 0); DPRINTF(IFILE, ("%s: freed node %p ino %#jx\n", __func__, node, (uintmax_t)node->nn_ino)); return (error); }
int nandfs_bmap_dirty_blocks(struct nandfs_node *node, struct buf *bp, int force) { int error; error = bmap_dirty_meta(node, bp->b_lblkno, force); if (error) nandfs_error("%s: cannot dirty buffer %p\n", __func__, bp); return (error); }
int nandfs_init_dir(struct vnode *dvp, uint64_t ino, uint64_t parent_ino) { if (nandfs_add_dirent(dvp, parent_ino, "..", 2, DT_DIR) || nandfs_add_dirent(dvp, ino, ".", 1, DT_DIR)) { nandfs_error("%s: cannot initialize dir ino:%jd(pino:%jd)\n", __func__, ino, parent_ino); return (-1); } return (0); }
static int nandfs_cleaner_choose_segment(struct nandfs_device *fsdev, uint64_t **segpp, uint64_t nsegs, uint64_t *rseg) { struct nandfs_suinfo *suinfo; uint64_t i, ssegs; int error; suinfo = malloc(sizeof(*suinfo) * nsegs, M_NANDFSTEMP, M_ZERO | M_WAITOK); if (*rseg >= fsdev->nd_fsdata.f_nsegments) *rseg = 0; retry: error = nandfs_get_segment_info_filter(fsdev, suinfo, nsegs, *rseg, &ssegs, NANDFS_SEGMENT_USAGE_DIRTY, NANDFS_SEGMENT_USAGE_ACTIVE | NANDFS_SEGMENT_USAGE_ERROR | NANDFS_SEGMENT_USAGE_GC); if (error) { nandfs_error("%s:%d", __FILE__, __LINE__); goto out; } if (ssegs == 0 && *rseg != 0) { *rseg = 0; goto retry; } print_suinfo(suinfo, ssegs); for (i = 0; i < ssegs; i++) { (**segpp) = suinfo[i].nsi_num; (*segpp)++; } *rseg = suinfo[i - 1].nsi_num + 1; out: free(suinfo, M_NANDFSTEMP); return (error); }
int nandfs_bmap_lookup(struct nandfs_node *node, nandfs_lbn_t lblk, nandfs_daddr_t *vblk) { int error = 0; if (node->nn_ino == NANDFS_GC_INO && lblk >= 0) *vblk = lblk; else error = bmap_lookup(node, lblk, vblk); DPRINTF(TRANSLATE, ("%s: error %d ino %#jx lblocknr %#jx -> %#jx\n", __func__, error, (uintmax_t)node->nn_ino, (uintmax_t)lblk, (uintmax_t)*vblk)); if (error) nandfs_error("%s: returned %d", __func__, error); return (error); }
/* * Make buffer dirty, it will be updated soon but first it need to be * gathered by syncer. */ int nandfs_touch_segment(struct nandfs_device *fsdev, uint64_t seg) { struct nandfs_node *su_node; struct buf *bp; uint64_t blk, offset; int error; su_node = fsdev->nd_su_node; ASSERT_VOP_LOCKED(NTOV(su_node), __func__); nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); if (error) { brelse(bp); nandfs_error("%s: cannot preallocate new segment\n", __func__); return (error); } else nandfs_dirty_buf(bp, 1); DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); return (error); }
int nandfs_bmap_update_block(struct nandfs_node *node, struct buf *bp, nandfs_lbn_t blknr) { nandfs_lbn_t lblk; int error; lblk = bp->b_lblkno; nandfs_vblk_set(bp, blknr); DPRINTF(BMAP, ("%s: node: %p ino: %#jx bp: %p lblk: %#jx blk: %#jx\n", __func__, node, (uintmax_t)node->nn_ino, bp, (uintmax_t)lblk, (uintmax_t)blknr)); error = nandfs_bmap_update_mapping(node, lblk, blknr); if (error) { nandfs_error("%s: cannot update lblk:%jx to blk:%jx for " "node:%p, error:%d\n", __func__, (uintmax_t)lblk, (uintmax_t)blknr, node, error); return (error); } return (error); }
/* Alloc new segment */ int nandfs_alloc_segment(struct nandfs_device *fsdev, uint64_t *seg) { struct nandfs_node *su_node; struct nandfs_sufile_header *su_header; struct nandfs_segment_usage *su_usage; struct buf *bp_header, *bp; uint64_t blk, vblk, offset, i, rest, nsegments; uint16_t seg_size; int error, found; seg_size = fsdev->nd_fsdata.f_segment_usage_size; nsegments = fsdev->nd_fsdata.f_nsegments; su_node = fsdev->nd_su_node; ASSERT_VOP_LOCKED(NTOV(su_node), __func__); /* Read header buffer */ error = nandfs_bread(su_node, 0, NOCRED, 0, &bp_header); if (error) { brelse(bp_header); return (error); } su_header = (struct nandfs_sufile_header *)bp_header->b_data; /* Get last allocated segment */ i = su_header->sh_last_alloc + 1; found = 0; bp = NULL; while (!found) { nandfs_seg_usage_blk_offset(fsdev, i, &blk, &offset); if(blk != 0) { error = nandfs_bmap_lookup(su_node, blk, &vblk); if (error) { nandfs_error("%s: cannot find vblk for blk " "blk:%jx\n", __func__, blk); return (error); } if (vblk) error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); else error = nandfs_bcreate(su_node, blk, NOCRED, 0, &bp); if (error) { nandfs_error("%s: cannot create/read " "vblk:%jx\n", __func__, vblk); if (bp) brelse(bp); return (error); } su_usage = SU_USAGE_OFF(bp, offset); } else { su_usage = SU_USAGE_OFF(bp_header, offset); bp = bp_header; } rest = (fsdev->nd_blocksize - offset) / seg_size; /* Go through all su usage in block */ while (rest) { /* When last check start from beggining */ if (i == nsegments) break; if (!su_usage->su_flags) { su_usage->su_flags = 1; found = 1; break; } su_usage++; i++; /* If all checked return error */ if (i == su_header->sh_last_alloc) { DPRINTF(SEG, ("%s: cannot allocate segment \n", __func__)); brelse(bp_header); if (blk != 0) brelse(bp); return (1); } rest--; } if (!found) { /* Otherwise read another block */ if (blk != 0) brelse(bp); if (i == nsegments) { blk = 0; i = 0; } else blk++; offset = 0; } } if (found) { *seg = i; su_header->sh_last_alloc = i; su_header->sh_ncleansegs--; su_header->sh_ndirtysegs++; fsdev->nd_super.s_free_blocks_count = su_header->sh_ncleansegs * fsdev->nd_fsdata.f_blocks_per_segment; fsdev->nd_clean_segs--; /* * It is mostly called from syncer() so we want to force * making buf dirty. */ error = nandfs_dirty_buf(bp_header, 1); if (error) { if (bp && bp != bp_header) brelse(bp); return (error); } if (bp && bp != bp_header) nandfs_dirty_buf(bp, 1); DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)i)); return (0); } DPRINTF(SEG, ("%s: failed\n", __func__)); return (1); }
int nandfs_vblock_alloc(struct nandfs_device *nandfsdev, nandfs_daddr_t *vblock) { struct nandfs_node *dat; struct nandfs_mdt *mdt; struct nandfs_alloc_request req; struct nandfs_dat_entry *dat_entry; uint64_t start; uint32_t entry; int locked, error; dat = nandfsdev->nd_dat_node; mdt = &nandfsdev->nd_dat_mdt; start = nandfsdev->nd_last_cno + 1; locked = NANDFS_VOP_ISLOCKED(NTOV(dat)); if (!locked) VOP_LOCK(NTOV(dat), LK_EXCLUSIVE); req.entrynum = 0; /* Alloc vblock number */ error = nandfs_find_free_entry(mdt, dat, &req); if (error) { nandfs_error("%s: cannot find free vblk entry\n", __func__); if (!locked) VOP_UNLOCK(NTOV(dat), 0); return (error); } /* Read/create buffer */ error = nandfs_get_entry_block(mdt, dat, &req, &entry, 1); if (error) { nandfs_error("%s: cannot get free vblk entry\n", __func__); nandfs_abort_entry(&req); if (!locked) VOP_UNLOCK(NTOV(dat), 0); return (error); } /* Fill out vblock data */ dat_entry = (struct nandfs_dat_entry *) req.bp_entry->b_data; dat_entry[entry].de_start = start; dat_entry[entry].de_end = UINTMAX_MAX; dat_entry[entry].de_blocknr = 0; /* Commit allocation */ error = nandfs_alloc_entry(mdt, &req); if (error) { nandfs_error("%s: cannot get free vblk entry\n", __func__); if (!locked) VOP_UNLOCK(NTOV(dat), 0); return (error); } /* Return allocated vblock */ *vblock = req.entrynum; DPRINTF(DAT, ("%s: allocated vblock %#jx\n", __func__, (uintmax_t)*vblock)); if (!locked) VOP_UNLOCK(NTOV(dat), 0); return (error); }
int bmap_insert_block(struct nandfs_node *node, nandfs_lbn_t lblk, nandfs_daddr_t vblk) { struct nandfs_inode *ip; struct nandfs_indir a[NIADDR+1], *ap; struct buf *bp; nandfs_daddr_t daddr; int error; int num, *nump, i; DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx\n", __func__, node, lblk, vblk)); ip = &node->nn_inode; ap = a; nump = # error = bmap_getlbns(node, lblk, ap, nump); if (error) return (error); DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx got num=%d\n", __func__, node, lblk, vblk, num)); if (num == 0) { DPRINTF(BMAP, ("%s: node %p lblk=%jx direct block\n", __func__, node, lblk)); ip->i_db[lblk] = vblk; return (0); } DPRINTF(BMAP, ("%s: node %p lblk=%jx indirect block level %d\n", __func__, node, lblk, ap->in_off)); if (num == 1) { DPRINTF(BMAP, ("%s: node %p lblk=%jx indirect block: inserting " "%jx as vblk for indirect block %d\n", __func__, node, lblk, vblk, ap->in_off)); ip->i_ib[ap->in_off] = vblk; return (0); } bp = NULL; daddr = ip->i_ib[a[0].in_off]; for (i = 1; i < num; i++) { if (bp) brelse(bp); if (daddr == 0) { DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx create " "block %jx %d\n", __func__, node, lblk, vblk, a[i].in_lbn, a[i].in_off)); error = nandfs_bcreate_meta(node, a[i].in_lbn, NOCRED, 0, &bp); if (error) return (error); } else { DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx read " "block %jx %d\n", __func__, node, daddr, vblk, a[i].in_lbn, a[i].in_off)); error = nandfs_bread_meta(node, a[i].in_lbn, NOCRED, 0, &bp); if (error) { brelse(bp); return (error); } } daddr = ((nandfs_daddr_t *)bp->b_data)[a[i].in_off]; } i--; DPRINTF(BMAP, ("%s: bmap node %p lblk=%jx vblk=%jx inserting vblk level %d at " "offset %d at %jx\n", __func__, node, lblk, vblk, i, a[i].in_off, daddr)); if (!bp) { nandfs_error("%s: cannot find indirect block\n", __func__); return (-1); } ((nandfs_daddr_t *)bp->b_data)[a[i].in_off] = vblk; error = nandfs_dirty_buf_meta(bp, 0); if (error) { nandfs_warning("%s: dirty failed buf: %p\n", __func__, bp); return (error); } DPRINTF(BMAP, ("%s: exiting node %p lblk=%jx vblk=%jx\n", __func__, node, lblk, vblk)); return (error); }
int bmap_truncate_mapping(struct nandfs_node *node, nandfs_lbn_t lastblk, nandfs_lbn_t todo) { struct nandfs_inode *ip; struct nandfs_indir a[NIADDR + 1], f[NIADDR], *ap; nandfs_daddr_t indir_lbn[NIADDR]; nandfs_daddr_t *copy; int error, level; nandfs_lbn_t left, tosub; struct nandfs_device *fsdev; int cleaned, i; int num, *nump; DPRINTF(BMAP, ("%s: node %p lastblk %jx truncating by %jx\n", __func__, node, lastblk, todo)); ip = &node->nn_inode; fsdev = node->nn_nandfsdev; ap = a; nump = # error = bmap_getlbns(node, lastblk, ap, nump); if (error) return (error); indir_lbn[SINGLE] = -NDADDR; indir_lbn[DOUBLE] = indir_lbn[SINGLE] - MNINDIR(fsdev) - 1; indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - MNINDIR(fsdev) * MNINDIR(fsdev) - 1; for (i = 0; i < NIADDR; i++) { f[i].in_off = MNINDIR(fsdev) - 1; f[i].in_lbn = 0xdeadbeef; } left = todo; #ifdef DEBUG a[num].in_off = -1; #endif ap++; num -= 2; if (num < 0) goto direct; copy = malloc(MNINDIR(fsdev) * sizeof(nandfs_daddr_t) * (num + 1), M_NANDFSTEMP, M_WAITOK); for (level = num; level >= SINGLE && left > 0; level--) { cleaned = 0; if (ip->i_ib[level] == 0) { tosub = blocks_inside(fsdev, level, ap); if (tosub > left) left = 0; else left -= tosub; } else { if (ap == f) ap->in_lbn = indir_lbn[level]; error = bmap_truncate_indirect(node, level, &left, &cleaned, ap, f, copy); if (error) { nandfs_error("%s: error %d when truncate " "at level %d\n", __func__, error, level); return (error); } } if (cleaned) { nandfs_vblock_end(fsdev, ip->i_ib[level]); ip->i_ib[level] = 0; } ap = f; } free(copy, M_NANDFSTEMP); direct: if (num < 0) i = lastblk; else i = NDADDR - 1; for (; i >= 0 && left > 0; i--) { if (ip->i_db[i] != 0) { error = nandfs_bdestroy(node, ip->i_db[i]); if (error) { nandfs_error("%s: cannot destroy " "block %jx, error %d\n", __func__, (uintmax_t)ip->i_db[i], error); return (error); } ip->i_db[i] = 0; } left--; } KASSERT(left == 0, ("truncated wrong number of blocks (%jd should be 0)", left)); return (error); }
static int nandfs_cleaner_clean_segments(struct nandfs_device *nffsdev, struct nandfs_vinfo *vinfo, uint32_t nvinfo, struct nandfs_period *pd, uint32_t npd, struct nandfs_bdesc *bdesc, uint32_t nbdesc, uint64_t *segments, uint32_t nsegs) { struct nandfs_node *gc; struct buf *bp; uint32_t i; int error = 0; gc = nffsdev->nd_gc_node; DPRINTF(CLEAN, ("%s: enter\n", __func__)); VOP_LOCK(NTOV(gc), LK_EXCLUSIVE); for (i = 0; i < nvinfo; i++) { if (!vinfo[i].nvi_alive) continue; DPRINTF(CLEAN, ("%s: read vblknr:%#jx blk:%#jx\n", __func__, (uintmax_t)vinfo[i].nvi_vblocknr, (uintmax_t)vinfo[i].nvi_blocknr)); error = nandfs_bread(nffsdev->nd_gc_node, vinfo[i].nvi_blocknr, NULL, 0, &bp); if (error) { nandfs_error("%s:%d", __FILE__, __LINE__); VOP_UNLOCK(NTOV(gc), 0); goto out; } nandfs_vblk_set(bp, vinfo[i].nvi_vblocknr); nandfs_buf_set(bp, NANDFS_VBLK_ASSIGNED); nandfs_dirty_buf(bp, 1); } VOP_UNLOCK(NTOV(gc), 0); /* Delete checkpoints */ for (i = 0; i < npd; i++) { DPRINTF(CLEAN, ("delete checkpoint: %jx\n", (uintmax_t)pd[i].p_start)); error = nandfs_delete_cp(nffsdev->nd_cp_node, pd[i].p_start, pd[i].p_end); if (error) { nandfs_error("%s:%d", __FILE__, __LINE__); goto out; } } /* Update vblocks */ for (i = 0; i < nvinfo; i++) { if (vinfo[i].nvi_alive) continue; DPRINTF(CLEAN, ("freeing vblknr: %jx\n", vinfo[i].nvi_vblocknr)); error = nandfs_vblock_free(nffsdev, vinfo[i].nvi_vblocknr); if (error) { nandfs_error("%s:%d", __FILE__, __LINE__); goto out; } } error = nandfs_process_bdesc(nffsdev, bdesc, nbdesc); if (error) { nandfs_error("%s:%d", __FILE__, __LINE__); goto out; } /* Add segments to clean */ if (nffsdev->nd_free_count) { nffsdev->nd_free_base = realloc(nffsdev->nd_free_base, (nffsdev->nd_free_count + nsegs) * sizeof(uint64_t), M_NANDFSTEMP, M_WAITOK | M_ZERO); memcpy(&nffsdev->nd_free_base[nffsdev->nd_free_count], segments, nsegs * sizeof(uint64_t)); nffsdev->nd_free_count += nsegs; } else { nffsdev->nd_free_base = malloc(nsegs * sizeof(uint64_t), M_NANDFSTEMP, M_WAITOK|M_ZERO); memcpy(nffsdev->nd_free_base, segments, nsegs * sizeof(uint64_t)); nffsdev->nd_free_count = nsegs; } out: DPRINTF(CLEAN, ("%s: exit error %d\n", __func__, error)); return (error); }
static int nandfs_cleaner_body(struct nandfs_device *fsdev, uint64_t *rseg) { struct nandfs_vinfo *vinfo, *vip, *vipi; struct nandfs_bdesc *bdesc, *bdp, *bdpi; struct nandfs_cpstat cpstat; struct nandfs_cpinfo *cpinfo = NULL; uint64_t *segnums, *segp; int select, selected; int error = 0; int nsegs; int i; nsegs = nandfs_cleaner_segments; vip = vinfo = malloc(sizeof(*vinfo) * fsdev->nd_fsdata.f_blocks_per_segment * nsegs, M_NANDFSTEMP, M_ZERO | M_WAITOK); bdp = bdesc = malloc(sizeof(*bdesc) * fsdev->nd_fsdata.f_blocks_per_segment * nsegs, M_NANDFSTEMP, M_ZERO | M_WAITOK); segp = segnums = malloc(sizeof(*segnums) * nsegs, M_NANDFSTEMP, M_WAITOK); error = nandfs_cleaner_choose_segment(fsdev, &segp, nsegs, rseg); if (error) { nandfs_error("%s:%d", __FILE__, __LINE__); goto out; } if (segnums == segp) goto out; selected = 0; for (i = 0; i < segp - segnums; i++) { error = nandfs_cleaner_iterate_segment(fsdev, segnums[i], &vip, &bdp, &select); if (error) { /* * XXX deselect (see below)? */ goto out; } if (!select) segnums[i] = NANDFS_NOSEGMENT; else { error = nandfs_markgc_segment(fsdev, segnums[i]); if (error) { nandfs_error("%s:%d\n", __FILE__, __LINE__); goto out; } selected++; } } if (selected == 0) { MPASS(vinfo == vip); MPASS(bdesc == bdp); goto out; } error = nandfs_get_cpstat(fsdev->nd_cp_node, &cpstat); if (error) { nandfs_error("%s:%d\n", __FILE__, __LINE__); goto out; } if (cpstat.ncp_nss != 0) { cpinfo = malloc(sizeof(struct nandfs_cpinfo) * cpstat.ncp_nss, M_NANDFSTEMP, M_WAITOK); error = nandfs_get_cpinfo(fsdev->nd_cp_node, 1, NANDFS_SNAPSHOT, cpinfo, cpstat.ncp_nss, NULL); if (error) { nandfs_error("%s:%d\n", __FILE__, __LINE__); goto out_locked; } } NANDFS_WRITELOCK(fsdev); DPRINTF(CLEAN, ("%s: got lock\n", __func__)); error = nandfs_get_dat_vinfo(fsdev, vinfo, vip - vinfo); if (error) { nandfs_error("%s:%d\n", __FILE__, __LINE__); goto out_locked; } nandfs_cleaner_vinfo_mark_alive(fsdev, vinfo, vip - vinfo, cpinfo, cpstat.ncp_nss); error = nandfs_get_dat_bdescs(fsdev, bdesc, bdp - bdesc); if (error) { nandfs_error("%s:%d\n", __FILE__, __LINE__); goto out_locked; } nandfs_cleaner_bdesc_mark_alive(fsdev, bdesc, bdp - bdesc); DPRINTF(CLEAN, ("got:\n")); for (vipi = vinfo; vipi < vip; vipi++) { DPRINTF(CLEAN, ("v ino %jx vblocknr %jx start %jx end %jx " "alive %d\n", vipi->nvi_ino, vipi->nvi_vblocknr, vipi->nvi_start, vipi->nvi_end, vipi->nvi_alive)); } for (bdpi = bdesc; bdpi < bdp; bdpi++) { DPRINTF(CLEAN, ("b oblocknr %jx blocknr %jx offset %jx " "alive %d\n", bdpi->bd_oblocknr, bdpi->bd_blocknr, bdpi->bd_offset, bdpi->bd_alive)); } DPRINTF(CLEAN, ("end list\n")); error = nandfs_cleaner_clean_segments(fsdev, vinfo, vip - vinfo, NULL, 0, bdesc, bdp - bdesc, segnums, segp - segnums); if (error) nandfs_error("%s:%d\n", __FILE__, __LINE__); out_locked: NANDFS_WRITEUNLOCK(fsdev); out: free(cpinfo, M_NANDFSTEMP); free(segnums, M_NANDFSTEMP); free(bdesc, M_NANDFSTEMP); free(vinfo, M_NANDFSTEMP); return (error); }
int nandfs_remove_dirent(struct vnode *dvp, struct nandfs_node *node, struct componentname *cnp) { struct nandfs_node *dir_node; struct nandfs_dir_entry *dirent, *pdirent; struct buf *bp; uint64_t filesize, blocknr, ino, offset; uint32_t blocksize, limit, off; uint16_t newsize; uint8_t *pos; int error, found; dir_node = VTON(dvp); filesize = dir_node->nn_inode.i_size; if (!filesize) return (0); if (node) { offset = node->nn_diroff; ino = node->nn_ino; } else { offset = dir_node->nn_diroff; ino = NANDFS_WHT_INO; } dirent = pdirent = NULL; blocksize = dir_node->nn_nandfsdev->nd_blocksize; blocknr = offset / blocksize; DPRINTF(LOOKUP, ("rm direntry dvp %p node %p ino %#jx at off %#jx\n", dvp, node, (uintmax_t)ino, (uintmax_t)offset)); error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp); if (error) { brelse(bp); return (error); } pos = bp->b_data; off = 0; found = 0; limit = offset % blocksize; pdirent = (struct nandfs_dir_entry *) bp->b_data; while (off <= limit) { dirent = (struct nandfs_dir_entry *) (pos + off); if ((off == limit) && (dirent->inode == ino)) { found = 1; break; } if (dirent->inode != 0) pdirent = dirent; off += dirent->rec_len; } if (!found) { nandfs_error("cannot find entry to remove"); brelse(bp); return (error); } DPRINTF(LOOKUP, ("rm dirent ino %#jx at %#x with size %#x\n", (uintmax_t)dirent->inode, off, dirent->rec_len)); newsize = (uintptr_t)dirent - (uintptr_t)pdirent; newsize += dirent->rec_len; pdirent->rec_len = newsize; dirent->inode = 0; error = nandfs_dirty_buf(bp, 0); if (error) return (error); dir_node->nn_flags |= IN_CHANGE | IN_UPDATE; /* If last one modify filesize */ if ((offset + NANDFS_DIR_REC_LEN(dirent->name_len)) == filesize) { filesize = blocknr * blocksize + ((uintptr_t)pdirent - (uintptr_t)pos) + NANDFS_DIR_REC_LEN(pdirent->name_len); dir_node->nn_inode.i_size = filesize; } return (0); }