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: Pekka Enberg <penberg@cs.helsinki.fi>
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c
index 02e91e1..5ce06a0 100644
--- a/fs/nilfs2/ioctl.c
+++ b/fs/nilfs2/ioctl.c
@@ -105,7 +105,11 @@
 	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_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 @@
 {
 	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_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 @@
 {
 	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_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 @@
 {
 	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 @@
 {
 	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;