diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-04-09 13:52:01 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-04-11 22:30:22 -0400 |
commit | 2ba48ce513c4e545318d22b138861d5876edf906 (patch) | |
tree | 0e2a5130ead5c71f0b079b1acd620fba98f99256 | |
parent | 3309dd04cbcd2cdad168485af5cf3576b5051e49 (diff) |
mirror O_APPEND and O_DIRECT into iocb->ki_flags
... avoiding write_iter/fcntl races.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/aio.c | 2 | ||||
-rw-r--r-- | fs/btrfs/file.c | 2 | ||||
-rw-r--r-- | fs/ceph/file.c | 8 | ||||
-rw-r--r-- | fs/ext4/file.c | 4 | ||||
-rw-r--r-- | fs/fuse/file.c | 2 | ||||
-rw-r--r-- | fs/gfs2/file.c | 2 | ||||
-rw-r--r-- | fs/nfs/file.c | 6 | ||||
-rw-r--r-- | fs/ocfs2/file.c | 10 | ||||
-rw-r--r-- | fs/xfs/xfs_file.c | 4 | ||||
-rw-r--r-- | include/linux/fs.h | 15 | ||||
-rw-r--r-- | mm/filemap.c | 6 |
11 files changed, 38 insertions, 23 deletions
@@ -1502,7 +1502,7 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | |||
1502 | } | 1502 | } |
1503 | req->common.ki_pos = iocb->aio_offset; | 1503 | req->common.ki_pos = iocb->aio_offset; |
1504 | req->common.ki_complete = aio_complete; | 1504 | req->common.ki_complete = aio_complete; |
1505 | req->common.ki_flags = 0; | 1505 | req->common.ki_flags = iocb_flags(req->common.ki_filp); |
1506 | 1506 | ||
1507 | if (iocb->aio_flags & IOCB_FLAG_RESFD) { | 1507 | if (iocb->aio_flags & IOCB_FLAG_RESFD) { |
1508 | /* | 1508 | /* |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index c64d11c41eeb..faa7d390841b 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -1794,7 +1794,7 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, | |||
1794 | if (sync) | 1794 | if (sync) |
1795 | atomic_inc(&BTRFS_I(inode)->sync_writers); | 1795 | atomic_inc(&BTRFS_I(inode)->sync_writers); |
1796 | 1796 | ||
1797 | if (file->f_flags & O_DIRECT) { | 1797 | if (iocb->ki_flags & IOCB_DIRECT) { |
1798 | num_written = __btrfs_direct_write(iocb, from, pos); | 1798 | num_written = __btrfs_direct_write(iocb, from, pos); |
1799 | } else { | 1799 | } else { |
1800 | num_written = __btrfs_buffered_write(file, from, pos); | 1800 | num_written = __btrfs_buffered_write(file, from, pos); |
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 3f0b9339d823..b9b8eb225f66 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c | |||
@@ -457,7 +457,7 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i, | |||
457 | if (ret < 0) | 457 | if (ret < 0) |
458 | return ret; | 458 | return ret; |
459 | 459 | ||
460 | if (file->f_flags & O_DIRECT) { | 460 | if (iocb->ki_flags & IOCB_DIRECT) { |
461 | while (iov_iter_count(i)) { | 461 | while (iov_iter_count(i)) { |
462 | size_t start; | 462 | size_t start; |
463 | ssize_t n; | 463 | ssize_t n; |
@@ -828,7 +828,7 @@ again: | |||
828 | return ret; | 828 | return ret; |
829 | 829 | ||
830 | if ((got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0 || | 830 | if ((got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0 || |
831 | (iocb->ki_filp->f_flags & O_DIRECT) || | 831 | (iocb->ki_flags & IOCB_DIRECT) || |
832 | (fi->flags & CEPH_F_SYNC)) { | 832 | (fi->flags & CEPH_F_SYNC)) { |
833 | 833 | ||
834 | dout("aio_sync_read %p %llx.%llx %llu~%u got cap refs on %s\n", | 834 | dout("aio_sync_read %p %llx.%llx %llu~%u got cap refs on %s\n", |
@@ -995,12 +995,12 @@ retry_snap: | |||
995 | inode, ceph_vinop(inode), pos, count, ceph_cap_string(got)); | 995 | inode, ceph_vinop(inode), pos, count, ceph_cap_string(got)); |
996 | 996 | ||
997 | if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 || | 997 | if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 || |
998 | (file->f_flags & O_DIRECT) || (fi->flags & CEPH_F_SYNC)) { | 998 | (iocb->ki_flags & IOCB_DIRECT) || (fi->flags & CEPH_F_SYNC)) { |
999 | struct iov_iter data; | 999 | struct iov_iter data; |
1000 | mutex_unlock(&inode->i_mutex); | 1000 | mutex_unlock(&inode->i_mutex); |
1001 | /* we might need to revert back to that point */ | 1001 | /* we might need to revert back to that point */ |
1002 | data = *from; | 1002 | data = *from; |
1003 | if (file->f_flags & O_DIRECT) | 1003 | if (iocb->ki_flags & IOCB_DIRECT) |
1004 | written = ceph_sync_direct_write(iocb, &data, pos); | 1004 | written = ceph_sync_direct_write(iocb, &data, pos); |
1005 | else | 1005 | else |
1006 | written = ceph_sync_write(iocb, &data, pos); | 1006 | written = ceph_sync_write(iocb, &data, pos); |
diff --git a/fs/ext4/file.c b/fs/ext4/file.c index c10785f10d1d..53bbc0b1995f 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c | |||
@@ -95,7 +95,7 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
95 | struct inode *inode = file_inode(iocb->ki_filp); | 95 | struct inode *inode = file_inode(iocb->ki_filp); |
96 | struct mutex *aio_mutex = NULL; | 96 | struct mutex *aio_mutex = NULL; |
97 | struct blk_plug plug; | 97 | struct blk_plug plug; |
98 | int o_direct = io_is_direct(file); | 98 | int o_direct = iocb->ki_flags & IOCB_DIRECT; |
99 | int overwrite = 0; | 99 | int overwrite = 0; |
100 | ssize_t ret; | 100 | ssize_t ret; |
101 | 101 | ||
@@ -106,7 +106,7 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
106 | if (o_direct && | 106 | if (o_direct && |
107 | ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && | 107 | ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && |
108 | !is_sync_kiocb(iocb) && | 108 | !is_sync_kiocb(iocb) && |
109 | (file->f_flags & O_APPEND || | 109 | (iocb->ki_flags & IOCB_APPEND || |
110 | ext4_unaligned_aio(inode, from, iocb->ki_pos))) { | 110 | ext4_unaligned_aio(inode, from, iocb->ki_pos))) { |
111 | aio_mutex = ext4_aio_mutex(inode); | 111 | aio_mutex = ext4_aio_mutex(inode); |
112 | mutex_lock(aio_mutex); | 112 | mutex_lock(aio_mutex); |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index b86c8e08399a..5ef05b5c4cff 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -1177,7 +1177,7 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
1177 | if (err) | 1177 | if (err) |
1178 | goto out; | 1178 | goto out; |
1179 | 1179 | ||
1180 | if (file->f_flags & O_DIRECT) { | 1180 | if (iocb->ki_flags & IOCB_DIRECT) { |
1181 | loff_t pos = iocb->ki_pos; | 1181 | loff_t pos = iocb->ki_pos; |
1182 | written = generic_file_direct_write(iocb, from, pos); | 1182 | written = generic_file_direct_write(iocb, from, pos); |
1183 | if (written < 0 || !iov_iter_count(from)) | 1183 | if (written < 0 || !iov_iter_count(from)) |
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 614bb42cb7e1..08329afa1339 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c | |||
@@ -709,7 +709,7 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
709 | 709 | ||
710 | gfs2_size_hint(file, iocb->ki_pos, iov_iter_count(from)); | 710 | gfs2_size_hint(file, iocb->ki_pos, iov_iter_count(from)); |
711 | 711 | ||
712 | if (file->f_flags & O_APPEND) { | 712 | if (iocb->ki_flags & IOCB_APPEND) { |
713 | struct gfs2_holder gh; | 713 | struct gfs2_holder gh; |
714 | 714 | ||
715 | ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh); | 715 | ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh); |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index f6a3adedf027..14364dc001f7 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -170,7 +170,7 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to) | |||
170 | struct inode *inode = file_inode(iocb->ki_filp); | 170 | struct inode *inode = file_inode(iocb->ki_filp); |
171 | ssize_t result; | 171 | ssize_t result; |
172 | 172 | ||
173 | if (iocb->ki_filp->f_flags & O_DIRECT) | 173 | if (iocb->ki_flags & IOCB_DIRECT) |
174 | return nfs_file_direct_read(iocb, to, iocb->ki_pos); | 174 | return nfs_file_direct_read(iocb, to, iocb->ki_pos); |
175 | 175 | ||
176 | dprintk("NFS: read(%pD2, %zu@%lu)\n", | 176 | dprintk("NFS: read(%pD2, %zu@%lu)\n", |
@@ -680,7 +680,7 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) | |||
680 | if (result) | 680 | if (result) |
681 | return result; | 681 | return result; |
682 | 682 | ||
683 | if (file->f_flags & O_DIRECT) | 683 | if (iocb->ki_flags & IOCB_DIRECT) |
684 | return nfs_file_direct_write(iocb, from, pos); | 684 | return nfs_file_direct_write(iocb, from, pos); |
685 | 685 | ||
686 | dprintk("NFS: write(%pD2, %zu@%Ld)\n", | 686 | dprintk("NFS: write(%pD2, %zu@%Ld)\n", |
@@ -692,7 +692,7 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) | |||
692 | /* | 692 | /* |
693 | * O_APPEND implies that we must revalidate the file length. | 693 | * O_APPEND implies that we must revalidate the file length. |
694 | */ | 694 | */ |
695 | if (file->f_flags & O_APPEND) { | 695 | if (iocb->ki_flags & IOCB_APPEND) { |
696 | result = nfs_revalidate_file_size(inode, file); | 696 | result = nfs_revalidate_file_size(inode, file); |
697 | if (result) | 697 | if (result) |
698 | goto out; | 698 | goto out; |
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index b93919f50f0f..cd37f6cd4d51 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -2274,8 +2274,8 @@ static ssize_t ocfs2_file_write_iter(struct kiocb *iocb, | |||
2274 | if (count == 0) | 2274 | if (count == 0) |
2275 | return 0; | 2275 | return 0; |
2276 | 2276 | ||
2277 | appending = file->f_flags & O_APPEND ? 1 : 0; | 2277 | appending = iocb->ki_flags & IOCB_APPEND ? 1 : 0; |
2278 | direct_io = file->f_flags & O_DIRECT ? 1 : 0; | 2278 | direct_io = iocb->ki_flags & IOCB_DIRECT ? 1 : 0; |
2279 | 2279 | ||
2280 | mutex_lock(&inode->i_mutex); | 2280 | mutex_lock(&inode->i_mutex); |
2281 | 2281 | ||
@@ -2429,7 +2429,7 @@ relock: | |||
2429 | 2429 | ||
2430 | out_dio: | 2430 | out_dio: |
2431 | /* buffered aio wouldn't have proper lock coverage today */ | 2431 | /* buffered aio wouldn't have proper lock coverage today */ |
2432 | BUG_ON(ret == -EIOCBQUEUED && !(file->f_flags & O_DIRECT)); | 2432 | BUG_ON(ret == -EIOCBQUEUED && !(iocb->ki_flags & IOCB_DIRECT)); |
2433 | 2433 | ||
2434 | if (unlikely(written <= 0)) | 2434 | if (unlikely(written <= 0)) |
2435 | goto no_sync; | 2435 | goto no_sync; |
@@ -2546,7 +2546,7 @@ static ssize_t ocfs2_file_read_iter(struct kiocb *iocb, | |||
2546 | * buffered reads protect themselves in ->readpage(). O_DIRECT reads | 2546 | * buffered reads protect themselves in ->readpage(). O_DIRECT reads |
2547 | * need locks to protect pending reads from racing with truncate. | 2547 | * need locks to protect pending reads from racing with truncate. |
2548 | */ | 2548 | */ |
2549 | if (filp->f_flags & O_DIRECT) { | 2549 | if (iocb->ki_flags & IOCB_DIRECT) { |
2550 | have_alloc_sem = 1; | 2550 | have_alloc_sem = 1; |
2551 | ocfs2_iocb_set_sem_locked(iocb); | 2551 | ocfs2_iocb_set_sem_locked(iocb); |
2552 | 2552 | ||
@@ -2580,7 +2580,7 @@ static ssize_t ocfs2_file_read_iter(struct kiocb *iocb, | |||
2580 | trace_generic_file_aio_read_ret(ret); | 2580 | trace_generic_file_aio_read_ret(ret); |
2581 | 2581 | ||
2582 | /* buffered aio wouldn't have proper lock coverage today */ | 2582 | /* buffered aio wouldn't have proper lock coverage today */ |
2583 | BUG_ON(ret == -EIOCBQUEUED && !(filp->f_flags & O_DIRECT)); | 2583 | BUG_ON(ret == -EIOCBQUEUED && !(iocb->ki_flags & IOCB_DIRECT)); |
2584 | 2584 | ||
2585 | /* see ocfs2_file_write_iter */ | 2585 | /* see ocfs2_file_write_iter */ |
2586 | if (ret == -EIOCBQUEUED || !ocfs2_iocb_is_rw_locked(iocb)) { | 2586 | if (ret == -EIOCBQUEUED || !ocfs2_iocb_is_rw_locked(iocb)) { |
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 28d157807b42..1f12ad0a8585 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -279,7 +279,7 @@ xfs_file_read_iter( | |||
279 | 279 | ||
280 | XFS_STATS_INC(xs_read_calls); | 280 | XFS_STATS_INC(xs_read_calls); |
281 | 281 | ||
282 | if (unlikely(file->f_flags & O_DIRECT)) | 282 | if (unlikely(iocb->ki_flags & IOCB_DIRECT)) |
283 | ioflags |= XFS_IO_ISDIRECT; | 283 | ioflags |= XFS_IO_ISDIRECT; |
284 | if (file->f_mode & FMODE_NOCMTIME) | 284 | if (file->f_mode & FMODE_NOCMTIME) |
285 | ioflags |= XFS_IO_INVIS; | 285 | ioflags |= XFS_IO_INVIS; |
@@ -804,7 +804,7 @@ xfs_file_write_iter( | |||
804 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) | 804 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) |
805 | return -EIO; | 805 | return -EIO; |
806 | 806 | ||
807 | if (unlikely(file->f_flags & O_DIRECT)) | 807 | if (unlikely(iocb->ki_flags & IOCB_DIRECT)) |
808 | ret = xfs_file_dio_aio_write(iocb, from); | 808 | ret = xfs_file_dio_aio_write(iocb, from); |
809 | else | 809 | else |
810 | ret = xfs_file_buffered_aio_write(iocb, from); | 810 | ret = xfs_file_buffered_aio_write(iocb, from); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index b4aa400ac723..b1d7db28c13c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -315,6 +315,8 @@ struct address_space; | |||
315 | struct writeback_control; | 315 | struct writeback_control; |
316 | 316 | ||
317 | #define IOCB_EVENTFD (1 << 0) | 317 | #define IOCB_EVENTFD (1 << 0) |
318 | #define IOCB_APPEND (1 << 1) | ||
319 | #define IOCB_DIRECT (1 << 2) | ||
318 | 320 | ||
319 | struct kiocb { | 321 | struct kiocb { |
320 | struct file *ki_filp; | 322 | struct file *ki_filp; |
@@ -329,10 +331,13 @@ static inline bool is_sync_kiocb(struct kiocb *kiocb) | |||
329 | return kiocb->ki_complete == NULL; | 331 | return kiocb->ki_complete == NULL; |
330 | } | 332 | } |
331 | 333 | ||
334 | static inline int iocb_flags(struct file *file); | ||
335 | |||
332 | static inline void init_sync_kiocb(struct kiocb *kiocb, struct file *filp) | 336 | static inline void init_sync_kiocb(struct kiocb *kiocb, struct file *filp) |
333 | { | 337 | { |
334 | *kiocb = (struct kiocb) { | 338 | *kiocb = (struct kiocb) { |
335 | .ki_filp = filp, | 339 | .ki_filp = filp, |
340 | .ki_flags = iocb_flags(filp), | ||
336 | }; | 341 | }; |
337 | } | 342 | } |
338 | 343 | ||
@@ -2779,6 +2784,16 @@ static inline bool io_is_direct(struct file *filp) | |||
2779 | return (filp->f_flags & O_DIRECT) || IS_DAX(file_inode(filp)); | 2784 | return (filp->f_flags & O_DIRECT) || IS_DAX(file_inode(filp)); |
2780 | } | 2785 | } |
2781 | 2786 | ||
2787 | static inline int iocb_flags(struct file *file) | ||
2788 | { | ||
2789 | int res = 0; | ||
2790 | if (file->f_flags & O_APPEND) | ||
2791 | res |= IOCB_APPEND; | ||
2792 | if (io_is_direct(file)) | ||
2793 | res |= IOCB_DIRECT; | ||
2794 | return res; | ||
2795 | } | ||
2796 | |||
2782 | static inline ino_t parent_ino(struct dentry *dentry) | 2797 | static inline ino_t parent_ino(struct dentry *dentry) |
2783 | { | 2798 | { |
2784 | ino_t res; | 2799 | ino_t res; |
diff --git a/mm/filemap.c b/mm/filemap.c index 243997a26e7c..405de370e657 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -1694,7 +1694,7 @@ generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter) | |||
1694 | loff_t *ppos = &iocb->ki_pos; | 1694 | loff_t *ppos = &iocb->ki_pos; |
1695 | loff_t pos = *ppos; | 1695 | loff_t pos = *ppos; |
1696 | 1696 | ||
1697 | if (io_is_direct(file)) { | 1697 | if (iocb->ki_flags & IOCB_DIRECT) { |
1698 | struct address_space *mapping = file->f_mapping; | 1698 | struct address_space *mapping = file->f_mapping; |
1699 | struct inode *inode = mapping->host; | 1699 | struct inode *inode = mapping->host; |
1700 | size_t count = iov_iter_count(iter); | 1700 | size_t count = iov_iter_count(iter); |
@@ -2271,7 +2271,7 @@ inline ssize_t generic_write_checks(struct kiocb *iocb, struct iov_iter *from) | |||
2271 | return 0; | 2271 | return 0; |
2272 | 2272 | ||
2273 | /* FIXME: this is for backwards compatibility with 2.4 */ | 2273 | /* FIXME: this is for backwards compatibility with 2.4 */ |
2274 | if (file->f_flags & O_APPEND) | 2274 | if (iocb->ki_flags & IOCB_APPEND) |
2275 | iocb->ki_pos = i_size_read(inode); | 2275 | iocb->ki_pos = i_size_read(inode); |
2276 | 2276 | ||
2277 | pos = iocb->ki_pos; | 2277 | pos = iocb->ki_pos; |
@@ -2545,7 +2545,7 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
2545 | if (err) | 2545 | if (err) |
2546 | goto out; | 2546 | goto out; |
2547 | 2547 | ||
2548 | if (io_is_direct(file)) { | 2548 | if (iocb->ki_flags & IOCB_DIRECT) { |
2549 | loff_t pos, endbyte; | 2549 | loff_t pos, endbyte; |
2550 | 2550 | ||
2551 | written = generic_file_direct_write(iocb, from, iocb->ki_pos); | 2551 | written = generic_file_direct_write(iocb, from, iocb->ki_pos); |