aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBarry Naujok <bnaujok@sgi.com>2008-05-21 02:58:22 -0400
committerNiv Sardi <xaiki@debian.org>2008-07-28 02:58:40 -0400
commit384f3ced07efdddf6838f6527366089d37843c94 (patch)
tree13037bc99115f6f940b6fe924b75dc48e0577678
parent9403540c0653122ca34884a180439ddbfcbcb524 (diff)
[XFS] Return case-insensitive match for dentry cache
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. To avoid polluting the dcache, we implement a new directory inode operations for lookup. xfs_vn_ci_lookup() stores the correct case name in the dcache. The "actual name" is only allocated and returned for a case- insensitive match and not an actual match. Another unusual interaction with the dcache is not storing negative dentries like other filesystems doing a d_add(dentry, NULL) when an ENOENT is returned. During the VFS lookup, if a dentry returned has no inode, dput is called and ENOENT is returned. By not doing a d_add, this actually removes it completely from the dcache to be reused. create/rename have to be modified to support unhashed dentries being passed in. SGI-PV: 981521 SGI-Modid: xfs-linux-melb:xfs-kern:31208a Signed-off-by: Barry Naujok <bnaujok@sgi.com> Signed-off-by: Christoph Hellwig <hch@infradead.org>
-rw-r--r--fs/xfs/linux-2.6/xfs_export.c2
-rw-r--r--fs/xfs/linux-2.6/xfs_iops.c57
-rw-r--r--fs/xfs/linux-2.6/xfs_iops.h1
-rw-r--r--fs/xfs/xfs_da_btree.h1
-rw-r--r--fs/xfs/xfs_dir2.c40
-rw-r--r--fs/xfs/xfs_dir2.h6
-rw-r--r--fs/xfs/xfs_dir2_block.c9
-rw-r--r--fs/xfs/xfs_dir2_leaf.c5
-rw-r--r--fs/xfs/xfs_dir2_node.c16
-rw-r--r--fs/xfs/xfs_dir2_sf.c17
-rw-r--r--fs/xfs/xfs_vnodeops.c19
-rw-r--r--fs/xfs/xfs_vnodeops.h2
12 files changed, 146 insertions, 29 deletions
diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c
index c672b3238b14..987fe84f7b13 100644
--- a/fs/xfs/linux-2.6/xfs_export.c
+++ b/fs/xfs/linux-2.6/xfs_export.c
@@ -215,7 +215,7 @@ xfs_fs_get_parent(
215 struct xfs_inode *cip; 215 struct xfs_inode *cip;
216 struct dentry *parent; 216 struct dentry *parent;
217 217
218 error = xfs_lookup(XFS_I(child->d_inode), &xfs_name_dotdot, &cip); 218 error = xfs_lookup(XFS_I(child->d_inode), &xfs_name_dotdot, &cip, NULL);
219 if (unlikely(error)) 219 if (unlikely(error))
220 return ERR_PTR(-error); 220 return ERR_PTR(-error);
221 221
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c
index 13b6cfd366c2..9f0f8ee8d44d 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/linux-2.6/xfs_iops.c
@@ -382,7 +382,7 @@ xfs_vn_lookup(
382 return ERR_PTR(-ENAMETOOLONG); 382 return ERR_PTR(-ENAMETOOLONG);
383 383
384 xfs_dentry_to_name(&name, dentry); 384 xfs_dentry_to_name(&name, dentry);
385 error = xfs_lookup(XFS_I(dir), &name, &cip); 385 error = xfs_lookup(XFS_I(dir), &name, &cip, NULL);
386 if (unlikely(error)) { 386 if (unlikely(error)) {
387 if (unlikely(error != ENOENT)) 387 if (unlikely(error != ENOENT))
388 return ERR_PTR(-error); 388 return ERR_PTR(-error);
@@ -393,6 +393,42 @@ xfs_vn_lookup(
393 return d_splice_alias(cip->i_vnode, dentry); 393 return d_splice_alias(cip->i_vnode, dentry);
394} 394}
395 395
396STATIC struct dentry *
397xfs_vn_ci_lookup(
398 struct inode *dir,
399 struct dentry *dentry,
400 struct nameidata *nd)
401{
402 struct xfs_inode *ip;
403 struct xfs_name xname;
404 struct xfs_name ci_name;
405 struct qstr dname;
406 int error;
407
408 if (dentry->d_name.len >= MAXNAMELEN)
409 return ERR_PTR(-ENAMETOOLONG);
410
411 xfs_dentry_to_name(&xname, dentry);
412 error = xfs_lookup(XFS_I(dir), &xname, &ip, &ci_name);
413 if (unlikely(error)) {
414 if (unlikely(error != ENOENT))
415 return ERR_PTR(-error);
416 d_add(dentry, NULL);
417 return NULL;
418 }
419
420 /* if exact match, just splice and exit */
421 if (!ci_name.name)
422 return d_splice_alias(ip->i_vnode, dentry);
423
424 /* else case-insensitive match... */
425 dname.name = ci_name.name;
426 dname.len = ci_name.len;
427 dentry = d_add_ci(ip->i_vnode, dentry, &dname);
428 kmem_free(ci_name.name);
429 return dentry;
430}
431
396STATIC int 432STATIC int
397xfs_vn_link( 433xfs_vn_link(
398 struct dentry *old_dentry, 434 struct dentry *old_dentry,
@@ -892,6 +928,25 @@ const struct inode_operations xfs_dir_inode_operations = {
892 .removexattr = xfs_vn_removexattr, 928 .removexattr = xfs_vn_removexattr,
893}; 929};
894 930
931const struct inode_operations xfs_dir_ci_inode_operations = {
932 .create = xfs_vn_create,
933 .lookup = xfs_vn_ci_lookup,
934 .link = xfs_vn_link,
935 .unlink = xfs_vn_unlink,
936 .symlink = xfs_vn_symlink,
937 .mkdir = xfs_vn_mkdir,
938 .rmdir = xfs_vn_rmdir,
939 .mknod = xfs_vn_mknod,
940 .rename = xfs_vn_rename,
941 .permission = xfs_vn_permission,
942 .getattr = xfs_vn_getattr,
943 .setattr = xfs_vn_setattr,
944 .setxattr = xfs_vn_setxattr,
945 .getxattr = xfs_vn_getxattr,
946 .listxattr = xfs_vn_listxattr,
947 .removexattr = xfs_vn_removexattr,
948};
949
895const struct inode_operations xfs_symlink_inode_operations = { 950const struct inode_operations xfs_symlink_inode_operations = {
896 .readlink = generic_readlink, 951 .readlink = generic_readlink,
897 .follow_link = xfs_vn_follow_link, 952 .follow_link = xfs_vn_follow_link,
diff --git a/fs/xfs/linux-2.6/xfs_iops.h b/fs/xfs/linux-2.6/xfs_iops.h
index 14d0deb7afff..3b4df5863e4a 100644
--- a/fs/xfs/linux-2.6/xfs_iops.h
+++ b/fs/xfs/linux-2.6/xfs_iops.h
@@ -20,6 +20,7 @@
20 20
21extern const struct inode_operations xfs_inode_operations; 21extern const struct inode_operations xfs_inode_operations;
22extern const struct inode_operations xfs_dir_inode_operations; 22extern const struct inode_operations xfs_dir_inode_operations;
23extern const struct inode_operations xfs_dir_ci_inode_operations;
23extern const struct inode_operations xfs_symlink_inode_operations; 24extern const struct inode_operations xfs_symlink_inode_operations;
24 25
25extern const struct file_operations xfs_file_operations; 26extern const struct file_operations xfs_file_operations;
diff --git a/fs/xfs/xfs_da_btree.h b/fs/xfs/xfs_da_btree.h
index 8face64c11fb..8be0b00ede9a 100644
--- a/fs/xfs/xfs_da_btree.h
+++ b/fs/xfs/xfs_da_btree.h
@@ -143,6 +143,7 @@ typedef struct xfs_da_args {
143#define XFS_DA_OP_RENAME 0x0002 /* this is an atomic rename op */ 143#define XFS_DA_OP_RENAME 0x0002 /* this is an atomic rename op */
144#define XFS_DA_OP_ADDNAME 0x0004 /* this is an add operation */ 144#define XFS_DA_OP_ADDNAME 0x0004 /* this is an add operation */
145#define XFS_DA_OP_OKNOENT 0x0008 /* lookup/add op, ENOENT ok, else die */ 145#define XFS_DA_OP_OKNOENT 0x0008 /* lookup/add op, ENOENT ok, else die */
146#define XFS_DA_OP_CILOOKUP 0x0010 /* lookup to return CI name if found */
146 147
147/* 148/*
148 * Structure to describe buffer(s) for a block. 149 * Structure to describe buffer(s) for a block.
diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c
index 3387acd3e471..882609c699c8 100644
--- a/fs/xfs/xfs_dir2.c
+++ b/fs/xfs/xfs_dir2.c
@@ -193,14 +193,43 @@ xfs_dir_createname(
193} 193}
194 194
195/* 195/*
196 * If doing a CI lookup and case-insensitive match, dup actual name into
197 * args.value. Return EEXIST for success (ie. name found) or an error.
198 */
199int
200xfs_dir_cilookup_result(
201 struct xfs_da_args *args,
202 const char *name,
203 int len)
204{
205 if (args->cmpresult == XFS_CMP_DIFFERENT)
206 return ENOENT;
207 if (args->cmpresult != XFS_CMP_CASE ||
208 !(args->op_flags & XFS_DA_OP_CILOOKUP))
209 return EEXIST;
210
211 args->value = kmem_alloc(len, KM_MAYFAIL);
212 if (!args->value)
213 return ENOMEM;
214
215 memcpy(args->value, name, len);
216 args->valuelen = len;
217 return EEXIST;
218}
219
220/*
196 * Lookup a name in a directory, give back the inode number. 221 * Lookup a name in a directory, give back the inode number.
222 * If ci_name is not NULL, returns the actual name in ci_name if it differs
223 * to name, or ci_name->name is set to NULL for an exact match.
197 */ 224 */
225
198int 226int
199xfs_dir_lookup( 227xfs_dir_lookup(
200 xfs_trans_t *tp, 228 xfs_trans_t *tp,
201 xfs_inode_t *dp, 229 xfs_inode_t *dp,
202 struct xfs_name *name, 230 struct xfs_name *name,
203 xfs_ino_t *inum) /* out: inode number */ 231 xfs_ino_t *inum, /* out: inode number */
232 struct xfs_name *ci_name) /* out: actual name if CI match */
204{ 233{
205 xfs_da_args_t args; 234 xfs_da_args_t args;
206 int rval; 235 int rval;
@@ -217,6 +246,8 @@ xfs_dir_lookup(
217 args.whichfork = XFS_DATA_FORK; 246 args.whichfork = XFS_DATA_FORK;
218 args.trans = tp; 247 args.trans = tp;
219 args.op_flags = XFS_DA_OP_OKNOENT; 248 args.op_flags = XFS_DA_OP_OKNOENT;
249 if (ci_name)
250 args.op_flags |= XFS_DA_OP_CILOOKUP;
220 args.cmpresult = XFS_CMP_DIFFERENT; 251 args.cmpresult = XFS_CMP_DIFFERENT;
221 252
222 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) 253 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
@@ -233,8 +264,13 @@ xfs_dir_lookup(
233 rval = xfs_dir2_node_lookup(&args); 264 rval = xfs_dir2_node_lookup(&args);
234 if (rval == EEXIST) 265 if (rval == EEXIST)
235 rval = 0; 266 rval = 0;
236 if (rval == 0) 267 if (!rval) {
237 *inum = args.inumber; 268 *inum = args.inumber;
269 if (ci_name) {
270 ci_name->name = args.value;
271 ci_name->len = args.valuelen;
272 }
273 }
238 return rval; 274 return rval;
239} 275}
240 276
diff --git a/fs/xfs/xfs_dir2.h b/fs/xfs/xfs_dir2.h
index 6392f939029f..1d9ef96f33aa 100644
--- a/fs/xfs/xfs_dir2.h
+++ b/fs/xfs/xfs_dir2.h
@@ -74,7 +74,8 @@ extern int xfs_dir_createname(struct xfs_trans *tp, struct xfs_inode *dp,
74 xfs_fsblock_t *first, 74 xfs_fsblock_t *first,
75 struct xfs_bmap_free *flist, xfs_extlen_t tot); 75 struct xfs_bmap_free *flist, xfs_extlen_t tot);
76extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp, 76extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
77 struct xfs_name *name, xfs_ino_t *inum); 77 struct xfs_name *name, xfs_ino_t *inum,
78 struct xfs_name *ci_name);
78extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp, 79extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
79 struct xfs_name *name, xfs_ino_t ino, 80 struct xfs_name *name, xfs_ino_t ino,
80 xfs_fsblock_t *first, 81 xfs_fsblock_t *first,
@@ -99,4 +100,7 @@ extern int xfs_dir2_isleaf(struct xfs_trans *tp, struct xfs_inode *dp,
99extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db, 100extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db,
100 struct xfs_dabuf *bp); 101 struct xfs_dabuf *bp);
101 102
103extern int xfs_dir_cilookup_result(struct xfs_da_args *args, const char *name,
104 int len);
105
102#endif /* __XFS_DIR2_H__ */ 106#endif /* __XFS_DIR2_H__ */
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c
index dee225918db2..e2fa0a1d8e96 100644
--- a/fs/xfs/xfs_dir2_block.c
+++ b/fs/xfs/xfs_dir2_block.c
@@ -610,14 +610,15 @@ xfs_dir2_block_lookup(
610 /* 610 /*
611 * Get the offset from the leaf entry, to point to the data. 611 * Get the offset from the leaf entry, to point to the data.
612 */ 612 */
613 dep = (xfs_dir2_data_entry_t *) 613 dep = (xfs_dir2_data_entry_t *)((char *)block +
614 ((char *)block + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(blp[ent].address))); 614 xfs_dir2_dataptr_to_off(mp, be32_to_cpu(blp[ent].address)));
615 /* 615 /*
616 * Fill in inode number, release the block. 616 * Fill in inode number, CI name if appropriate, release the block.
617 */ 617 */
618 args->inumber = be64_to_cpu(dep->inumber); 618 args->inumber = be64_to_cpu(dep->inumber);
619 error = xfs_dir_cilookup_result(args, dep->name, dep->namelen);
619 xfs_da_brelse(args->trans, bp); 620 xfs_da_brelse(args->trans, bp);
620 return XFS_ERROR(EEXIST); 621 return XFS_ERROR(error);
621} 622}
622 623
623/* 624/*
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c
index 2ebbed4f1b0d..f110242d6dfc 100644
--- a/fs/xfs/xfs_dir2_leaf.c
+++ b/fs/xfs/xfs_dir2_leaf.c
@@ -1299,12 +1299,13 @@ xfs_dir2_leaf_lookup(
1299 ((char *)dbp->data + 1299 ((char *)dbp->data +
1300 xfs_dir2_dataptr_to_off(dp->i_mount, be32_to_cpu(lep->address))); 1300 xfs_dir2_dataptr_to_off(dp->i_mount, be32_to_cpu(lep->address)));
1301 /* 1301 /*
1302 * Return the found inode number. 1302 * Return the found inode number & CI name if appropriate
1303 */ 1303 */
1304 args->inumber = be64_to_cpu(dep->inumber); 1304 args->inumber = be64_to_cpu(dep->inumber);
1305 error = xfs_dir_cilookup_result(args, dep->name, dep->namelen);
1305 xfs_da_brelse(tp, dbp); 1306 xfs_da_brelse(tp, dbp);
1306 xfs_da_brelse(tp, lbp); 1307 xfs_da_brelse(tp, lbp);
1307 return XFS_ERROR(EEXIST); 1308 return XFS_ERROR(error);
1308} 1309}
1309 1310
1310/* 1311/*
diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c
index c71cff85950c..1b5430223461 100644
--- a/fs/xfs/xfs_dir2_node.c
+++ b/fs/xfs/xfs_dir2_node.c
@@ -549,7 +549,7 @@ xfs_dir2_leafn_lookup_for_entry(
549 xfs_dir2_data_entry_t *dep; /* data block entry */ 549 xfs_dir2_data_entry_t *dep; /* data block entry */
550 xfs_inode_t *dp; /* incore directory inode */ 550 xfs_inode_t *dp; /* incore directory inode */
551 int error; /* error return value */ 551 int error; /* error return value */
552 int di; /* data entry index */ 552 int di = -1; /* data entry index */
553 int index; /* leaf entry index */ 553 int index; /* leaf entry index */
554 xfs_dir2_leaf_t *leaf; /* leaf structure */ 554 xfs_dir2_leaf_t *leaf; /* leaf structure */
555 xfs_dir2_leaf_entry_t *lep; /* leaf entry */ 555 xfs_dir2_leaf_entry_t *lep; /* leaf entry */
@@ -577,6 +577,7 @@ xfs_dir2_leafn_lookup_for_entry(
577 if (state->extravalid) { 577 if (state->extravalid) {
578 curbp = state->extrablk.bp; 578 curbp = state->extrablk.bp;
579 curdb = state->extrablk.blkno; 579 curdb = state->extrablk.blkno;
580 di = state->extrablk.index;
580 } 581 }
581 /* 582 /*
582 * Loop over leaf entries with the right hash value. 583 * Loop over leaf entries with the right hash value.
@@ -637,7 +638,6 @@ xfs_dir2_leafn_lookup_for_entry(
637 } 638 }
638 /* Didn't find an exact match. */ 639 /* Didn't find an exact match. */
639 error = ENOENT; 640 error = ENOENT;
640 di = -1;
641 ASSERT(index == be16_to_cpu(leaf->hdr.count) || 641 ASSERT(index == be16_to_cpu(leaf->hdr.count) ||
642 (args->op_flags & XFS_DA_OP_OKNOENT)); 642 (args->op_flags & XFS_DA_OP_OKNOENT));
643out: 643out:
@@ -652,7 +652,7 @@ out:
652 state->extravalid = 0; 652 state->extravalid = 0;
653 } 653 }
654 /* 654 /*
655 * Return the index, that will be the insertion point. 655 * Return the index, that will be the deletion point for remove/replace.
656 */ 656 */
657 *indexp = index; 657 *indexp = index;
658 return XFS_ERROR(error); 658 return XFS_ERROR(error);
@@ -1820,8 +1820,14 @@ xfs_dir2_node_lookup(
1820 error = xfs_da_node_lookup_int(state, &rval); 1820 error = xfs_da_node_lookup_int(state, &rval);
1821 if (error) 1821 if (error)
1822 rval = error; 1822 rval = error;
1823 else if (rval == ENOENT && args->cmpresult == XFS_CMP_CASE) 1823 else if (rval == ENOENT && args->cmpresult == XFS_CMP_CASE) {
1824 rval = EEXIST; /* a case-insensitive match was found */ 1824 /* If a CI match, dup the actual name and return EEXIST */
1825 xfs_dir2_data_entry_t *dep;
1826
1827 dep = (xfs_dir2_data_entry_t *)((char *)state->extrablk.bp->
1828 data + state->extrablk.index);
1829 rval = xfs_dir_cilookup_result(args, dep->name, dep->namelen);
1830 }
1825 /* 1831 /*
1826 * Release the btree blocks and leaf block. 1832 * Release the btree blocks and leaf block.
1827 */ 1833 */
diff --git a/fs/xfs/xfs_dir2_sf.c b/fs/xfs/xfs_dir2_sf.c
index 9409fd3e565f..b46af0013ec9 100644
--- a/fs/xfs/xfs_dir2_sf.c
+++ b/fs/xfs/xfs_dir2_sf.c
@@ -812,9 +812,11 @@ xfs_dir2_sf_lookup(
812{ 812{
813 xfs_inode_t *dp; /* incore directory inode */ 813 xfs_inode_t *dp; /* incore directory inode */
814 int i; /* entry index */ 814 int i; /* entry index */
815 int error;
815 xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ 816 xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */
816 xfs_dir2_sf_t *sfp; /* shortform structure */ 817 xfs_dir2_sf_t *sfp; /* shortform structure */
817 enum xfs_dacmp cmp; /* comparison result */ 818 enum xfs_dacmp cmp; /* comparison result */
819 xfs_dir2_sf_entry_t *ci_sfep; /* case-insens. entry */
818 820
819 xfs_dir2_trace_args("sf_lookup", args); 821 xfs_dir2_trace_args("sf_lookup", args);
820 xfs_dir2_sf_check(args); 822 xfs_dir2_sf_check(args);
@@ -852,6 +854,7 @@ xfs_dir2_sf_lookup(
852 /* 854 /*
853 * Loop over all the entries trying to match ours. 855 * Loop over all the entries trying to match ours.
854 */ 856 */
857 ci_sfep = NULL;
855 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->hdr.count; 858 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->hdr.count;
856 i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) { 859 i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
857 /* 860 /*
@@ -867,19 +870,19 @@ xfs_dir2_sf_lookup(
867 xfs_dir2_sf_inumberp(sfep)); 870 xfs_dir2_sf_inumberp(sfep));
868 if (cmp == XFS_CMP_EXACT) 871 if (cmp == XFS_CMP_EXACT)
869 return XFS_ERROR(EEXIST); 872 return XFS_ERROR(EEXIST);
873 ci_sfep = sfep;
870 } 874 }
871 } 875 }
872 ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); 876 ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
873 /* 877 /*
874 * Here, we can only be doing a lookup (not a rename or replace). 878 * Here, we can only be doing a lookup (not a rename or replace).
875 * If a case-insensitive match was found earlier, return "found". 879 * If a case-insensitive match was not found, return ENOENT.
876 */ 880 */
877 if (args->cmpresult == XFS_CMP_CASE) 881 if (!ci_sfep)
878 return XFS_ERROR(EEXIST); 882 return XFS_ERROR(ENOENT);
879 /* 883 /* otherwise process the CI match as required by the caller */
880 * Didn't find it. 884 error = xfs_dir_cilookup_result(args, ci_sfep->name, ci_sfep->namelen);
881 */ 885 return XFS_ERROR(error);
882 return XFS_ERROR(ENOENT);
883} 886}
884 887
885/* 888/*
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 9b8b87fcd4ec..b6a065eb25a5 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -1610,12 +1610,18 @@ xfs_inactive(
1610 return VN_INACTIVE_CACHE; 1610 return VN_INACTIVE_CACHE;
1611} 1611}
1612 1612
1613 1613/*
1614 * Lookups up an inode from "name". If ci_name is not NULL, then a CI match
1615 * is allowed, otherwise it has to be an exact match. If a CI match is found,
1616 * ci_name->name will point to a the actual name (caller must free) or
1617 * will be set to NULL if an exact match is found.
1618 */
1614int 1619int
1615xfs_lookup( 1620xfs_lookup(
1616 xfs_inode_t *dp, 1621 xfs_inode_t *dp,
1617 struct xfs_name *name, 1622 struct xfs_name *name,
1618 xfs_inode_t **ipp) 1623 xfs_inode_t **ipp,
1624 struct xfs_name *ci_name)
1619{ 1625{
1620 xfs_ino_t inum; 1626 xfs_ino_t inum;
1621 int error; 1627 int error;
@@ -1627,7 +1633,7 @@ xfs_lookup(
1627 return XFS_ERROR(EIO); 1633 return XFS_ERROR(EIO);
1628 1634
1629 lock_mode = xfs_ilock_map_shared(dp); 1635 lock_mode = xfs_ilock_map_shared(dp);
1630 error = xfs_dir_lookup(NULL, dp, name, &inum); 1636 error = xfs_dir_lookup(NULL, dp, name, &inum, ci_name);
1631 xfs_iunlock_map_shared(dp, lock_mode); 1637 xfs_iunlock_map_shared(dp, lock_mode);
1632 1638
1633 if (error) 1639 if (error)
@@ -1635,12 +1641,15 @@ xfs_lookup(
1635 1641
1636 error = xfs_iget(dp->i_mount, NULL, inum, 0, 0, ipp, 0); 1642 error = xfs_iget(dp->i_mount, NULL, inum, 0, 0, ipp, 0);
1637 if (error) 1643 if (error)
1638 goto out; 1644 goto out_free_name;
1639 1645
1640 xfs_itrace_ref(*ipp); 1646 xfs_itrace_ref(*ipp);
1641 return 0; 1647 return 0;
1642 1648
1643 out: 1649out_free_name:
1650 if (ci_name)
1651 kmem_free(ci_name->name);
1652out:
1644 *ipp = NULL; 1653 *ipp = NULL;
1645 return error; 1654 return error;
1646} 1655}
diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h
index 57335ba4ce53..7e9a8b241f21 100644
--- a/fs/xfs/xfs_vnodeops.h
+++ b/fs/xfs/xfs_vnodeops.h
@@ -22,7 +22,7 @@ int xfs_fsync(struct xfs_inode *ip);
22int xfs_release(struct xfs_inode *ip); 22int xfs_release(struct xfs_inode *ip);
23int xfs_inactive(struct xfs_inode *ip); 23int xfs_inactive(struct xfs_inode *ip);
24int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name, 24int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name,
25 struct xfs_inode **ipp); 25 struct xfs_inode **ipp, struct xfs_name *ci_name);
26int xfs_create(struct xfs_inode *dp, struct xfs_name *name, mode_t mode, 26int xfs_create(struct xfs_inode *dp, struct xfs_name *name, mode_t mode,
27 xfs_dev_t rdev, struct xfs_inode **ipp, struct cred *credp); 27 xfs_dev_t rdev, struct xfs_inode **ipp, struct cred *credp);
28int xfs_remove(struct xfs_inode *dp, struct xfs_name *name, 28int xfs_remove(struct xfs_inode *dp, struct xfs_name *name,