ext4: convert dx_probe() to use the ERR_PTR convention

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
Theodore Ts'o 2014-08-29 20:52:17 -04:00
parent 1c2150283c
commit dd73b5d5cb
1 changed files with 35 additions and 54 deletions

View File

@ -253,8 +253,7 @@ static unsigned dx_node_limit(struct inode *dir);
static struct dx_frame *dx_probe(const struct qstr *d_name, static struct dx_frame *dx_probe(const struct qstr *d_name,
struct inode *dir, struct inode *dir,
struct dx_hash_info *hinfo, struct dx_hash_info *hinfo,
struct dx_frame *frame, struct dx_frame *frame);
int *err);
static void dx_release(struct dx_frame *frames); static void dx_release(struct dx_frame *frames);
static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize, static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize,
struct dx_hash_info *hinfo, struct dx_map_entry map[]); struct dx_hash_info *hinfo, struct dx_map_entry map[]);
@ -670,29 +669,25 @@ struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir,
*/ */
static struct dx_frame * static struct dx_frame *
dx_probe(const struct qstr *d_name, struct inode *dir, dx_probe(const struct qstr *d_name, struct inode *dir,
struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err) struct dx_hash_info *hinfo, struct dx_frame *frame_in)
{ {
unsigned count, indirect; unsigned count, indirect;
struct dx_entry *at, *entries, *p, *q, *m; struct dx_entry *at, *entries, *p, *q, *m;
struct dx_root *root; struct dx_root *root;
struct buffer_head *bh;
struct dx_frame *frame = frame_in; struct dx_frame *frame = frame_in;
struct dx_frame *ret_err = ERR_PTR(ERR_BAD_DX_DIR);
u32 hash; u32 hash;
frame->bh = NULL; frame->bh = ext4_read_dirblock(dir, 0, INDEX);
bh = ext4_read_dirblock(dir, 0, INDEX); if (IS_ERR(frame->bh))
if (IS_ERR(bh)) { return (struct dx_frame *) frame->bh;
*err = PTR_ERR(bh);
goto fail; root = (struct dx_root *) frame->bh->b_data;
}
root = (struct dx_root *) bh->b_data;
if (root->info.hash_version != DX_HASH_TEA && if (root->info.hash_version != DX_HASH_TEA &&
root->info.hash_version != DX_HASH_HALF_MD4 && root->info.hash_version != DX_HASH_HALF_MD4 &&
root->info.hash_version != DX_HASH_LEGACY) { root->info.hash_version != DX_HASH_LEGACY) {
ext4_warning(dir->i_sb, "Unrecognised inode hash code %d", ext4_warning(dir->i_sb, "Unrecognised inode hash code %d",
root->info.hash_version); root->info.hash_version);
brelse(bh);
*err = ERR_BAD_DX_DIR;
goto fail; goto fail;
} }
hinfo->hash_version = root->info.hash_version; hinfo->hash_version = root->info.hash_version;
@ -706,16 +701,12 @@ dx_probe(const struct qstr *d_name, struct inode *dir,
if (root->info.unused_flags & 1) { if (root->info.unused_flags & 1) {
ext4_warning(dir->i_sb, "Unimplemented inode hash flags: %#06x", ext4_warning(dir->i_sb, "Unimplemented inode hash flags: %#06x",
root->info.unused_flags); root->info.unused_flags);
brelse(bh);
*err = ERR_BAD_DX_DIR;
goto fail; goto fail;
} }
if ((indirect = root->info.indirect_levels) > 1) { if ((indirect = root->info.indirect_levels) > 1) {
ext4_warning(dir->i_sb, "Unimplemented inode hash depth: %#06x", ext4_warning(dir->i_sb, "Unimplemented inode hash depth: %#06x",
root->info.indirect_levels); root->info.indirect_levels);
brelse(bh);
*err = ERR_BAD_DX_DIR;
goto fail; goto fail;
} }
@ -725,27 +716,21 @@ dx_probe(const struct qstr *d_name, struct inode *dir,
if (dx_get_limit(entries) != dx_root_limit(dir, if (dx_get_limit(entries) != dx_root_limit(dir,
root->info.info_length)) { root->info.info_length)) {
ext4_warning(dir->i_sb, "dx entry: limit != root limit"); ext4_warning(dir->i_sb, "dx entry: limit != root limit");
brelse(bh);
*err = ERR_BAD_DX_DIR;
goto fail; goto fail;
} }
dxtrace(printk("Look up %x", hash)); dxtrace(printk("Look up %x", hash));
while (1) while (1) {
{
count = dx_get_count(entries); count = dx_get_count(entries);
if (!count || count > dx_get_limit(entries)) { if (!count || count > dx_get_limit(entries)) {
ext4_warning(dir->i_sb, ext4_warning(dir->i_sb,
"dx entry: no count or count > limit"); "dx entry: no count or count > limit");
brelse(bh); goto fail;
*err = ERR_BAD_DX_DIR;
goto fail2;
} }
p = entries + 1; p = entries + 1;
q = entries + count - 1; q = entries + count - 1;
while (p <= q) while (p <= q) {
{
m = p + (q - p)/2; m = p + (q - p)/2;
dxtrace(printk(".")); dxtrace(printk("."));
if (dx_get_hash(m) > hash) if (dx_get_hash(m) > hash)
@ -754,8 +739,7 @@ dx_probe(const struct qstr *d_name, struct inode *dir,
p = m + 1; p = m + 1;
} }
if (0) // linear search cross check if (0) { // linear search cross check
{
unsigned n = count - 1; unsigned n = count - 1;
at = entries; at = entries;
while (n--) while (n--)
@ -772,38 +756,35 @@ dx_probe(const struct qstr *d_name, struct inode *dir,
at = p - 1; at = p - 1;
dxtrace(printk(" %x->%u\n", at == entries? 0: dx_get_hash(at), dx_get_block(at))); dxtrace(printk(" %x->%u\n", at == entries? 0: dx_get_hash(at), dx_get_block(at)));
frame->bh = bh;
frame->entries = entries; frame->entries = entries;
frame->at = at; frame->at = at;
if (!indirect--) return frame; if (!indirect--)
bh = ext4_read_dirblock(dir, dx_get_block(at), INDEX); return frame;
if (IS_ERR(bh)) { frame++;
*err = PTR_ERR(bh); frame->bh = ext4_read_dirblock(dir, dx_get_block(at), INDEX);
goto fail2; if (IS_ERR(frame->bh)) {
ret_err = (struct dx_frame *) frame->bh;
frame->bh = NULL;
goto fail;
} }
entries = ((struct dx_node *) bh->b_data)->entries; entries = ((struct dx_node *) frame->bh->b_data)->entries;
if (dx_get_limit(entries) != dx_node_limit (dir)) { if (dx_get_limit(entries) != dx_node_limit (dir)) {
ext4_warning(dir->i_sb, ext4_warning(dir->i_sb,
"dx entry: limit != node limit"); "dx entry: limit != node limit");
brelse(bh); goto fail;
*err = ERR_BAD_DX_DIR;
goto fail2;
} }
frame++;
frame->bh = NULL;
} }
fail2: fail:
while (frame >= frame_in) { while (frame >= frame_in) {
brelse(frame->bh); brelse(frame->bh);
frame--; frame--;
} }
fail: if (ret_err == ERR_PTR(ERR_BAD_DX_DIR))
if (*err == ERR_BAD_DX_DIR)
ext4_warning(dir->i_sb, ext4_warning(dir->i_sb,
"Corrupt dir inode %lu, running e2fsck is " "Corrupt dir inode %lu, running e2fsck is "
"recommended.", dir->i_ino); "recommended.", dir->i_ino);
return NULL; return ret_err;
} }
static void dx_release (struct dx_frame *frames) static void dx_release (struct dx_frame *frames)
@ -989,9 +970,9 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
} }
hinfo.hash = start_hash; hinfo.hash = start_hash;
hinfo.minor_hash = 0; hinfo.minor_hash = 0;
frame = dx_probe(NULL, dir, &hinfo, frames, &err); frame = dx_probe(NULL, dir, &hinfo, frames);
if (!frame) if (IS_ERR(frame))
return err; return PTR_ERR(frame);
/* Add '.' and '..' from the htree header */ /* Add '.' and '..' from the htree header */
if (!start_hash && !start_minor_hash) { if (!start_hash && !start_minor_hash) {
@ -1369,11 +1350,11 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct q
struct dx_frame frames[2], *frame; struct dx_frame frames[2], *frame;
struct buffer_head *bh; struct buffer_head *bh;
ext4_lblk_t block; ext4_lblk_t block;
int err = 0, retval; int retval;
frame = dx_probe(d_name, dir, &hinfo, frames, &err); frame = dx_probe(d_name, dir, &hinfo, frames);
if (err) if (IS_ERR(frame))
return ERR_PTR(err); return (struct buffer_head *) frame;
do { do {
block = dx_get_block(frame->at); block = dx_get_block(frame->at);
bh = ext4_read_dirblock(dir, block, DIRENT); bh = ext4_read_dirblock(dir, block, DIRENT);
@ -1977,9 +1958,9 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
struct ext4_dir_entry_2 *de; struct ext4_dir_entry_2 *de;
int err; int err;
frame = dx_probe(&dentry->d_name, dir, &hinfo, frames, &err); frame = dx_probe(&dentry->d_name, dir, &hinfo, frames);
if (!frame) if (IS_ERR(frame))
return err; return PTR_ERR(frame);
entries = frame->entries; entries = frame->entries;
at = frame->at; at = frame->at;
bh = ext4_read_dirblock(dir, dx_get_block(frame->at), DIRENT); bh = ext4_read_dirblock(dir, dx_get_block(frame->at), DIRENT);