diff mbox series

[3/3,experimental] another way to deal with scopes for overlayfs real_fd-under-inode_lock

Message ID 20241003234855.GD147780@ZenIV (mailing list archive)
State New
Headers show
Series introduce struct fderr, convert overlayfs uses to that | expand

Commit Message

Al Viro Oct. 3, 2024, 11:48 p.m. UTC
[incremental to the previous]

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/overlayfs/file.c | 113 +++++++++++++++++++++-----------------------
 1 file changed, 55 insertions(+), 58 deletions(-)
diff mbox series

Patch

diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c
index a0ab981b13d9..e10a009d32e7 100644
--- a/fs/overlayfs/file.c
+++ b/fs/overlayfs/file.c
@@ -268,6 +268,15 @@  static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter)
 				      &ctx);
 }
 
+static ssize_t ovl_write_locked(struct kiocb *iocb, struct iov_iter *iter, int ifl,
+				 struct backing_file_ctx *ctx)
+{
+	CLASS(fd_real, real)(ctx->user_file);
+	if (fd_empty(real))
+		return fd_err(real);
+	return backing_file_write_iter(fd_file(real), iter, iocb, ifl, ctx);
+}
+
 static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
 {
 	struct file *file = iocb->ki_filp;
@@ -287,14 +296,6 @@  static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
 	/* Update mode */
 	ovl_copyattr(inode);
 
-	{
-
-	CLASS(fd_real, real)(file);
-	if (fd_empty(real)) {
-		ret = fd_err(real);
-		goto out_unlock;
-	}
-
 	if (!ovl_should_sync(OVL_FS(inode->i_sb)))
 		ifl &= ~(IOCB_DSYNC | IOCB_SYNC);
 
@@ -303,11 +304,8 @@  static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
 	 * this property in case it is set by the issuer.
 	 */
 	ifl &= ~IOCB_DIO_CALLER_COMP;
-	ret = backing_file_write_iter(fd_file(real), iter, iocb, ifl, &ctx);
-
-	}
+	ret = ovl_write_locked(iocb, iter, ifl, &ctx);
 
-out_unlock:
 	inode_unlock(inode);
 
 	return ret;
@@ -331,6 +329,16 @@  static ssize_t ovl_splice_read(struct file *in, loff_t *ppos,
 					&ctx);
 }
 
+static ssize_t ovl_splice_locked(struct pipe_inode_info *pipe, 
+				 loff_t *ppos, size_t len, unsigned int flags,
+				 struct backing_file_ctx *ctx)
+{
+	CLASS(fd_real, real)(ctx->user_file);
+	if (fd_empty(real))
+		return fd_err(real);
+	return backing_file_splice_write(pipe, fd_file(real), ppos, len, flags, ctx);
+}
+
 /*
  * Calling iter_file_splice_write() directly from overlay's f_op may deadlock
  * due to lock order inversion between pipe->mutex in iter_file_splice_write()
@@ -353,19 +361,7 @@  static ssize_t ovl_splice_write(struct pipe_inode_info *pipe, struct file *out,
 	inode_lock(inode);
 	/* Update mode */
 	ovl_copyattr(inode);
-
-	{
-
-	CLASS(fd_real, real)(out);
-	if (fd_empty(real)) {
-		ret = fd_err(real);
-		goto out_unlock;
-	}
-
-	ret = backing_file_splice_write(pipe, fd_file(real), ppos, len, flags, &ctx);
-
-	}
-out_unlock:
+	ret = ovl_splice_locked(pipe, ppos, len, flags, &ctx);
 	inode_unlock(inode);
 
 	return ret;
@@ -409,25 +405,14 @@  static int ovl_mmap(struct file *file, struct vm_area_struct *vma)
 	return backing_file_mmap(realfile, vma, &ctx);
 }
 
-static long ovl_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
+static long ovl_fallocate_locked(struct file *file, int mode, loff_t offset, loff_t len)
 {
-	struct inode *inode = file_inode(file);
 	const struct cred *old_cred;
 	int ret;
 
-	inode_lock(inode);
-	/* Update mode */
-	ovl_copyattr(inode);
-	ret = file_remove_privs(file);
-	if (ret)
-		goto out_unlock;
-	{
-
 	CLASS(fd_real, real)(file);
-	if (fd_empty(real)) {
-		ret = fd_err(real);
-		goto out_unlock;
-	}
+	if (fd_empty(real))
+		return fd_err(real);
 
 	old_cred = ovl_override_creds(file_inode(file)->i_sb);
 	ret = vfs_fallocate(fd_file(real), mode, offset, len);
@@ -435,9 +420,20 @@  static long ovl_fallocate(struct file *file, int mode, loff_t offset, loff_t len
 
 	/* Update size */
 	ovl_file_modified(file);
+	return ret;
+}
 
-	}
-out_unlock:
+static long ovl_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
+{
+	struct inode *inode = file_inode(file);
+	int ret;
+
+	inode_lock(inode);
+	/* Update mode */
+	ovl_copyattr(inode);
+	ret = file_remove_privs(file);
+	if (!ret)
+		ret = ovl_fallocate_locked(file, mode, offset, len);
 	inode_unlock(inode);
 
 	return ret;
@@ -465,36 +461,28 @@  enum ovl_copyop {
 	OVL_DEDUPE,
 };
 
-static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in,
+static loff_t ovl_copyfile_locked(struct file *file_in, loff_t pos_in,
 			    struct file *file_out, loff_t pos_out,
 			    loff_t len, unsigned int flags, enum ovl_copyop op)
 {
-	struct inode *inode_out = file_inode(file_out);
 	const struct cred *old_cred;
 	loff_t ret;
 
-	inode_lock(inode_out);
 	if (op != OVL_DEDUPE) {
 		/* Update mode */
-		ovl_copyattr(inode_out);
+		ovl_copyattr(file_inode(file_out));
 		ret = file_remove_privs(file_out);
 		if (ret)
-			goto out_unlock;
+			return ret;
 	}
 
-	{
-
 	CLASS(fd_real, real_out)(file_out);
-	if (fd_empty(real_out)) {
-		ret = fd_err(real_out);
-		goto out_unlock;
-	}
+	if (fd_empty(real_out))
+		return fd_err(real_out);
 
 	CLASS(fd_real, real_in)(file_in);
-	if (fd_empty(real_in)) {
-		ret = fd_err(real_in);
-		goto out_unlock;
-	}
+	if (fd_empty(real_in))
+		return fd_err(real_in);
 
 	old_cred = ovl_override_creds(file_inode(file_out)->i_sb);
 	switch (op) {
@@ -518,10 +506,19 @@  static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in,
 
 	/* Update size */
 	ovl_file_modified(file_out);
+	return ret;
+}
 
-	}
+static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in,
+			    struct file *file_out, loff_t pos_out,
+			    loff_t len, unsigned int flags, enum ovl_copyop op)
+{
+	struct inode *inode_out = file_inode(file_out);
+	loff_t ret;
 
-out_unlock:
+	inode_lock(inode_out);
+	ret = ovl_copyfile_locked(file_in, pos_in, file_out, pos_out,
+				  len, flags, op);
 	inode_unlock(inode_out);
 
 	return ret;