[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>
This commit is contained in:
Roman Zippel 2008-04-29 17:02:20 +02:00 committed by Al Viro
parent a15306365a
commit dca3c33652
5 changed files with 41 additions and 46 deletions

View file

@ -48,7 +48,7 @@ struct affs_ext_key {
* affs fs inode data in memory * affs fs inode data in memory
*/ */
struct affs_inode_info { struct affs_inode_info {
u32 i_opencnt; atomic_t i_opencnt;
struct semaphore i_link_lock; /* Protects internal inode access. */ struct semaphore i_link_lock; /* Protects internal inode access. */
struct semaphore i_ext_lock; /* Protects internal inode access. */ struct semaphore i_ext_lock; /* Protects internal inode access. */
#define i_hash_lock i_ext_lock #define i_hash_lock i_ext_lock
@ -170,8 +170,6 @@ extern int affs_rename(struct inode *old_dir, struct dentry *old_dentry,
extern unsigned long affs_parent_ino(struct inode *dir); extern unsigned long affs_parent_ino(struct inode *dir);
extern struct inode *affs_new_inode(struct inode *dir); extern struct inode *affs_new_inode(struct inode *dir);
extern int affs_notify_change(struct dentry *dentry, struct iattr *attr); extern int affs_notify_change(struct dentry *dentry, struct iattr *attr);
extern void affs_put_inode(struct inode *inode);
extern void affs_drop_inode(struct inode *inode);
extern void affs_delete_inode(struct inode *inode); extern void affs_delete_inode(struct inode *inode);
extern void affs_clear_inode(struct inode *inode); extern void affs_clear_inode(struct inode *inode);
extern struct inode *affs_iget(struct super_block *sb, extern struct inode *affs_iget(struct super_block *sb,

View file

@ -48,8 +48,9 @@ affs_file_open(struct inode *inode, struct file *filp)
{ {
if (atomic_read(&filp->f_count) != 1) if (atomic_read(&filp->f_count) != 1)
return 0; return 0;
pr_debug("AFFS: open(%d)\n", AFFS_I(inode)->i_opencnt); pr_debug("AFFS: open(%lu,%d)\n",
AFFS_I(inode)->i_opencnt++; inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt));
atomic_inc(&AFFS_I(inode)->i_opencnt);
return 0; return 0;
} }
@ -58,10 +59,16 @@ affs_file_release(struct inode *inode, struct file *filp)
{ {
if (atomic_read(&filp->f_count) != 0) if (atomic_read(&filp->f_count) != 0)
return 0; return 0;
pr_debug("AFFS: release(%d)\n", AFFS_I(inode)->i_opencnt); pr_debug("AFFS: release(%lu, %d)\n",
AFFS_I(inode)->i_opencnt--; inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt));
if (!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); affs_free_prealloc(inode);
mutex_unlock(&inode->i_mutex);
}
return 0; return 0;
} }
@ -180,7 +187,7 @@ affs_get_extblock(struct inode *inode, u32 ext)
/* inline the simplest case: same extended block as last time */ /* inline the simplest case: same extended block as last time */
struct buffer_head *bh = AFFS_I(inode)->i_ext_bh; struct buffer_head *bh = AFFS_I(inode)->i_ext_bh;
if (ext == AFFS_I(inode)->i_ext_last) if (ext == AFFS_I(inode)->i_ext_last)
atomic_inc(&bh->b_count); get_bh(bh);
else else
/* we have to do more (not inlined) */ /* we have to do more (not inlined) */
bh = affs_get_extblock_slow(inode, ext); bh = affs_get_extblock_slow(inode, ext);
@ -306,7 +313,7 @@ affs_get_extblock_slow(struct inode *inode, u32 ext)
affs_brelse(AFFS_I(inode)->i_ext_bh); affs_brelse(AFFS_I(inode)->i_ext_bh);
AFFS_I(inode)->i_ext_last = ext; AFFS_I(inode)->i_ext_last = ext;
AFFS_I(inode)->i_ext_bh = bh; AFFS_I(inode)->i_ext_bh = bh;
atomic_inc(&bh->b_count); get_bh(bh);
return bh; return bh;
@ -324,7 +331,6 @@ affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_resul
pr_debug("AFFS: get_block(%u, %lu)\n", (u32)inode->i_ino, (unsigned long)block); pr_debug("AFFS: get_block(%u, %lu)\n", (u32)inode->i_ino, (unsigned long)block);
BUG_ON(block > (sector_t)0x7fffffffUL); BUG_ON(block > (sector_t)0x7fffffffUL);
if (block >= AFFS_I(inode)->i_blkcnt) { if (block >= AFFS_I(inode)->i_blkcnt) {
@ -827,6 +833,8 @@ affs_truncate(struct inode *inode)
res = mapping->a_ops->write_begin(NULL, mapping, size, 0, 0, &page, &fsdata); res = mapping->a_ops->write_begin(NULL, mapping, size, 0, 0, &page, &fsdata);
if (!res) if (!res)
res = mapping->a_ops->write_end(NULL, mapping, size, 0, 0, page, fsdata); 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); mark_inode_dirty(inode);
return; return;
} else if (inode->i_size == AFFS_I(inode)->mmu_private) } else if (inode->i_size == AFFS_I(inode)->mmu_private)
@ -862,6 +870,7 @@ affs_truncate(struct inode *inode)
blk++; blk++;
} else } else
AFFS_HEAD(ext_bh)->first_data = 0; AFFS_HEAD(ext_bh)->first_data = 0;
AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(i);
size = AFFS_SB(sb)->s_hashsize; size = AFFS_SB(sb)->s_hashsize;
if (size > blkcnt - blk + i) if (size > blkcnt - blk + i)
size = blkcnt - blk + i; size = blkcnt - blk + i;

View file

@ -58,7 +58,7 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino)
AFFS_I(inode)->i_extcnt = 1; AFFS_I(inode)->i_extcnt = 1;
AFFS_I(inode)->i_ext_last = ~1; AFFS_I(inode)->i_ext_last = ~1;
AFFS_I(inode)->i_protect = prot; 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_blkcnt = 0;
AFFS_I(inode)->i_lc = NULL; AFFS_I(inode)->i_lc = NULL;
AFFS_I(inode)->i_lc_size = 0; AFFS_I(inode)->i_lc_size = 0;
@ -108,8 +108,6 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino)
inode->i_mode |= S_IFDIR; inode->i_mode |= S_IFDIR;
} else } else
inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR; 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? */ /* Maybe it should be controlled by mount parameter? */
//inode->i_mode |= S_ISVTX; //inode->i_mode |= S_ISVTX;
inode->i_op = &affs_dir_inode_operations; inode->i_op = &affs_dir_inode_operations;
@ -244,32 +242,13 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr)
return error; return error;
} }
void
affs_put_inode(struct inode *inode)
{
pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
affs_free_prealloc(inode);
}
void
affs_drop_inode(struct inode *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 void
affs_delete_inode(struct inode *inode) affs_delete_inode(struct inode *inode)
{ {
pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
truncate_inode_pages(&inode->i_data, 0); truncate_inode_pages(&inode->i_data, 0);
inode->i_size = 0; inode->i_size = 0;
if (S_ISREG(inode->i_mode)) affs_truncate(inode);
affs_truncate(inode);
clear_inode(inode); clear_inode(inode);
affs_free_block(inode->i_sb, inode->i_ino); affs_free_block(inode->i_sb, inode->i_ino);
} }
@ -277,9 +256,12 @@ affs_delete_inode(struct inode *inode)
void void
affs_clear_inode(struct inode *inode) 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); 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) { if (cache_page) {
pr_debug("AFFS: freeing ext cache\n"); pr_debug("AFFS: freeing ext cache\n");
AFFS_I(inode)->i_lc = NULL; AFFS_I(inode)->i_lc = NULL;
@ -316,7 +298,7 @@ affs_new_inode(struct inode *dir)
inode->i_ino = block; inode->i_ino = block;
inode->i_nlink = 1; inode->i_nlink = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; 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_blkcnt = 0;
AFFS_I(inode)->i_lc = NULL; AFFS_I(inode)->i_lc = NULL;
AFFS_I(inode)->i_lc_size = 0; AFFS_I(inode)->i_lc_size = 0;
@ -369,12 +351,12 @@ affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s3
switch (type) { switch (type) {
case ST_LINKFILE: case ST_LINKFILE:
case ST_LINKDIR: case ST_LINKDIR:
inode_bh = bh;
retval = -ENOSPC; retval = -ENOSPC;
block = affs_alloc_block(dir, dir->i_ino); block = affs_alloc_block(dir, dir->i_ino);
if (!block) if (!block)
goto err; goto err;
retval = -EIO; retval = -EIO;
inode_bh = bh;
bh = affs_getzeroblk(sb, block); bh = affs_getzeroblk(sb, block);
if (!bh) if (!bh)
goto err; goto err;

View file

@ -234,7 +234,8 @@ affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
int int
affs_unlink(struct inode *dir, struct dentry *dentry) 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); (int)dentry->d_name.len, dentry->d_name.name);
return affs_remove_header(dentry); return affs_remove_header(dentry);
@ -302,7 +303,8 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
int int
affs_rmdir(struct inode *dir, struct dentry *dentry) 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); (int)dentry->d_name.len, dentry->d_name.name);
return affs_remove_header(dentry); return affs_remove_header(dentry);

View file

@ -71,12 +71,18 @@ static struct kmem_cache * affs_inode_cachep;
static struct inode *affs_alloc_inode(struct super_block *sb) static struct inode *affs_alloc_inode(struct super_block *sb)
{ {
struct affs_inode_info *ei; struct affs_inode_info *i;
ei = (struct affs_inode_info *)kmem_cache_alloc(affs_inode_cachep, GFP_KERNEL);
if (!ei) i = kmem_cache_alloc(affs_inode_cachep, GFP_KERNEL);
if (!i)
return NULL; 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) static void affs_destroy_inode(struct inode *inode)
@ -114,8 +120,6 @@ static const struct super_operations affs_sops = {
.alloc_inode = affs_alloc_inode, .alloc_inode = affs_alloc_inode,
.destroy_inode = affs_destroy_inode, .destroy_inode = affs_destroy_inode,
.write_inode = affs_write_inode, .write_inode = affs_write_inode,
.put_inode = affs_put_inode,
.drop_inode = affs_drop_inode,
.delete_inode = affs_delete_inode, .delete_inode = affs_delete_inode,
.clear_inode = affs_clear_inode, .clear_inode = affs_clear_inode,
.put_super = affs_put_super, .put_super = affs_put_super,