[PATCH 4/7] XFS: Return case-insensitive match for dentry cache

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This implements the code to store the actual filename found
during a lookup in the dentry cache and to avoid multiple entries
in the dcache pointing to the same inode.

It also introduces a new type, xfs_name, which is similar to the
dentry cache's qstr type. It contains a pointer to a zone allocated
string (MAXNAMELEN sized) and the length of the actual name. This
string does not need to be NULL terminated (a counted string).

xfs_name_t is only used in the lookup path for this patch, but may
be used in other locations too if desired. It maybe desirable not
to use xfs_name_t at all in the lookup functions but stick to
separate parameters (which will mean 7 instead of 5 arguments).

To avoid polluting the dcache, we implement a new directory inode
operations for lookup. xfs_vn_ci_lookup() interacts directly with
the dcache and the code was derived from ntfs_lookup() in
fs/ntfs/namei.c. The dentry hash and compare overrides introduced
in the ASCII-CI patch has been removed.

The "actual name" is only allocated and returned for a case-
insensitive match and not an actual match.

Signed-off-by: Barry Naujok <bnaujok@xxxxxxx>

---
 fs/xfs/linux-2.6/xfs_export.c |    2 
 fs/xfs/linux-2.6/xfs_iops.c   |  165 +++++++++++++++++++++++++++++++-----------
 fs/xfs/linux-2.6/xfs_iops.h   |    1 
 fs/xfs/linux-2.6/xfs_super.c  |    5 +
 fs/xfs/linux-2.6/xfs_vnode.h  |    1 
 fs/xfs/xfs_da_btree.c         |   16 ++++
 fs/xfs/xfs_da_btree.h         |   13 +++
 fs/xfs/xfs_dir2.c             |   28 +++++--
 fs/xfs/xfs_dir2.h             |    4 -
 fs/xfs/xfs_dir2_block.c       |    9 ++
 fs/xfs/xfs_dir2_leaf.c        |    9 ++
 fs/xfs/xfs_dir2_node.c        |   20 ++++-
 fs/xfs/xfs_dir2_sf.c          |   13 +++
 fs/xfs/xfs_rename.c           |    5 +
 fs/xfs/xfs_utils.c            |   12 ++-
 fs/xfs/xfs_utils.h            |    6 +
 fs/xfs/xfs_vfsops.c           |    2 
 fs/xfs/xfs_vnodeops.c         |   15 +++
 fs/xfs/xfs_vnodeops.h         |    4 -
 19 files changed, 264 insertions(+), 66 deletions(-)

