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); }
/* 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_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); }
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); }