Re: buffer layer error at fs/buffer.c:1166

Andrew Morton (akpm@digeo.com)
Tue, 05 Nov 2002 20:33:23 -0800


Jordan Breeding wrote:
>
> Hello,
>
> I get these errors while using 2.5.46-bk:
>
> VFS: brelse: Trying to free free buffer
> buffer layer error at fs/buffer.c:1166
> Pass this trace through ksymoops for reporting
> Call Trace:
> [<c01585b6>] __brelse+0x36/0x40
> [<c01587d7>] bh_lru_install+0xc7/0x100
> [<c0158875>] __find_get_block+0x65/0x70
> [<c0158443>] __getblk_slow+0x23/0x110
> [<c01588db>] __getblk+0x5b/0x70
> [<c01943a8>] ext3_getblk+0xa8/0x300
> [<c0194633>] ext3_bread+0x33/0xb0
> [<c0197c5f>] dx_probe+0x4f/0x310
> [<c0194633>] ext3_bread+0x33/0xb0
> [<c01980fd>] ext3_htree_fill_tree+0x9d/0x1d0

There is a refcounting problem somewhere in htree. Chris came uo
with the below patch. Does it fix it for you?

fs/ext3/namei.c | 50 ++++++++++++++++++++++++++++----------------------
1 files changed, 28 insertions(+), 22 deletions(-)

--- 25/fs/ext3/namei.c~htree-fix Tue Nov 5 18:48:52 2002
+++ 25-akpm/fs/ext3/namei.c Tue Nov 5 18:48:52 2002
@@ -880,18 +880,18 @@ static struct buffer_head * ext3_dx_find
top = (struct ext3_dir_entry_2 *) ((char *) de + sb->s_blocksize -
EXT3_DIR_REC_LEN(0));
for (; de < top; de = ext3_next_entry(de))
- if (ext3_match (namelen, name, de)) {
- if (!ext3_check_dir_entry("ext3_find_entry",
- dir, de, bh,
- (block<<EXT3_BLOCK_SIZE_BITS(sb))
- +((char *)de - bh->b_data))) {
- brelse (bh);
- goto errout;
+ if (ext3_match (namelen, name, de)) {
+ if (!ext3_check_dir_entry("ext3_find_entry",
+ dir, de, bh,
+ (block<<EXT3_BLOCK_SIZE_BITS(sb))
+ +((char *)de - bh->b_data))) {
+ brelse (bh);
+ goto errout;
+ }
+ *res_dir = de;
+ dx_release (frames);
+ return bh;
}
- *res_dir = de;
- dx_release (frames);
- return bh;
- }
brelse (bh);
/* Check to see if we should continue to search */
retval = ext3_htree_next_block(dir, hash, frame,
@@ -1129,7 +1129,7 @@ errout:
*/
static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
struct inode *inode, struct ext3_dir_entry_2 *de,
- struct buffer_head * bh)
+ struct buffer_head * bh, int *buffull)
{
struct inode *dir = dentry->d_parent->d_inode;
const char *name = dentry->d_name.name;
@@ -1160,8 +1160,11 @@ static int add_dirent_to_buf(handle_t *h
de = (struct ext3_dir_entry_2 *)((char *)de + rlen);
offset += rlen;
}
- if ((char *) de > top)
+ if ((char *) de > top) {
+ assert(buffull);
+ *buffull = 1;
return -ENOSPC;
+ }
}
BUFFER_TRACE(bh, "get_write_access");
err = ext3_journal_get_write_access(handle, bh);
@@ -1286,7 +1289,7 @@ static int make_indexed_dir(handle_t *ha
if (!(de))
return retval;

- return add_dirent_to_buf(handle, dentry, inode, de, bh);
+ return add_dirent_to_buf(handle, dentry, inode, de, bh, NULL);
}
#endif

@@ -1308,7 +1311,7 @@ static int ext3_add_entry (handle_t *han
struct buffer_head * bh;
struct ext3_dir_entry_2 *de;
struct super_block * sb;
- int retval;
+ int retval,buffull;
#ifdef CONFIG_EXT3_INDEX
int dx_fallback=0;
#endif
@@ -1335,8 +1338,10 @@ static int ext3_add_entry (handle_t *han
bh = ext3_bread(handle, dir, block, 0, &retval);
if(!bh)
return retval;
- retval = add_dirent_to_buf(handle, dentry, inode, 0, bh);
- if (retval != -ENOSPC)
+ buffull = 0;
+ retval = add_dirent_to_buf(handle, dentry, inode, 0, bh,
+ &buffull);
+ if (!buffull)
return retval;

#ifdef CONFIG_EXT3_INDEX
@@ -1353,7 +1358,7 @@ static int ext3_add_entry (handle_t *han
de->inode = 0;
de->rec_len = cpu_to_le16(rlen = blocksize);
nlen = 0;
- return add_dirent_to_buf(handle, dentry, inode, de, bh);
+ return add_dirent_to_buf(handle, dentry, inode, de, bh, NULL);
}

#ifdef CONFIG_EXT3_INDEX
@@ -1370,7 +1375,7 @@ static int ext3_dx_add_entry(handle_t *h
struct inode *dir = dentry->d_parent->d_inode;
struct super_block * sb = dir->i_sb;
struct ext3_dir_entry_2 *de;
- int err;
+ int err,buffull;

frame = dx_probe(dentry, 0, &hinfo, frames, &err);
if (!frame)
@@ -1386,8 +1391,9 @@ static int ext3_dx_add_entry(handle_t *h
if (err)
goto journal_error;

- err = add_dirent_to_buf(handle, dentry, inode, 0, bh);
- if (err != -ENOSPC) {
+ buffull = 0;
+ err = add_dirent_to_buf(handle, dentry, inode, 0, bh, &buffull);
+ if (!buffull) {
bh = 0;
goto cleanup;
}
@@ -1479,7 +1485,7 @@ static int ext3_dx_add_entry(handle_t *h
de = do_split(handle, dir, &bh, frame, &hinfo, &err);
if (!de)
goto cleanup;
- err = add_dirent_to_buf(handle, dentry, inode, de, bh);
+ err = add_dirent_to_buf(handle, dentry, inode, de, bh, NULL);
bh = 0;
goto cleanup;

_
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/