Index: kern_ci/fs/xfs/linux-2.6/xfs_export.c
===================================================================
--- kern_ci.orig/fs/xfs/linux-2.6/xfs_export.c
+++ kern_ci/fs/xfs/linux-2.6/xfs_export.c
@@ -216,7 +216,7 @@ xfs_fs_get_parent(
 	struct xfs_inode	*cip;
 	struct dentry		*parent;
 
-	error = xfs_lookup(XFS_I(child->d_inode), &dotdot, &cip);
+	error = xfs_lookup(XFS_I(child->d_inode), &dotdot.d_name, &cip, NULL);
 	if (unlikely(error))
 		return ERR_PTR(-error);
 
Index: kern_ci/fs/xfs/linux-2.6/xfs_iops.c
===================================================================
--- kern_ci.orig/fs/xfs/linux-2.6/xfs_iops.c
+++ kern_ci/fs/xfs/linux-2.6/xfs_iops.c
@@ -375,27 +375,125 @@ xfs_vn_lookup(
 {
 	struct xfs_inode *cip;
 	int		error;
-	struct xfs_mount *mp = XFS_I(dir)->i_mount;
+
+	if (dentry->d_name.len >= MAXNAMELEN)
+		return ERR_PTR(-ENAMETOOLONG);
+
+	error = xfs_lookup(XFS_I(dir), &dentry->d_name, &cip, NULL);
+	if (unlikely(error)) {
+		if (unlikely(error != ENOENT))
+			return ERR_PTR(-error);
+		d_add(dentry, NULL);
+		return NULL;
+	}
+
+	return d_splice_alias(cip->i_vnode, dentry);
+}
+
+STATIC struct dentry *
+xfs_vn_ci_lookup(
+	struct inode	*dir,
+	struct dentry	*dentry,
+	struct nameidata *nd)
+{
+	struct xfs_inode *cip;
+	int		error;
 	struct dentry	*result;
+	struct qstr	ci_name = {0, 0, NULL};
+	struct inode	*inode;
 
 	if (dentry->d_name.len >= MAXNAMELEN)
 		return ERR_PTR(-ENAMETOOLONG);
 
-	if (xfs_sb_version_hasoldci(&mp->m_sb))
-		dentry->d_op = &xfs_ci_dentry_operations;
+	error = xfs_lookup(XFS_I(dir), &dentry->d_name, &cip, &ci_name);
 
-	error = xfs_lookup(XFS_I(dir), dentry, &cip);
 	if (unlikely(error)) {
 		if (unlikely(error != ENOENT))
 			return ERR_PTR(-error);
 		d_add(dentry, NULL);
 		return NULL;
 	}
+	inode = cip->i_vnode;
+
+	/* if exact match, just splice and exit */
+	if (!ci_name.name) {
+		result = d_splice_alias(inode, dentry);
+		return result;
+	}
 
-	result = d_splice_alias(cip->i_vnode, dentry);
-	if (result)
-		result->d_op = dentry->d_op;
-	return result;
+	/*
+	 * case-insensitive match, create a dentry to return and fill it
+	 * in with the correctly cased name. Parameter "dentry" is not
+	 * used anymore and the caller will free it.
+	 * Derived from fs/ntfs/namei.c
+	 */
+
+	ci_name.hash = full_name_hash(ci_name.name, ci_name.len);
+
+	/* Does an existing dentry match? */
+	result = d_lookup(dentry->d_parent, &ci_name);
+	if (!result) {
+		/* if not, create one */
+		result = d_alloc(dentry->d_parent, &ci_name);
+		xfs_da_name_free((char *)ci_name.name);
+		if (!result)
+			return ERR_PTR(-ENOMEM);
+		dentry = d_splice_alias(inode, result);
+		if (dentry) {
+			dput(result);
+			return dentry;
+		}
+		return result;
+	}
+	xfs_da_name_free((char *)ci_name.name);
+
+	/* an existing dentry matches, use it */
+
+	if (result->d_inode) {
+		/*
+		 * already an inode attached, deref the inode that was
+		 * refcounted with xfs_lookup and return the dentry.
+		 */
+		if (unlikely(result->d_inode != inode)) {
+			/* This can happen because bad inodes are unhashed. */
+			BUG_ON(!is_bad_inode(inode));
+			BUG_ON(!is_bad_inode(result->d_inode));
+		}
+		iput(inode);
+		return result;
+	}
+
+	if (!S_ISDIR(inode->i_mode)) {
+		/* not a directory, easy to handle */
+		d_instantiate(result, inode);
+		return result;
+	}
+
+	spin_lock(&dcache_lock);
+	if (list_empty(&inode->i_dentry)) {
+		/*
+		 * Directory without a 'disconnected' dentry; we need to do
+		 * d_instantiate() by hand because it takes dcache_lock which
+		 * we already hold.
+		 */
+		list_add(&result->d_alias, &inode->i_dentry);
+		result->d_inode = inode;
+		spin_unlock(&dcache_lock);
+		security_d_instantiate(result, inode);
+		return result;
+	}
+	/*
+	 * Directory with a 'disconnected' dentry; get a reference to the
+	 * 'disconnected' dentry.
+	 */
+	dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias);
+	dget_locked(dentry);
+	spin_unlock(&dcache_lock);
+	security_d_instantiate(result, inode);
+	d_move(dentry, result);
+	iput(inode);
+	dput(result);
+	return dentry;
 }
 
 STATIC int
@@ -886,6 +984,25 @@ const struct inode_operations xfs_dir_in
 	.removexattr		= xfs_vn_removexattr,
 };
 
