@@ -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;
[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(-)