|
@@ -25,6 +25,7 @@
|
|
|
typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
|
|
|
typedef ssize_t (*iov_fn_t)(struct kiocb *, const struct iovec *,
|
|
|
unsigned long, loff_t);
|
|
|
+typedef ssize_t (*iter_fn_t)(struct kiocb *, struct iov_iter *);
|
|
|
|
|
|
const struct file_operations generic_ro_fops = {
|
|
|
.llseek = generic_file_llseek,
|
|
@@ -390,6 +391,27 @@ ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *pp
|
|
|
|
|
|
EXPORT_SYMBOL(do_sync_read);
|
|
|
|
|
|
+ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
|
|
|
+{
|
|
|
+ struct iovec iov = { .iov_base = buf, .iov_len = len };
|
|
|
+ struct kiocb kiocb;
|
|
|
+ struct iov_iter iter;
|
|
|
+ ssize_t ret;
|
|
|
+
|
|
|
+ init_sync_kiocb(&kiocb, filp);
|
|
|
+ kiocb.ki_pos = *ppos;
|
|
|
+ kiocb.ki_nbytes = len;
|
|
|
+ iov_iter_init(&iter, READ, &iov, 1, len);
|
|
|
+
|
|
|
+ ret = filp->f_op->read_iter(&kiocb, &iter);
|
|
|
+ if (-EIOCBQUEUED == ret)
|
|
|
+ ret = wait_on_sync_kiocb(&kiocb);
|
|
|
+ *ppos = kiocb.ki_pos;
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+EXPORT_SYMBOL(new_sync_read);
|
|
|
+
|
|
|
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
|
|
|
{
|
|
|
ssize_t ret;
|
|
@@ -406,8 +428,10 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
|
|
|
count = ret;
|
|
|
if (file->f_op->read)
|
|
|
ret = file->f_op->read(file, buf, count, pos);
|
|
|
- else
|
|
|
+ else if (file->f_op->aio_read)
|
|
|
ret = do_sync_read(file, buf, count, pos);
|
|
|
+ else
|
|
|
+ ret = new_sync_read(file, buf, count, pos);
|
|
|
if (ret > 0) {
|
|
|
fsnotify_access(file);
|
|
|
add_rchar(current, ret);
|
|
@@ -439,6 +463,27 @@ ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, lof
|
|
|
|
|
|
EXPORT_SYMBOL(do_sync_write);
|
|
|
|
|
|
+ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
|
|
|
+{
|
|
|
+ struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
|
|
|
+ struct kiocb kiocb;
|
|
|
+ struct iov_iter iter;
|
|
|
+ ssize_t ret;
|
|
|
+
|
|
|
+ init_sync_kiocb(&kiocb, filp);
|
|
|
+ kiocb.ki_pos = *ppos;
|
|
|
+ kiocb.ki_nbytes = len;
|
|
|
+ iov_iter_init(&iter, WRITE, &iov, 1, len);
|
|
|
+
|
|
|
+ ret = filp->f_op->write_iter(&kiocb, &iter);
|
|
|
+ if (-EIOCBQUEUED == ret)
|
|
|
+ ret = wait_on_sync_kiocb(&kiocb);
|
|
|
+ *ppos = kiocb.ki_pos;
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+EXPORT_SYMBOL(new_sync_write);
|
|
|
+
|
|
|
ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos)
|
|
|
{
|
|
|
mm_segment_t old_fs;
|
|
@@ -455,8 +500,10 @@ ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t
|
|
|
count = MAX_RW_COUNT;
|
|
|
if (file->f_op->write)
|
|
|
ret = file->f_op->write(file, p, count, pos);
|
|
|
- else
|
|
|
+ else if (file->f_op->aio_write)
|
|
|
ret = do_sync_write(file, p, count, pos);
|
|
|
+ else
|
|
|
+ ret = new_sync_write(file, p, count, pos);
|
|
|
set_fs(old_fs);
|
|
|
if (ret > 0) {
|
|
|
fsnotify_modify(file);
|
|
@@ -483,8 +530,10 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_
|
|
|
file_start_write(file);
|
|
|
if (file->f_op->write)
|
|
|
ret = file->f_op->write(file, buf, count, pos);
|
|
|
- else
|
|
|
+ else if (file->f_op->aio_write)
|
|
|
ret = do_sync_write(file, buf, count, pos);
|
|
|
+ else
|
|
|
+ ret = new_sync_write(file, buf, count, pos);
|
|
|
if (ret > 0) {
|
|
|
fsnotify_modify(file);
|
|
|
add_wchar(current, ret);
|
|
@@ -601,6 +650,25 @@ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to)
|
|
|
}
|
|
|
EXPORT_SYMBOL(iov_shorten);
|
|
|
|
|
|
+static ssize_t do_iter_readv_writev(struct file *filp, int rw, const struct iovec *iov,
|
|
|
+ unsigned long nr_segs, size_t len, loff_t *ppos, iter_fn_t fn)
|
|
|
+{
|
|
|
+ struct kiocb kiocb;
|
|
|
+ struct iov_iter iter;
|
|
|
+ ssize_t ret;
|
|
|
+
|
|
|
+ init_sync_kiocb(&kiocb, filp);
|
|
|
+ kiocb.ki_pos = *ppos;
|
|
|
+ kiocb.ki_nbytes = len;
|
|
|
+
|
|
|
+ iov_iter_init(&iter, rw, iov, nr_segs, len);
|
|
|
+ ret = fn(&kiocb, &iter);
|
|
|
+ if (ret == -EIOCBQUEUED)
|
|
|
+ ret = wait_on_sync_kiocb(&kiocb);
|
|
|
+ *ppos = kiocb.ki_pos;
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov,
|
|
|
unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn)
|
|
|
{
|
|
@@ -738,6 +806,7 @@ static ssize_t do_readv_writev(int type, struct file *file,
|
|
|
ssize_t ret;
|
|
|
io_fn_t fn;
|
|
|
iov_fn_t fnv;
|
|
|
+ iter_fn_t iter_fn;
|
|
|
|
|
|
ret = rw_copy_check_uvector(type, uvector, nr_segs,
|
|
|
ARRAY_SIZE(iovstack), iovstack, &iov);
|
|
@@ -753,13 +822,18 @@ static ssize_t do_readv_writev(int type, struct file *file,
|
|
|
if (type == READ) {
|
|
|
fn = file->f_op->read;
|
|
|
fnv = file->f_op->aio_read;
|
|
|
+ iter_fn = file->f_op->read_iter;
|
|
|
} else {
|
|
|
fn = (io_fn_t)file->f_op->write;
|
|
|
fnv = file->f_op->aio_write;
|
|
|
+ iter_fn = file->f_op->write_iter;
|
|
|
file_start_write(file);
|
|
|
}
|
|
|
|
|
|
- if (fnv)
|
|
|
+ if (iter_fn)
|
|
|
+ ret = do_iter_readv_writev(file, type, iov, nr_segs, tot_len,
|
|
|
+ pos, iter_fn);
|
|
|
+ else if (fnv)
|
|
|
ret = do_sync_readv_writev(file, iov, nr_segs, tot_len,
|
|
|
pos, fnv);
|
|
|
else
|
|
@@ -912,6 +986,7 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
|
|
|
ssize_t ret;
|
|
|
io_fn_t fn;
|
|
|
iov_fn_t fnv;
|
|
|
+ iter_fn_t iter_fn;
|
|
|
|
|
|
ret = compat_rw_copy_check_uvector(type, uvector, nr_segs,
|
|
|
UIO_FASTIOV, iovstack, &iov);
|
|
@@ -927,13 +1002,18 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
|
|
|
if (type == READ) {
|
|
|
fn = file->f_op->read;
|
|
|
fnv = file->f_op->aio_read;
|
|
|
+ iter_fn = file->f_op->read_iter;
|
|
|
} else {
|
|
|
fn = (io_fn_t)file->f_op->write;
|
|
|
fnv = file->f_op->aio_write;
|
|
|
+ iter_fn = file->f_op->write_iter;
|
|
|
file_start_write(file);
|
|
|
}
|
|
|
|
|
|
- if (fnv)
|
|
|
+ if (iter_fn)
|
|
|
+ ret = do_iter_readv_writev(file, type, iov, nr_segs, tot_len,
|
|
|
+ pos, iter_fn);
|
|
|
+ else if (fnv)
|
|
|
ret = do_sync_readv_writev(file, iov, nr_segs, tot_len,
|
|
|
pos, fnv);
|
|
|
else
|