+const struct inode_operations xfs_dir_ci_inode_operations = {
+	.create			= xfs_vn_create,
+	.lookup			= xfs_vn_ci_lookup,
+	.link			= xfs_vn_link,
+	.unlink			= xfs_vn_unlink,
+	.symlink		= xfs_vn_symlink,
+	.mkdir			= xfs_vn_mkdir,
+	.rmdir			= xfs_vn_rmdir,
+	.mknod			= xfs_vn_mknod,
+	.rename			= xfs_vn_rename,
+	.permission		= xfs_vn_permission,
+	.getattr		= xfs_vn_getattr,
+	.setattr		= xfs_vn_setattr,
+	.setxattr		= xfs_vn_setxattr,
+	.getxattr		= xfs_vn_getxattr,
+	.listxattr		= xfs_vn_listxattr,
+	.removexattr		= xfs_vn_removexattr,
+};
+
 const struct inode_operations xfs_symlink_inode_operations = {
 	.readlink		= generic_readlink,
 	.follow_link		= xfs_vn_follow_link,
@@ -899,35 +1016,3 @@ const struct inode_operations xfs_symlin
 	.removexattr		= xfs_vn_removexattr,
 };
 
-STATIC int
-xfs_ci_dentry_hash(
-	struct dentry	*dir,
-	struct qstr	*this)
-{
-	this->hash = xfs_dir_hashname(XFS_I(dir->d_inode),
-				this->name, this->len);
-	return 0;
-}
-
-STATIC int
-xfs_ci_dentry_compare(
-	struct dentry	*dir,
-	struct qstr	*a,
-	struct qstr	*b)
-{
-	int	result = xfs_dir_compname(XFS_I(dir->d_inode), a->name, a->len,
-					b->name, b->len) == XFS_CMP_DIFFERENT;
-	/*
-	 * result == 0 if a match is found, and if so, copy the name in "b"
-	 * to "a" to cope with negative dentries getting the correct name.
-	 */
-	if (result == 0)
-		memcpy((unsigned char *)a->name, b->name, a->len);
-	return result;
-}
-
-struct dentry_operations xfs_ci_dentry_operations =
-{
-	.d_hash = xfs_ci_dentry_hash,
-	.d_compare = xfs_ci_dentry_compare,
-};
Index: kern_ci/fs/xfs/linux-2.6/xfs_iops.h
===================================================================
--- kern_ci.orig/fs/xfs/linux-2.6/xfs_iops.h
+++ kern_ci/fs/xfs/linux-2.6/xfs_iops.h
@@ -20,6 +20,7 @@
 
 extern const struct inode_operations xfs_inode_operations;
 extern const struct inode_operations xfs_dir_inode_operations;
+extern const struct inode_operations xfs_dir_ci_inode_operations;
 extern const struct inode_operations xfs_symlink_inode_operations;
 
 extern const struct file_operations xfs_file_operations;
