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