svn commit: r254205 - in stable/9/sys: conf fs/ext2fs modules/ext2fs

Pedro F. Giffuni pfg at FreeBSD.org
Sun Aug 11 02:53:20 UTC 2013


Author: pfg
Date: Sun Aug 11 02:53:18 2013
New Revision: 254205
URL: http://svnweb.freebsd.org/changeset/base/254205

Log:
  MFC	r252890, 252906, r252907, r253861, r254104:
  
  Implementation of the HTree directory index.
  
  This is a port of NetBSD's GSoC 2012 Ext3 HTree directory indexing
  by Vyacheslav Matyushin.  It was cleaned up and enhanced for FreeBSD
  by Zheng Liu (lz@).
  
  This is an excellent example of work shared among different projects:
  Vyacheslav was able to look at an early prototype from Zheng Liu who
  was also able to check the code from Haiku (with permission).
  
  As in linux, the feature is not available by default and must be
  enabled explicitly with tune2fs. We still do not support the
  workarounds required in readdir for NFS.
  
  Submitted by:	Zheng Liu
  Tested by:	Mike Ma
  Sponsored by:	Google Inc.

Added:
  stable/9/sys/fs/ext2fs/ext2_hash.c
     - copied, changed from r252890, head/sys/fs/ext2fs/ext2_hash.c
  stable/9/sys/fs/ext2fs/ext2_htree.c
     - copied, changed from r252890, head/sys/fs/ext2fs/ext2_htree.c
  stable/9/sys/fs/ext2fs/htree.h
     - copied unchanged from r252890, head/sys/fs/ext2fs/htree.h
Modified:
  stable/9/sys/conf/files
  stable/9/sys/fs/ext2fs/ext2_dir.h
  stable/9/sys/fs/ext2fs/ext2_extern.h
  stable/9/sys/fs/ext2fs/ext2_inode_cnv.c
  stable/9/sys/fs/ext2fs/ext2_lookup.c
  stable/9/sys/fs/ext2fs/ext2_vfsops.c
  stable/9/sys/fs/ext2fs/ext2fs.h
  stable/9/sys/modules/ext2fs/Makefile
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/conf/   (props changed)
  stable/9/sys/fs/   (props changed)
  stable/9/sys/modules/   (props changed)

Modified: stable/9/sys/conf/files
==============================================================================
--- stable/9/sys/conf/files	Sun Aug 11 01:57:54 2013	(r254204)
+++ stable/9/sys/conf/files	Sun Aug 11 02:53:18 2013	(r254205)
@@ -2377,6 +2377,8 @@ fs/ext2fs/ext2_balloc.c		optional ext2fs
 fs/ext2fs/ext2_bmap.c		optional ext2fs
 fs/ext2fs/ext2_inode.c		optional ext2fs
 fs/ext2fs/ext2_inode_cnv.c	optional ext2fs
+fs/ext2fs/ext2_hash.c		optional ext2fs
+fs/ext2fs/ext2_htree.c		optional ext2fs
 fs/ext2fs/ext2_lookup.c		optional ext2fs
 fs/ext2fs/ext2_subr.c		optional ext2fs
 fs/ext2fs/ext2_vfsops.c		optional ext2fs

Modified: stable/9/sys/fs/ext2fs/ext2_dir.h
==============================================================================
--- stable/9/sys/fs/ext2fs/ext2_dir.h	Sun Aug 11 01:57:54 2013	(r254204)
+++ stable/9/sys/fs/ext2fs/ext2_dir.h	Sun Aug 11 02:53:18 2013	(r254205)
@@ -40,6 +40,21 @@ struct	ext2fs_direct {
 	uint16_t e2d_namlen;		/* length of string in e2d_name */
 	char e2d_name[EXT2FS_MAXNAMLEN];/* name with length<=EXT2FS_MAXNAMLEN */
 };
