aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2016-06-29 10:03:55 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2016-06-29 10:03:55 -0400
commit03bea60409328de54e4ff7ec41672e12a9cb0908 (patch)
treee63b692eeb24c559c1e9b56369b18751a7bb9d5f
parenta4859d75944a726533ab86d24bb5ffd1b2b7d6cc (diff)
ovl: get_write_access() in truncate
When truncating a file we should check write access on the underlying inode. And we should do so on the lower file as well (before copy-up) for consistency. Original patch and test case by Aihua Zhang. - - >o >o - - test.c - - >o >o - - #include <stdio.h> #include <errno.h> #include <unistd.h> int main(int argc, char *argv[]) { int ret; ret = truncate(argv[0], 4096); if (ret != -1) { fprintf(stderr, "truncate(argv[0]) should have failed\n"); return 1; } if (errno != ETXTBSY) { perror("truncate(argv[0])"); return 1; } return 0; } - - >o >o - - >o >o - - >o >o - - Reported-by: Aihua Zhang <zhangaihua1@huawei.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Cc: <stable@vger.kernel.org>
-rw-r--r--fs/overlayfs/inode.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 8514d692042b..c831c2e5f803 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -59,16 +59,37 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
59 if (err) 59 if (err)
60 goto out; 60 goto out;
61 61
62 if (attr->ia_valid & ATTR_SIZE) {
63 struct inode *realinode = d_inode(ovl_dentry_real(dentry));
64
65 err = -ETXTBSY;
66 if (atomic_read(&realinode->i_writecount) < 0)
67 goto out_drop_write;
68 }
69
62 err = ovl_copy_up(dentry); 70 err = ovl_copy_up(dentry);
63 if (!err) { 71 if (!err) {
72 struct inode *winode = NULL;
73
64 upperdentry = ovl_dentry_upper(dentry); 74 upperdentry = ovl_dentry_upper(dentry);
65 75
76 if (attr->ia_valid & ATTR_SIZE) {
77 winode = d_inode(upperdentry);
78 err = get_write_access(winode);
79 if (err)
80 goto out_drop_write;
81 }
82
66 inode_lock(upperdentry->d_inode); 83 inode_lock(upperdentry->d_inode);
67 err = notify_change(upperdentry, attr, NULL); 84 err = notify_change(upperdentry, attr, NULL);
68 if (!err) 85 if (!err)
69 ovl_copyattr(upperdentry->d_inode, dentry->d_inode); 86 ovl_copyattr(upperdentry->d_inode, dentry->d_inode);
70 inode_unlock(upperdentry->d_inode); 87 inode_unlock(upperdentry->d_inode);
88
89 if (winode)
90 put_write_access(winode);
71 } 91 }
92out_drop_write:
72 ovl_drop_write(dentry); 93 ovl_drop_write(dentry);
73out: 94out:
74 return err; 95 return err;