Index: kern_ci/fs/xfs/linux-2.6/xfs_super.c
===================================================================
--- kern_ci.orig/fs/xfs/linux-2.6/xfs_super.c
+++ kern_ci/fs/xfs/linux-2.6/xfs_super.c
@@ -566,7 +566,10 @@ xfs_set_inodeops(
 		inode->i_mapping->a_ops = &xfs_address_space_operations;
 		break;
 	case S_IFDIR:
-		inode->i_op = &xfs_dir_inode_operations;
+		inode->i_op =
+			xfs_sb_version_hasoldci(&XFS_I(inode)->i_mount->m_sb) ?
+				&xfs_dir_ci_inode_operations :
+				&xfs_dir_inode_operations;
 		inode->i_fop = &xfs_dir_file_operations;
 		break;
 	case S_IFLNK:
Index: kern_ci/fs/xfs/linux-2.6/xfs_vnode.h
===================================================================
--- kern_ci.orig/fs/xfs/linux-2.6/xfs_vnode.h
+++ kern_ci/fs/xfs/linux-2.6/xfs_vnode.h
@@ -26,6 +26,7 @@ struct attrlist_cursor_kern;
 typedef struct dentry	bhv_vname_t;
 typedef __u64		bhv_vnumber_t;
 typedef struct inode	bhv_vnode_t;
+typedef struct qstr	bhv_vstr_t;
 
 #define VN_ISLNK(vp)	S_ISLNK((vp)->i_mode)
 #define VN_ISREG(vp)	S_ISREG((vp)->i_mode)
Index: kern_ci/fs/xfs/xfs_da_btree.c
===================================================================
--- kern_ci.orig/fs/xfs/xfs_da_btree.c
+++ kern_ci/fs/xfs/xfs_da_btree.c
@@ -2176,6 +2176,22 @@ xfs_da_reada_buf(
 		return rval;
 }
 
+
+kmem_zone_t	*xfs_da_name_zone;
+
+uchar_t *
+xfs_da_name_alloc(void)
+{
+	return kmem_zone_zalloc(xfs_da_name_zone, KM_SLEEP);
+}
+
+void
+xfs_da_name_free(const uchar_t *name)
+{
+	kmem_zone_free(xfs_da_name_zone, (void *)name);
+}
+
+
 kmem_zone_t *xfs_da_state_zone;	/* anchor for state struct zone */
 kmem_zone_t *xfs_dabuf_zone;		/* dabuf zone */
 
Index: kern_ci/fs/xfs/xfs_da_btree.h
===================================================================
--- kern_ci.orig/fs/xfs/xfs_da_btree.h
+++ kern_ci/fs/xfs/xfs_da_btree.h
@@ -224,6 +224,14 @@ typedef struct xfs_nameops {
 	xfs_compname_t		compname;
 } xfs_nameops_t;
 
+/*
+ * Counted string for names, *name should be allocated and freed with
+ * xfs_da_name_alloc and xfs_da_name_free. len must not exceed MAXNAMELEN.
+ */
+typedef struct xfs_name {
+	const uchar_t	*name;
+	int		len;
+} xfs_name_t;
 
 #ifdef __KERNEL__
 /*========================================================================
@@ -277,6 +285,11 @@ uint xfs_da_hashname(const uchar_t *name
 xfs_dacmp_t xfs_da_compname(const uchar_t *name1, int len1,
 			    const uchar_t *name2, int len2);
 
+/* returns/frees a MAXNAMELEN buffer from a zone */
+extern struct kmem_zone *xfs_da_name_zone;
+uchar_t *xfs_da_name_alloc(void);
+void xfs_da_name_free(const uchar_t *name);
+
 xfs_da_state_t *xfs_da_state_alloc(void);
 void xfs_da_state_free(xfs_da_state_t *state);
 
Index: kern_ci/fs/xfs/xfs_dir2.c
===================================================================
--- kern_ci.orig/fs/xfs/xfs_dir2.c
+++ kern_ci/fs/xfs/xfs_dir2.c
@@ -242,15 +242,16 @@ xfs_dir_createname(
 }
 
 /*
- * Lookup a name in a directory, give back the inode number.
+ * Lookup a name in a directory, give back the inode number and also
+ * the actual name if a case-insensitive match.
  */
 int
 xfs_dir_lookup(
 	xfs_trans_t	*tp,
 	xfs_inode_t	*dp,
-	char		*name,
-	int		namelen,
-	xfs_ino_t	*inum)		/* out: inode number */
+	xfs_name_t	*name,
+	xfs_ino_t	*inum,		/* out: inode number */
+	xfs_name_t	*ci_name)	/* out: actual name if different */
 {
 	xfs_da_args_t	args;
 	int		rval;
@@ -259,9 +260,9 @@ xfs_dir_lookup(
 	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 	XFS_STATS_INC(xs_dir_lookup);
 
-	args.name = name;
-	args.namelen = namelen;
-	args.hashval = xfs_dir_hashname(dp, name, namelen);
+	args.name = name->name;
+	args.namelen = name->len;
+	args.hashval = xfs_dir_hashname(dp, name->name, name->len);
 	args.inumber = 0;
 	args.dp = dp;
 	args.firstblock = NULL;
@@ -272,6 +273,8 @@ xfs_dir_lookup(
 	args.justcheck = args.addname = 0;
 	args.oknoent = 1;
 	args.cmpresult = XFS_CMP_DIFFERENT;
+	args.value = NULL;
+	args.valuelen = 0;
 
 	if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
 		rval = xfs_dir2_sf_lookup(&args);
@@ -287,8 +290,17 @@ xfs_dir_lookup(
 		rval = xfs_dir2_node_lookup(&args);
 	if (rval == EEXIST)
 		rval = 0;
-	if (rval == 0)
+	if (rval == 0) {
 		*inum = args.inumber;
+		if (args.value) {
+			ASSERT(args->cmpresult == XFS_CMP_CASE);
+			if (ci_name) {
+				ci_name->name = args.value;
+				ci_name->len = args.valuelen;
+			} else
+				xfs_da_name_free(args.value);
+		}
+	}
 	return rval;
 }
 
Index: kern_ci/fs/xfs/xfs_dir2.h
===================================================================
--- kern_ci.orig/fs/xfs/xfs_dir2.h
+++ kern_ci/fs/xfs/xfs_dir2.h
@@ -26,6 +26,7 @@ struct xfs_bmap_free;
 struct xfs_inode;
 struct xfs_mount;
 struct xfs_trans;
+struct xfs_name;
 
 /*
  * Directory version 2.
@@ -72,7 +73,8 @@ extern int xfs_dir_createname(struct xfs
 				xfs_fsblock_t *first,
 				struct xfs_bmap_free *flist, xfs_extlen_t tot);
 extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
-				char *name, int namelen, xfs_ino_t *inum);
+				struct xfs_name *name, xfs_ino_t *inum,
+				struct xfs_name *ci_name);
 extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
 				char *name, int namelen, xfs_ino_t ino,
 				xfs_fsblock_t *first,
Index: kern_ci/fs/xfs/xfs_dir2_block.c
===================================================================
--- kern_ci.orig/fs/xfs/xfs_dir2_block.c
+++ kern_ci/fs/xfs/xfs_dir2_block.c
@@ -616,6 +616,15 @@ xfs_dir2_block_lookup(
 	 * Fill in inode number, release the block.
 	 */
 	args->inumber = be64_to_cpu(dep->inumber);
+	/*
+	 * If a case-insensitive match, allocate a buffer and copy the actual
+	 * name into the buffer. Return it via args->value.
+	 */
+	if (args->cmpresult == XFS_CMP_CASE) {
+		args->value = xfs_da_name_alloc();
+		memcpy(args->value, dep->name, dep->namelen);
+		args->valuelen = dep->namelen;
+	}
 	xfs_da_brelse(args->trans, bp);
 	return XFS_ERROR(EEXIST);
 }
Index: kern_ci/fs/xfs/xfs_dir2_leaf.c
===================================================================
--- kern_ci.orig/fs/xfs/xfs_dir2_leaf.c
+++ kern_ci/fs/xfs/xfs_dir2_leaf.c
@@ -1301,6 +1301,15 @@ xfs_dir2_leaf_lookup(
 	 * Return the found inode number.
 	 */
 	args->inumber = be64_to_cpu(dep->inumber);
+	/*
+	 * If a case-insensitive match, allocate a buffer and copy the actual
+	 * name into the buffer. Return it via args->value.
+	 */
+	if (args->cmpresult == XFS_CMP_CASE) {
+		args->value = xfs_da_name_alloc();
+		memcpy(args->value, dep->name, dep->namelen);
+		args->valuelen = dep->namelen;
+	}
 	xfs_da_brelse(tp, dbp);
 	xfs_da_brelse(tp, lbp);
 	return XFS_ERROR(EEXIST);
Index: kern_ci/fs/xfs/xfs_dir2_node.c
===================================================================
--- kern_ci.orig/fs/xfs/xfs_dir2_node.c
+++ kern_ci/fs/xfs/xfs_dir2_node.c
@@ -643,6 +643,8 @@ xfs_dir2_leafn_lookup_for_entry(
 			xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
 		/*
 		 * Compare the entry, return it if it matches.
+		 * "oknoent" is set for lookup and clear for
+		 * remove and replace.
 		 */
 		cmp = args->oknoent ?
 			xfs_dir_compname(dp, dep->name, dep->namelen,
@@ -1857,10 +1859,22 @@ xfs_dir2_node_lookup(
 	if (error)
 		rval = error;
 	/*
-	 * If case-insensitive match was found in a leaf, return EEXIST.
-	 */
-	else if (rval == ENOENT && args->cmpresult == XFS_CMP_CASE)
+	 * If case-insensitive match was found (xfs_dir2_leafn_lookup_int
+	 * returns ENOENT for a case-insensitive match, but sets
+	 * args->cmpresult to XFS_CMP_CASE):
+	 *   - Allocate a buffer and copy the actual name into the buffer and
+	 *       return it via args->value.
+	 *   - set rval to EEXIST
+	 */
+	else if (rval == ENOENT && args->cmpresult == XFS_CMP_CASE) {
+		xfs_dir2_data_entry_t	*dep = (xfs_dir2_data_entry_t *)
+					((char *)state->extrablk.bp->data +
+						state->extrablk.index);
+		args->value = xfs_da_name_alloc();
+		memcpy(args->value, dep->name, dep->namelen);
+		args->valuelen = dep->namelen;
 		rval = EEXIST;
+	}
 	/*
 	 * Release the btree blocks and leaf block.
 	 */
Index: kern_ci/fs/xfs/xfs_dir2_sf.c
===================================================================
--- kern_ci.orig/fs/xfs/xfs_dir2_sf.c
+++ kern_ci/fs/xfs/xfs_dir2_sf.c
@@ -815,6 +815,7 @@ xfs_dir2_sf_lookup(
 	xfs_dir2_sf_entry_t	*sfep;		/* shortform directory entry */
 	xfs_dir2_sf_t		*sfp;		/* shortform structure */
 	xfs_dacmp_t		cmp;		/* comparison result */
+	xfs_dir2_sf_entry_t	*ci_sfep;	/* case-insens. entry */
 
 	xfs_dir2_trace_args("sf_lookup", args);
 	xfs_dir2_sf_check(args);
@@ -852,6 +853,7 @@ xfs_dir2_sf_lookup(
 	/*
 	 * Loop over all the entries trying to match ours.
 	 */
+	ci_sfep = NULL;
 	for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
 	     i < sfp->hdr.count;
 	     i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
@@ -864,10 +866,19 @@ xfs_dir2_sf_lookup(
 					xfs_dir2_sf_inumberp(sfep));
 			if (cmp == XFS_CMP_EXACT)
 				return XFS_ERROR(EEXIST);
+			ci_sfep = sfep;
 		}
 	}
-	if (args->cmpresult == XFS_CMP_CASE)
+	if (args->cmpresult == XFS_CMP_CASE) {
+		/*
+		 * If a case-insensitive match, allocate a buffer and copy the
+		 * actual name into the buffer and return it via args->value.
+		 */
+		args->value = xfs_da_name_alloc();
+		memcpy(args->value, ci_sfep->name, ci_sfep->namelen);
+		args->valuelen = ci_sfep->namelen;
 		return XFS_ERROR(EEXIST);
+	}
 	/*
 	 * Didn't find it.
 	 */
Index: kern_ci/fs/xfs/xfs_rename.c
===================================================================
--- kern_ci.orig/fs/xfs/xfs_rename.c
+++ kern_ci/fs/xfs/xfs_rename.c
@@ -100,6 +100,7 @@ xfs_lock_for_rename(
 	int			i, j;
 	uint			lock_mode;
 	int			diff_dirs = (dp1 != dp2);
+	xfs_name_t		name2;
 
 	ip2 = NULL;
 
@@ -125,7 +126,9 @@ xfs_lock_for_rename(
 		lock_mode = xfs_ilock_map_shared(dp2);
 	}
 
-	error = xfs_dir_lookup_int(dp2, lock_mode, vname2, &inum2, &ip2);
+	name2.name = VNAME(vname2);
+	name2.len = VNAMELEN(vname2);
+	error = xfs_dir_lookup_int(dp2, lock_mode, &name2, &inum2, &ip2, NULL);
 	if (error == ENOENT) {		/* target does not need to exist. */
 		inum2 = 0;
 	} else if (error) {
Index: kern_ci/fs/xfs/xfs_utils.c
===================================================================
--- kern_ci.orig/fs/xfs/xfs_utils.c
+++ kern_ci/fs/xfs/xfs_utils.c
@@ -24,6 +24,7 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
+#include "xfs_da_btree.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
@@ -45,15 +46,16 @@ int
 xfs_dir_lookup_int(
 	xfs_inode_t	*dp,
 	uint		lock_mode,
-	bhv_vname_t	*dentry,
+	xfs_name_t	*name,
 	xfs_ino_t	*inum,
-	xfs_inode_t	**ipp)
+	xfs_inode_t	**ipp,
+	xfs_name_t	*ci_name)
 {
 	int		error;
 
 	xfs_itrace_entry(dp);
 
-	error = xfs_dir_lookup(NULL, dp, VNAME(dentry), VNAMELEN(dentry), inum);
+	error = xfs_dir_lookup(NULL, dp, name, inum, ci_name);
 	if (!error) {
 		/*
 		 * Unlock the directory. We do this because we can't
@@ -80,6 +82,10 @@ xfs_dir_lookup_int(
 			xfs_ilock(dp, lock_mode);
 			error = XFS_ERROR(ENOENT);
 		}
+		if (error && ci_name && ci_name->name) {
+			xfs_da_name_free(ci_name->name);
+			ci_name->name = NULL;
+		}
 	}
 	return error;
 }
Index: kern_ci/fs/xfs/xfs_utils.h
===================================================================
--- kern_ci.orig/fs/xfs/xfs_utils.h
+++ kern_ci/fs/xfs/xfs_utils.h
@@ -18,11 +18,13 @@
 #ifndef __XFS_UTILS_H__
 #define __XFS_UTILS_H__
 
+struct xfs_name;
+
 #define IRELE(ip)	VN_RELE(XFS_ITOV(ip))
 #define IHOLD(ip)	VN_HOLD(XFS_ITOV(ip))
 
-extern int xfs_dir_lookup_int (xfs_inode_t *, uint, bhv_vname_t *, xfs_ino_t *,
-				xfs_inode_t **);
+extern int xfs_dir_lookup_int (xfs_inode_t *, uint, struct xfs_name *,
+				xfs_ino_t *, xfs_inode_t **, struct xfs_name *);
 extern int xfs_truncate_file (xfs_mount_t *, xfs_inode_t *);
 extern int xfs_dir_ialloc (xfs_trans_t **, xfs_inode_t *, mode_t, xfs_nlink_t,
 				xfs_dev_t, cred_t *, prid_t, int,
Index: kern_ci/fs/xfs/xfs_vfsops.c
===================================================================
--- kern_ci.orig/fs/xfs/xfs_vfsops.c
+++ kern_ci/fs/xfs/xfs_vfsops.c
@@ -74,6 +74,7 @@ xfs_init(void)
 	xfs_btree_cur_zone = kmem_zone_init(sizeof(xfs_btree_cur_t),
 					    "xfs_btree_cur");
 	xfs_trans_zone = kmem_zone_init(sizeof(xfs_trans_t), "xfs_trans");
+	xfs_da_name_zone = kmem_zone_init(MAXNAMELEN, "xfs_da_name");
 	xfs_da_state_zone =
 		kmem_zone_init(sizeof(xfs_da_state_t), "xfs_da_state");
 	xfs_dabuf_zone = kmem_zone_init(sizeof(xfs_dabuf_t), "xfs_dabuf");
@@ -177,6 +178,7 @@ xfs_cleanup(void)
 	kmem_zone_destroy(xfs_btree_cur_zone);
 	kmem_zone_destroy(xfs_inode_zone);
 	kmem_zone_destroy(xfs_trans_zone);
+	kmem_zone_destroy(xfs_da_name_zone);
 	kmem_zone_destroy(xfs_da_state_zone);
 	kmem_zone_destroy(xfs_dabuf_zone);
 	kmem_zone_destroy(xfs_buf_item_zone);
Index: kern_ci/fs/xfs/xfs_vnodeops.c
===================================================================
--- kern_ci.orig/fs/xfs/xfs_vnodeops.c
+++ kern_ci/fs/xfs/xfs_vnodeops.c
@@ -1762,24 +1762,33 @@ xfs_inactive(
 int
 xfs_lookup(
 	xfs_inode_t		*dp,
-	bhv_vname_t		*dentry,
-	xfs_inode_t		**ipp)
+	bhv_vstr_t		*d_name,
+	xfs_inode_t		**ipp,
+	bhv_vstr_t		*ci_name)
 {
 	xfs_inode_t		*ip;
 	xfs_ino_t		e_inum;
 	int			error;
 	uint			lock_mode;
+	xfs_name_t		name, rname;
 
 	xfs_itrace_entry(dp);
 
 	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 		return XFS_ERROR(EIO);
 
+	name.name = (uchar_t *)d_name->name;
+	name.len = d_name->len;
+	rname.name = NULL;
 	lock_mode = xfs_ilock_map_shared(dp);
-	error = xfs_dir_lookup_int(dp, lock_mode, dentry, &e_inum, &ip);
+	error = xfs_dir_lookup_int(dp, lock_mode, &name, &e_inum, &ip, &rname);
 	if (!error) {
 		*ipp = ip;
 		xfs_itrace_ref(ip);
+		if (rname.name) {
+			ci_name->name = rname.name;
+			ci_name->len = rname.len;
+		}
 	}
 	xfs_iunlock_map_shared(dp, lock_mode);
 	return error;
Index: kern_ci/fs/xfs/xfs_vnodeops.h
===================================================================
--- kern_ci.orig/fs/xfs/xfs_vnodeops.h
+++ kern_ci/fs/xfs/xfs_vnodeops.h
@@ -23,8 +23,8 @@ int xfs_fsync(struct xfs_inode *ip, int 
 		xfs_off_t stop);
 int xfs_release(struct xfs_inode *ip);
 int xfs_inactive(struct xfs_inode *ip);
-int xfs_lookup(struct xfs_inode *dp, bhv_vname_t *dentry,
-		struct xfs_inode **ipp);
+int xfs_lookup(struct xfs_inode *dp, bhv_vstr_t *d_name,
+		struct xfs_inode **ipp, bhv_vstr_t *ci_name);
 int xfs_create(struct xfs_inode *dp, bhv_vname_t *dentry, mode_t mode,
 		xfs_dev_t rdev, struct xfs_inode **ipp, struct cred *credp);
 int xfs_remove(struct xfs_inode *dp, bhv_vname_t	*dentry);

-- 
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux