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

Commit 47420c79 authored by Ryusuke Konishi's avatar Ryusuke Konishi Committed by Linus Torvalds
Browse files

nilfs2: avoid double error caused by nilfs_transaction_end



Pekka Enberg pointed out that double error handlings found after
nilfs_transaction_end() can be avoided by separating abort operation:

 OK, I don't understand this. The only way nilfs_transaction_end() can
 fail is if we have NILFS_TI_SYNC set and we fail to construct the
 segment. But why do we want to construct a segment if we don't commit?

 I guess what I'm asking is why don't we have a separate
 nilfs_transaction_abort() function that can't fail for the erroneous
 case to avoid this double error value tracking thing?

This does the separation and renames nilfs_transaction_end() to
nilfs_transaction_commit() for clarification.

Since, some calls of these functions were used just for exclusion control
against the segment constructor, they are replaced with semaphore
operations.

Acked-by: default avatarPekka Enberg <penberg@cs.helsinki.fi>
Signed-off-by: default avatarRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent a2e7d2df
Loading
Loading
Loading
Loading
+14 −9
Original line number Diff line number Diff line
@@ -77,7 +77,6 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff,
			goto out;
		err = nilfs_bmap_insert(ii->i_bmap, (unsigned long)blkoff,
					(unsigned long)bh_result);
		nilfs_transaction_end(inode->i_sb, !err);
		if (unlikely(err != 0)) {
			if (err == -EEXIST) {
				/*
@@ -100,8 +99,10 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff,
					    inode->i_ino);
				err = -EIO;
			}
			nilfs_transaction_abort(inode->i_sb);
			goto out;
		}
		nilfs_transaction_commit(inode->i_sb); /* never fails */
		/* Error handling should be detailed */
		set_buffer_new(bh_result);
		map_bh(bh_result, inode->i_sb, 0); /* dbn must be changed
@@ -203,7 +204,7 @@ static int nilfs_write_begin(struct file *file, struct address_space *mapping,
	err = block_write_begin(file, mapping, pos, len, flags, pagep,
				fsdata, nilfs_get_block);
	if (unlikely(err))
		nilfs_transaction_end(inode->i_sb, 0);
		nilfs_transaction_abort(inode->i_sb);
	return err;
}

@@ -221,7 +222,7 @@ static int nilfs_write_end(struct file *file, struct address_space *mapping,
	copied = generic_write_end(file, mapping, pos, len, copied, page,
				   fsdata);
	nilfs_set_file_dirty(NILFS_SB(inode->i_sb), inode, nr_dirty);
	err = nilfs_transaction_end(inode->i_sb, 1);
	err = nilfs_transaction_commit(inode->i_sb);
	return err ? : copied;
}

@@ -641,7 +642,7 @@ void nilfs_truncate(struct inode *inode)
		nilfs_set_transaction_flag(NILFS_TI_SYNC);

	nilfs_set_file_dirty(NILFS_SB(sb), inode, 0);
	nilfs_transaction_end(sb, 1);
	nilfs_transaction_commit(sb);
	/* May construct a logical segment and may fail in sync mode.
	   But truncate has no return value. */
}
@@ -669,7 +670,7 @@ void nilfs_delete_inode(struct inode *inode)
	/* nilfs_free_inode() marks inode buffer dirty */
	if (IS_SYNC(inode))
		nilfs_set_transaction_flag(NILFS_TI_SYNC);
	nilfs_transaction_end(sb, 1);
	nilfs_transaction_commit(sb);
	/* May construct a logical segment and may fail in sync mode.
	   But delete_inode has no return value. */
}
@@ -679,7 +680,7 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr)
	struct nilfs_transaction_info ti;
	struct inode *inode = dentry->d_inode;
	struct super_block *sb = inode->i_sb;
	int err, err2;
	int err;

	err = inode_change_ok(inode, iattr);
	if (err)
@@ -691,8 +692,12 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr)
	err = inode_setattr(inode, iattr);
	if (!err && (iattr->ia_valid & ATTR_MODE))
		err = nilfs_acl_chmod(inode);
	err2 = nilfs_transaction_end(sb, 1);
	return err ? : err2;
	if (likely(!err))
		err = nilfs_transaction_commit(sb);
	else
		nilfs_transaction_abort(sb);

	return err;
}

