]> err.no Git - linux-2.6/blobdiff - fs/xfs/xfs_dir2.c
[XFS] Return case-insensitive match for dentry cache
[linux-2.6] / fs / xfs / xfs_dir2.c
index 7cb26529766b7759c2ed743273d0942d71765a15..882609c699c8cb68ce8c62e19e0feb5afcff7e22 100644 (file)
@@ -46,6 +46,8 @@
 
 struct xfs_name xfs_name_dotdot = {"..", 2};
 
+extern const struct xfs_nameops xfs_default_nameops;
+
 void
 xfs_dir_mount(
        xfs_mount_t     *mp)
@@ -65,6 +67,7 @@ xfs_dir_mount(
                (mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) /
                (uint)sizeof(xfs_da_node_entry_t);
        mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100;
+       mp->m_dirnameops = &xfs_default_nameops;
 }
 
 /*
@@ -164,7 +167,7 @@ xfs_dir_createname(
 
        args.name = name->name;
        args.namelen = name->len;
-       args.hashval = xfs_da_hashname(name->name, name->len);
+       args.hashval = dp->i_mount->m_dirnameops->hashname(name);
        args.inumber = inum;
        args.dp = dp;
        args.firstblock = first;
@@ -172,8 +175,7 @@ xfs_dir_createname(
        args.total = total;
        args.whichfork = XFS_DATA_FORK;
        args.trans = tp;
-       args.justcheck = 0;
-       args.addname = args.oknoent = 1;
+       args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
 
        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
                rval = xfs_dir2_sf_addname(&args);
@@ -190,15 +192,44 @@ xfs_dir_createname(
        return rval;
 }
 
+/*
+ * If doing a CI lookup and case-insensitive match, dup actual name into
+ * args.value. Return EEXIST for success (ie. name found) or an error.
+ */
+int
+xfs_dir_cilookup_result(
+       struct xfs_da_args *args,
+       const char      *name,
+       int             len)
+{
+       if (args->cmpresult == XFS_CMP_DIFFERENT)
+               return ENOENT;
+       if (args->cmpresult != XFS_CMP_CASE ||
+                                       !(args->op_flags & XFS_DA_OP_CILOOKUP))
+               return EEXIST;
+
+       args->value = kmem_alloc(len, KM_MAYFAIL);
+       if (!args->value)
+               return ENOMEM;
+
+       memcpy(args->value, name, len);
+       args->valuelen = len;
+       return EEXIST;
+}
+
 /*
  * Lookup a name in a directory, give back the inode number.
+ * If ci_name is not NULL, returns the actual name in ci_name if it differs
+ * to name, or ci_name->name is set to NULL for an exact match.
  */
+
 int
 xfs_dir_lookup(
        xfs_trans_t     *tp,
        xfs_inode_t     *dp,
        struct xfs_name *name,
-       xfs_ino_t       *inum)          /* out: inode number */
+       xfs_ino_t       *inum,          /* out: inode number */
+       struct xfs_name *ci_name)       /* out: actual name if CI match */
 {
        xfs_da_args_t   args;
        int             rval;
@@ -210,11 +241,14 @@ xfs_dir_lookup(
 
        args.name = name->name;
        args.namelen = name->len;
-       args.hashval = xfs_da_hashname(name->name, name->len);
+       args.hashval = dp->i_mount->m_dirnameops->hashname(name);
        args.dp = dp;
        args.whichfork = XFS_DATA_FORK;
        args.trans = tp;
-       args.oknoent = 1;
+       args.op_flags = XFS_DA_OP_OKNOENT;
+       if (ci_name)
+               args.op_flags |= XFS_DA_OP_CILOOKUP;
+       args.cmpresult = XFS_CMP_DIFFERENT;
 
        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
                rval = xfs_dir2_sf_lookup(&args);
@@ -230,8 +264,13 @@ xfs_dir_lookup(
                rval = xfs_dir2_node_lookup(&args);
        if (rval == EEXIST)
                rval = 0;
-       if (rval == 0)
+       if (!rval) {
                *inum = args.inumber;
+               if (ci_name) {
+                       ci_name->name = args.value;
+                       ci_name->len = args.valuelen;
+               }
+       }
        return rval;
 }
 
@@ -257,7 +296,7 @@ xfs_dir_removename(
 
        args.name = name->name;
        args.namelen = name->len;
-       args.hashval = xfs_da_hashname(name->name, name->len);
+       args.hashval = dp->i_mount->m_dirnameops->hashname(name);
        args.inumber = ino;
        args.dp = dp;
        args.firstblock = first;
@@ -265,7 +304,7 @@ xfs_dir_removename(
        args.total = total;
        args.whichfork = XFS_DATA_FORK;
        args.trans = tp;
-       args.justcheck = args.addname = args.oknoent = 0;
+       args.op_flags = 0;
 
        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
                rval = xfs_dir2_sf_removename(&args);
@@ -340,7 +379,7 @@ xfs_dir_replace(
 
        args.name = name->name;
        args.namelen = name->len;
-       args.hashval = xfs_da_hashname(name->name, name->len);
+       args.hashval = dp->i_mount->m_dirnameops->hashname(name);
        args.inumber = inum;
        args.dp = dp;
        args.firstblock = first;
@@ -348,7 +387,7 @@ xfs_dir_replace(
        args.total = total;
        args.whichfork = XFS_DATA_FORK;
        args.trans = tp;
-       args.justcheck = args.addname = args.oknoent = 0;
+       args.op_flags = 0;
 
        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
                rval = xfs_dir2_sf_replace(&args);
@@ -388,11 +427,12 @@ xfs_dir_canenter(
 
        args.name = name->name;
        args.namelen = name->len;
-       args.hashval = xfs_da_hashname(name->name, name->len);
+       args.hashval = dp->i_mount->m_dirnameops->hashname(name);
        args.dp = dp;
        args.whichfork = XFS_DATA_FORK;
        args.trans = tp;
-       args.justcheck = args.addname = args.oknoent = 1;
+       args.op_flags = XFS_DA_OP_JUSTCHECK | XFS_DA_OP_ADDNAME |
+                                                       XFS_DA_OP_OKNOENT;
 
        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
                rval = xfs_dir2_sf_addname(&args);
@@ -493,7 +533,7 @@ xfs_dir2_grow_inode(
                                        args->firstblock, args->total,
                                        &mapp[mapi], &nmap, args->flist,
                                        NULL))) {
-                               kmem_free(mapp, sizeof(*mapp) * count);
+                               kmem_free(mapp);
                                return error;
                        }
                        if (nmap < 1)
@@ -525,14 +565,14 @@ xfs_dir2_grow_inode(
            mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount !=
            bno + count) {
                if (mapp != &map)
-                       kmem_free(mapp, sizeof(*mapp) * count);
+                       kmem_free(mapp);
                return XFS_ERROR(ENOSPC);
        }
        /*
         * Done with the temporary mapping table.
         */
        if (mapp != &map)
-               kmem_free(mapp, sizeof(*mapp) * count);
+               kmem_free(mapp);
        *dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno);
        /*
         * Update file's size if this is the data space and it grew.