Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dca3c336 authored by Roman Zippel's avatar Roman Zippel Committed by Al Viro
Browse files

[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: default avatarRoman Zippel <zippel@linux-m68k.org>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent a1530636
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -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,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 struct inode		*affs_new_inode(struct inode *dir);
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_clear_inode(struct inode *inode);
extern struct inode		*affs_iget(struct super_block *sb,
+17 −8
Original line number Diff line number Diff line
@@ -48,8 +48,9 @@ affs_file_open(struct inode *inode, struct file *filp)
{
	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 @@ affs_file_release(struct inode *inode, struct file *filp)
{
	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 @@ affs_get_extblock(struct inode *inode, u32 ext)
	/* 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 @@ 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 +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);


	BUG_ON(block > (sector_t)0x7fffffffUL);

	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);
		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 @@ 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;
+8 −26
Original line number Diff line number Diff line
@@ -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_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;
@@ -108,8 +108,6 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino)
			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;
@@ -244,31 +242,12 @@ out:
	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
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);
	clear_inode(inode);
	affs_free_block(inode->i_sb, inode->i_ino);
@@ -277,9 +256,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;
@@ -316,7 +298,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;
@@ -369,12 +351,12 @@ affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s3
	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;
+4 −2
Original line number Diff line number Diff line
@@ -234,7 +234,8 @@ affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
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);
@@ -302,7 +303,8 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
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);
+11 −7
Original line number Diff line number Diff line
@@ -71,12 +71,18 @@ static struct kmem_cache * affs_inode_cachep;

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 = 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)
@@ -114,8 +120,6 @@ static const struct super_operations affs_sops = {
	.alloc_inode	= affs_alloc_inode,
	.destroy_inode	= affs_destroy_inode,
	.write_inode	= affs_write_inode,
	.put_inode	= affs_put_inode,
	.drop_inode	= affs_drop_inode,
	.delete_inode	= affs_delete_inode,
	.clear_inode	= affs_clear_inode,
	.put_super	= affs_put_super,