static int nandfs_bad_segment(struct nandfs_device *fsdev, uint64_t seg) { 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) { 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_ERROR; DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); nandfs_dirty_buf(bp, 1); 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_markgc_segment(struct nandfs_device *fsdev, uint64_t seg) { 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; VOP_LOCK(NTOV(su_node), LK_EXCLUSIVE); nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); if (error) { brelse(bp); VOP_UNLOCK(NTOV(su_node), 0); return (error); } su_usage = SU_USAGE_OFF(bp, offset); MPASS((su_usage->su_flags & NANDFS_SEGMENT_USAGE_GC) == 0); su_usage->su_flags |= NANDFS_SEGMENT_USAGE_GC; brelse(bp); VOP_UNLOCK(NTOV(su_node), 0); DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); return (0); }
int nandfs_find_entry(struct nandfs_mdt* mdt, struct nandfs_node *nnode, struct nandfs_alloc_request *req) { uint64_t dblock, bblock, eblock; uint32_t offset; int error; nandfs_mdt_trans_blk(mdt, req->entrynum, &dblock, &bblock, &eblock, &offset); error = nandfs_bread(nnode, dblock, NOCRED, 0, &req->bp_desc); if (error) { brelse(req->bp_desc); return (error); } error = nandfs_bread(nnode, bblock, NOCRED, 0, &req->bp_bitmap); if (error) { brelse(req->bp_desc); brelse(req->bp_bitmap); return (error); } error = nandfs_bread(nnode, eblock, NOCRED, 0, &req->bp_entry); if (error) { brelse(req->bp_desc); brelse(req->bp_bitmap); brelse(req->bp_entry); return (error); } DPRINTF(ALLOC, ("%s: desc_buf: %p bitmap_buf %p entry_buf %p offset %x\n", __func__, req->bp_desc, req->bp_bitmap, req->bp_entry, offset)); return (0); }
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); }
int nandfs_update_dirent(struct vnode *dvp, struct nandfs_node *fnode, struct nandfs_node *tnode) { struct nandfs_node *dir_node; struct nandfs_dir_entry *dirent; struct buf *bp; uint64_t file_size, blocknr; uint32_t blocksize, off; uint8_t *pos; int error; dir_node = VTON(dvp); file_size = dir_node->nn_inode.i_size; if (!file_size) return (0); DPRINTF(LOOKUP, ("chg direntry dvp %p ino %#jx to in %#jx at off %#jx\n", dvp, (uintmax_t)tnode->nn_ino, (uintmax_t)fnode->nn_ino, (uintmax_t)tnode->nn_diroff)); blocksize = dir_node->nn_nandfsdev->nd_blocksize; blocknr = tnode->nn_diroff / blocksize; off = tnode->nn_diroff % blocksize; error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp); if (error) { brelse(bp); return (error); } pos = bp->b_data; dirent = (struct nandfs_dir_entry *) (pos + off); KASSERT((dirent->inode == tnode->nn_ino), ("direntry mismatch")); dirent->inode = fnode->nn_ino; error = nandfs_dirty_buf(bp, 0); if (error) return (error); return (0); }
int nandfs_update_parent_dir(struct vnode *dvp, uint64_t newparent) { struct nandfs_dir_entry *dirent; struct nandfs_node *dir_node; struct buf *bp; int error; dir_node = VTON(dvp); error = nandfs_bread(dir_node, 0, NOCRED, 0, &bp); if (error) { brelse(bp); return (error); } dirent = (struct nandfs_dir_entry *)bp->b_data; dirent->inode = newparent; error = nandfs_dirty_buf(bp, 0); if (error) return (error); return (0); }
int nandfs_get_entry_block(struct nandfs_mdt *mdt, struct nandfs_node *node, struct nandfs_alloc_request *req, uint32_t *entry, int create) { struct buf *bp; nandfs_lbn_t blocknr; int error; /* Find buffer number for given entry */ nandfs_mdt_trans(mdt, req->entrynum, &blocknr, entry); DPRINTF(ALLOC, ("%s: ino %#jx entrynum:%#jx block:%#jx entry:%x\n", __func__, (uintmax_t)node->nn_ino, (uintmax_t)req->entrynum, (uintmax_t)blocknr, *entry)); /* Read entry block or create if 'create' parameter is not zero */ bp = NULL; if (blocknr < node->nn_inode.i_blocks) error = nandfs_bread(node, blocknr, NOCRED, 0, &bp); else if (create) error = nandfs_bcreate(node, blocknr, NOCRED, 0, &bp); else error = E2BIG; if (error) { DPRINTF(ALLOC, ("%s: ino %#jx block %#jx entry %x error %d\n", __func__, (uintmax_t)node->nn_ino, (uintmax_t)blocknr, *entry, error)); if (bp) brelse(bp); return (error); } MPASS(nandfs_vblk_get(bp) != 0 || node->nn_ino == NANDFS_DAT_INO); req->bp_entry = bp; return (0); }
int nandfs_get_seg_stat(struct nandfs_device *nandfsdev, struct nandfs_seg_stat *nss) { struct nandfs_sufile_header *suhdr; struct nandfs_node *su_node; struct buf *bp; int err; su_node = nandfsdev->nd_su_node; NANDFS_WRITELOCK(nandfsdev); VOP_LOCK(NTOV(su_node), LK_SHARED); err = nandfs_bread(nandfsdev->nd_su_node, 0, NOCRED, 0, &bp); if (err) { brelse(bp); VOP_UNLOCK(NTOV(su_node), 0); NANDFS_WRITEUNLOCK(nandfsdev); return (-1); } suhdr = (struct nandfs_sufile_header *)bp->b_data; nss->nss_nsegs = nandfsdev->nd_fsdata.f_nsegments; nss->nss_ncleansegs = suhdr->sh_ncleansegs; nss->nss_ndirtysegs = suhdr->sh_ndirtysegs; nss->nss_ctime = 0; nss->nss_nongc_ctime = nandfsdev->nd_ts.tv_sec; nss->nss_prot_seq = nandfsdev->nd_seg_sequence; brelse(bp); VOP_UNLOCK(NTOV(su_node), 0); NANDFS_WRITEUNLOCK(nandfsdev); return (0); }
/* * 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); }
/* 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_get_segment_info_filter(struct nandfs_device *fsdev, struct nandfs_suinfo *nsi, uint32_t nmembs, uint64_t segment, uint64_t *nsegs, uint32_t filter, uint32_t nfilter) { struct nandfs_segment_usage *su; struct nandfs_node *su_node; struct buf *bp; uint64_t curr, blocknr, blockoff, i; uint32_t flags; int err = 0; curr = ~(0); lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL); su_node = fsdev->nd_su_node; VOP_LOCK(NTOV(su_node), LK_SHARED); bp = NULL; if (nsegs != NULL) *nsegs = 0; for (i = 0; i < nmembs; segment++) { if (segment == fsdev->nd_fsdata.f_nsegments) break; nandfs_seg_usage_blk_offset(fsdev, segment, &blocknr, &blockoff); if (i == 0 || curr != blocknr) { if (bp != NULL) brelse(bp); err = nandfs_bread(su_node, blocknr, NOCRED, 0, &bp); if (err) { goto out; } curr = blocknr; } su = SU_USAGE_OFF(bp, blockoff); flags = su->su_flags; if (segment == fsdev->nd_seg_num || segment == fsdev->nd_next_seg_num) flags |= NANDFS_SEGMENT_USAGE_ACTIVE; if (nfilter != 0 && (flags & nfilter) != 0) continue; if (filter != 0 && (flags & filter) == 0) continue; nsi->nsi_num = segment; nsi->nsi_lastmod = su->su_lastmod; nsi->nsi_blocks = su->su_nblocks; nsi->nsi_flags = flags; nsi++; i++; if (nsegs != NULL) (*nsegs)++; } out: if (bp != NULL) brelse(bp); VOP_UNLOCK(NTOV(su_node), 0); lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL); return (err); }
int nandfs_find_free_entry(struct nandfs_mdt *mdt, struct nandfs_node *node, struct nandfs_alloc_request *req) { nandfs_daddr_t desc, group, maxgroup, maxdesc, pos = 0; nandfs_daddr_t start_group, start_desc; nandfs_daddr_t desc_block, group_block; nandfs_daddr_t file_blocks; struct nandfs_block_group_desc *descriptors; struct buf *bp, *bp2; uint32_t *mask, i, mcount, msize; int error; file_blocks = node->nn_inode.i_blocks; maxgroup = 0x100000000ull / mdt->entries_per_group; maxdesc = maxgroup / mdt->groups_per_desc_block; start_group = req->entrynum / mdt->entries_per_group; start_desc = start_group / mdt->groups_per_desc_block; bp = bp2 = NULL; restart: for (desc = start_desc; desc < maxdesc; desc++) { nandfs_get_desc_block_nr(mdt, desc, &desc_block); if (bp) brelse(bp); if (desc_block < file_blocks) { error = nandfs_bread(node, desc_block, NOCRED, 0, &bp); if (error) { brelse(bp); return (error); } } else { error = nandfs_bcreate(node, desc_block, NOCRED, 0, &bp); if (error) return (error); file_blocks++; init_desc_block(mdt, bp->b_data); } descriptors = (struct nandfs_block_group_desc *) bp->b_data; for (group = start_group; group < mdt->groups_per_desc_block; group++) { if (descriptors[group].bg_nfrees > 0) { nandfs_get_group_block_nr(mdt, group, &group_block); if (bp2) brelse(bp2); if (group_block < file_blocks) { error = nandfs_bread(node, group_block, NOCRED, 0, &bp2); if (error) { brelse(bp); return (error); } } else { error = nandfs_bcreate(node, group_block, NOCRED, 0, &bp2); if (error) return (error); file_blocks++; } mask = (uint32_t *)bp2->b_data; msize = (sizeof(uint32_t) * __CHAR_BIT); mcount = mdt->entries_per_group / msize; for (i = 0; i < mcount; i++) { if (mask[i] == UINT32_MAX) continue; pos = ffs(~mask[i]) - 1; pos += (msize * i); pos += (group * mdt->entries_per_group); pos += desc * group * mdt->groups_per_desc_block * mdt->entries_per_group; goto found; } } } start_group = 0; } if (start_desc != 0) { maxdesc = start_desc; start_desc = 0; req->entrynum = 0; goto restart; } return (ENOENT); found: req->entrynum = pos; req->bp_desc = bp; req->bp_bitmap = bp2; DPRINTF(ALLOC, ("%s: desc: %p bitmap: %p entry: %#jx\n", __func__, req->bp_desc, req->bp_bitmap, (uintmax_t)pos)); return (0); }
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); }
/* Make segment free */ int nandfs_free_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, offset; int error; su_node = fsdev->nd_su_node; ASSERT_VOP_LOCKED(NTOV(su_node), __func__); /* Read su header */ 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; nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); /* Read su usage block if other than su header block */ if (blk != 0) { error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); if (error) { brelse(bp); brelse(bp_header); return (error); } } else bp = bp_header; /* Reset su usage data */ su_usage = SU_USAGE_OFF(bp, offset); su_usage->su_lastmod = fsdev->nd_ts.tv_sec; su_usage->su_nblocks = 0; su_usage->su_flags = 0; /* Update clean/dirty counter in header */ su_header->sh_ncleansegs++; su_header->sh_ndirtysegs--; /* * Make buffers dirty, called by cleaner * so force dirty even if no much space left * on device */ nandfs_dirty_buf(bp_header, 1); if (bp != bp_header) nandfs_dirty_buf(bp, 1); /* Update free block count */ fsdev->nd_super.s_free_blocks_count = su_header->sh_ncleansegs * fsdev->nd_fsdata.f_blocks_per_segment; fsdev->nd_clean_segs++; DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); return (0); }
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); }
int nandfs_add_dirent(struct vnode *dvp, uint64_t ino, char *nameptr, long namelen, uint8_t type) { struct nandfs_node *dir_node = VTON(dvp); struct nandfs_dir_entry *dirent, *pdirent; uint32_t blocksize = dir_node->nn_nandfsdev->nd_blocksize; uint64_t filesize = dir_node->nn_inode.i_size; uint64_t inode_blks = dir_node->nn_inode.i_blocks; uint32_t off, rest; uint8_t *pos; struct buf *bp; int error; pdirent = NULL; bp = NULL; if (inode_blks) { error = nandfs_bread(dir_node, inode_blks - 1, NOCRED, 0, &bp); if (error) { brelse(bp); return (error); } pos = bp->b_data; off = 0; while (off < blocksize) { pdirent = (struct nandfs_dir_entry *) (pos + off); if (!pdirent->rec_len) { pdirent = NULL; break; } off += pdirent->rec_len; } if (pdirent) rest = pdirent->rec_len - NANDFS_DIR_REC_LEN(pdirent->name_len); else rest = blocksize; if (rest < NANDFS_DIR_REC_LEN(namelen)) { /* Do not update pdirent as new block is created */ pdirent = NULL; brelse(bp); /* Set to NULL to create new */ bp = NULL; filesize += rest; } } /* If no bp found create new */ if (!bp) { error = nandfs_bcreate(dir_node, inode_blks, NOCRED, 0, &bp); if (error) return (error); off = 0; pos = bp->b_data; } /* Modify pdirent if exists */ if (pdirent) { DPRINTF(LOOKUP, ("modify pdirent %p\n", pdirent)); /* modify last de */ off -= pdirent->rec_len; pdirent->rec_len = NANDFS_DIR_REC_LEN(pdirent->name_len); off += pdirent->rec_len; } /* Create new dirent */ dirent = (struct nandfs_dir_entry *) (pos + off); dirent->rec_len = blocksize - off; dirent->inode = ino; dirent->name_len = namelen; memset(dirent->name, 0, NANDFS_DIR_NAME_LEN(namelen)); memcpy(dirent->name, nameptr, namelen); dirent->file_type = type; filesize += NANDFS_DIR_REC_LEN(dirent->name_len); DPRINTF(LOOKUP, ("create dir_entry '%.*s' at %p with size %x " "new filesize: %jx\n", (int)namelen, dirent->name, dirent, dirent->rec_len, (uintmax_t)filesize)); error = nandfs_dirty_buf(bp, 0); if (error) return (error); dir_node->nn_inode.i_size = filesize; dir_node->nn_flags |= IN_CHANGE | IN_UPDATE; vnode_pager_setsize(dvp, filesize); return (0); }