+
+enum slotstatus {
+	NONE,
+	COMPACT,
+	FOUND
+};
+
+struct ext2fs_searchslot {
+	enum slotstatus slotstatus;
+	doff_t slotoffset;	/* offset of area with free space */
+	int slotsize;		/* size of area at slotoffset */
+	int slotfreespace;	/* amount of space free in slot */
+	int slotneeded;		/* sizeof the entry we are seeking */
+};
+
 /*
  * The new version of the directory entry.  Since EXT2 structures are
  * stored in intel byte order, and the name_len field could never be

Modified: stable/9/sys/fs/ext2fs/ext2_extern.h
==============================================================================
--- stable/9/sys/fs/ext2fs/ext2_extern.h	Sun Aug 11 01:57:54 2013	(r254204)
+++ stable/9/sys/fs/ext2fs/ext2_extern.h	Sun Aug 11 02:53:18 2013	(r254205)
@@ -40,12 +40,15 @@
 #define	_FS_EXT2FS_EXT2_EXTERN_H_
 
 struct ext2fs_dinode;
+struct ext2fs_direct_2;
+struct ext2fs_searchslot;
 struct indir;
 struct inode;
 struct mount;
 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 *,
@@ -81,6 +84,18 @@ int	ext2_dirempty(struct inode *, ino_t,
 int	ext2_checkpath(struct inode *, struct inode *, struct ucred *);
 int	cg_has_sb(int i);
 int	ext2_inactive(struct vop_inactive_args *);
+int	ext2_htree_add_entry(struct vnode *, struct ext2fs_direct_2 *,
+	    struct componentname *);
+int	ext2_htree_create_index(struct vnode *, struct componentname *,
+	    struct ext2fs_direct_2 *);
+int	ext2_htree_has_idx(struct inode *);
+int	ext2_htree_hash(const char *, int, uint32_t *, int, uint32_t *,
+	    uint32_t *);
+int	ext2_htree_lookup(struct inode *, const char *, int, struct buf **,
+	    int *, doff_t *, doff_t *, doff_t *, struct ext2fs_searchslot *);
+int	ext2_search_dirblock(struct inode *, void *, int *, const char *, int,
+	    int *, doff_t *, doff_t *, doff_t *, struct ext2fs_searchslot *);
+
 
 /* Flags to low-level allocation routines.
  * The low 16-bits are reserved for IO_ flags from vnode.h.

Copied and modified: stable/9/sys/fs/ext2fs/ext2_hash.c (from r252890, head/sys/fs/ext2fs/ext2_hash.c)
==============================================================================
--- head/sys/fs/ext2fs/ext2_hash.c	Sat Jul  6 18:28:06 2013	(r252890, copy source)
+++ stable/9/sys/fs/ext2fs/ext2_hash.c	Sun Aug 11 02:53:18 2013	(r254205)
@@ -27,6 +27,30 @@
  * $FreeBSD$
  */
 
+/*
+ * The following notice applies to the code in ext2_half_md4():
+ *
+ * Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD4 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD4 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/conf.h>
@@ -49,7 +73,7 @@
 
 /*
  * FF, GG, and HH are transformations for rounds 1, 2, and 3.
- * Rotation is separated from addition to prevent recompuatation
+ * Rotation is separated from addition to prevent recomputation.
  */
 #define FF(a, b, c, d, x, s) { \
 	(a) += F ((b), (c), (d)) + (x); \
@@ -69,13 +93,13 @@
 /*
  * MD4 basic transformation.  It transforms state based on block.
  *
- * This is a half md4 algorithm because in Linux it uses this algorithm in dir
- * index.  This function is copied from kern/md4c.c file and is modified as
- * necessary.
+ * This is a half md4 algorithm since Linux uses this algorithm for dir
+ * index.  This function is derived from the RSA Data Security, Inc. MD4
+ * Message-Digest Algorithm and was modified as necessary.
  *
  * The return value of this function is uint32_t in Linux, but actually we don't
- * need to check this value.  So in our version this function don't return any
- * values.
+ * need to check this value, so in our version this function doesn't return any
+ * value.
  */
 static void
 ext2_half_md4(uint32_t hash[4], uint32_t data[8])

