Hi,
On Thu, 7 Feb 2008, Christoph Hellwig wrote:
> Then affs doesn't really survive fsstress from ltp very well. The first
> lockdep warning I got is from my implement drop_inode patch but even
> with that things look quite bad, with both lockdep warnings
> and lots of 'VFS: brelse: Trying to free free buffer' with following
> stack trace.
>
> Any idea how to proceed with affs?
With the patch below on top of yours, affs will survive a little longer.
There were a few problems with recovering from allocation failures (and
there are probably a few left).
bye, Roman
Index: linux/fs/affs/affs.h
===================================================================
--- linux.orig/fs/affs/affs.h
+++ linux/fs/affs/affs.h
@@ -48,7 +48,7 @@ struct affs_ext_key {
* affs fs inode data in memory
*/
struct affs_inode_info {
- u32 i_opencnt;
+ atomic_t i_opencnt;
struct semaphore i_link_lock; /* Protects internal inode
access. */
struct semaphore i_ext_lock; /* Protects internal inode
access. */
#define i_hash_lock i_ext_lock
@@ -170,7 +170,6 @@ extern int affs_rename(struct inode *old
extern unsigned long affs_parent_ino(struct inode *dir);
extern struct inode *affs_new_inode(struct inode *dir);
extern int affs_notify_change(struct dentry *dentry,
struct iattr *attr);
-extern void affs_drop_inode(struct inode *inode);
extern void affs_delete_inode(struct inode *inode);
extern void affs_clear_inode(struct inode *inode);
extern void affs_read_inode(struct inode *inode);
Index: linux/fs/affs/file.c
===================================================================
--- linux.orig/fs/affs/file.c
+++ linux/fs/affs/file.c
@@ -48,8 +48,8 @@ affs_file_open(struct inode *inode, stru
{
if (atomic_read(&filp->f_count) != 1)
return 0;
- pr_debug("AFFS: open(%d)\n", AFFS_I(inode)->i_opencnt);
- AFFS_I(inode)->i_opencnt++;
+ pr_debug("AFFS: open(%lu,%d)\n", inode->i_ino,
atomic_read(&AFFS_I(inode)->i_opencnt));
+ atomic_inc(&AFFS_I(inode)->i_opencnt);
return 0;
}
@@ -58,10 +58,14 @@ affs_file_release(struct inode *inode, s
{
if (atomic_read(&filp->f_count) != 0)
return 0;
- pr_debug("AFFS: release(%d)\n", AFFS_I(inode)->i_opencnt);
- AFFS_I(inode)->i_opencnt--;
- if (!AFFS_I(inode)->i_opencnt)
+ pr_debug("AFFS: release(%lu, %d)\n", inode->i_ino,
atomic_read(&AFFS_I(inode)->i_opencnt));
+ if (atomic_dec_and_test(&AFFS_I(inode)->i_opencnt)) {
+ mutex_lock(&inode->i_mutex);
+ if (inode->i_size != AFFS_I(inode)->mmu_private)
+ affs_truncate(inode);
affs_free_prealloc(inode);
+ mutex_unlock(&inode->i_mutex);
+ }
return 0;
}
@@ -180,7 +184,7 @@ affs_get_extblock(struct inode *inode, u
/* inline the simplest case: same extended block as last time */
struct buffer_head *bh = AFFS_I(inode)->i_ext_bh;
if (ext == AFFS_I(inode)->i_ext_last)
- atomic_inc(&bh->b_count);
+ get_bh(bh);
else
/* we have to do more (not inlined) */
bh = affs_get_extblock_slow(inode, ext);
@@ -306,7 +310,7 @@ store_ext:
affs_brelse(AFFS_I(inode)->i_ext_bh);
AFFS_I(inode)->i_ext_last = ext;
AFFS_I(inode)->i_ext_bh = bh;
- atomic_inc(&bh->b_count);
+ get_bh(bh);
return bh;
@@ -324,7 +328,6 @@ affs_get_block(struct inode *inode, sect
pr_debug("AFFS: get_block(%u, %lu)\n", (u32)inode->i_ino, (unsigned
long)block);
-
if (block > (sector_t)0x7fffffffUL)
BUG();
@@ -834,6 +837,8 @@ affs_truncate(struct inode *inode)
res = mapping->a_ops->write_begin(NULL, mapping, size, 0, 0,
&page, &fsdata);
if (!res)
res = mapping->a_ops->write_end(NULL, mapping, size, 0,
0, page, fsdata);
+ else
+ inode->i_size = AFFS_I(inode)->mmu_private;
mark_inode_dirty(inode);
return;
} else if (inode->i_size == AFFS_I(inode)->mmu_private)
@@ -869,6 +874,7 @@ affs_truncate(struct inode *inode)
blk++;
} else
AFFS_HEAD(ext_bh)->first_data = 0;
+ AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(i);
size = AFFS_SB(sb)->s_hashsize;
if (size > blkcnt - blk + i)
size = blkcnt - blk + i;
Index: linux/fs/affs/inode.c
===================================================================
--- linux.orig/fs/affs/inode.c
+++ linux/fs/affs/inode.c
@@ -53,7 +53,7 @@ affs_read_inode(struct inode *inode)
AFFS_I(inode)->i_extcnt = 1;
AFFS_I(inode)->i_ext_last = ~1;
AFFS_I(inode)->i_protect = prot;
- AFFS_I(inode)->i_opencnt = 0;
+ atomic_set(&AFFS_I(inode)->i_opencnt, 0);
AFFS_I(inode)->i_blkcnt = 0;
AFFS_I(inode)->i_lc = NULL;
AFFS_I(inode)->i_lc_size = 0;
@@ -103,8 +103,6 @@ affs_read_inode(struct inode *inode)
inode->i_mode |= S_IFDIR;
} else
inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR;
- if (tail->link_chain)
- inode->i_nlink = 2;
/* Maybe it should be controlled by mount parameter? */
//inode->i_mode |= S_ISVTX;
inode->i_op = &affs_dir_inode_operations;
@@ -239,26 +237,12 @@ out:
}
void
-affs_drop_inode(struct inode *inode)
-{
- affs_free_prealloc(inode);
-
- mutex_lock(&inode->i_mutex);
- if (inode->i_size != AFFS_I(inode)->mmu_private)
- affs_truncate(inode);
- mutex_unlock(&inode->i_mutex);
-
- generic_drop_inode(inode);
-}
-
-void
affs_delete_inode(struct inode *inode)
{
pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n", inode->i_ino,
inode->i_nlink);
truncate_inode_pages(&inode->i_data, 0);
inode->i_size = 0;
- if (S_ISREG(inode->i_mode))
- affs_truncate(inode);
+ affs_truncate(inode);
clear_inode(inode);
affs_free_block(inode->i_sb, inode->i_ino);
}
@@ -266,9 +250,12 @@ affs_delete_inode(struct inode *inode)
void
affs_clear_inode(struct inode *inode)
{
- unsigned long cache_page = (unsigned long) AFFS_I(inode)->i_lc;
+ unsigned long cache_page;
pr_debug("AFFS: clear_inode(ino=%lu, nlink=%u)\n", inode->i_ino,
inode->i_nlink);
+
+ affs_free_prealloc(inode);
+ cache_page = (unsigned long)AFFS_I(inode)->i_lc;
if (cache_page) {
pr_debug("AFFS: freeing ext cache\n");
AFFS_I(inode)->i_lc = NULL;
@@ -305,7 +292,7 @@ affs_new_inode(struct inode *dir)
inode->i_ino = block;
inode->i_nlink = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
- AFFS_I(inode)->i_opencnt = 0;
+ atomic_set(&AFFS_I(inode)->i_opencnt, 0);
AFFS_I(inode)->i_blkcnt = 0;
AFFS_I(inode)->i_lc = NULL;
AFFS_I(inode)->i_lc_size = 0;
@@ -358,12 +345,12 @@ affs_add_entry(struct inode *dir, struct
switch (type) {
case ST_LINKFILE:
case ST_LINKDIR:
- inode_bh = bh;
retval = -ENOSPC;
block = affs_alloc_block(dir, dir->i_ino);
if (!block)
goto err;
retval = -EIO;
+ inode_bh = bh;
bh = affs_getzeroblk(sb, block);
if (!bh)
goto err;
Index: linux/fs/affs/namei.c
===================================================================
--- linux.orig/fs/affs/namei.c
+++ linux/fs/affs/namei.c
@@ -236,7 +236,8 @@ affs_lookup(struct inode *dir, struct de
int
affs_unlink(struct inode *dir, struct dentry *dentry)
{
- pr_debug("AFFS: unlink(dir=%d, \"%.*s\")\n", (u32)dir->i_ino,
+ pr_debug("AFFS: unlink(dir=%d, %lu \"%.*s\")\n", (u32)dir->i_ino,
+ dentry->d_inode->i_ino,
(int)dentry->d_name.len, dentry->d_name.name);
return affs_remove_header(dentry);
@@ -304,7 +305,8 @@ affs_mkdir(struct inode *dir, struct den
int
affs_rmdir(struct inode *dir, struct dentry *dentry)
{
- pr_debug("AFFS: rmdir(dir=%u, \"%.*s\")\n", (u32)dir->i_ino,
+ pr_debug("AFFS: rmdir(dir=%u, %lu \"%.*s\")\n", (u32)dir->i_ino,
+ dentry->d_inode->i_ino,
(int)dentry->d_name.len, dentry->d_name.name);
return affs_remove_header(dentry);
Index: linux/fs/affs/super.c
===================================================================
--- linux.orig/fs/affs/super.c
+++ linux/fs/affs/super.c
@@ -71,12 +71,18 @@ static struct kmem_cache * affs_inode_ca
static struct inode *affs_alloc_inode(struct super_block *sb)
{
- struct affs_inode_info *ei;
- ei = (struct affs_inode_info *)kmem_cache_alloc(affs_inode_cachep,
GFP_KERNEL);
- if (!ei)
+ struct affs_inode_info *i;
+
+ i = (struct affs_inode_info *)kmem_cache_alloc(affs_inode_cachep,
GFP_KERNEL);
+ if (!i)
return NULL;
- ei->vfs_inode.i_version = 1;
- return &ei->vfs_inode;
+
+ i->vfs_inode.i_version = 1;
+ i->i_lc = NULL;
+ i->i_ext_bh = NULL;
+ i->i_pa_cnt = 0;
+
+ return &i->vfs_inode;
}
static void affs_destroy_inode(struct inode *inode)
@@ -115,7 +121,6 @@ static const struct super_operations aff
.destroy_inode = affs_destroy_inode,
.read_inode = affs_read_inode,
.write_inode = affs_write_inode,
- .drop_inode = affs_drop_inode,
.delete_inode = affs_delete_inode,
.clear_inode = affs_clear_inode,
.put_super = affs_put_super,
-
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html