chasing elusive "Trying to free free buffer"

Tigran Aivazian (tigran@sco.COM)
Thu, 21 Oct 1999 08:31:30 +0100 (BST)


Hi,

I am implementing link(2) method for BFS filesystem and I get "Trying to
free free buffer" each time I cross a block boundary when adding a new
directory entry. So, I instrumented __brelse() somewhat:

void __brelse(struct buffer_head * buf)
{
int *ret = &buf;
touch_buffer(buf);

if (atomic_read(&buf->b_count)) {
atomic_dec(&buf->b_count);
return;
}
printk("VFS: brelse: %08x is trying to free buffer %08lx (%x)\n",
ret[-1], (unsigned long)buf, buf->b_blocknr);
}

and get something like this:

VFS: brelse: f881cfe3 is trying to free buffer c38491e0 (b)

the address f881cfe3 probably lies within bfs.o's text section but I can't
verify it as /proc/ksyms doesn't show where the module is loaded (btw,
isn't *this* alone a bug? /proc/ksyms shows text/rodata addresses on my
machine at home i586 but not this one SMP/i686. and I don't have
modversions configured on both machines).

So, if anyone cares enough to take a look at the link/add_entry()
implementations to see what's wrong with them, here they are.

Thanks,
Tigran.

int bfs_add_entry(struct inode * dir, const char * name, int namelen, int
ino)
{
struct buffer_head * bh;
struct bfs_dirent * de;
int block, sblock, eblock, off;
kdev_t dev;
int i;

if (!namelen || !dir || !dir->i_sb)
return -ENOENT;
if (namelen > BFS_NAMELEN)
return -ENAMETOOLONG;

dev = dir->i_dev;
sblock = dir->iu_sblock;
eblock = dir->iu_eblock;
for (block=sblock; block<=eblock; block++) {
bh = bread(dev, block, BFS_BSIZE);
if(!bh)
return -ENOSPC;
for (off=0; off<BFS_BSIZE; off+=BFS_DIRENT_SIZE) {
de = (struct bfs_dirent *)(bh->b_data + off);
if (!de->ino) {
if ((block-sblock)*BFS_BSIZE + off >=
dir->i_size) {
dir->i_size += BFS_DIRENT_SIZE;
dir->i_ctime = CURRENT_TIME;
}
dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(dir);
dir->i_version = ++event;
de->ino = ino;
for (i=0; i<BFS_NAMELEN; i++)
de->name[i] = (i < namelen) ?
name[i] : 0;
mark_buffer_dirty(bh, 1);
brelse(bh);
return 0;
}
}
brelse(bh);
}
return -ENOSPC;
}

static int bfs_link(struct dentry * old, struct inode * dir, struct dentry
* new)
{
struct inode * inode = old->d_inode;
int err;

if (S_ISDIR(inode->i_mode))
return -EPERM;

err = bfs_add_entry(dir, new->d_name.name, new->d_name.len,
inode->i_ino);
if (err)
return err;
inode->i_nlink++;
inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
inode->i_count++;
d_instantiate(new, inode);
return 0;
}

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