aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_dir2.c
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 /fs/xfs/xfs_dir2.c
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>
Diffstat (limited to 'fs/xfs/xfs_dir2.c')
-rw-r--r--fs/xfs/xfs_dir2.c40
1 files changed, 38 insertions, 2 deletions
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