[PATCH] fix reservation discarding in affs
- remove affs_put_inode, so preallocations aren't discared unnecessarily
often.
- remove affs_drop_inode, it's called with a spinlock held, so it can't
use a mutex.
- make i_opencnt atomic
- avoid direct b_count manipulations
- a few allocation failure fixes, so that these are more gracefully
handled now.
Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
diff --git a/fs/affs/file.c b/fs/affs/file.c
index 1a4f092..6eac7bd 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -48,8 +48,9 @@
{
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 +59,16 @@
{
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 +187,7 @@
/* 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 +313,7 @@
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 +331,6 @@
pr_debug("AFFS: get_block(%u, %lu)\n", (u32)inode->i_ino, (unsigned long)block);
-
BUG_ON(block > (sector_t)0x7fffffffUL);
if (block >= AFFS_I(inode)->i_blkcnt) {
@@ -827,6 +833,8 @@
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)
@@ -862,6 +870,7 @@
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;