ocfs2: Wrap dirblock reads in a dedicated function.

We have ocfs2_bread() as a vestige of the original ext-based dir code.
It's only used by directories, though.  Turn it into
ocfs2_read_dir_block(), with a prototype matching the other metadata
read functions.  It's set up to validate dirblocks when the time comes.

Signed-off-by: Joel Becker <joel.becker@oracle.com>
Signed-off-by: Mark Fasheh <mfasheh@suse.com>
This commit is contained in:
Joel Becker 2008-11-13 14:49:17 -08:00 committed by Mark Fasheh
parent 5e96581a37
commit a22305cc69
1 changed files with 88 additions and 62 deletions

View File

@ -82,49 +82,6 @@ static int ocfs2_do_extend_dir(struct super_block *sb,
struct ocfs2_alloc_context *meta_ac,
struct buffer_head **new_bh);
static struct buffer_head *ocfs2_bread(struct inode *inode,
int block, int *err, int reada)
{
struct buffer_head *bh = NULL;
int tmperr;
u64 p_blkno;
int readflags = 0;
if (reada)
readflags |= OCFS2_BH_READAHEAD;
if (((u64)block << inode->i_sb->s_blocksize_bits) >=
i_size_read(inode)) {
BUG_ON(!reada);
return NULL;
}
down_read(&OCFS2_I(inode)->ip_alloc_sem);
tmperr = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL,
NULL);
up_read(&OCFS2_I(inode)->ip_alloc_sem);
if (tmperr < 0) {
mlog_errno(tmperr);
goto fail;
}
tmperr = ocfs2_read_blocks(inode, p_blkno, 1, &bh, readflags);
if (tmperr < 0)
goto fail;
tmperr = 0;
*err = 0;
return bh;
fail:
brelse(bh);
bh = NULL;
*err = -EIO;
return NULL;
}
/*
* bh passed here can be an inode block or a dir data block, depending
* on the inode inline data flag.
@ -250,6 +207,76 @@ out:
return NULL;
}
static int ocfs2_validate_dir_block(struct super_block *sb,
struct buffer_head *bh)
{
/*
* Nothing yet. We don't validate dirents here, that's handled
* in-place when the code walks them.
*/
return 0;
}
/*
* This function forces all errors to -EIO for consistency with its
* predecessor, ocfs2_bread(). We haven't audited what returning the
* real error codes would do to callers. We log the real codes with
* mlog_errno() before we squash them.
*/
static int ocfs2_read_dir_block(struct inode *inode, u64 v_block,
struct buffer_head **bh, int flags)
{
int rc = 0;
struct buffer_head *tmp = *bh;
u64 p_blkno;
if (((u64)v_block << inode->i_sb->s_blocksize_bits) >=
i_size_read(inode)) {
BUG_ON(!(flags & OCFS2_BH_READAHEAD));
goto out;
}
down_read(&OCFS2_I(inode)->ip_alloc_sem);
rc = ocfs2_extent_map_get_blocks(inode, v_block, &p_blkno, NULL,
NULL);
up_read(&OCFS2_I(inode)->ip_alloc_sem);
if (rc) {
mlog_errno(rc);
goto out;
}
if (!p_blkno) {
rc = -EIO;
mlog(ML_ERROR,
"Directory #%llu contains a hole at offset %llu\n",
(unsigned long long)OCFS2_I(inode)->ip_blkno,
(unsigned long long)v_block << inode->i_sb->s_blocksize_bits);
goto out;
}
rc = ocfs2_read_blocks(inode, p_blkno, 1, &tmp, flags);
if (rc) {
mlog_errno(rc);
goto out;
}
if (!(flags & OCFS2_BH_READAHEAD)) {
rc = ocfs2_validate_dir_block(inode->i_sb, tmp);
if (rc) {
brelse(tmp);
goto out;
}
}
/* If ocfs2_read_blocks() got us a new bh, pass it up. */
if (!*bh)
*bh = tmp;
out:
return rc ? -EIO : 0;
}
static struct buffer_head *ocfs2_find_entry_el(const char *name, int namelen,
struct inode *dir,
struct ocfs2_dir_entry **res_dir)
@ -296,15 +323,17 @@ restart:
}
num++;
bh = ocfs2_bread(dir, b++, &err, 1);
bh = NULL;
err = ocfs2_read_dir_block(dir, b++, &bh,
OCFS2_BH_READAHEAD);
bh_use[ra_max] = bh;
}
}
if ((bh = bh_use[ra_ptr++]) == NULL)
goto next;
if (ocfs2_read_block(dir, block, &bh)) {
if (ocfs2_read_dir_block(dir, block, &bh, 0)) {
/* read error, skip block & hope for the best.
* ocfs2_read_block() has released the bh. */
* ocfs2_read_dir_block() has released the bh. */
ocfs2_error(dir->i_sb, "reading directory %llu, "
"offset %lu\n",
(unsigned long long)OCFS2_I(dir)->ip_blkno,
@ -724,7 +753,6 @@ static int ocfs2_dir_foreach_blk_el(struct inode *inode,
int i, stored;
struct buffer_head * bh, * tmp;
struct ocfs2_dir_entry * de;
int err;
struct super_block * sb = inode->i_sb;
unsigned int ra_sectors = 16;
@ -735,12 +763,8 @@ static int ocfs2_dir_foreach_blk_el(struct inode *inode,
while (!error && !stored && *f_pos < i_size_read(inode)) {
blk = (*f_pos) >> sb->s_blocksize_bits;
bh = ocfs2_bread(inode, blk, &err, 0);
if (!bh) {
mlog(ML_ERROR,
"directory #%llu contains a hole at offset %lld\n",
(unsigned long long)OCFS2_I(inode)->ip_blkno,
*f_pos);
if (ocfs2_read_dir_block(inode, blk, &bh, 0)) {
/* Skip the corrupt dirblock and keep trying */
*f_pos += sb->s_blocksize - offset;
continue;
}
@ -754,8 +778,10 @@ static int ocfs2_dir_foreach_blk_el(struct inode *inode,
|| (((last_ra_blk - blk) << 9) <= (ra_sectors / 2))) {
for (i = ra_sectors >> (sb->s_blocksize_bits - 9);
i > 0; i--) {
tmp = ocfs2_bread(inode, ++blk, &err, 1);
brelse(tmp);
tmp = NULL;
if (!ocfs2_read_dir_block(inode, ++blk, &tmp,
OCFS2_BH_READAHEAD))
brelse(tmp);
}
last_ra_blk = blk;
ra_sectors = 8;
@ -828,6 +854,7 @@ revalidate:
}
offset = 0;
brelse(bh);
bh = NULL;
}
stored = 0;
@ -1680,8 +1707,8 @@ static int ocfs2_find_dir_space_el(struct inode *dir, const char *name,
struct super_block *sb = dir->i_sb;
int status;
bh = ocfs2_bread(dir, 0, &status, 0);
if (!bh) {
status = ocfs2_read_dir_block(dir, 0, &bh, 0);
if (status) {
mlog_errno(status);
goto bail;
}
@ -1702,11 +1729,10 @@ static int ocfs2_find_dir_space_el(struct inode *dir, const char *name,
status = -ENOSPC;
goto bail;
}
bh = ocfs2_bread(dir,
offset >> sb->s_blocksize_bits,
&status,
0);
if (!bh) {
status = ocfs2_read_dir_block(dir,
offset >> sb->s_blocksize_bits,
&bh, 0);
if (status) {
mlog_errno(status);
goto bail;
}