switch (vio->vui_io_subtype) {
case IO_NORMAL:
- vio->vui_iov = args->u.normal.via_iov;
- vio->vui_nrsegs = args->u.normal.via_nrsegs;
- vio->vui_tot_nrsegs = vio->vui_nrsegs;
+ vio->vui_iter = args->u.normal.via_iter;
+#ifndef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
+ vio->vui_tot_nrsegs = vio->vui_iter->nr_segs;
+#endif /* !HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
vio->vui_iocb = args->u.normal.via_iocb;
/* Direct IO reads must also take range lock,
* or multiple reads will try to work on the same pages
/* prepare IO restart */
if (count > 0 && args->via_io_subtype == IO_NORMAL) {
- args->u.normal.via_iov = vio->vui_iov;
- args->u.normal.via_nrsegs = vio->vui_tot_nrsegs;
+ args->u.normal.via_iter = vio->vui_iter;
+#ifndef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
+ args->u.normal.via_iter->nr_segs = vio->vui_tot_nrsegs;
+#endif /* !HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
}
}
GOTO(out, rc);
}
/*
+ * Read from a file (through the page cache).
+ */
+static ssize_t ll_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
+{
+ struct vvp_io_args *args;
+ struct lu_env *env;
+ ssize_t result;
+ int refcheck;
+
+ env = cl_env_get(&refcheck);
+ if (IS_ERR(env))
+ return PTR_ERR(env);
+
+ args = ll_env_args(env, IO_NORMAL);
+ args->u.normal.via_iter = to;
+ args->u.normal.via_iocb = iocb;
+
+ result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_READ,
+ &iocb->ki_pos, iov_iter_count(to));
+ cl_env_put(env, &refcheck);
+ return result;
+}
+
+/*
+ * Write to a file (through the page cache).
+ */
+static ssize_t ll_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
+{
+ struct vvp_io_args *args;
+ struct lu_env *env;
+ ssize_t result;
+ int refcheck;
+
+ env = cl_env_get(&refcheck);
+ if (IS_ERR(env))
+ return PTR_ERR(env);
+
+ args = ll_env_args(env, IO_NORMAL);
+ args->u.normal.via_iter = from;
+ args->u.normal.via_iocb = iocb;
+
+ result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_WRITE,
+ &iocb->ki_pos, iov_iter_count(from));
+ cl_env_put(env, &refcheck);
+ return result;
+}
+
+#ifndef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
+/*
* XXX: exact copy from kernel code (__generic_file_aio_write_nolock)
*/
static int ll_file_get_iov_count(const struct iovec *iov,
- unsigned long *nr_segs, size_t *count)
+ unsigned long *nr_segs, size_t *count)
{
- size_t cnt = 0;
- unsigned long seg;
+ size_t cnt = 0;
+ unsigned long seg;
- for (seg = 0; seg < *nr_segs; seg++) {
- const struct iovec *iv = &iov[seg];
+ for (seg = 0; seg < *nr_segs; seg++) {
+ const struct iovec *iv = &iov[seg];
- /*
- * If any segment has a negative length, or the cumulative
- * length ever wraps negative then return -EINVAL.
- */
- cnt += iv->iov_len;
- if (unlikely((ssize_t)(cnt|iv->iov_len) < 0))
- return -EINVAL;
- if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
- continue;
- if (seg == 0)
- return -EFAULT;
- *nr_segs = seg;
- cnt -= iv->iov_len; /* This segment is no good */
- break;
- }
- *count = cnt;
- return 0;
+ /*
+ * If any segment has a negative length, or the cumulative
+ * length ever wraps negative then return -EINVAL.
+ */
+ cnt += iv->iov_len;
+ if (unlikely((ssize_t)(cnt|iv->iov_len) < 0))
+ return -EINVAL;
+ if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
+ continue;
+ if (seg == 0)
+ return -EFAULT;
+ *nr_segs = seg;
+ cnt -= iv->iov_len; /* This segment is no good */
+ break;
+ }
+ *count = cnt;
+ return 0;
}
static ssize_t ll_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
- struct lu_env *env;
- struct vvp_io_args *args;
- struct iovec *local_iov;
- size_t count;
- ssize_t result;
- int refcheck;
- ENTRY;
+ struct iovec *local_iov;
+ struct iov_iter *to;
+ size_t iov_count;
+ ssize_t result;
+ ENTRY;
- result = ll_file_get_iov_count(iov, &nr_segs, &count);
- if (result)
- RETURN(result);
-
- env = cl_env_get(&refcheck);
- if (IS_ERR(env))
- RETURN(PTR_ERR(env));
+ result = ll_file_get_iov_count(iov, &nr_segs, &iov_count);
+ if (result)
+ RETURN(result);
if (nr_segs == 1) {
+ struct lu_env *env;
+ int refcheck;
+
+ env = cl_env_get(&refcheck);
+ if (IS_ERR(env))
+ RETURN(PTR_ERR(env));
+
local_iov = &ll_env_info(env)->lti_local_iov;
*local_iov = *iov;
+
+ cl_env_put(env, &refcheck);
} else {
OBD_ALLOC(local_iov, sizeof(*iov) * nr_segs);
- if (local_iov == NULL) {
- cl_env_put(env, &refcheck);
+ if (local_iov == NULL)
RETURN(-ENOMEM);
- }
memcpy(local_iov, iov, sizeof(*iov) * nr_segs);
}
- args = ll_env_args(env, IO_NORMAL);
- args->u.normal.via_iov = local_iov;
- args->u.normal.via_nrsegs = nr_segs;
- args->u.normal.via_iocb = iocb;
-
- result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_READ,
- &iocb->ki_pos, count);
+ OBD_ALLOC_PTR(to);
+ if (to == NULL) {
+ result = -ENOMEM;
+ goto out;
+ }
+# ifdef HAVE_IOV_ITER_INIT_DIRECTION
+ iov_iter_init(to, READ, local_iov, nr_segs, iov_count);
+# else /* !HAVE_IOV_ITER_INIT_DIRECTION */
+ iov_iter_init(to, local_iov, nr_segs, iov_count, 0);
+# endif /* HAVE_IOV_ITER_INIT_DIRECTION */
- cl_env_put(env, &refcheck);
+ result = ll_file_read_iter(iocb, to);
+ OBD_FREE_PTR(to);
+out:
if (nr_segs > 1)
OBD_FREE(local_iov, sizeof(*iov) * nr_segs);
static ssize_t ll_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
- struct lu_env *env;
- struct vvp_io_args *args;
- struct iovec *local_iov;
- size_t count;
- ssize_t result;
- int refcheck;
- ENTRY;
-
- result = ll_file_get_iov_count(iov, &nr_segs, &count);
- if (result)
- RETURN(result);
+ struct iovec *local_iov;
+ struct iov_iter *from;
+ size_t iov_count;
+ ssize_t result;
+ ENTRY;
- env = cl_env_get(&refcheck);
- if (IS_ERR(env))
- RETURN(PTR_ERR(env));
+ result = ll_file_get_iov_count(iov, &nr_segs, &iov_count);
+ if (result)
+ RETURN(result);
if (nr_segs == 1) {
+ struct lu_env *env;
+ int refcheck;
+
+ env = cl_env_get(&refcheck);
+ if (IS_ERR(env))
+ RETURN(PTR_ERR(env));
+
local_iov = &ll_env_info(env)->lti_local_iov;
*local_iov = *iov;
+
+ cl_env_put(env, &refcheck);
} else {
OBD_ALLOC(local_iov, sizeof(*iov) * nr_segs);
- if (local_iov == NULL) {
- cl_env_put(env, &refcheck);
+ if (local_iov == NULL)
RETURN(-ENOMEM);
- }
memcpy(local_iov, iov, sizeof(*iov) * nr_segs);
}
- args = ll_env_args(env, IO_NORMAL);
- args->u.normal.via_iov = local_iov;
- args->u.normal.via_nrsegs = nr_segs;
- args->u.normal.via_iocb = iocb;
+ OBD_ALLOC_PTR(from);
+ if (from == NULL) {
+ result = -ENOMEM;
+ goto out;
+ }
+# ifdef HAVE_IOV_ITER_INIT_DIRECTION
+ iov_iter_init(from, WRITE, local_iov, nr_segs, iov_count);
+# else /* !HAVE_IOV_ITER_INIT_DIRECTION */
+ iov_iter_init(from, local_iov, nr_segs, iov_count, 0);
+# endif /* HAVE_IOV_ITER_INIT_DIRECTION */
- result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_WRITE,
- &iocb->ki_pos, count);
- cl_env_put(env, &refcheck);
+ result = ll_file_write_iter(iocb, from);
+ OBD_FREE_PTR(from);
+out:
if (nr_segs > 1)
OBD_FREE(local_iov, sizeof(*iov) * nr_segs);
cl_env_put(env, &refcheck);
RETURN(result);
}
+#endif /* !HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
/*
* Send file content (through pagecache) somewhere with helper
/* -o localflock - only provides locally consistent flock locks */
struct file_operations ll_file_operations = {
- .read = ll_file_read,
- .aio_read = ll_file_aio_read,
- .write = ll_file_write,
- .aio_write = ll_file_aio_write,
- .unlocked_ioctl = ll_file_ioctl,
- .open = ll_file_open,
- .release = ll_file_release,
- .mmap = ll_file_mmap,
- .llseek = ll_file_seek,
- .splice_read = ll_file_splice_read,
- .fsync = ll_fsync,
- .flush = ll_flush
+#ifdef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
+ .read = new_sync_read,
+ .read_iter = ll_file_read_iter,
+ .write = new_sync_write,
+ .write_iter = ll_file_write_iter,
+#else /* !HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
+ .read = ll_file_read,
+ .aio_read = ll_file_aio_read,
+ .write = ll_file_write,
+ .aio_write = ll_file_aio_write,
+#endif /* HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
+ .unlocked_ioctl = ll_file_ioctl,
+ .open = ll_file_open,
+ .release = ll_file_release,
+ .mmap = ll_file_mmap,
+ .llseek = ll_file_seek,
+ .splice_read = ll_file_splice_read,
+ .fsync = ll_fsync,
+ .flush = ll_flush
};
struct file_operations ll_file_operations_flock = {
- .read = ll_file_read,
- .aio_read = ll_file_aio_read,
- .write = ll_file_write,
- .aio_write = ll_file_aio_write,
- .unlocked_ioctl = ll_file_ioctl,
- .open = ll_file_open,
- .release = ll_file_release,
- .mmap = ll_file_mmap,
- .llseek = ll_file_seek,
- .splice_read = ll_file_splice_read,
- .fsync = ll_fsync,
- .flush = ll_flush,
- .flock = ll_file_flock,
- .lock = ll_file_flock
+#ifdef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
+ .read = new_sync_read,
+ .read_iter = ll_file_read_iter,
+ .write = new_sync_write,
+ .write_iter = ll_file_write_iter,
+#else /* !HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
+ .read = ll_file_read,
+ .aio_read = ll_file_aio_read,
+ .write = ll_file_write,
+ .aio_write = ll_file_aio_write,
+#endif /* HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
+ .unlocked_ioctl = ll_file_ioctl,
+ .open = ll_file_open,
+ .release = ll_file_release,
+ .mmap = ll_file_mmap,
+ .llseek = ll_file_seek,
+ .splice_read = ll_file_splice_read,
+ .fsync = ll_fsync,
+ .flush = ll_flush,
+ .flock = ll_file_flock,
+ .lock = ll_file_flock
};
/* These are for -o noflock - to return ENOSYS on flock calls */
struct file_operations ll_file_operations_noflock = {
- .read = ll_file_read,
- .aio_read = ll_file_aio_read,
- .write = ll_file_write,
- .aio_write = ll_file_aio_write,
- .unlocked_ioctl = ll_file_ioctl,
- .open = ll_file_open,
- .release = ll_file_release,
- .mmap = ll_file_mmap,
- .llseek = ll_file_seek,
- .splice_read = ll_file_splice_read,
- .fsync = ll_fsync,
- .flush = ll_flush,
- .flock = ll_file_noflock,
- .lock = ll_file_noflock
+#ifdef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
+ .read = new_sync_read,
+ .read_iter = ll_file_read_iter,
+ .write = new_sync_write,
+ .write_iter = ll_file_write_iter,
+#else /* !HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
+ .read = ll_file_read,
+ .aio_read = ll_file_aio_read,
+ .write = ll_file_write,
+ .aio_write = ll_file_aio_write,
+#endif /* HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
+ .unlocked_ioctl = ll_file_ioctl,
+ .open = ll_file_open,
+ .release = ll_file_release,
+ .mmap = ll_file_mmap,
+ .llseek = ll_file_seek,
+ .splice_read = ll_file_splice_read,
+ .fsync = ll_fsync,
+ .flush = ll_flush,
+ .flock = ll_file_noflock,
+ .lock = ll_file_noflock
};
struct inode_operations ll_file_inode_operations = {
struct vm_area_struct *vma;
struct cl_lock_descr *descr = &vti->vti_descr;
ldlm_policy_data_t policy;
- unsigned long addr;
- unsigned long seg;
- ssize_t count;
- int result = 0;
- ENTRY;
+#ifdef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
+ struct iovec iov;
+ struct iov_iter i;
+#else
+ unsigned long seg;
+#endif
+ int result = 0;
+ ENTRY;
LASSERT(io->ci_type == CIT_READ || io->ci_type == CIT_WRITE);
if (!cl_is_normalio(env, io))
RETURN(0);
- if (vio->vui_iov == NULL) /* nfs or loop back device write */
+ /* nfs or loop back device write */
+ if (vio->vui_iter == NULL)
RETURN(0);
/* No MM (e.g. NFS)? No vmas too. */
if (mm == NULL)
RETURN(0);
- for (seg = 0; seg < vio->vui_nrsegs; seg++) {
- const struct iovec *iv = &vio->vui_iov[seg];
+#ifdef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
+ iov_for_each(iov, i, *(vio->vui_iter)) {
+#else /* !HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
+ for (seg = 0; seg < vio->vui_iter->nr_segs; seg++) {
+ const struct iovec iov = vio->vui_iter->iov[seg];
+#endif /* HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
+ unsigned long addr = (unsigned long)iov.iov_base;
+ size_t count = iov.iov_len;
- addr = (unsigned long)iv->iov_base;
- count = iv->iov_len;
if (count == 0)
continue;
struct vvp_io *vio = cl2vvp_io(env, ios);
struct cl_io *io = ios->cis_io;
struct cl_object *obj = ios->cis_io->ci_obj;
+#ifndef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
struct iovec *iov;
-
+#endif
CLOBINVRNT(env, obj, vvp_object_invariant(obj));
if (!cl_is_normalio(env, io))
return;
- LASSERT(vio->vui_tot_nrsegs >= vio->vui_nrsegs);
+#ifdef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
+ vio->vui_tot_count -= nob;
+ iov_iter_reexpand(vio->vui_iter, vio->vui_tot_count);
+#else /* !HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
+ LASSERT(vio->vui_tot_nrsegs >= vio->vui_iter->nr_segs);
LASSERT(vio->vui_tot_count >= nob);
/* Restore the iov changed in vvp_io_update_iov() */
if (vio->vui_iov_olen > 0) {
- vio->vui_iov[vio->vui_nrsegs - 1].iov_len = vio->vui_iov_olen;
+ unsigned long idx = vio->vui_iter->nr_segs - 1;
+
+ /* In the latest kernels iov is const so that
+ * changes are done using iter helpers. In older
+ * kernels those helpers don't exist we lustre
+ * has to do some of the management of the iter
+ * itself. */
+ iov = (struct iovec *)&vio->vui_iter->iov[idx];
+ iov->iov_len = vio->vui_iov_olen;
vio->vui_iov_olen = 0;
}
- /* advance iov */
- iov = vio->vui_iov;
+ /* In the latest kernels special helpers exist to help
+ * advance the iov but we don't have that in older kernels
+ * so we need to do the book keeping ourselves. */
+ iov = (struct iovec *)vio->vui_iter->iov;
while (nob > 0) {
if (iov->iov_len > nob) {
iov->iov_len -= nob;
vio->vui_tot_nrsegs--;
}
- vio->vui_iov = iov;
+ vio->vui_iter->iov = iov;
vio->vui_tot_count -= nob;
+#endif /* HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
}
static void vvp_io_update_iov(const struct lu_env *env,
struct vvp_io *vio, struct cl_io *io)
{
- int i;
size_t size = io->u.ci_rw.crw_count;
+#ifdef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
+ if (!cl_is_normalio(env, io) || vio->vui_iter == NULL)
+ return;
+
+ iov_iter_truncate(vio->vui_iter, size);
+#else /* !HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
+ unsigned long i;
vio->vui_iov_olen = 0;
if (!cl_is_normalio(env, io) || vio->vui_tot_nrsegs == 0)
return;
for (i = 0; i < vio->vui_tot_nrsegs; i++) {
- struct iovec *iv = &vio->vui_iov[i];
+ struct iovec *iv = (struct iovec *) &vio->vui_iter->iov[i];
if (iv->iov_len < size) {
size -= iv->iov_len;
}
}
- vio->vui_nrsegs = i + 1;
- LASSERTF(vio->vui_tot_nrsegs >= vio->vui_nrsegs,
+ vio->vui_iter->nr_segs = i + 1;
+ LASSERTF(vio->vui_tot_nrsegs >= vio->vui_iter->nr_segs,
"tot_nrsegs: %lu, nrsegs: %lu\n",
- vio->vui_tot_nrsegs, vio->vui_nrsegs);
+ vio->vui_tot_nrsegs, vio->vui_iter->nr_segs);
+#endif /* !HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
}
static int vvp_io_rw_lock(const struct lu_env *env, struct cl_io *io,
switch (vio->vui_io_subtype) {
case IO_NORMAL:
LASSERT(vio->vui_iocb->ki_pos == pos);
+#ifdef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
+ result = generic_file_read_iter(vio->vui_iocb, vio->vui_iter);
+#else
result = generic_file_aio_read(vio->vui_iocb,
- vio->vui_iov, vio->vui_nrsegs,
+ vio->vui_iter->iov,
+ vio->vui_iter->nr_segs,
vio->vui_iocb->ki_pos);
+#endif
break;
case IO_SPLICE:
result = generic_file_splice_read(file, &pos,
RETURN(-EFBIG);
}
- if (vio->vui_iov == NULL) {
+ if (vio->vui_iter == NULL) {
/* from a temp io in ll_cl_init(). */
result = 0;
} else {
* consistency, proper locking to protect against writes,
* trucates, etc. is handled in the higher layers of lustre.
*/
+#ifdef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
+ result = generic_file_write_iter(vio->vui_iocb, vio->vui_iter);
+#else
result = __generic_file_aio_write(vio->vui_iocb,
- vio->vui_iov, vio->vui_nrsegs,
+ vio->vui_iter->iov,
+ vio->vui_iter->nr_segs,
&vio->vui_iocb->ki_pos);
+#endif
if (result > 0 || result == -EIOCBQUEUED) {
ssize_t err;
result = 1;
else {
vio->vui_tot_count = count;
+#ifndef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
vio->vui_tot_nrsegs = 0;
+#endif
}
/* for read/write, we store the jobid in the inode, and