int nilfs_load_inode_block(struct nilfs_sb_info *sbi, struct inode *inode,
@@ -817,5 +822,5 @@ void nilfs_dirty_inode(struct inode *inode)
	nilfs_transaction_begin(inode->i_sb, &ti, 0);
	if (likely(inode->i_ino != NILFS_SKETCH_INO))
		nilfs_mark_inode_dirty(inode);
	nilfs_transaction_end(inode->i_sb, 1); /* never fails */
	nilfs_transaction_commit(inode->i_sb); /* never fails */
}
+34 −24
Original line number Diff line number Diff line
@@ -105,7 +105,11 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp,
	nilfs_transaction_begin(inode->i_sb, &ti, 0);
	ret = nilfs_cpfile_change_cpmode(
		cpfile, cpmode.cm_cno, cpmode.cm_mode);
	nilfs_transaction_end(inode->i_sb, !ret);
	if (unlikely(ret < 0)) {
		nilfs_transaction_abort(inode->i_sb);
		return ret;
	}
	nilfs_transaction_commit(inode->i_sb); /* never fails */
	return ret;
}

@@ -125,7 +129,11 @@ nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp,

	nilfs_transaction_begin(inode->i_sb, &ti, 0);
	ret = nilfs_cpfile_delete_checkpoint(cpfile, cno);
	nilfs_transaction_end(inode->i_sb, !ret);
	if (unlikely(ret < 0)) {
		nilfs_transaction_abort(inode->i_sb);
		return ret;
	}
	nilfs_transaction_commit(inode->i_sb); /* never fails */
	return ret;
}

@@ -142,16 +150,17 @@ static int nilfs_ioctl_get_cpinfo(struct inode *inode, struct file *filp,
{
	struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
	struct nilfs_argv argv;
	struct nilfs_transaction_info ti;
	int ret;

	if (copy_from_user(&argv, argp, sizeof(argv)))
		return -EFAULT;

	nilfs_transaction_begin(inode->i_sb, &ti, 0);
	down_read(&nilfs->ns_segctor_sem);
	ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd),
				    nilfs_ioctl_do_get_cpinfo);
	nilfs_transaction_end(inode->i_sb, 0);
	up_read(&nilfs->ns_segctor_sem);
	if (ret < 0)
		return ret;

	if (copy_to_user(argp, &argv, sizeof(argv)))
		ret = -EFAULT;
