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 /fs | |
| 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>
Diffstat (limited to 'fs')
| -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, |
