PERFORCE change 218340 for review
Zheng Liu
lz at FreeBSD.org
Tue Oct 9 14:54:04 UTC 2012
http://p4web.freebsd.org/@@218340?ac=10
Change 218340 by lz at gnehzuil-desktop on 2012/10/09 14:53:40
Add directory entry into htree index.
Affected files ...
.. //depot/projects/soc2010/extfs/src/sys/fs/ext2fs/ext2_extern.h#11 edit
.. //depot/projects/soc2010/extfs/src/sys/fs/ext2fs/ext2_htree.c#7 edit
.. //depot/projects/soc2010/extfs/src/sys/fs/ext2fs/ext2_lookup.c#9 edit
Differences ...
==== //depot/projects/soc2010/extfs/src/sys/fs/ext2fs/ext2_extern.h#11 (text+ko) ====
@@ -48,6 +48,7 @@
struct vfsconf;
struct vnode;
+int ext2_add_entry(struct vnode *, struct ext2fs_direct_2 *);
int ext2_alloc(struct inode *,
int32_t, int32_t, int, struct ucred *, int32_t *);
int ext2_balloc(struct inode *,
@@ -89,6 +90,8 @@
uint32_t *, uint32_t *);
/* ext2_htree.c */
+int ext2_htree_add_entry(struct vnode *, struct ext2fs_direct_2 *,
+ struct componentname *cnp);
int ext2_htree_has_idx(struct inode *);
int ext2_htree_lookup(struct inode *, const char *, int, struct buf **,
int *, doff_t *, doff_t *, doff_t *, struct ext2fs_searchslot *);
==== //depot/projects/soc2010/extfs/src/sys/fs/ext2fs/ext2_htree.c#7 (text+ko) ====
@@ -68,6 +68,7 @@
uint32_t hash, uint32_t blk);
static void ext2_htree_insert_entry(struct ext2fs_htree_lookup_info *info,
uint32_t hash, uint32_t blk);
+static uint32_t ext2_htree_node_limit(struct inode *ip);
static void ext2_htree_set_block(struct ext2fs_htree_entry *ep, uint32_t blk);
static void ext2_htree_set_count(struct ext2fs_htree_entry *ep, uint16_t cnt);
static void ext2_htree_set_hash(struct ext2fs_htree_entry *ep, uint32_t hash);
@@ -77,6 +78,7 @@
uint32_t *split_hash, struct ext2fs_direct_2 *entry);
static void ext2_htree_release(struct ext2fs_htree_lookup_info *info);
static uint32_t ext2_htree_root_limit(struct inode *ip, int len);
+static int ext2_htree_writebuf(struct ext2fs_htree_lookup_info *info);
int
ext2_htree_has_idx(struct inode *ip)
@@ -200,6 +202,18 @@
return (space / sizeof(struct ext2fs_htree_entry));
}
+static uint32_t
+ext2_htree_node_limit(struct inode *ip)
+{
+ struct m_ext2fs *fs;
+ uint32_t space;
+
+ fs = ip->i_e2fs;
+ space = fs->e2fs_bsize - EXT2_DIR_REC_LEN(0);
+
+ return (space / sizeof(struct ext2fs_htree_entry));
+}
+
static int
ext2_htree_find_leaf(struct inode *ip, const char *name, int namelen,
uint32_t *hash, uint8_t *hash_ver,
@@ -315,7 +329,6 @@
bsize = m_fs->e2fs_bsize;
vp = ITOV(ip);
- return (-1);
/* TODO: print error msg because we don't lookup '.' and '..' */
memset(&info, 0, sizeof(info));
@@ -391,6 +404,21 @@
return (error);
}
+static int
+ext2_htree_writebuf(struct ext2fs_htree_lookup_info *info)
+{
+ int i, error;
+
+ for (i = 0; i < info->h_levels_num; i++) {
+ struct buf *bp = info->h_levels[i].h_bp;
+ error = bwrite(bp);
+ if (error)
+ return (error);
+ }
+
+ return (0);
+}
+
static void
ext2_htree_insert_entry_to_level(struct ext2fs_htree_lookup_level *level,
uint32_t hash, uint32_t blk)
@@ -680,3 +708,184 @@
free(buf2, M_TEMP);
return (error);
}
+
+/*
+ * Add an entry to the directory using htree index.
+ */
+int
+ext2_htree_add_entry(struct vnode *dvp, struct ext2fs_direct_2 *entry,
+ struct componentname *cnp)
+{
+ struct ext2fs_htree_entry *entries, *leaf_node;
+ struct ext2fs_htree_lookup_info info;
+ struct buf *bp = NULL;
+ struct ext2fs *fs;
+ struct m_ext2fs *m_fs;
+ struct inode *ip;
+ uint16_t ent_num;
+ uint32_t dirhash, split_hash;
+ uint32_t blksize, blknum;
+ uint64_t cursize, dirsize;
+ uint8_t hash_version;
+ char *newdirblock = NULL;
+ char *newidxblock = NULL;
+ struct ext2fs_htree_node *dst_node;
+ struct ext2fs_htree_entry *dst_entries;
+ struct ext2fs_htree_entry *root_entires;
+ struct buf *dst_bp = NULL;
+ int error, write_bp = 0, write_dst_bp = 0, write_info = 0;
+
+ ip = VTOI(dvp);
+ m_fs = ip->i_e2fs;
+ fs = m_fs->e2fs;
+ blksize = m_fs->e2fs_bsize;
+
+ if (ip->i_count != 0)
+ return ext2_add_entry(dvp, entry);
+
+ /* Target directory block is full, split it */
+ memset(&info, 0, sizeof(info));
+ error = ext2_htree_find_leaf(ip, entry->e2d_name, entry->e2d_namlen,
+ &dirhash, &hash_version, &info);
+ if (error)
+ return (error);
+
+ entries = info.h_levels[info.h_levels_num - 1].h_entries;
+ ent_num = ext2_htree_get_count(entries);
+ if (ent_num == ext2_htree_get_limit(entries)) {
+ /* Split the index node. */
+ root_entires = info.h_levels[0].h_entries;
+ newidxblock = malloc(blksize, M_TEMP, M_WAITOK | M_ZERO);
+ dst_node = (struct ext2fs_htree_node *)newidxblock;
+ dst_entries = dst_node->h_entries;
+ memset(&dst_node->h_fake_dirent, 0,
+ sizeof(dst_node->h_fake_dirent));
+ dst_node->h_fake_dirent.e2d_reclen = blksize;
+
+ cursize = roundup(ip->i_size, blksize);
+ dirsize = roundup(ip->i_size, blksize) + blksize;
+ blknum = dirsize / blksize - 1;
+
+ error = ext2_htree_append_block(dvp, newidxblock,
+ cnp, blksize);
+ if (error)
+ goto finish;
+ error = ext2_blkatoff(dvp, cursize, NULL, &dst_bp);
+ if (error)
+ goto finish;
+ dst_node = (struct ext2fs_htree_node *)dst_bp->b_data;
+ dst_entries = dst_node->h_entries;
+
+ if (info.h_levels_num == 2) {
+ uint16_t src_ent_num, dst_ent_num;
+
+ if (ext2_htree_get_count(root_entires) ==
+ ext2_htree_get_limit(root_entires)) {
+ /* Directory index is full */
+ error = EIO;
+ goto finish;
+ }
+
+ src_ent_num = ent_num / 2;
+ dst_ent_num = ent_num - src_ent_num;
+ split_hash = ext2_htree_get_hash(entries + src_ent_num);
+
+ /* Move half of index entries to the new index node */
+ memcpy(dst_entries, entries + src_ent_num,
+ dst_ent_num * sizeof(struct ext2fs_htree_entry));
+ ext2_htree_set_count(entries, src_ent_num);
+ ext2_htree_set_count(dst_entries, dst_ent_num);
+ ext2_htree_set_limit(dst_entries,
+ ext2_htree_node_limit(ip));
+
+ if (info.h_levels[1].h_entry >= entries + src_ent_num) {
+ struct buf *tmp = info.h_levels[1].h_bp;
+ info.h_levels[1].h_bp = dst_bp;
+ dst_bp = tmp;
+
+ info.h_levels[1].h_entry =
+ info.h_levels[1].h_entry -
+ (entries + src_ent_num) +
+ dst_entries;
+ info.h_levels[1].h_entries = dst_entries;
+ }
+ ext2_htree_insert_entry_to_level(&info.h_levels[0],
+ split_hash, blknum);
+
+ /* Write new index node to disk */
+ error = bwrite(dst_bp);
+ ip->i_flag |= IN_CHANGE | IN_UPDATE;
+ if (error)
+ goto finish;
+ write_dst_bp = 1;
+ } else {
+ /* Create second level for htree index */
+ struct ext2fs_htree_root *idx_root;
+
+ memcpy(dst_entries, entries,
+ ent_num * sizeof(struct ext2fs_htree_entry));
+ ext2_htree_set_limit(dst_entries,
+ ext2_htree_node_limit(ip));
+
+ idx_root = (struct ext2fs_htree_root *)
+ info.h_levels[0].h_bp->b_data;
+ idx_root->h_info.h_ind_levels = 1;
+
+ ext2_htree_set_count(entries, 1);
+ ext2_htree_set_block(entries, blknum);
+
+ info.h_levels_num = 2;
+ info.h_levels[1].h_entries = dst_entries;
+ info.h_levels[1].h_entry = info.h_levels[0].h_entry -
+ info.h_levels[0].h_entries + dst_entries;
+ info.h_levels[1].h_bp = dst_bp;
+ }
+ }
+
+ leaf_node = info.h_levels[info.h_levels_num - 1].h_entry;
+ blknum = ext2_htree_get_block(leaf_node);
+ error = ext2_blkatoff(dvp, blknum * blksize, NULL, &bp);
+ if (error)
+ goto finish;
+
+ /* Split target directory block */
+ newdirblock = malloc(blksize, M_TEMP, M_WAITOK | M_ZERO);
+ ext2_htree_split_dirblock((char *)bp->b_data, newdirblock, blksize,
+ fs->e3fs_hash_seed, hash_version, &split_hash, entry);
+ cursize = roundup(ip->i_size, blksize);
+ dirsize = roundup(ip->i_size, blksize) + blksize;
+ blknum = dirsize / blksize - 1;
+
+ /* Add index entry for the new directory block */
+ ext2_htree_insert_entry(&info, split_hash, blknum);
+
+ /* Write the new directory block to the end of the directory */
+ error = ext2_htree_append_block(dvp, newdirblock, cnp, blksize);
+ if (error)
+ goto finish;
+
+ /* Write the target directory block */
+ error = bwrite(bp);
+ ip->i_flag |= IN_CHANGE | IN_UPDATE;
+ if (error)
+ goto finish;
+ write_bp = 1;
+
+ /* Write the index block */
+ error = ext2_htree_writebuf(&info);
+ if (!error)
+ write_info = 1;
+
+finish:
+ if (dst_bp != NULL && !write_dst_bp)
+ brelse(dst_bp);
+ if (bp != NULL && !write_bp)
+ brelse(bp);
+ if (newdirblock != NULL)
+ free(newdirblock, M_TEMP);
+ if (newidxblock != NULL)
+ free(newidxblock, M_TEMP);
+ if (!write_info)
+ ext2_htree_release(&info);
+ return (error);
+}
==== //depot/projects/soc2010/extfs/src/sys/fs/ext2fs/ext2_lookup.c#9 (text+ko) ====
@@ -868,15 +868,11 @@
struct vnode *dvp;
struct componentname *cnp;
{
- struct ext2fs_direct_2 *ep, *nep;
struct inode *dp;
- struct buf *bp;
struct ext2fs_direct_2 newdir;
struct iovec aiov;
struct uio auio;
- u_int dsize;
- int error, loc, newentrysize, spacefree;
- char *dirbuf;
+ int error, newentrysize;
int DIRBLKSIZ = ip->i_e2fs->e2fs_bsize;
@@ -895,7 +891,17 @@
bcopy(cnp->cn_nameptr, newdir.e2d_name, (unsigned)cnp->cn_namelen + 1);
newentrysize = EXT2_DIR_REC_LEN(newdir.e2d_namlen);
- if (ip->i_e2fs->e2fs->e2fs_features_compat & EXT2F_COMPAT_DIR_INDEX) {
+ if (ext2_htree_has_idx(dp)) {
+ error = ext2_htree_add_entry(dvp, &newdir, cnp);
+ if (error) {
+ dp->i_flags &= ~EXT2_DIR_INDEX;
+ dp->i_flag |= IN_CHANGE | IN_UPDATE;
+ }
+ return (error);
+ }
+
+ if (ip->i_e2fs->e2fs->e2fs_features_compat & EXT2F_COMPAT_DIR_INDEX &&
+ !ext2_htree_has_idx(dp)) {
if ((dp->i_size / DIRBLKSIZ) == 1 &&
dp->i_offset == DIRBLKSIZ) {
/*
@@ -937,6 +943,29 @@
return (error);
}
+ error = ext2_add_entry(dvp, &newdir);
+ if (!error && dp->i_endoff && dp->i_endoff < dp->i_size)
+ error = ext2_truncate(dvp, (off_t)dp->i_endoff, IO_SYNC,
+ cnp->cn_cred, cnp->cn_thread);
+ return (error);
+}
+
+/*
+ * Insert an entry into the directory block.
+ * Compact the contents.
+ */
+int
+ext2_add_entry(struct vnode *dvp, struct ext2fs_direct_2 *entry)
+{
+ struct ext2fs_direct_2 *ep, *nep;
+ struct inode *dp;
+ struct buf *bp;
+ u_int dsize;
+ int error, loc, newentrysize, spacefree;
+ char *dirbuf;
+
+ dp = VTOI(dvp);
+
/*
* If dp->i_count is non-zero, then namei found space
* for the new entry in the range dp->i_offset to
@@ -968,6 +997,7 @@
* dp->i_offset + dp->i_count would yield the
* space.
*/
+ newentrysize = EXT2_DIR_REC_LEN(entry->e2d_namlen);
ep = (struct ext2fs_direct_2 *)dirbuf;
dsize = EXT2_DIR_REC_LEN(ep->e2d_namlen);
spacefree = ep->e2d_reclen - dsize;
@@ -993,15 +1023,15 @@
if (ep->e2d_ino == 0) {
if (spacefree + dsize < newentrysize)
panic("ext2_direnter: compact1");
- newdir.e2d_reclen = spacefree + dsize;
+ entry->e2d_reclen = spacefree + dsize;
} else {
if (spacefree < newentrysize)
panic("ext2_direnter: compact2");
- newdir.e2d_reclen = spacefree;
+ entry->e2d_reclen = spacefree;
ep->e2d_reclen = dsize;
ep = (struct ext2fs_direct_2 *)((char *)ep + dsize);
}
- bcopy((caddr_t)&newdir, (caddr_t)ep, (u_int)newentrysize);
+ bcopy((caddr_t)entry, (caddr_t)ep, (u_int)newentrysize);
if (DOINGASYNC(dvp)) {
bdwrite(bp);
error = 0;
@@ -1009,10 +1039,8 @@
error = bwrite(bp);
}
dp->i_flag |= IN_CHANGE | IN_UPDATE;
- if (!error && dp->i_endoff && dp->i_endoff < dp->i_size)
- error = ext2_truncate(dvp, (off_t)dp->i_endoff, IO_SYNC,
- cnp->cn_cred, cnp->cn_thread);
- return (error);
+
+ return (0);
}
/*
More information about the p4-projects
mailing list