@@ -161,14 +170,13 @@ static int nilfs_ioctl_get_cpinfo(struct inode *inode, struct file *filp,
static int nilfs_ioctl_get_cpstat(struct inode *inode, struct file *filp,
				  unsigned int cmd, void __user *argp)
{
	struct inode *cpfile = NILFS_SB(inode->i_sb)->s_nilfs->ns_cpfile;
	struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
	struct nilfs_cpstat cpstat;
	struct nilfs_transaction_info ti;
	int ret;

	nilfs_transaction_begin(inode->i_sb, &ti, 0);
	ret = nilfs_cpfile_get_stat(cpfile, &cpstat);
	nilfs_transaction_end(inode->i_sb, 0);
	down_read(&nilfs->ns_segctor_sem);
	ret = nilfs_cpfile_get_stat(nilfs->ns_cpfile, &cpstat);
	up_read(&nilfs->ns_segctor_sem);
	if (ret < 0)
		return ret;

@@ -189,16 +197,17 @@ static int nilfs_ioctl_get_suinfo(struct inode *inode, struct file *filp,
{
	struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
	struct nilfs_argv argv;
	struct nilfs_transaction_info ti;
	int ret;

	if (copy_from_user(&argv, argp, sizeof(argv)))
		return -EFAULT;

	nilfs_transaction_begin(inode->i_sb, &ti, 0);
	down_read(&nilfs->ns_segctor_sem);
	ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd),
				    nilfs_ioctl_do_get_suinfo);
	nilfs_transaction_end(inode->i_sb, 0);
	up_read(&nilfs->ns_segctor_sem);
	if (ret < 0)
		return ret;

	if (copy_to_user(argp, &argv, sizeof(argv)))
		ret = -EFAULT;
@@ -208,14 +217,13 @@ static int nilfs_ioctl_get_suinfo(struct inode *inode, struct file *filp,
static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp,
				  unsigned int cmd, void __user *argp)
{
	struct inode *sufile = NILFS_SB(inode->i_sb)->s_nilfs->ns_sufile;
	struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
	struct nilfs_sustat sustat;
	struct nilfs_transaction_info ti;
	int ret;

	nilfs_transaction_begin(inode->i_sb, &ti, 0);
	ret = nilfs_sufile_get_stat(sufile, &sustat);
	nilfs_transaction_end(inode->i_sb, 0);
	down_read(&nilfs->ns_segctor_sem);
	ret = nilfs_sufile_get_stat(nilfs->ns_sufile, &sustat);
	up_read(&nilfs->ns_segctor_sem);
	if (ret < 0)
		return ret;

@@ -236,16 +244,17 @@ static int nilfs_ioctl_get_vinfo(struct inode *inode, struct file *filp,
{
	struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
	struct nilfs_argv argv;
	struct nilfs_transaction_info ti;
	int ret;

	if (copy_from_user(&argv, argp, sizeof(argv)))
		return -EFAULT;

	nilfs_transaction_begin(inode->i_sb, &ti, 0);
	down_read(&nilfs->ns_segctor_sem);
	ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd),
				    nilfs_ioctl_do_get_vinfo);
	nilfs_transaction_end(inode->i_sb, 0);
	up_read(&nilfs->ns_segctor_sem);
	if (ret < 0)
		return ret;

	if (copy_to_user(argp, &argv, sizeof(argv)))
		ret = -EFAULT;
@@ -280,16 +289,17 @@ static int nilfs_ioctl_get_bdescs(struct inode *inode, struct file *filp,
{
	struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
	struct nilfs_argv argv;
	struct nilfs_transaction_info ti;
	int ret;

	if (copy_from_user(&argv, argp, sizeof(argv)))
		return -EFAULT;

	nilfs_transaction_begin(inode->i_sb, &ti, 0);
	down_read(&nilfs->ns_segctor_sem);
	ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd),
				    nilfs_ioctl_do_get_bdescs);
	nilfs_transaction_end(inode->i_sb, 0);
	up_read(&nilfs->ns_segctor_sem);
	if (ret < 0)
		return ret;

	if (copy_to_user(argp, &argv, sizeof(argv)))
		ret = -EFAULT;
+4 −1
Original line number Diff line number Diff line
@@ -123,7 +123,10 @@ static int nilfs_mdt_create_block(struct inode *inode, unsigned long block,
	brelse(bh);

 failed_unlock:
	nilfs_transaction_end(sb, !err);
	if (likely(!err))
		err = nilfs_transaction_commit(sb);
	else
		nilfs_transaction_abort(sb);
	if (writer)
		nilfs_put_writer(nilfs);
 out:
+51 −23
Original line number Diff line number Diff line
@@ -109,7 +109,7 @@ static int nilfs_create(struct inode *dir, struct dentry *dentry, int mode,
{
	struct inode *inode;
	struct nilfs_transaction_info ti;
	int err, err2;
	int err;

	err = nilfs_transaction_begin(dir->i_sb, &ti, 1);
	if (err)
@@ -123,8 +123,12 @@ static int nilfs_create(struct inode *dir, struct dentry *dentry, int mode,
		mark_inode_dirty(inode);
		err = nilfs_add_nondir(dentry, inode);
	}
	err2 = nilfs_transaction_end(dir->i_sb, !err);
	return err ? : err2;
	if (!err)
		err = nilfs_transaction_commit(dir->i_sb);
	else
		nilfs_transaction_abort(dir->i_sb);

	return err;
}

static int
@@ -132,7 +136,7 @@ nilfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
{
	struct inode *inode;
	struct nilfs_transaction_info ti;
	int err, err2;
	int err;

	if (!new_valid_dev(rdev))
		return -EINVAL;
@@ -147,8 +151,12 @@ nilfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
		mark_inode_dirty(inode);
		err = nilfs_add_nondir(dentry, inode);
	}
	err2 = nilfs_transaction_end(dir->i_sb, !err);
	return err ? : err2;
	if (!err)
		err = nilfs_transaction_commit(dir->i_sb);
	else
		nilfs_transaction_abort(dir->i_sb);

	return err;
}

static int nilfs_symlink(struct inode *dir, struct dentry *dentry,
@@ -158,7 +166,7 @@ static int nilfs_symlink(struct inode *dir, struct dentry *dentry,
	struct super_block *sb = dir->i_sb;
	unsigned l = strlen(symname)+1;
	struct inode *inode;
	int err, err2;
	int err;

	if (l > sb->s_blocksize)
		return -ENAMETOOLONG;
@@ -184,8 +192,12 @@ static int nilfs_symlink(struct inode *dir, struct dentry *dentry,

	err = nilfs_add_nondir(dentry, inode);
out:
	err2 = nilfs_transaction_end(dir->i_sb, !err);
	return err ? : err2;
	if (!err)
		err = nilfs_transaction_commit(dir->i_sb);
	else
		nilfs_transaction_abort(dir->i_sb);

	return err;

out_fail:
	inode_dec_link_count(inode);
@@ -198,7 +210,7 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir,
{
	struct inode *inode = old_dentry->d_inode;
	struct nilfs_transaction_info ti;
	int err, err2;
	int err;

	if (inode->i_nlink >= NILFS_LINK_MAX)
		return -EMLINK;
@@ -212,15 +224,19 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir,
	atomic_inc(&inode->i_count);

	err = nilfs_add_nondir(dentry, inode);
	err2 = nilfs_transaction_end(dir->i_sb, !err);
	return err ? : err2;
	if (!err)
		err = nilfs_transaction_commit(dir->i_sb);
	else
		nilfs_transaction_abort(dir->i_sb);

	return err;
}

static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
	struct inode *inode;
	struct nilfs_transaction_info ti;
	int err, err2;
	int err;

	if (dir->i_nlink >= NILFS_LINK_MAX)
		return -EMLINK;
@@ -252,8 +268,12 @@ static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)

	d_instantiate(dentry, inode);
out:
	err2 = nilfs_transaction_end(dir->i_sb, !err);
	return err ? : err2;
	if (!err)
		err = nilfs_transaction_commit(dir->i_sb);
	else
		nilfs_transaction_abort(dir->i_sb);

	return err;

out_fail:
	inode_dec_link_count(inode);
@@ -270,7 +290,7 @@ static int nilfs_unlink(struct inode *dir, struct dentry *dentry)
	struct nilfs_dir_entry *de;
	struct page *page;
	struct nilfs_transaction_info ti;
	int err, err2;
	int err;

	err = nilfs_transaction_begin(dir->i_sb, &ti, 0);
	if (err)
@@ -300,15 +320,19 @@ static int nilfs_unlink(struct inode *dir, struct dentry *dentry)
	inode_dec_link_count(inode);
	err = 0;
out:
	err2 = nilfs_transaction_end(dir->i_sb, !err);
	return err ? : err2;
	if (!err)
		err = nilfs_transaction_commit(dir->i_sb);
	else
		nilfs_transaction_abort(dir->i_sb);

	return err;
}

static int nilfs_rmdir(struct inode *dir, struct dentry *dentry)
{
	struct inode *inode = dentry->d_inode;
	struct nilfs_transaction_info ti;
	int err, err2;
	int err;

	err = nilfs_transaction_begin(dir->i_sb, &ti, 0);
	if (err)
@@ -323,8 +347,12 @@ static int nilfs_rmdir(struct inode *dir, struct dentry *dentry)
			inode_dec_link_count(dir);
		}
	}
	err2 = nilfs_transaction_end(dir->i_sb, !err);
	return err ? : err2;
	if (!err)
		err = nilfs_transaction_commit(dir->i_sb);
	else
		nilfs_transaction_abort(dir->i_sb);

	return err;
}

static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,
@@ -404,7 +432,7 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,
		inode_dec_link_count(old_dir);
	}

	err = nilfs_transaction_end(old_dir->i_sb, 1);
	err = nilfs_transaction_commit(old_dir->i_sb);
	return err;

out_dir:
@@ -416,7 +444,7 @@ out_old:
	kunmap(old_page);
	page_cache_release(old_page);
out:
	nilfs_transaction_end(old_dir->i_sb, 0);
	nilfs_transaction_abort(old_dir->i_sb);
	return err;
}

+2 −1
Original line number Diff line number Diff line
@@ -166,7 +166,8 @@ struct nilfs_transaction_info {

int nilfs_transaction_begin(struct super_block *,
			    struct nilfs_transaction_info *, int);
int nilfs_transaction_end(struct super_block *, int);
int nilfs_transaction_commit(struct super_block *);
void nilfs_transaction_abort(struct super_block *);

static inline void nilfs_set_transaction_flag(unsigned int flag)
{
Loading