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, ...@@ -152,6 +152,11 @@ static void ocfs2_init_dir_trailer(struct inode *inode,
trailer->db_blkno = cpu_to_le64(bh->b_blocknr); 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 * bh passed here can be an inode block or a dir data block, depending
* on the inode inline data flag. * on the inode inline data flag.
...@@ -483,36 +488,46 @@ static struct buffer_head *ocfs2_find_entry_el(const char *name, int namelen, ...@@ -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'. * Try to find an entry of the provided name within 'dir'.
* *
* If nothing was found, NULL is returned. Otherwise, a buffer_head * If nothing was found, -ENOENT is returned. Otherwise, zero is
* and pointer to the dir entry are passed back. * returned and the struct 'res' will contain information useful to
* other directory manipulation functions.
* *
* Caller can NOT assume anything about the contents of the * 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, * any one of the manipulation functions (add entry, delete entry,
* etc). As an example, bh in the extent directory case is a data * 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. * block, in the inline-data case it actually points to an inode.
*/ */
struct buffer_head *ocfs2_find_entry(const char *name, int namelen, int ocfs2_find_entry(const char *name, int namelen,
struct inode *dir, struct inode *dir, struct ocfs2_dir_lookup_result *lookup)
struct ocfs2_dir_entry **res_dir)
{ {
*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) 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. * Update inode number and type of a previously found directory entry.
*/ */
int ocfs2_update_entry(struct inode *dir, handle_t *handle, 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) struct inode *new_entry_inode)
{ {
int ret; int ret;
ocfs2_journal_access_func access = ocfs2_journal_access_db; 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 * 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, ...@@ -629,13 +644,14 @@ static inline int ocfs2_delete_entry_el(handle_t *handle,
*/ */
int ocfs2_delete_entry(handle_t *handle, int ocfs2_delete_entry(handle_t *handle,
struct inode *dir, struct inode *dir,
struct ocfs2_dir_entry *de_del, struct ocfs2_dir_lookup_result *res)
struct buffer_head *bh)
{ {
if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) 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, ...@@ -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 /* we don't always have a dentry for what we want to add, so people
* like orphan dir can call this instead. * like orphan dir can call this instead.
* *
* If you pass me insert_bh, I'll skip the search of the other dir * The lookup context must have been filled from
* blocks and put the record in there. * ocfs2_prepare_dir_for_insert.
*/ */
int __ocfs2_add_entry(handle_t *handle, int __ocfs2_add_entry(handle_t *handle,
struct inode *dir, struct inode *dir,
const char *name, int namelen, const char *name, int namelen,
struct inode *inode, u64 blkno, struct inode *inode, u64 blkno,
struct buffer_head *parent_fe_bh, struct buffer_head *parent_fe_bh,
struct buffer_head *insert_bh) struct ocfs2_dir_lookup_result *lookup)
{ {
unsigned long offset; unsigned long offset;
unsigned short rec_len; unsigned short rec_len;
...@@ -683,6 +699,7 @@ int __ocfs2_add_entry(handle_t *handle, ...@@ -683,6 +699,7 @@ int __ocfs2_add_entry(handle_t *handle,
struct super_block *sb = dir->i_sb; struct super_block *sb = dir->i_sb;
int retval, status; int retval, status;
unsigned int size = sb->s_blocksize; unsigned int size = sb->s_blocksize;
struct buffer_head *insert_bh = lookup->dl_leaf_bh;
char *data_start = insert_bh->b_data; char *data_start = insert_bh->b_data;
mlog_entry_void(); mlog_entry_void();
...@@ -1071,31 +1088,22 @@ int ocfs2_find_files_on_disk(const char *name, ...@@ -1071,31 +1088,22 @@ int ocfs2_find_files_on_disk(const char *name,
int namelen, int namelen,
u64 *blkno, u64 *blkno,
struct inode *inode, struct inode *inode,
struct buffer_head **dirent_bh, struct ocfs2_dir_lookup_result *lookup)
struct ocfs2_dir_entry **dirent)
{ {
int status = -ENOENT; int status = -ENOENT;
mlog_entry("(name=%.*s, blkno=%p, inode=%p, dirent_bh=%p, dirent=%p)\n", mlog(0, "name=%.*s, blkno=%p, inode=%llu\n", namelen, name, blkno,
namelen, name, blkno, inode, dirent_bh, dirent); (unsigned long long)OCFS2_I(inode)->ip_blkno);
*dirent_bh = ocfs2_find_entry(name, namelen, inode, dirent); status = ocfs2_find_entry(name, namelen, inode, lookup);
if (!*dirent_bh || !*dirent) { if (status)
status = -ENOENT;
goto leave; goto leave;
}
*blkno = le64_to_cpu((*dirent)->inode); *blkno = le64_to_cpu(lookup->dl_entry->inode);
status = 0; status = 0;
leave: leave:
if (status < 0) {
*dirent = NULL;
brelse(*dirent_bh);
*dirent_bh = NULL;
}
mlog_exit(status);
return status; return status;
} }
...@@ -1107,11 +1115,10 @@ int ocfs2_lookup_ino_from_name(struct inode *dir, const char *name, ...@@ -1107,11 +1115,10 @@ int ocfs2_lookup_ino_from_name(struct inode *dir, const char *name,
int namelen, u64 *blkno) int namelen, u64 *blkno)
{ {
int ret; int ret;
struct buffer_head *bh = NULL; struct ocfs2_dir_lookup_result lookup = { NULL, };
struct ocfs2_dir_entry *dirent = NULL;
ret = ocfs2_find_files_on_disk(name, namelen, blkno, dir, &bh, &dirent); ret = ocfs2_find_files_on_disk(name, namelen, blkno, dir, &lookup);
brelse(bh); ocfs2_free_dir_lookup_result(&lookup);
return ret; return ret;
} }
...@@ -1128,20 +1135,18 @@ int ocfs2_check_dir_for_entry(struct inode *dir, ...@@ -1128,20 +1135,18 @@ int ocfs2_check_dir_for_entry(struct inode *dir,
int namelen) int namelen)
{ {
int ret; int ret;
struct buffer_head *dirent_bh = NULL; struct ocfs2_dir_lookup_result lookup = { NULL, };
struct ocfs2_dir_entry *dirent = NULL;
mlog_entry("dir %llu, name '%.*s'\n", mlog_entry("dir %llu, name '%.*s'\n",
(unsigned long long)OCFS2_I(dir)->ip_blkno, namelen, name); (unsigned long long)OCFS2_I(dir)->ip_blkno, namelen, name);
ret = -EEXIST; ret = -EEXIST;
dirent_bh = ocfs2_find_entry(name, namelen, dir, &dirent); if (ocfs2_find_entry(name, namelen, dir, &lookup) == 0)
if (dirent_bh)
goto bail; goto bail;
ret = 0; ret = 0;
bail: bail:
brelse(dirent_bh); ocfs2_free_dir_lookup_result(&lookup);
mlog_exit(ret); mlog_exit(ret);
return ret; return ret;
...@@ -1970,12 +1975,18 @@ static int ocfs2_find_dir_space_el(struct inode *dir, const char *name, ...@@ -1970,12 +1975,18 @@ static int ocfs2_find_dir_space_el(struct inode *dir, const char *name,
return status; 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, int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
struct inode *dir, struct inode *dir,
struct buffer_head *parent_fe_bh, struct buffer_head *parent_fe_bh,
const char *name, const char *name,
int namelen, int namelen,
struct buffer_head **ret_de_bh) struct ocfs2_dir_lookup_result *lookup)
{ {
int ret; int ret;
unsigned int blocks_wanted = 1; unsigned int blocks_wanted = 1;
...@@ -1984,8 +1995,6 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb, ...@@ -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", mlog(0, "getting ready to insert namelen %d into dir %llu\n",
namelen, (unsigned long long)OCFS2_I(dir)->ip_blkno); namelen, (unsigned long long)OCFS2_I(dir)->ip_blkno);
*ret_de_bh = NULL;
if (!namelen) { if (!namelen) {
ret = -EINVAL; ret = -EINVAL;
mlog_errno(ret); mlog_errno(ret);
...@@ -2020,7 +2029,7 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb, ...@@ -2020,7 +2029,7 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
BUG_ON(!bh); BUG_ON(!bh);
} }
*ret_de_bh = bh; lookup->dl_leaf_bh = bh;
bh = NULL; bh = NULL;
out: out:
brelse(bh); brelse(bh);
......
...@@ -26,44 +26,48 @@ ...@@ -26,44 +26,48 @@
#ifndef OCFS2_DIR_H #ifndef OCFS2_DIR_H
#define OCFS2_DIR_H #define OCFS2_DIR_H
struct buffer_head *ocfs2_find_entry(const char *name, struct ocfs2_dir_lookup_result {
int namelen, struct buffer_head *dl_leaf_bh;
struct inode *dir, struct ocfs2_dir_entry *dl_entry;
struct ocfs2_dir_entry **res_dir); };
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, int ocfs2_delete_entry(handle_t *handle,
struct inode *dir, struct inode *dir,
struct ocfs2_dir_entry *de_del, struct ocfs2_dir_lookup_result *res);
struct buffer_head *bh);
int __ocfs2_add_entry(handle_t *handle, int __ocfs2_add_entry(handle_t *handle,
struct inode *dir, struct inode *dir,
const char *name, int namelen, const char *name, int namelen,
struct inode *inode, u64 blkno, struct inode *inode, u64 blkno,
struct buffer_head *parent_fe_bh, 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, static inline int ocfs2_add_entry(handle_t *handle,
struct dentry *dentry, struct dentry *dentry,
struct inode *inode, u64 blkno, struct inode *inode, u64 blkno,
struct buffer_head *parent_fe_bh, 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, return __ocfs2_add_entry(handle, dentry->d_parent->d_inode,
dentry->d_name.name, dentry->d_name.len, 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, 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); struct inode *new_entry_inode);
int ocfs2_check_dir_for_entry(struct inode *dir, int ocfs2_check_dir_for_entry(struct inode *dir,
const char *name, const char *name,
int namelen); int namelen);
int ocfs2_empty_dir(struct inode *inode); int ocfs2_empty_dir(struct inode *inode);
int ocfs2_find_files_on_disk(const char *name, int ocfs2_find_files_on_disk(const char *name,
int namelen, int namelen,
u64 *blkno, u64 *blkno,
struct inode *inode, struct inode *inode,
struct buffer_head **dirent_bh, struct ocfs2_dir_lookup_result *res);
struct ocfs2_dir_entry **dirent);
int ocfs2_lookup_ino_from_name(struct inode *dir, const char *name, int ocfs2_lookup_ino_from_name(struct inode *dir, const char *name,
int namelen, u64 *blkno); int namelen, u64 *blkno);
int ocfs2_readdir(struct file *filp, void *dirent, filldir_t filldir); 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, ...@@ -74,7 +78,7 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
struct buffer_head *parent_fe_bh, struct buffer_head *parent_fe_bh,
const char *name, const char *name,
int namelen, int namelen,
struct buffer_head **ret_de_bh); struct ocfs2_dir_lookup_result *lookup);
struct ocfs2_alloc_context; struct ocfs2_alloc_context;
int ocfs2_fill_new_dir(struct ocfs2_super *osb, int ocfs2_fill_new_dir(struct ocfs2_super *osb,
handle_t *handle, 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