Copied and modified: stable/9/sys/fs/ext2fs/ext2_htree.c (from r252890, head/sys/fs/ext2fs/ext2_htree.c)
==============================================================================
--- head/sys/fs/ext2fs/ext2_htree.c	Sat Jul  6 18:28:06 2013	(r252890, copy source)
+++ stable/9/sys/fs/ext2fs/ext2_htree.c	Sun Aug 11 02:53:18 2013	(r254205)
@@ -313,7 +313,7 @@ error:
 }
 
 /*
- * Try to lookup an directory entry in HTree index
+ * Try to lookup a directory entry in HTree index
  */
 int
 ext2_htree_lookup(struct inode *ip, const char *name, int namelen,
@@ -458,7 +458,7 @@ ext2_htree_insert_entry(struct ext2fs_ht
 }
 
 /*
- * Compare two entry sort descriptiors by name hash value.
+ * Compare two entry sort descriptors by name hash value.
  * This is used together with qsort.
  */
 static int
@@ -584,7 +584,7 @@ ext2_htree_split_dirblock(char *block1, 
 		ep = (struct ext2fs_direct_2 *)(block1 + offset);
 		offset += ep->e2d_reclen;
 		if (last->e2d_ino) {
-			/* trim the existing slot */
+			/* Trim the existing slot */
 			last->e2d_reclen = entry_len;
 			last = (struct ext2fs_direct_2 *)
 			   ((char *)last + entry_len);

Modified: stable/9/sys/fs/ext2fs/ext2_inode_cnv.c
==============================================================================
--- stable/9/sys/fs/ext2fs/ext2_inode_cnv.c	Sun Aug 11 01:57:54 2013	(r254204)
+++ stable/9/sys/fs/ext2fs/ext2_inode_cnv.c	Sun Aug 11 02:53:18 2013	(r254205)
@@ -91,7 +91,7 @@ ext2_ei2i(struct ext2fs_dinode *ei, stru
 		ip->i_birthtime = ei->e2di_crtime;
 		ip->i_birthnsec = XTIME_TO_NSEC(ei->e2di_crtime_extra);
 	}
-	ip->i_flags = 0;
+	ip->i_flags = ei->e2di_flags;
 	ip->i_flags |= (ei->e2di_flags & EXT2_APPEND) ? SF_APPEND : 0;
 	ip->i_flags |= (ei->e2di_flags & EXT2_IMMUTABLE) ? SF_IMMUTABLE : 0;
 	ip->i_flags |= (ei->e2di_flags & EXT2_NODUMP) ? UF_NODUMP : 0;
@@ -135,7 +135,6 @@ ext2_i2ei(struct inode *ip, struct ext2f
 		ei->e2di_crtime_extra = NSEC_TO_XTIME(ip->i_birthnsec);
 	}
 	ei->e2di_flags = ip->i_flags;
-	ei->e2di_flags = 0;
 	ei->e2di_flags |= (ip->i_flags & SF_APPEND) ? EXT2_APPEND: 0;
 	ei->e2di_flags |= (ip->i_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE: 0;
 	ei->e2di_flags |= (ip->i_flags & UF_NODUMP) ? EXT2_NODUMP: 0;

Modified: stable/9/sys/fs/ext2fs/ext2_lookup.c
==============================================================================
--- stable/9/sys/fs/ext2fs/ext2_lookup.c	Sun Aug 11 01:57:54 2013	(r254204)
+++ stable/9/sys/fs/ext2fs/ext2_lookup.c	Sun Aug 11 02:53:18 2013	(r254205)
@@ -113,9 +113,19 @@ static u_char dt_to_ext2_ft[] = {
 
 static int	ext2_dirbadentry(struct vnode *dp, struct ext2fs_direct_2 *de,
 		    int entryoffsetinblock);
+static int	ext2_is_dot_entry(struct componentname *cnp);
 static int	ext2_lookup_ino(struct vnode *vdp, struct vnode **vpp,
 		    struct componentname *cnp, ino_t *dd_ino);
 
+static int
+ext2_is_dot_entry(struct componentname *cnp)
+{
+	if (cnp->cn_namelen <= 2 && cnp->cn_nameptr[0] == '.' &&
+	    (cnp->cn_nameptr[1] == '.' || cnp->cn_nameptr[1] == '0'))
+		return (1);
+	return (0);
+}
+
 /*
  * Vnode op for reading directories.
  *
@@ -287,13 +297,9 @@ ext2_lookup_ino(struct vnode *vdp, struc
 	struct buf *bp;			/* a buffer of directory entries */
 	struct ext2fs_direct_2 *ep;	/* the current directory entry */
 	int entryoffsetinblock;		/* offset of ep in bp's buffer */
-	enum {NONE, COMPACT, FOUND} slotstatus;
-	doff_t slotoffset;		/* offset of area with free space */
+	struct ext2fs_searchslot ss;
 	doff_t i_diroff;		/* cached i_diroff value */
 	doff_t i_offset;		/* cached i_offset value */
-	int slotsize;			/* size of area at slotoffset */
-	int slotfreespace;		/* amount of space free in slot */
-	int slotneeded;			/* size of the entry we're seeking */
 	int numdirpasses;		/* strategy for directory search */
 	doff_t endsearch;		/* offset to end directory search */
 	doff_t prevoff;			/* prev entry dp->i_offset */
@@ -301,12 +307,13 @@ ext2_lookup_ino(struct vnode *vdp, struc
 	struct vnode *tdp;		/* returned by VFS_VGET */
 	doff_t enduseful;		/* pointer past last used dir slot */
 	u_long bmask;			/* block offset mask */
-	int namlen, error;
+	int error;
 	struct ucred *cred = cnp->cn_cred;
 	int flags = cnp->cn_flags;
 	int nameiop = cnp->cn_nameiop;
 	ino_t ino, ino1;
 	int ltype;
+	int entry_found = 0;
 
 	int	DIRBLKSIZ = VTOI(vdp)->i_e2fs->e2fs_bsize;
 
@@ -317,13 +324,11 @@ ext2_lookup_ino(struct vnode *vdp, struc
 	bmask = VFSTOEXT2(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
 restart:
 	bp = NULL;
-	slotoffset = -1;
+	ss.slotoffset = -1;
 
 	/*
 	 * We now have a segment name to search for, and a directory to search.
-	 */
-
-	/*
+	 *
 	 * Suppress search for slots unless creating
 	 * file and at end of pathname, in which case
 	 * we watch for a place to put the new file in
@@ -331,18 +336,46 @@ restart:
 	 */
 	ino = 0;
 	i_diroff = dp->i_diroff;
-	slotstatus = FOUND;
-	slotfreespace = slotsize = slotneeded = 0;
+	ss.slotstatus = FOUND;
+	ss.slotfreespace = ss.slotsize = ss.slotneeded = 0;
 	if ((nameiop == CREATE || nameiop == RENAME) &&
 	    (flags & ISLASTCN)) {
-		slotstatus = NONE;
-		slotneeded = EXT2_DIR_REC_LEN(cnp->cn_namelen);
+		ss.slotstatus = NONE;
+		ss.slotneeded = EXT2_DIR_REC_LEN(cnp->cn_namelen);
 		/* was
-		slotneeded = (sizeof(struct direct) - MAXNAMLEN +
+		ss.slotneeded = (sizeof(struct direct) - MAXNAMLEN +
 			cnp->cn_namelen + 3) &~ 3; */
 	}
 
 	/*
+	 * Try to lookup dir entry using htree directory index.
+	 *
+	 * If we got an error or we want to find '.' or '..' entry,
+	 * we will fall back to linear search.
+	 */
+	if (!ext2_is_dot_entry(cnp) && ext2_htree_has_idx(dp)) {
+		numdirpasses = 1;
+		entryoffsetinblock = 0;
+		switch (ext2_htree_lookup(dp, cnp->cn_nameptr, cnp->cn_namelen,
+				&bp, &entryoffsetinblock, &i_offset, &prevoff,
+				&enduseful, &ss)) {
+		case 0:
+			ep = (struct ext2fs_direct_2 *)((char *)bp->b_data +
+				(i_offset & bmask));
+			goto foundentry;
+		case ENOENT:
+			i_offset = roundup2(dp->i_size, DIRBLKSIZ);
+			goto notfound;
+		default:
+			/*
+			 * Something failed; just fallback to do a linear
+			 * search.
+			 */
+			break;
+		}
+	}
+
+	/*
 	 * If there is cached information on a previous search of
 	 * this directory, pick up where we last left off.
 	 * We cache only lookups as these are the most common
@@ -376,96 +409,38 @@ searchloop:
 		/*
 		 * If necessary, get the next directory block.
 		 */
-		if ((i_offset & bmask) == 0) {
-			if (bp != NULL)
-				brelse(bp);
-			if ((error =
-			    ext2_blkatoff(vdp, (off_t)i_offset, NULL,
-			    &bp)) != 0)
-				return (error);
-			entryoffsetinblock = 0;
-		}
+		if (bp != NULL)
+			brelse(bp);
+		error = ext2_blkatoff(vdp, (off_t)i_offset, NULL, &bp);
+		if (error != 0)
+			return (error);
+		entryoffsetinblock = 0;
 		/*
 		 * If still looking for a slot, and at a DIRBLKSIZE
 		 * boundary, have to start looking for free space again.
 		 */
-		if (slotstatus == NONE &&
+		if (ss.slotstatus == NONE &&
 		    (entryoffsetinblock & (DIRBLKSIZ - 1)) == 0) {
-			slotoffset = -1;
-			slotfreespace = 0;
+			ss.slotoffset = -1;
+			ss.slotfreespace = 0;
 		}
-		/*
-		 * Get pointer to next entry.
-		 * Full validation checks are slow, so we only check
-		 * enough to insure forward progress through the
-		 * directory. Complete checks can be run by setting
-		 * "vfs.e2fs.dirchk" to be true.
-		 */
-		ep = (struct ext2fs_direct_2 *)
-			((char *)bp->b_data + entryoffsetinblock);
-		if (ep->e2d_reclen == 0 ||
-		    (dirchk && ext2_dirbadentry(vdp, ep, entryoffsetinblock))) {
-			int i;
-			ext2_dirbad(dp, i_offset, "mangled entry");
-			i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
-			i_offset += i;
-			entryoffsetinblock += i;
-			continue;
-		}
-
-		/*
-		 * If an appropriate sized slot has not yet been found,
-		 * check to see if one is available. Also accumulate space
-		 * in the current block so that we can determine if
-		 * compaction is viable.
-		 */
-		if (slotstatus != FOUND) {
-			int size = ep->e2d_reclen;
-
-			if (ep->e2d_ino != 0)
-				size -= EXT2_DIR_REC_LEN(ep->e2d_namlen);
-			if (size > 0) {
-				if (size >= slotneeded) {
-					slotstatus = FOUND;
-					slotoffset = i_offset;
-					slotsize = ep->e2d_reclen;
-				} else if (slotstatus == NONE) {
-					slotfreespace += size;
-					if (slotoffset == -1)
-						slotoffset = i_offset;
-					if (slotfreespace >= slotneeded) {
-						slotstatus = COMPACT;
-						slotsize = i_offset +
-						      ep->e2d_reclen - slotoffset;
-					}
-				}
-			}
+		error = ext2_search_dirblock(dp, bp->b_data, &entry_found,
+				cnp->cn_nameptr, cnp->cn_namelen,
+				&entryoffsetinblock, &i_offset, &prevoff,
+				&enduseful, &ss);
+		if (error != 0) {
+			brelse(bp);
+			return (error);
 		}
-
-		/*
-		 * Check for a name match.
-		 */
-		if (ep->e2d_ino) {
-			namlen = ep->e2d_namlen;
-			if (namlen == cnp->cn_namelen &&
-			    !bcmp(cnp->cn_nameptr, ep->e2d_name,
-				(unsigned)namlen)) {
-				/*
-				 * Save directory entry's inode number and
-				 * reclen in ndp->ni_ufs area, and release
-				 * directory buffer.
-				 */
-				ino = ep->e2d_ino;
-				goto found;
-			}
+		if (entry_found) {
+			ep = (struct ext2fs_direct_2 *)((char *)bp->b_data +
+				(entryoffsetinblock & bmask));
+foundentry:
+			ino = ep->e2d_ino;
+			goto found;
 		}
-		prevoff = i_offset;
-		i_offset += ep->e2d_reclen;
-		entryoffsetinblock += ep->e2d_reclen;
-		if (ep->e2d_ino)
-			enduseful = i_offset;
 	}
-/* notfound: */
+notfound:
 	/*
 	 * If we started in the middle of the directory and failed
 	 * to find our target, we must check the beginning as well.
@@ -500,15 +475,15 @@ searchloop:
 		 * can be put in the range from dp->i_offset to
 		 * dp->i_offset + dp->i_count.
 		 */
-		if (slotstatus == NONE) {
+		if (ss.slotstatus == NONE) {
 			dp->i_offset = roundup2(dp->i_size, DIRBLKSIZ);
 			dp->i_count = 0;
 			enduseful = dp->i_offset;
 		} else {
-			dp->i_offset = slotoffset;
-			dp->i_count = slotsize;
-			if (enduseful < slotoffset + slotsize)
-				enduseful = slotoffset + slotsize;
+			dp->i_offset = ss.slotoffset;
+			dp->i_count = ss.slotsize;
+			if (enduseful < ss.slotoffset + ss.slotsize)
+				enduseful = ss.slotoffset + ss.slotsize;
 		}
 		dp->i_endoff = roundup2(enduseful, DIRBLKSIZ);
 		/*
@@ -714,6 +689,102 @@ found:
 	return (0);
 }
 
+int
+ext2_search_dirblock(struct inode *ip, void *data, int *foundp,
+	const char *name, int namelen, int *entryoffsetinblockp,
+	doff_t *offp, doff_t *prevoffp, doff_t *endusefulp,
+	struct ext2fs_searchslot *ssp)
+{
+	struct vnode *vdp;
+	struct ext2fs_direct_2 *ep, *top;
+	uint32_t bsize = ip->i_e2fs->e2fs_bsize;
+	int offset = *entryoffsetinblockp;
+	int namlen;
+
+	vdp = ITOV(ip);
+
+	ep = (struct ext2fs_direct_2 *)((char *)data + offset);
+	top = (struct ext2fs_direct_2 *)((char *)data +
+		bsize - EXT2_DIR_REC_LEN(0));
+
+	while (ep < top) {
+		/*
+		 * Full validation checks are slow, so we only check
+		 * enough to insure forward progress through the
+		 * directory. Complete checks can be run by setting
+		 * "vfs.e2fs.dirchk" to be true.
+		 */
+		if (ep->e2d_reclen == 0 ||
+		    (dirchk && ext2_dirbadentry(vdp, ep, offset))) {
+			int i;
+			ext2_dirbad(ip, *offp, "mangled entry");
+			i = bsize - (offset & (bsize - 1));
+			*offp += i;
+			offset += i;
+			continue;
+		}
+
+		/*
+		 * If an appropriate sized slot has not yet been found,
+		 * check to see if one is available. Also accumulate space
+		 * in the current block so that we can determine if
+		 * compaction is viable.
+		 */
+		if (ssp->slotstatus != FOUND) {
+			int size = ep->e2d_reclen;
+
+			if (ep->e2d_ino != 0)
+				size -= EXT2_DIR_REC_LEN(ep->e2d_namlen);
+			if (size > 0) {
+				if (size >= ssp->slotneeded) {
+					ssp->slotstatus = FOUND;
+					ssp->slotoffset = *offp;
+					ssp->slotsize = ep->e2d_reclen;
+				} else if (ssp->slotstatus == NONE) {
+					ssp->slotfreespace += size;
+					if (ssp->slotoffset == -1)
+						ssp->slotoffset = *offp;
+					if (ssp->slotfreespace >= ssp->slotneeded) {
+						ssp->slotstatus = COMPACT;
+						ssp->slotsize = *offp +
+							ep->e2d_reclen -
+							ssp->slotoffset;
+					}
+				}
+			}
+		}
+
+		/*
+		 * Check for a name match.
+		 */
+		if (ep->e2d_ino) {
+			namlen = ep->e2d_namlen;
+			if (namlen == namelen &&
+			    !bcmp(name, ep->e2d_name, (unsigned)namlen)) {
+				/*
+				 * Save directory entry's inode number and
+				 * reclen in ndp->ni_ufs area, and release
+				 * directory buffer.
+				 */
+				*foundp = 1;
+				return (0);
+			}
+		}
+		*prevoffp = *offp;
+		*offp += ep->e2d_reclen;
+		offset += ep->e2d_reclen;
+		*entryoffsetinblockp = offset;
+		if (ep->e2d_ino)
+			*endusefulp = *offp;
+		/*
+		 * Get pointer to the next entry.
+		 */
+		ep = (struct ext2fs_direct_2 *)((char *)data + offset);
+	}
+
+	return (0);
+}
+
 void
 ext2_dirbad(struct inode *ip, doff_t offset, char *how)
 {
@@ -781,16 +852,12 @@ ext2_dirbadentry(struct vnode *dp, struc
 int
 ext2_direnter(struct inode *ip, 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     DIRBLKSIZ = ip->i_e2fs->e2fs_bsize;
+	int error, newentrysize;
+	int DIRBLKSIZ = ip->i_e2fs->e2fs_bsize;
 
 
 #ifdef INVARIANTS
@@ -807,6 +874,28 @@ ext2_direnter(struct inode *ip, struct v
 		newdir.e2d_type = EXT2_FT_UNKNOWN;
 	bcopy(cnp->cn_nameptr, newdir.e2d_name, (unsigned)cnp->cn_namelen + 1);
 	newentrysize = EXT2_DIR_REC_LEN(newdir.e2d_namlen);
+
+	if (ext2_htree_has_idx(dp)) {
+		error = ext2_htree_add_entry(dvp, &newdir, cnp);
+		if (error) {
+			dp->i_flags &= ~EXT4_INDEX;
+			dp->i_flags |= IN_CHANGE | IN_UPDATE;
+		}
+		return (error);
+	}
+
+	if (EXT2_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_DIRHASHINDEX) &&
+	    !ext2_htree_has_idx(dp)) {
+		if ((dp->i_size / DIRBLKSIZ) == 1 &&
+		    dp->i_offset == DIRBLKSIZ) {
+			/*
+			 * Making indexed directory when one block is not
+			 * enough to save all entries.
+			 */
+			return ext2_htree_create_index(dvp, cnp, &newdir);
+		}
+	}
+
 	if (dp->i_count == 0) {
 		/*
 		 * If dp->i_count is 0, then namei could find no
@@ -838,6 +927,29 @@ ext2_direnter(struct inode *ip, struct v
 		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
@@ -869,6 +981,7 @@ ext2_direnter(struct inode *ip, struct v
 	 * 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;
@@ -894,15 +1007,15 @@ ext2_direnter(struct inode *ip, struct v
 	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;
@@ -910,9 +1023,6 @@ ext2_direnter(struct inode *ip, struct v
 		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);
 }
 

Modified: stable/9/sys/fs/ext2fs/ext2_vfsops.c
==============================================================================
--- stable/9/sys/fs/ext2fs/ext2_vfsops.c	Sun Aug 11 01:57:54 2013	(r254204)
+++ stable/9/sys/fs/ext2fs/ext2_vfsops.c	Sun Aug 11 02:53:18 2013	(r254205)
@@ -399,6 +399,18 @@ compute_sb_data(struct vnode *devvp, str
 		fs->e2fs_maxfilesize = 0x7fffffff;
 	else
 		fs->e2fs_maxfilesize = 0x7fffffffffffffff;
+
+	if (es->e4fs_flags & E2FS_UNSIGNED_HASH) {
+		fs->e2fs_uhash = 3;
+	} else if ((es->e4fs_flags & E2FS_SIGNED_HASH) == 0) {
+#ifdef __CHAR_UNSIGNED__
+		es->e4fs_flags |= E2FS_UNSIGNED_HASH;
+		fs->e2fs_uhash = 3;
+#else
+		es->e4fs_flags |= E2FS_SIGNED_HASH;
+#endif
+	}
+
 	return (0);
 }
 

Modified: stable/9/sys/fs/ext2fs/ext2fs.h
==============================================================================
--- stable/9/sys/fs/ext2fs/ext2fs.h	Sun Aug 11 01:57:54 2013	(r254204)
+++ stable/9/sys/fs/ext2fs/ext2fs.h	Sun Aug 11 02:53:18 2013	(r254205)
@@ -147,6 +147,7 @@ struct m_ext2fs {
 	int32_t  e2fs_contigsumsize;    /* size of cluster summary array */
 	int32_t *e2fs_maxcluster;       /* max cluster in each cyl group */
 	struct   csum *e2fs_clustersum; /* cluster summary in each cyl group */
+	int32_t  e2fs_uhash;	  /* 3 if hash should be signed, 0 if not */
 };
 
 /* cluster summary information */
@@ -228,6 +229,12 @@ struct csum {
 #define	E2FS_ISCLEAN			0x0001	/* Unmounted cleanly */
 #define	E2FS_ERRORS			0x0002	/* Errors detected */
 
+/*
+ * Filesystem miscellaneous flags
+ */
+#define E2FS_SIGNED_HASH	0x0001
+#define E2FS_UNSIGNED_HASH	0x0002
+
 /* ext2 file system block group descriptor */
 
 struct ext2_gd {

Copied: stable/9/sys/fs/ext2fs/htree.h (from r252890, head/sys/fs/ext2fs/htree.h)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/9/sys/fs/ext2fs/htree.h	Sun Aug 11 02:53:18 2013	(r254205, copy of r252890, head/sys/fs/ext2fs/htree.h)
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2010, 2012 Zheng Liu <lz at freebsd.org>
+ * Copyright (c) 2012, Vyacheslav Matyushin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _FS_EXT2FS_HTREE_H_
+#define _FS_EXT2FS_HTREE_H_
+
+/* EXT3 HTree directory indexing */
+
+#define EXT2_HTREE_LEGACY		0
+#define EXT2_HTREE_HALF_MD4		1
+#define EXT2_HTREE_TEA			2
+#define EXT2_HTREE_LEGACY_UNSIGNED	3
+#define EXT2_HTREE_HALF_MD4_UNSIGNED	4
+#define EXT2_HTREE_TEA_UNSIGNED		5
+
+#define EXT2_HTREE_EOF 0x7FFFFFFF
+
+struct ext2fs_fake_direct {
+	uint32_t e2d_ino;	/* inode number of entry */
+	uint16_t e2d_reclen;	/* length of this record */
+	uint8_t  e2d_namlen;	/* length of string in d_name */
+	uint8_t  e2d_type;	/* file type */
+};
+
+struct ext2fs_htree_count {
+	uint16_t h_entries_max;
+	uint16_t h_entries_num;
+};
+
+struct ext2fs_htree_entry {
+	uint32_t h_hash;
+	uint32_t h_blk;
+};
+
+struct ext2fs_htree_root_info {
+	uint32_t h_reserved1;
+	uint8_t  h_hash_version;
+	uint8_t  h_info_len;
+	uint8_t  h_ind_levels;
+	uint8_t  h_reserved2;
+};
+
+struct ext2fs_htree_root {
+	struct ext2fs_fake_direct h_dot;
+	char h_dot_name[4];
+	struct ext2fs_fake_direct h_dotdot;
+	char h_dotdot_name[4];
+	struct ext2fs_htree_root_info h_info;
+	struct ext2fs_htree_entry h_entries[0];
+};
+
+struct ext2fs_htree_node {
+	struct ext2fs_fake_direct h_fake_dirent;
+	struct ext2fs_htree_entry h_entries[0];
+};
+
+struct ext2fs_htree_lookup_level {
+	struct buf *h_bp;
+	struct ext2fs_htree_entry *h_entries;
+	struct ext2fs_htree_entry *h_entry;
+};
+
+struct ext2fs_htree_lookup_info {
+	struct ext2fs_htree_lookup_level h_levels[2];
+	uint32_t h_levels_num;
+};
+
+struct ext2fs_htree_sort_entry {
+	uint16_t h_offset;
+	uint16_t h_size;
+	uint32_t h_hash;
+};
+
+#endif /* !_FS_EXT2FS_HTREE_H_ */

Modified: stable/9/sys/modules/ext2fs/Makefile
==============================================================================
--- stable/9/sys/modules/ext2fs/Makefile	Sun Aug 11 01:57:54 2013	(r254204)
+++ stable/9/sys/modules/ext2fs/Makefile	Sun Aug 11 02:53:18 2013	(r254205)
@@ -3,8 +3,8 @@
 .PATH:	${.CURDIR}/../../fs/ext2fs
 KMOD=	ext2fs
 SRCS=	opt_ddb.h opt_directio.h opt_quota.h opt_suiddir.h vnode_if.h \
-	ext2_alloc.c ext2_balloc.c ext2_bmap.c ext2_inode.c \
-	ext2_inode_cnv.c ext2_lookup.c ext2_subr.c ext2_vfsops.c \
+	ext2_alloc.c ext2_balloc.c ext2_bmap.c ext2_hash.c ext2_htree.c \
+	ext2_inode.c ext2_inode_cnv.c ext2_lookup.c ext2_subr.c ext2_vfsops.c \
 	ext2_vnops.c
 
 .include <bsd.kmod.mk>


More information about the svn-src-stable mailing list