xfs
[Top] [All Lists]

[PATCH 01/13] libxfs: return the first match during case-insensitive loo

To: linux-fsdevel@xxxxxxxxxxxxxxx
Subject: [PATCH 01/13] libxfs: return the first match during case-insensitive lookup
From: Ben Myers <bpm@xxxxxxx>
Date: Thu, 18 Sep 2014 15:33:17 -0500
Cc: xfs@xxxxxxxxxxx, olaf@xxxxxxx, tinguely@xxxxxxx
Delivered-to: xfs@xxxxxxxxxxx
In-reply-to: <20140918203114.GN4482@xxxxxxx>
References: <20140918195650.GI19952@xxxxxxx> <20140918203114.GN4482@xxxxxxx>
User-agent: Mutt/1.5.20 (2009-06-14)
From: Olaf Weber <olaf@xxxxxxx>

Change the XFS case-insensitive lookup code to return the first match found,
even if it is not an exact match. Whether a filesystem uses case-insensitive
lookups is determined by a superblock bit set during filesystem creation.
This means that normal use cannot create two files that both match the same
filename.

Signed-off-by: Olaf Weber <olaf@xxxxxxx>
---
 libxfs/xfs_dir2_block.c | 17 ++++-------
 libxfs/xfs_dir2_leaf.c  | 38 ++++-------------------
 libxfs/xfs_dir2_node.c  | 80 ++++++++++++++++++-------------------------------
 libxfs/xfs_dir2_sf.c    |  8 ++---
 4 files changed, 44 insertions(+), 99 deletions(-)

diff --git a/libxfs/xfs_dir2_block.c b/libxfs/xfs_dir2_block.c
index cede01f..2880431 100644
--- a/libxfs/xfs_dir2_block.c
+++ b/libxfs/xfs_dir2_block.c
@@ -705,28 +705,21 @@ xfs_dir2_block_lookup_int(
                dep = (xfs_dir2_data_entry_t *)
                        ((char *)hdr + xfs_dir2_dataptr_to_off(mp, addr));
                /*
-                * Compare name and if it's an exact match, return the index
-                * and buffer. If it's the first case-insensitive match, store
-                * the index and buffer and continue looking for an exact match.
+                * Compare name and if it's a match, return the
+                * index and buffer.
                 */
                cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen);
-               if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
+               if (cmp != XFS_CMP_DIFFERENT) {
                        args->cmpresult = cmp;
                        *bpp = bp;
                        *entno = mid;
-                       if (cmp == XFS_CMP_EXACT)
-                               return 0;
+                       return 0;
                }
        } while (++mid < be32_to_cpu(btp->count) &&
                        be32_to_cpu(blp[mid].hashval) == hash);
 
        ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
-       /*
-        * Here, we can only be doing a lookup (not a rename or replace).
-        * If a case-insensitive match was found earlier, return success.
-        */
-       if (args->cmpresult == XFS_CMP_CASE)
-               return 0;
+       ASSERT(args->cmpresult == XFS_CMP_DIFFERENT);
        /*
         * No match, release the buffer and return ENOENT.
         */
