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>
This commit is contained in:
parent
3309dd04cb
commit
2ba48ce513
11 changed files with 38 additions and 23 deletions
2
fs/aio.c
2
fs/aio.c
|
@ -1502,7 +1502,7 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
|
||||||
}
|
}
|
||||||
req->common.ki_pos = iocb->aio_offset;
|
req->common.ki_pos = iocb->aio_offset;
|
||||||
req->common.ki_complete = aio_complete;
|
req->common.ki_complete = aio_complete;
|
||||||
req->common.ki_flags = 0;
|
req->common.ki_flags = iocb_flags(req->common.ki_filp);
|
||||||
|
|
||||||
if (iocb->aio_flags & IOCB_FLAG_RESFD) {
|
if (iocb->aio_flags & IOCB_FLAG_RESFD) {
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1794,7 +1794,7 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
|
||||||
if (sync)
|
if (sync)
|
||||||
atomic_inc(&BTRFS_I(inode)->sync_writers);
|
atomic_inc(&BTRFS_I(inode)->sync_writers);
|
||||||
|
|
||||||
if (file->f_flags & O_DIRECT) {
|
if (iocb->ki_flags & IOCB_DIRECT) {
|
||||||
num_written = __btrfs_direct_write(iocb, from, pos);
|
num_written = __btrfs_direct_write(iocb, from, pos);
|
||||||
} else {
|
} else {
|
||||||
num_written = __btrfs_buffered_write(file, from, pos);
|
num_written = __btrfs_buffered_write(file, from, pos);
|
||||||
|
|
|
@ -457,7 +457,7 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (file->f_flags & O_DIRECT) {
|
if (iocb->ki_flags & IOCB_DIRECT) {
|
||||||
while (iov_iter_count(i)) {
|
while (iov_iter_count(i)) {
|
||||||
size_t start;
|
size_t start;
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
|
@ -828,7 +828,7 @@ static ssize_t ceph_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0 ||
|
if ((got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0 ||
|
||||||
(iocb->ki_filp->f_flags & O_DIRECT) ||
|
(iocb->ki_flags & IOCB_DIRECT) ||
|
||||||
(fi->flags & CEPH_F_SYNC)) {
|
(fi->flags & CEPH_F_SYNC)) {
|
||||||
|
|
||||||
dout("aio_sync_read %p %llx.%llx %llu~%u got cap refs on %s\n",
|
dout("aio_sync_read %p %llx.%llx %llu~%u got cap refs on %s\n",
|
||||||
|
@ -995,12 +995,12 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||||
inode, ceph_vinop(inode), pos, count, ceph_cap_string(got));
|
inode, ceph_vinop(inode), pos, count, ceph_cap_string(got));
|
||||||
|
|
||||||
if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 ||
|
if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 ||
|
||||||
(file->f_flags & O_DIRECT) || (fi->flags & CEPH_F_SYNC)) {
|
(iocb->ki_flags & IOCB_DIRECT) || (fi->flags & CEPH_F_SYNC)) {
|
||||||
struct iov_iter data;
|
struct iov_iter data;
|
||||||
mutex_unlock(&inode->i_mutex);
|
mutex_unlock(&inode->i_mutex);
|
||||||
/* we might need to revert back to that point */
|
/* we might need to revert back to that point */
|
||||||
data = *from;
|
data = *from;
|
||||||
if (file->f_flags & O_DIRECT)
|
if (iocb->ki_flags & IOCB_DIRECT)
|
||||||
written = ceph_sync_direct_write(iocb, &data, pos);
|
written = ceph_sync_direct_write(iocb, &data, pos);
|
||||||
else
|
else
|
||||||
written = ceph_sync_write(iocb, &data, pos);
|
written = ceph_sync_write(iocb, &data, pos);
|
||||||
|
|
|
@ -95,7 +95,7 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||||
struct inode *inode = file_inode(iocb->ki_filp);
|
struct inode *inode = file_inode(iocb->ki_filp);
|
||||||
struct mutex *aio_mutex = NULL;
|
struct mutex *aio_mutex = NULL;
|
||||||
struct blk_plug plug;
|
struct blk_plug plug;
|
||||||
int o_direct = io_is_direct(file);
|
int o_direct = iocb->ki_flags & IOCB_DIRECT;
|
||||||
int overwrite = 0;
|
int overwrite = 0;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||||
if (o_direct &&
|
if (o_direct &&
|
||||||
ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) &&
|
ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) &&
|
||||||
!is_sync_kiocb(iocb) &&
|
!is_sync_kiocb(iocb) &&
|
||||||
(file->f_flags & O_APPEND ||
|
(iocb->ki_flags & IOCB_APPEND ||
|
||||||
ext4_unaligned_aio(inode, from, iocb->ki_pos))) {
|
ext4_unaligned_aio(inode, from, iocb->ki_pos))) {
|
||||||
aio_mutex = ext4_aio_mutex(inode);
|
aio_mutex = ext4_aio_mutex(inode);
|
||||||
mutex_lock(aio_mutex);
|
mutex_lock(aio_mutex);
|
||||||
|
|
|
@ -1177,7 +1177,7 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (file->f_flags & O_DIRECT) {
|
if (iocb->ki_flags & IOCB_DIRECT) {
|
||||||
loff_t pos = iocb->ki_pos;
|
loff_t pos = iocb->ki_pos;
|
||||||
written = generic_file_direct_write(iocb, from, pos);
|
written = generic_file_direct_write(iocb, from, pos);
|
||||||
if (written < 0 || !iov_iter_count(from))
|
if (written < 0 || !iov_iter_count(from))
|
||||||
|
|
|
@ -709,7 +709,7 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||||
|
|
||||||
gfs2_size_hint(file, iocb->ki_pos, iov_iter_count(from));
|
gfs2_size_hint(file, iocb->ki_pos, iov_iter_count(from));
|
||||||
|
|
||||||
if (file->f_flags & O_APPEND) {
|
if (iocb->ki_flags & IOCB_APPEND) {
|
||||||
struct gfs2_holder gh;
|
struct gfs2_holder gh;
|
||||||
|
|
||||||
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
|
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
|
||||||
|
|
|
@ -170,7 +170,7 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to)
|
||||||
struct inode *inode = file_inode(iocb->ki_filp);
|
struct inode *inode = file_inode(iocb->ki_filp);
|
||||||
ssize_t result;
|
ssize_t result;
|
||||||
|
|
||||||
if (iocb->ki_filp->f_flags & O_DIRECT)
|
if (iocb->ki_flags & IOCB_DIRECT)
|
||||||
return nfs_file_direct_read(iocb, to, iocb->ki_pos);
|
return nfs_file_direct_read(iocb, to, iocb->ki_pos);
|
||||||
|
|
||||||
dprintk("NFS: read(%pD2, %zu@%lu)\n",
|
dprintk("NFS: read(%pD2, %zu@%lu)\n",
|
||||||
|
@ -680,7 +680,7 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
|
||||||
if (result)
|
if (result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
if (file->f_flags & O_DIRECT)
|
if (iocb->ki_flags & IOCB_DIRECT)
|
||||||
return nfs_file_direct_write(iocb, from, pos);
|
return nfs_file_direct_write(iocb, from, pos);
|
||||||
|
|
||||||
dprintk("NFS: write(%pD2, %zu@%Ld)\n",
|
dprintk("NFS: write(%pD2, %zu@%Ld)\n",
|
||||||
|
@ -692,7 +692,7 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
|
||||||
/*
|
/*
|
||||||
* O_APPEND implies that we must revalidate the file length.
|
* O_APPEND implies that we must revalidate the file length.
|
||||||
*/
|
*/
|
||||||
if (file->f_flags & O_APPEND) {
|
if (iocb->ki_flags & IOCB_APPEND) {
|
||||||
result = nfs_revalidate_file_size(inode, file);
|
result = nfs_revalidate_file_size(inode, file);
|
||||||
if (result)
|
if (result)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
@ -2274,8 +2274,8 @@ static ssize_t ocfs2_file_write_iter(struct kiocb *iocb,
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
appending = file->f_flags & O_APPEND ? 1 : 0;
|
appending = iocb->ki_flags & IOCB_APPEND ? 1 : 0;
|
||||||
direct_io = file->f_flags & O_DIRECT ? 1 : 0;
|
direct_io = iocb->ki_flags & IOCB_DIRECT ? 1 : 0;
|
||||||
|
|
||||||
mutex_lock(&inode->i_mutex);
|
mutex_lock(&inode->i_mutex);
|
||||||
|
|
||||||
|
@ -2429,7 +2429,7 @@ static ssize_t ocfs2_file_write_iter(struct kiocb *iocb,
|
||||||
|
|
||||||
out_dio:
|
out_dio:
|
||||||
/* buffered aio wouldn't have proper lock coverage today */
|
/* buffered aio wouldn't have proper lock coverage today */
|
||||||
BUG_ON(ret == -EIOCBQUEUED && !(file->f_flags & O_DIRECT));
|
BUG_ON(ret == -EIOCBQUEUED && !(iocb->ki_flags & IOCB_DIRECT));
|
||||||
|
|
||||||
if (unlikely(written <= 0))
|
if (unlikely(written <= 0))
|
||||||
goto no_sync;
|
goto no_sync;
|
||||||
|
@ -2546,7 +2546,7 @@ static ssize_t ocfs2_file_read_iter(struct kiocb *iocb,
|
||||||
* buffered reads protect themselves in ->readpage(). O_DIRECT reads
|
* buffered reads protect themselves in ->readpage(). O_DIRECT reads
|
||||||
* need locks to protect pending reads from racing with truncate.
|
* need locks to protect pending reads from racing with truncate.
|
||||||
*/
|
*/
|
||||||
if (filp->f_flags & O_DIRECT) {
|
if (iocb->ki_flags & IOCB_DIRECT) {
|
||||||
have_alloc_sem = 1;
|
have_alloc_sem = 1;
|
||||||
ocfs2_iocb_set_sem_locked(iocb);
|
ocfs2_iocb_set_sem_locked(iocb);
|
||||||
|
|
||||||
|
@ -2580,7 +2580,7 @@ static ssize_t ocfs2_file_read_iter(struct kiocb *iocb,
|
||||||
trace_generic_file_aio_read_ret(ret);
|
trace_generic_file_aio_read_ret(ret);
|
||||||
|
|
||||||
/* buffered aio wouldn't have proper lock coverage today */
|
/* buffered aio wouldn't have proper lock coverage today */
|
||||||
BUG_ON(ret == -EIOCBQUEUED && !(filp->f_flags & O_DIRECT));
|
BUG_ON(ret == -EIOCBQUEUED && !(iocb->ki_flags & IOCB_DIRECT));
|
||||||
|
|
||||||
/* see ocfs2_file_write_iter */
|
/* see ocfs2_file_write_iter */
|
||||||
if (ret == -EIOCBQUEUED || !ocfs2_iocb_is_rw_locked(iocb)) {
|
if (ret == -EIOCBQUEUED || !ocfs2_iocb_is_rw_locked(iocb)) {
|
||||||
|
|
|
@ -279,7 +279,7 @@ xfs_file_read_iter(
|
||||||
|
|
||||||
XFS_STATS_INC(xs_read_calls);
|
XFS_STATS_INC(xs_read_calls);
|
||||||
|
|
||||||
if (unlikely(file->f_flags & O_DIRECT))
|
if (unlikely(iocb->ki_flags & IOCB_DIRECT))
|
||||||
ioflags |= XFS_IO_ISDIRECT;
|
ioflags |= XFS_IO_ISDIRECT;
|
||||||
if (file->f_mode & FMODE_NOCMTIME)
|
if (file->f_mode & FMODE_NOCMTIME)
|
||||||
ioflags |= XFS_IO_INVIS;
|
ioflags |= XFS_IO_INVIS;
|
||||||
|
@ -804,7 +804,7 @@ xfs_file_write_iter(
|
||||||
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
|
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (unlikely(file->f_flags & O_DIRECT))
|
if (unlikely(iocb->ki_flags & IOCB_DIRECT))
|
||||||
ret = xfs_file_dio_aio_write(iocb, from);
|
ret = xfs_file_dio_aio_write(iocb, from);
|
||||||
else
|
else
|
||||||
ret = xfs_file_buffered_aio_write(iocb, from);
|
ret = xfs_file_buffered_aio_write(iocb, from);
|
||||||
|
|
|
@ -315,6 +315,8 @@ struct address_space;
|
||||||
struct writeback_control;
|
struct writeback_control;
|
||||||
|
|
||||||
#define IOCB_EVENTFD (1 << 0)
|
#define IOCB_EVENTFD (1 << 0)
|
||||||
|
#define IOCB_APPEND (1 << 1)
|
||||||
|
#define IOCB_DIRECT (1 << 2)
|
||||||
|
|
||||||
struct kiocb {
|
struct kiocb {
|
||||||
struct file *ki_filp;
|
struct file *ki_filp;
|
||||||
|
@ -329,10 +331,13 @@ static inline bool is_sync_kiocb(struct kiocb *kiocb)
|
||||||
return kiocb->ki_complete == NULL;
|
return kiocb->ki_complete == NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int iocb_flags(struct file *file);
|
||||||
|
|
||||||
static inline void init_sync_kiocb(struct kiocb *kiocb, struct file *filp)
|
static inline void init_sync_kiocb(struct kiocb *kiocb, struct file *filp)
|
||||||
{
|
{
|
||||||
*kiocb = (struct kiocb) {
|
*kiocb = (struct kiocb) {
|
||||||
.ki_filp = filp,
|
.ki_filp = filp,
|
||||||
|
.ki_flags = iocb_flags(filp),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2779,6 +2784,16 @@ static inline bool io_is_direct(struct file *filp)
|
||||||
return (filp->f_flags & O_DIRECT) || IS_DAX(file_inode(filp));
|
return (filp->f_flags & O_DIRECT) || IS_DAX(file_inode(filp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int iocb_flags(struct file *file)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
if (file->f_flags & O_APPEND)
|
||||||
|
res |= IOCB_APPEND;
|
||||||
|
if (io_is_direct(file))
|
||||||
|
res |= IOCB_DIRECT;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static inline ino_t parent_ino(struct dentry *dentry)
|
static inline ino_t parent_ino(struct dentry *dentry)
|
||||||
{
|
{
|
||||||
ino_t res;
|
ino_t res;
|
||||||
|
|
|
@ -1694,7 +1694,7 @@ generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
|
||||||
loff_t *ppos = &iocb->ki_pos;
|
loff_t *ppos = &iocb->ki_pos;
|
||||||
loff_t pos = *ppos;
|
loff_t pos = *ppos;
|
||||||
|
|
||||||
if (io_is_direct(file)) {
|
if (iocb->ki_flags & IOCB_DIRECT) {
|
||||||
struct address_space *mapping = file->f_mapping;
|
struct address_space *mapping = file->f_mapping;
|
||||||
struct inode *inode = mapping->host;
|
struct inode *inode = mapping->host;
|
||||||
size_t count = iov_iter_count(iter);
|
size_t count = iov_iter_count(iter);
|
||||||
|
@ -2271,7 +2271,7 @@ inline ssize_t generic_write_checks(struct kiocb *iocb, struct iov_iter *from)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* FIXME: this is for backwards compatibility with 2.4 */
|
/* FIXME: this is for backwards compatibility with 2.4 */
|
||||||
if (file->f_flags & O_APPEND)
|
if (iocb->ki_flags & IOCB_APPEND)
|
||||||
iocb->ki_pos = i_size_read(inode);
|
iocb->ki_pos = i_size_read(inode);
|
||||||
|
|
||||||
pos = iocb->ki_pos;
|
pos = iocb->ki_pos;
|
||||||
|
@ -2545,7 +2545,7 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (io_is_direct(file)) {
|
if (iocb->ki_flags & IOCB_DIRECT) {
|
||||||
loff_t pos, endbyte;
|
loff_t pos, endbyte;
|
||||||
|
|
||||||
written = generic_file_direct_write(iocb, from, iocb->ki_pos);
|
written = generic_file_direct_write(iocb, from, iocb->ki_pos);
|
||||||
|
|
Loading…
Reference in a new issue