diff options
author | Barry Naujok <bnaujok@sgi.com> | 2008-05-21 02:58:22 -0400 |
---|---|---|
committer | Niv Sardi <xaiki@debian.org> | 2008-07-28 02:58:40 -0400 |
commit | 384f3ced07efdddf6838f6527366089d37843c94 (patch) | |
tree | 13037bc99115f6f940b6fe924b75dc48e0577678 | |
parent | 9403540c0653122ca34884a180439ddbfcbcb524 (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.c | 2 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_iops.c | 57 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_iops.h | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_da_btree.h | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_dir2.c | 40 | ||||
-rw-r--r-- | fs/xfs/xfs_dir2.h | 6 | ||||
-rw-r--r-- | fs/xfs/xfs_dir2_block.c | 9 | ||||
-rw-r--r-- | fs/xfs/xfs_dir2_leaf.c | 5 | ||||
-rw-r--r-- | fs/xfs/xfs_dir2_node.c | 16 | ||||
-rw-r--r-- | fs/xfs/xfs_dir2_sf.c | 17 | ||||
-rw-r--r-- | fs/xfs/xfs_vnodeops.c | 19 | ||||
-rw-r--r-- | fs/xfs/xfs_vnodeops.h | 2 |
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 | ||
396 | STATIC struct dentry * | ||
397 | xfs_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 | |||
396 | STATIC int | 432 | STATIC int |
397 | xfs_vn_link( | 433 | xfs_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 | ||
931 | const 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 | |||
895 | const struct inode_operations xfs_symlink_inode_operations = { | 950 | const 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 | ||
21 | extern const struct inode_operations xfs_inode_operations; | 21 | extern const struct inode_operations xfs_inode_operations; |
22 | extern const struct inode_operations xfs_dir_inode_operations; | 22 | extern const struct inode_operations xfs_dir_inode_operations; |
23 | extern const struct inode_operations xfs_dir_ci_inode_operations; | ||
23 | extern const struct inode_operations xfs_symlink_inode_operations; | 24 | extern const struct inode_operations xfs_symlink_inode_operations; |
24 | 25 | ||
25 | extern const struct file_operations xfs_file_operations; | 26 | extern 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 | */ | ||
199 | int | ||
200 | xfs_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 | |||
198 | int | 226 | int |
199 | xfs_dir_lookup( | 227 | xfs_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); |
76 | extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp, | 76 | extern 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); | ||
78 | extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp, | 79 | extern 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, | |||
99 | extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db, | 100 | extern 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 | ||
103 | extern 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)); |
643 | out: | 643 | out: |
@@ -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 | */ | ||
1614 | int | 1619 | int |
1615 | xfs_lookup( | 1620 | xfs_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: | 1649 | out_free_name: |
1650 | if (ci_name) | ||
1651 | kmem_free(ci_name->name); | ||
1652 | out: | ||
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); | |||
22 | int xfs_release(struct xfs_inode *ip); | 22 | int xfs_release(struct xfs_inode *ip); |
23 | int xfs_inactive(struct xfs_inode *ip); | 23 | int xfs_inactive(struct xfs_inode *ip); |
24 | int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name, | 24 | int 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); |
26 | int xfs_create(struct xfs_inode *dp, struct xfs_name *name, mode_t mode, | 26 | int 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); |
28 | int xfs_remove(struct xfs_inode *dp, struct xfs_name *name, | 28 | int xfs_remove(struct xfs_inode *dp, struct xfs_name *name, |