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

Reply via email to