apfs: move dentry lookups to new function

Define apfs_dentry_lookup() to take care of dentry lookups, using the
code from apfs_inode_by_name().  The intention here was to imitate
apfs_inode_lookup(), but the issue of hash collisions makes it tricky
to avoid parsing the record.

This new function will soon be reused to modify existing directory
records.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
This commit is contained in:
Ernesto A. Fernández
2019-08-23 23:15:13 -03:00
parent c5d30eebd9
commit f6fcfcc0ef
+46 -18
View File
@@ -64,33 +64,31 @@ static int apfs_drec_from_query(struct apfs_query *query,
}
/**
* apfs_inode_by_name - Find the cnid for a given filename
* apfs_dentry_lookup - Lookup a dentry record in the catalog b-tree
* @dir: parent directory
* @child: filename
* @ino: on return, the inode number found
* @drec: on return, the directory record found
*
* Returns 0 and the inode number (which is the cnid of the file
* record); otherwise, return the appropriate error code.
* Runs a catalog query for @name in the @dir directory. On success, sets
* @drec and returns a pointer to the query structure. On failure, returns
* an appropriate error pointer.
*/
int apfs_inode_by_name(struct inode *dir, const struct qstr *child, u64 *ino)
static struct apfs_query *apfs_dentry_lookup(struct inode *dir,
const struct qstr *child,
struct apfs_drec *drec)
{
struct super_block *sb = dir->i_sb;
struct apfs_sb_info *sbi = APFS_SB(sb);
struct apfs_key key;
struct apfs_query *query;
struct apfs_drec drec;
u64 cnid = dir->i_ino;
int err;
down_read(&sbi->s_big_sem);
apfs_init_drec_hashed_key(sb, cnid, child->name, &key);
query = apfs_alloc_query(sbi->s_cat_root, NULL /* parent */);
if (!query) {
err = -ENOMEM;
goto out;
}
if (!query)
return ERR_PTR(-ENOMEM);
query->key = &key;
/*
@@ -103,15 +101,45 @@ int apfs_inode_by_name(struct inode *dir, const struct qstr *child, u64 *ino)
do {
err = apfs_btree_query(sb, &query);
if (err)
goto out;
err = apfs_drec_from_query(query, &drec);
goto fail;
err = apfs_drec_from_query(query, drec);
if (err)
goto out;
} while (unlikely(apfs_filename_cmp(sb, child->name, drec.name)));
goto fail;
} while (unlikely(apfs_filename_cmp(sb, child->name, drec->name)));
*ino = drec.ino;
out:
return query;
fail:
apfs_free_query(sb, query);
return ERR_PTR(err);
}
/**
* apfs_inode_by_name - Find the cnid for a given filename
* @dir: parent directory
* @child: filename
* @ino: on return, the inode number found
*
* Returns 0 and the inode number (which is the cnid of the file
* record); otherwise, return the appropriate error code.
*/
int apfs_inode_by_name(struct inode *dir, const struct qstr *child, u64 *ino)
{
struct super_block *sb = dir->i_sb;
struct apfs_sb_info *sbi = APFS_SB(sb);
struct apfs_query *query;
struct apfs_drec drec;
int err = 0;
down_read(&sbi->s_big_sem);
query = apfs_dentry_lookup(dir, child, &drec);
if (IS_ERR(query)) {
err = PTR_ERR(query);
goto out;
}
*ino = drec.ino;
apfs_free_query(sb, query);
out:
up_read(&sbi->s_big_sem);
return err;
}