Commit 4a12ca3a authored by Mark Fasheh's avatar Mark Fasheh

ocfs2: Introduce dir lookup helper struct

Many directory manipulation calls pass around a tuple of dirent, and it's
containing buffer_head. Dir indexing has a bit more state, but instead of
adding yet more arguments to functions, we introduce 'struct
ocfs2_dir_lookup_result'. In this patch, it simply holds the same tuple, but
future patches will add more state.
Signed-off-by: default avatarMark Fasheh <mfasheh@suse.com>
Acked-by: default avatarJoel Becker <joel.becker@oracle.com>
parent 59b526a3
......@@ -152,6 +152,11 @@ static void ocfs2_init_dir_trailer(struct inode *inode,
trailer->db_blkno = cpu_to_le64(bh->b_blocknr);
}
void ocfs2_free_dir_lookup_result(struct ocfs2_dir_lookup_result *res)
{
brelse(res->dl_leaf_bh);
}
/*
* bh passed here can be an inode block or a dir data block, depending
* on the inode inline data flag.
......@@ -483,36 +488,46 @@ static struct buffer_head *ocfs2_find_entry_el(const char *name, int namelen,
/*
* Try to find an entry of the provided name within 'dir'.
*
* If nothing was found, NULL is returned. Otherwise, a buffer_head
* and pointer to the dir entry are passed back.
* If nothing was found, -ENOENT is returned. Otherwise, zero is
* returned and the struct 'res' will contain information useful to
* other directory manipulation functions.
*
* Caller can NOT assume anything about the contents of the
* buffer_head - it is passed back only so that it can be passed into
* buffer_heads - they are passed back only so that it can be passed into
* any one of the manipulation functions (add entry, delete entry,
* etc). As an example, bh in the extent directory case is a data
* block, in the inline-data case it actually points to an inode.
*/
struct buffer_head *ocfs2_find_entry(const char *name, int namelen,
struct inode *dir,
struct ocfs2_dir_entry **res_dir)
int ocfs2_find_entry(const char *name, int namelen,
struct inode *dir, struct ocfs2_dir_lookup_result *lookup)
{
*res_dir = NULL;
struct buffer_head *bh;
struct ocfs2_dir_entry *res_dir = NULL;
if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
return ocfs2_find_entry_id(name, namelen, dir, res_dir);
bh = ocfs2_find_entry_id(name, namelen, dir, &res_dir);
else
bh = ocfs2_find_entry_el(name, namelen, dir, &res_dir);
return ocfs2_find_entry_el(name, namelen, dir, res_dir);
if (bh == NULL)
return -ENOENT;
lookup->dl_leaf_bh = bh;
lookup->dl_entry = res_dir;
return 0;
}
/*
* Update inode number and type of a previously found directory entry.
*/
int ocfs2_update_entry(struct inode *dir, handle_t *handle,
struct buffer_head *de_bh, struct ocfs2_dir_entry *de,
struct ocfs2_dir_lookup_result *res,
struct inode *new_entry_inode)
{
int ret;
ocfs2_journal_access_func access = ocfs2_journal_access_db;
struct ocfs2_dir_entry *de = res->dl_entry;
struct buffer_head *de_bh = res->dl_leaf_bh;
/*
* The same code works fine for both inline-data and extent
......@@ -629,13 +644,14 @@ static inline int ocfs2_delete_entry_el(handle_t *handle,
*/
int ocfs2_delete_entry(handle_t *handle,
struct inode *dir,
struct ocfs2_dir_entry *de_del,
struct buffer_head *bh)
struct ocfs2_dir_lookup_result *res)
{
if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
return ocfs2_delete_entry_id(handle, dir, de_del, bh);
return ocfs2_delete_entry_id(handle, dir, res->dl_entry,
res->dl_leaf_bh);
return ocfs2_delete_entry_el(handle, dir, de_del, bh);
return ocfs2_delete_entry_el(handle, dir, res->dl_entry,
res->dl_leaf_bh);
}
/*
......@@ -666,15 +682,15 @@ static inline int ocfs2_dirent_would_fit(struct ocfs2_dir_entry *de,
/* we don't always have a dentry for what we want to add, so people
* like orphan dir can call this instead.
*
* If you pass me insert_bh, I'll skip the search of the other dir
* blocks and put the record in there.
* The lookup context must have been filled from
* ocfs2_prepare_dir_for_insert.
*/
int __ocfs2_add_entry(handle_t *handle,
struct inode *dir,
const char *name, int namelen,
struct inode *inode, u64 blkno,
struct buffer_head *parent_fe_bh,
struct buffer_head *insert_bh)
struct ocfs2_dir_lookup_result *lookup)
{
unsigned long offset;
unsigned short rec_len;
......@@ -683,6 +699,7 @@ int __ocfs2_add_entry(handle_t *handle,
struct super_block *sb = dir->i_sb;
int retval, status;
unsigned int size = sb->s_blocksize;
struct buffer_head *insert_bh = lookup->dl_leaf_bh;
char *data_start = insert_bh->b_data;
mlog_entry_void();
......@@ -1071,31 +1088,22 @@ int ocfs2_find_files_on_disk(const char *name,
int namelen,
u64 *blkno,
struct inode *inode,
struct buffer_head **dirent_bh,
struct ocfs2_dir_entry **dirent)
struct ocfs2_dir_lookup_result *lookup)
{
int status = -ENOENT;
mlog_entry("(name=%.*s, blkno=%p, inode=%p, dirent_bh=%p, dirent=%p)\n",
namelen, name, blkno, inode, dirent_bh, dirent);
mlog(0, "name=%.*s, blkno=%p, inode=%llu\n", namelen, name, blkno,
(unsigned long long)OCFS2_I(inode)->ip_blkno);
*dirent_bh = ocfs2_find_entry(name, namelen, inode, dirent);
if (!*dirent_bh || !*dirent) {
status = -ENOENT;
status = ocfs2_find_entry(name, namelen, inode, lookup);
if (status)
goto leave;
}
*blkno = le64_to_cpu((*dirent)->inode);
*blkno = le64_to_cpu(lookup->dl_entry->inode);
status = 0;
leave:
if (status < 0) {
*dirent = NULL;
brelse(*dirent_bh);
*dirent_bh = NULL;
}
mlog_exit(status);
return status;
}
......@@ -1107,11 +1115,10 @@ int ocfs2_lookup_ino_from_name(struct inode *dir, const char *name,
int namelen, u64 *blkno)
{
int ret;
struct buffer_head *bh = NULL;
struct ocfs2_dir_entry *dirent = NULL;
struct ocfs2_dir_lookup_result lookup = { NULL, };
ret = ocfs2_find_files_on_disk(name, namelen, blkno, dir, &bh, &dirent);
brelse(bh);
ret = ocfs2_find_files_on_disk(name, namelen, blkno, dir, &lookup);
ocfs2_free_dir_lookup_result(&lookup);
return ret;
}
......@@ -1128,20 +1135,18 @@ int ocfs2_check_dir_for_entry(struct inode *dir,
int namelen)
{
int ret;
struct buffer_head *dirent_bh = NULL;
struct ocfs2_dir_entry *dirent = NULL;
struct ocfs2_dir_lookup_result lookup = { NULL, };
mlog_entry("dir %llu, name '%.*s'\n",
(unsigned long long)OCFS2_I(dir)->ip_blkno, namelen, name);
ret = -EEXIST;
dirent_bh = ocfs2_find_entry(name, namelen, dir, &dirent);
if (dirent_bh)
if (ocfs2_find_entry(name, namelen, dir, &lookup) == 0)
goto bail;
ret = 0;
bail:
brelse(dirent_bh);
ocfs2_free_dir_lookup_result(&lookup);
mlog_exit(ret);
return ret;
......@@ -1970,12 +1975,18 @@ static int ocfs2_find_dir_space_el(struct inode *dir, const char *name,
return status;
}
/*
* Get a directory ready for insert. Any directory allocation required
* happens here. Success returns zero, and enough context in the dir
* lookup result that ocfs2_add_entry() will be able complete the task
* with minimal performance impact.
*/
int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
struct inode *dir,
struct buffer_head *parent_fe_bh,
const char *name,
int namelen,
struct buffer_head **ret_de_bh)
struct ocfs2_dir_lookup_result *lookup)
{
int ret;
unsigned int blocks_wanted = 1;
......@@ -1984,8 +1995,6 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
mlog(0, "getting ready to insert namelen %d into dir %llu\n",
namelen, (unsigned long long)OCFS2_I(dir)->ip_blkno);
*ret_de_bh = NULL;
if (!namelen) {
ret = -EINVAL;
mlog_errno(ret);
......@@ -2020,7 +2029,7 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
BUG_ON(!bh);
}
*ret_de_bh = bh;
lookup->dl_leaf_bh = bh;
bh = NULL;
out:
brelse(bh);
......
......@@ -26,44 +26,48 @@
#ifndef OCFS2_DIR_H
#define OCFS2_DIR_H
struct buffer_head *ocfs2_find_entry(const char *name,
int namelen,
struct inode *dir,
struct ocfs2_dir_entry **res_dir);
struct ocfs2_dir_lookup_result {
struct buffer_head *dl_leaf_bh;
struct ocfs2_dir_entry *dl_entry;
};
void ocfs2_free_dir_lookup_result(struct ocfs2_dir_lookup_result *res);
int ocfs2_find_entry(const char *name, int namelen,
struct inode *dir,
struct ocfs2_dir_lookup_result *lookup);
int ocfs2_delete_entry(handle_t *handle,
struct inode *dir,
struct ocfs2_dir_entry *de_del,
struct buffer_head *bh);
struct ocfs2_dir_lookup_result *res);
int __ocfs2_add_entry(handle_t *handle,
struct inode *dir,
const char *name, int namelen,
struct inode *inode, u64 blkno,
struct buffer_head *parent_fe_bh,
struct buffer_head *insert_bh);
struct ocfs2_dir_lookup_result *lookup);
static inline int ocfs2_add_entry(handle_t *handle,
struct dentry *dentry,
struct inode *inode, u64 blkno,
struct buffer_head *parent_fe_bh,
struct buffer_head *insert_bh)
struct ocfs2_dir_lookup_result *lookup)
{
return __ocfs2_add_entry(handle, dentry->d_parent->d_inode,
dentry->d_name.name, dentry->d_name.len,
inode, blkno, parent_fe_bh, insert_bh);
inode, blkno, parent_fe_bh, lookup);
}
int ocfs2_update_entry(struct inode *dir, handle_t *handle,
struct buffer_head *de_bh, struct ocfs2_dir_entry *de,
struct ocfs2_dir_lookup_result *res,
struct inode *new_entry_inode);
int ocfs2_check_dir_for_entry(struct inode *dir,
const char *name,
int namelen);
int ocfs2_empty_dir(struct inode *inode);
int ocfs2_find_files_on_disk(const char *name,
int namelen,
u64 *blkno,
struct inode *inode,
struct buffer_head **dirent_bh,
struct ocfs2_dir_entry **dirent);
struct ocfs2_dir_lookup_result *res);
int ocfs2_lookup_ino_from_name(struct inode *dir, const char *name,
int namelen, u64 *blkno);
int ocfs2_readdir(struct file *filp, void *dirent, filldir_t filldir);
......@@ -74,7 +78,7 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
struct buffer_head *parent_fe_bh,
const char *name,
int namelen,
struct buffer_head **ret_de_bh);
struct ocfs2_dir_lookup_result *lookup);
struct ocfs2_alloc_context;
int ocfs2_fill_new_dir(struct ocfs2_super *osb,
handle_t *handle,
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment