|
@@ -161,9 +161,13 @@ struct kioctx {
|
|
|
unsigned id;
|
|
unsigned id;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+/*
|
|
|
|
|
+ * First field must be the file pointer in all the
|
|
|
|
|
+ * iocb unions! See also 'struct kiocb' in <linux/fs.h>
|
|
|
|
|
+ */
|
|
|
struct fsync_iocb {
|
|
struct fsync_iocb {
|
|
|
- struct work_struct work;
|
|
|
|
|
struct file *file;
|
|
struct file *file;
|
|
|
|
|
+ struct work_struct work;
|
|
|
bool datasync;
|
|
bool datasync;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
@@ -177,8 +181,15 @@ struct poll_iocb {
|
|
|
struct work_struct work;
|
|
struct work_struct work;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+/*
|
|
|
|
|
+ * NOTE! Each of the iocb union members has the file pointer
|
|
|
|
|
+ * as the first entry in their struct definition. So you can
|
|
|
|
|
+ * access the file pointer through any of the sub-structs,
|
|
|
|
|
+ * or directly as just 'ki_filp' in this struct.
|
|
|
|
|
+ */
|
|
|
struct aio_kiocb {
|
|
struct aio_kiocb {
|
|
|
union {
|
|
union {
|
|
|
|
|
+ struct file *ki_filp;
|
|
|
struct kiocb rw;
|
|
struct kiocb rw;
|
|
|
struct fsync_iocb fsync;
|
|
struct fsync_iocb fsync;
|
|
|
struct poll_iocb poll;
|
|
struct poll_iocb poll;
|
|
@@ -1054,6 +1065,8 @@ static inline void iocb_put(struct aio_kiocb *iocb)
|
|
|
{
|
|
{
|
|
|
if (refcount_read(&iocb->ki_refcnt) == 0 ||
|
|
if (refcount_read(&iocb->ki_refcnt) == 0 ||
|
|
|
refcount_dec_and_test(&iocb->ki_refcnt)) {
|
|
refcount_dec_and_test(&iocb->ki_refcnt)) {
|
|
|
|
|
+ if (iocb->ki_filp)
|
|
|
|
|
+ fput(iocb->ki_filp);
|
|
|
percpu_ref_put(&iocb->ki_ctx->reqs);
|
|
percpu_ref_put(&iocb->ki_ctx->reqs);
|
|
|
kmem_cache_free(kiocb_cachep, iocb);
|
|
kmem_cache_free(kiocb_cachep, iocb);
|
|
|
}
|
|
}
|
|
@@ -1418,7 +1431,6 @@ static void aio_complete_rw(struct kiocb *kiocb, long res, long res2)
|
|
|
file_end_write(kiocb->ki_filp);
|
|
file_end_write(kiocb->ki_filp);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- fput(kiocb->ki_filp);
|
|
|
|
|
aio_complete(iocb, res, res2);
|
|
aio_complete(iocb, res, res2);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1426,9 +1438,6 @@ static int aio_prep_rw(struct kiocb *req, const struct iocb *iocb)
|
|
|
{
|
|
{
|
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
|
|
- req->ki_filp = fget(iocb->aio_fildes);
|
|
|
|
|
- if (unlikely(!req->ki_filp))
|
|
|
|
|
- return -EBADF;
|
|
|
|
|
req->ki_complete = aio_complete_rw;
|
|
req->ki_complete = aio_complete_rw;
|
|
|
req->private = NULL;
|
|
req->private = NULL;
|
|
|
req->ki_pos = iocb->aio_offset;
|
|
req->ki_pos = iocb->aio_offset;
|
|
@@ -1445,7 +1454,7 @@ static int aio_prep_rw(struct kiocb *req, const struct iocb *iocb)
|
|
|
ret = ioprio_check_cap(iocb->aio_reqprio);
|
|
ret = ioprio_check_cap(iocb->aio_reqprio);
|
|
|
if (ret) {
|
|
if (ret) {
|
|
|
pr_debug("aio ioprio check cap error: %d\n", ret);
|
|
pr_debug("aio ioprio check cap error: %d\n", ret);
|
|
|
- goto out_fput;
|
|
|
|
|
|
|
+ return ret;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
req->ki_ioprio = iocb->aio_reqprio;
|
|
req->ki_ioprio = iocb->aio_reqprio;
|
|
@@ -1454,14 +1463,10 @@ static int aio_prep_rw(struct kiocb *req, const struct iocb *iocb)
|
|
|
|
|
|
|
|
ret = kiocb_set_rw_flags(req, iocb->aio_rw_flags);
|
|
ret = kiocb_set_rw_flags(req, iocb->aio_rw_flags);
|
|
|
if (unlikely(ret))
|
|
if (unlikely(ret))
|
|
|
- goto out_fput;
|
|
|
|
|
|
|
+ return ret;
|
|
|
|
|
|
|
|
req->ki_flags &= ~IOCB_HIPRI; /* no one is going to poll for this I/O */
|
|
req->ki_flags &= ~IOCB_HIPRI; /* no one is going to poll for this I/O */
|
|
|
return 0;
|
|
return 0;
|
|
|
-
|
|
|
|
|
-out_fput:
|
|
|
|
|
- fput(req->ki_filp);
|
|
|
|
|
- return ret;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static int aio_setup_rw(int rw, const struct iocb *iocb, struct iovec **iovec,
|
|
static int aio_setup_rw(int rw, const struct iocb *iocb, struct iovec **iovec,
|
|
@@ -1515,24 +1520,19 @@ static ssize_t aio_read(struct kiocb *req, const struct iocb *iocb,
|
|
|
if (ret)
|
|
if (ret)
|
|
|
return ret;
|
|
return ret;
|
|
|
file = req->ki_filp;
|
|
file = req->ki_filp;
|
|
|
-
|
|
|
|
|
- ret = -EBADF;
|
|
|
|
|
if (unlikely(!(file->f_mode & FMODE_READ)))
|
|
if (unlikely(!(file->f_mode & FMODE_READ)))
|
|
|
- goto out_fput;
|
|
|
|
|
|
|
+ return -EBADF;
|
|
|
ret = -EINVAL;
|
|
ret = -EINVAL;
|
|
|
if (unlikely(!file->f_op->read_iter))
|
|
if (unlikely(!file->f_op->read_iter))
|
|
|
- goto out_fput;
|
|
|
|
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
|
|
ret = aio_setup_rw(READ, iocb, &iovec, vectored, compat, &iter);
|
|
ret = aio_setup_rw(READ, iocb, &iovec, vectored, compat, &iter);
|
|
|
if (ret)
|
|
if (ret)
|
|
|
- goto out_fput;
|
|
|
|
|
|
|
+ return ret;
|
|
|
ret = rw_verify_area(READ, file, &req->ki_pos, iov_iter_count(&iter));
|
|
ret = rw_verify_area(READ, file, &req->ki_pos, iov_iter_count(&iter));
|
|
|
if (!ret)
|
|
if (!ret)
|
|
|
aio_rw_done(req, call_read_iter(file, req, &iter));
|
|
aio_rw_done(req, call_read_iter(file, req, &iter));
|
|
|
kfree(iovec);
|
|
kfree(iovec);
|
|
|
-out_fput:
|
|
|
|
|
- if (unlikely(ret))
|
|
|
|
|
- fput(file);
|
|
|
|
|
return ret;
|
|
return ret;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1549,16 +1549,14 @@ static ssize_t aio_write(struct kiocb *req, const struct iocb *iocb,
|
|
|
return ret;
|
|
return ret;
|
|
|
file = req->ki_filp;
|
|
file = req->ki_filp;
|
|
|
|
|
|
|
|
- ret = -EBADF;
|
|
|
|
|
if (unlikely(!(file->f_mode & FMODE_WRITE)))
|
|
if (unlikely(!(file->f_mode & FMODE_WRITE)))
|
|
|
- goto out_fput;
|
|
|
|
|
- ret = -EINVAL;
|
|
|
|
|
|
|
+ return -EBADF;
|
|
|
if (unlikely(!file->f_op->write_iter))
|
|
if (unlikely(!file->f_op->write_iter))
|
|
|
- goto out_fput;
|
|
|
|
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
|
|
ret = aio_setup_rw(WRITE, iocb, &iovec, vectored, compat, &iter);
|
|
ret = aio_setup_rw(WRITE, iocb, &iovec, vectored, compat, &iter);
|
|
|
if (ret)
|
|
if (ret)
|
|
|
- goto out_fput;
|
|
|
|
|
|
|
+ return ret;
|
|
|
ret = rw_verify_area(WRITE, file, &req->ki_pos, iov_iter_count(&iter));
|
|
ret = rw_verify_area(WRITE, file, &req->ki_pos, iov_iter_count(&iter));
|
|
|
if (!ret) {
|
|
if (!ret) {
|
|
|
/*
|
|
/*
|
|
@@ -1576,9 +1574,6 @@ static ssize_t aio_write(struct kiocb *req, const struct iocb *iocb,
|
|
|
aio_rw_done(req, call_write_iter(file, req, &iter));
|
|
aio_rw_done(req, call_write_iter(file, req, &iter));
|
|
|
}
|
|
}
|
|
|
kfree(iovec);
|
|
kfree(iovec);
|
|
|
-out_fput:
|
|
|
|
|
- if (unlikely(ret))
|
|
|
|
|
- fput(file);
|
|
|
|
|
return ret;
|
|
return ret;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1588,7 +1583,6 @@ static void aio_fsync_work(struct work_struct *work)
|
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
|
|
ret = vfs_fsync(req->file, req->datasync);
|
|
ret = vfs_fsync(req->file, req->datasync);
|
|
|
- fput(req->file);
|
|
|
|
|
aio_complete(container_of(req, struct aio_kiocb, fsync), ret, 0);
|
|
aio_complete(container_of(req, struct aio_kiocb, fsync), ret, 0);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1599,13 +1593,8 @@ static int aio_fsync(struct fsync_iocb *req, const struct iocb *iocb,
|
|
|
iocb->aio_rw_flags))
|
|
iocb->aio_rw_flags))
|
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
- req->file = fget(iocb->aio_fildes);
|
|
|
|
|
- if (unlikely(!req->file))
|
|
|
|
|
- return -EBADF;
|
|
|
|
|
- if (unlikely(!req->file->f_op->fsync)) {
|
|
|
|
|
- fput(req->file);
|
|
|
|
|
|
|
+ if (unlikely(!req->file->f_op->fsync))
|
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
req->datasync = datasync;
|
|
req->datasync = datasync;
|
|
|
INIT_WORK(&req->work, aio_fsync_work);
|
|
INIT_WORK(&req->work, aio_fsync_work);
|
|
@@ -1615,10 +1604,7 @@ static int aio_fsync(struct fsync_iocb *req, const struct iocb *iocb,
|
|
|
|
|
|
|
|
static inline void aio_poll_complete(struct aio_kiocb *iocb, __poll_t mask)
|
|
static inline void aio_poll_complete(struct aio_kiocb *iocb, __poll_t mask)
|
|
|
{
|
|
{
|
|
|
- struct file *file = iocb->poll.file;
|
|
|
|
|
-
|
|
|
|
|
aio_complete(iocb, mangle_poll(mask), 0);
|
|
aio_complete(iocb, mangle_poll(mask), 0);
|
|
|
- fput(file);
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void aio_poll_complete_work(struct work_struct *work)
|
|
static void aio_poll_complete_work(struct work_struct *work)
|
|
@@ -1743,9 +1729,6 @@ static ssize_t aio_poll(struct aio_kiocb *aiocb, const struct iocb *iocb)
|
|
|
|
|
|
|
|
INIT_WORK(&req->work, aio_poll_complete_work);
|
|
INIT_WORK(&req->work, aio_poll_complete_work);
|
|
|
req->events = demangle_poll(iocb->aio_buf) | EPOLLERR | EPOLLHUP;
|
|
req->events = demangle_poll(iocb->aio_buf) | EPOLLERR | EPOLLHUP;
|
|
|
- req->file = fget(iocb->aio_fildes);
|
|
|
|
|
- if (unlikely(!req->file))
|
|
|
|
|
- return -EBADF;
|
|
|
|
|
|
|
|
|
|
req->head = NULL;
|
|
req->head = NULL;
|
|
|
req->woken = false;
|
|
req->woken = false;
|
|
@@ -1788,10 +1771,8 @@ static ssize_t aio_poll(struct aio_kiocb *aiocb, const struct iocb *iocb)
|
|
|
spin_unlock_irq(&ctx->ctx_lock);
|
|
spin_unlock_irq(&ctx->ctx_lock);
|
|
|
|
|
|
|
|
out:
|
|
out:
|
|
|
- if (unlikely(apt.error)) {
|
|
|
|
|
- fput(req->file);
|
|
|
|
|
|
|
+ if (unlikely(apt.error))
|
|
|
return apt.error;
|
|
return apt.error;
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
if (mask)
|
|
if (mask)
|
|
|
aio_poll_complete(aiocb, mask);
|
|
aio_poll_complete(aiocb, mask);
|
|
@@ -1829,6 +1810,11 @@ static int __io_submit_one(struct kioctx *ctx, const struct iocb *iocb,
|
|
|
if (unlikely(!req))
|
|
if (unlikely(!req))
|
|
|
goto out_put_reqs_available;
|
|
goto out_put_reqs_available;
|
|
|
|
|
|
|
|
|
|
+ req->ki_filp = fget(iocb->aio_fildes);
|
|
|
|
|
+ ret = -EBADF;
|
|
|
|
|
+ if (unlikely(!req->ki_filp))
|
|
|
|
|
+ goto out_put_req;
|
|
|
|
|
+
|
|
|
if (iocb->aio_flags & IOCB_FLAG_RESFD) {
|
|
if (iocb->aio_flags & IOCB_FLAG_RESFD) {
|
|
|
/*
|
|
/*
|
|
|
* If the IOCB_FLAG_RESFD flag of aio_flags is set, get an
|
|
* If the IOCB_FLAG_RESFD flag of aio_flags is set, get an
|