diff --git a/libxfs/xfs_dir2_leaf.c b/libxfs/xfs_dir2_leaf.c
index 8e0cbc9..b1901d3 100644
--- a/libxfs/xfs_dir2_leaf.c
+++ b/libxfs/xfs_dir2_leaf.c
@@ -1246,7 +1246,6 @@ xfs_dir2_leaf_lookup_int(
        xfs_mount_t             *mp;            /* filesystem mount point */
        xfs_dir2_db_t           newdb;          /* new data block number */
        xfs_trans_t             *tp;            /* transaction pointer */
-       xfs_dir2_db_t           cidb = -1;      /* case match data block no. */
        enum xfs_dacmp          cmp;            /* name compare result */
        struct xfs_dir2_leaf_entry *ents;
        struct xfs_dir3_icleaf_hdr leafhdr;
@@ -1307,47 +1306,22 @@ xfs_dir2_leaf_lookup_int(
                dep = (xfs_dir2_data_entry_t *)((char *)dbp->b_addr +
                        xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
                /*
-                * Compare name and if it's an exact match, return the index
-                * and buffer. If it's the first case-insensitive match, store
-                * the index and buffer and continue looking for an exact match.
+                * Compare name and if it's a match, return the index
+                * and buffer.
                 */
                cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen);
-               if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
+               if (cmp != XFS_CMP_DIFFERENT) {
                        args->cmpresult = cmp;
                        *indexp = index;
-                       /* case exact match: return the current buffer. */
-                       if (cmp == XFS_CMP_EXACT) {
-                               *dbpp = dbp;
-                               return 0;
-                       }
-                       cidb = curdb;
+                       *dbpp = dbp;
+                       return 0;
                }
        }
        ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
-       /*
-        * Here, we can only be doing a lookup (not a rename or remove).
-        * If a case-insensitive match was found earlier, re-read the
-        * appropriate data block if required and return it.
-        */
-       if (args->cmpresult == XFS_CMP_CASE) {
-               ASSERT(cidb != -1);
-               if (cidb != curdb) {
-                       xfs_trans_brelse(tp, dbp);
-                       error = xfs_dir3_data_read(tp, dp,
-                                                  xfs_dir2_db_to_da(mp, cidb),
-                                                  -1, &dbp);
-                       if (error) {
-                               xfs_trans_brelse(tp, lbp);
-                               return error;
-                       }
-               }
-               *dbpp = dbp;
-               return 0;
-       }
+       ASSERT(args->cmpresult == XFS_CMP_DIFFERENT);
        /*
         * No match found, return ENOENT.
         */
-       ASSERT(cidb == -1);
        if (dbp)
                xfs_trans_brelse(tp, dbp);
        xfs_trans_brelse(tp, lbp);
diff --git a/libxfs/xfs_dir2_node.c b/libxfs/xfs_dir2_node.c
index 3737e4e..fb27506 100644
--- a/libxfs/xfs_dir2_node.c
+++ b/libxfs/xfs_dir2_node.c
@@ -702,6 +702,7 @@ xfs_dir2_leafn_lookup_for_entry(
        xfs_dir2_db_t           curdb = -1;     /* current data block number */
        xfs_dir2_data_entry_t   *dep;           /* data block entry */
        xfs_inode_t             *dp;            /* incore directory inode */
+       int                     di = -1;        /* data entry index */
        int                     error;          /* error return value */
        int                     index;          /* leaf entry index */
        xfs_dir2_leaf_t         *leaf;          /* leaf structure */
@@ -733,6 +734,7 @@ xfs_dir2_leafn_lookup_for_entry(
        if (state->extravalid) {
                curbp = state->extrablk.bp;
                curdb = state->extrablk.blkno;
+               di = state->extrablk.index;
        }
        /*
         * Loop over leaf entries with the right hash value.
@@ -757,27 +759,20 @@ xfs_dir2_leafn_lookup_for_entry(
                 */
                if (newdb != curdb) {
                        /*
-                        * If we had a block before that we aren't saving
-                        * for a CI name, drop it
+                        * If we had a block, drop it
                         */
-                       if (curbp && (args->cmpresult == XFS_CMP_DIFFERENT ||
-                                               curdb != state->extrablk.blkno))
+                       if (curbp) {
                                xfs_trans_brelse(tp, curbp);
+                               di = -1;
+                       }
                        /*
-                        * If needing the block that is saved with a CI match,
-                        * use it otherwise read in the new data block.
+                        * Read in the new data block.
                         */
-                       if (args->cmpresult != XFS_CMP_DIFFERENT &&
-                                       newdb == state->extrablk.blkno) {
-                               ASSERT(state->extravalid);
-                               curbp = state->extrablk.bp;
-                       } else {
-                               error = xfs_dir3_data_read(tp, dp,
-                                               xfs_dir2_db_to_da(mp, newdb),
-                                               -1, &curbp);
-                               if (error)
-                                       return error;
-                       }
+                       error = xfs_dir3_data_read(tp, dp,
+                                       xfs_dir2_db_to_da(mp, newdb),
+                                       -1, &curbp);
+                       if (error)
+                               return error;
                        xfs_dir3_data_check(dp, curbp);
                        curdb = newdb;
                }
@@ -787,53 +782,36 @@ xfs_dir2_leafn_lookup_for_entry(
                dep = (xfs_dir2_data_entry_t *)((char *)curbp->b_addr +
                        xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
                /*
-                * Compare the entry and if it's an exact match, return
-                * EEXIST immediately. If it's the first case-insensitive
-                * match, store the block & inode number and continue looking.
+                * Compare the entry and if it's a match, return
+                * EEXIST immediately.
                 */
                cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen);
-               if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
-                       /* If there is a CI match block, drop it */
-                       if (args->cmpresult != XFS_CMP_DIFFERENT &&
-                                               curdb != state->extrablk.blkno)
-                               xfs_trans_brelse(tp, state->extrablk.bp);
+               if (cmp != XFS_CMP_DIFFERENT) {
                        args->cmpresult = cmp;
                        args->inumber = be64_to_cpu(dep->inumber);
                        args->filetype = xfs_dir3_dirent_get_ftype(mp, dep);
-                       *indexp = index;
-                       state->extravalid = 1;
-                       state->extrablk.bp = curbp;
-                       state->extrablk.blkno = curdb;
-                       state->extrablk.index = (int)((char *)dep -
-                                                       (char *)curbp->b_addr);
-                       state->extrablk.magic = XFS_DIR2_DATA_MAGIC;
-                       curbp->b_ops = &xfs_dir3_data_buf_ops;
-                       xfs_trans_buf_set_type(tp, curbp, 
XFS_BLFT_DIR_DATA_BUF);
-                       if (cmp == XFS_CMP_EXACT)
-                               return XFS_ERROR(EEXIST);
+                       error = EEXIST;
+                       goto out;
                }
        }
+       /* Didn't find a match */
+       error = ENOENT;
        ASSERT(index == leafhdr.count || (args->op_flags & XFS_DA_OP_OKNOENT));
+out:
        if (curbp) {
-               if (args->cmpresult == XFS_CMP_DIFFERENT) {
-                       /* Giving back last used data block. */
-                       state->extravalid = 1;
-                       state->extrablk.bp = curbp;
-                       state->extrablk.index = -1;
-                       state->extrablk.blkno = curdb;
-                       state->extrablk.magic = XFS_DIR2_DATA_MAGIC;
-                       curbp->b_ops = &xfs_dir3_data_buf_ops;
-                       xfs_trans_buf_set_type(tp, curbp, 
XFS_BLFT_DIR_DATA_BUF);
-               } else {
-                       /* If the curbp is not the CI match block, drop it */
-                       if (state->extrablk.bp != curbp)
-                               xfs_trans_brelse(tp, curbp);
-               }
+               /* Giving back last used data block. */
+               state->extravalid = 1;
+               state->extrablk.bp = curbp;
+               state->extrablk.index = di;
+               state->extrablk.blkno = curdb;
+               state->extrablk.magic = XFS_DIR2_DATA_MAGIC;
+               curbp->b_ops = &xfs_dir3_data_buf_ops;
+               xfs_trans_buf_set_type(tp, curbp, XFS_BLFT_DIR_DATA_BUF);
        } else {
                state->extravalid = 0;
        }
        *indexp = index;
-       return XFS_ERROR(ENOENT);
+       return XFS_ERROR(error);
 }
 
 /*
diff --git a/libxfs/xfs_dir2_sf.c b/libxfs/xfs_dir2_sf.c
index 7580333..7b01d43 100644
--- a/libxfs/xfs_dir2_sf.c
+++ b/libxfs/xfs_dir2_sf.c
@@ -833,13 +833,12 @@ xfs_dir2_sf_lookup(
        for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
             i++, sfep = xfs_dir3_sf_nextentry(dp->i_mount, sfp, sfep)) {
                /*
-                * Compare name and if it's an exact match, return the inode
-                * number. If it's the first case-insensitive match, store the
-                * inode number and continue looking for an exact match.
+                * Compare name and if it's a match, return the inode
+                * number.
                 */
                cmp = dp->i_mount->m_dirnameops->compname(args, sfep->name,
                                                                sfep->namelen);
-               if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
+               if (cmp != XFS_CMP_DIFFERENT) {
                        args->cmpresult = cmp;
                        args->inumber = xfs_dir3_sfe_get_ino(dp->i_mount,
                                                             sfp, sfep);
@@ -848,6 +847,7 @@ xfs_dir2_sf_lookup(
                        if (cmp == XFS_CMP_EXACT)
                                return XFS_ERROR(EEXIST);
                        ci_sfep = sfep;
+                       break;
                }
        }
        ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
-- 
1.7.12.4

<Prev in Thread] Current Thread [Next in Thread>