Skip to content

Commit

Permalink
cifs_iovec_read: keep iov_iter between the calls of cifs_readdata_to_…
Browse files Browse the repository at this point in the history
…iov()

... we are doing them on adjacent parts of file, so what happens is that
each subsequent call works to rebuild the iov_iter to exact state it
had been abandoned in by previous one.  Just keep it through the entire
cifs_iovec_read().  And use copy_page_to_iter() instead of doing
kmap/copy_to_user/kunmap manually...

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
  • Loading branch information
Al Viro committed Apr 2, 2014
1 parent 6130f53 commit 7f25bba
Showing 1 changed file with 17 additions and 45 deletions.
62 changes: 17 additions & 45 deletions fs/cifs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -2727,56 +2727,27 @@ cifs_retry_async_readv(struct cifs_readdata *rdata)
/**
* cifs_readdata_to_iov - copy data from pages in response to an iovec
* @rdata: the readdata response with list of pages holding data
* @iov: vector in which we should copy the data
* @nr_segs: number of segments in vector
* @offset: offset into file of the first iovec
* @copied: used to return the amount of data copied to the iov
* @iter: destination for our data
*
* This function copies data from a list of pages in a readdata response into
* an array of iovecs. It will first calculate where the data should go
* based on the info in the readdata and then copy the data into that spot.
*/
static ssize_t
cifs_readdata_to_iov(struct cifs_readdata *rdata, const struct iovec *iov,
unsigned long nr_segs, loff_t offset, ssize_t *copied)
static int
cifs_readdata_to_iov(struct cifs_readdata *rdata, struct iov_iter *iter)
{
int rc = 0;
struct iov_iter ii;
size_t pos = rdata->offset - offset;
ssize_t remaining = rdata->bytes;
unsigned char *pdata;
size_t remaining = rdata->bytes;
unsigned int i;

/* set up iov_iter and advance to the correct offset */
iov_iter_init(&ii, iov, nr_segs, iov_length(iov, nr_segs), 0);
iov_iter_advance(&ii, pos);

*copied = 0;
for (i = 0; i < rdata->nr_pages; i++) {
ssize_t copy;
struct page *page = rdata->pages[i];

/* copy a whole page or whatever's left */
copy = min_t(ssize_t, remaining, PAGE_SIZE);

/* ...but limit it to whatever space is left in the iov */
copy = min_t(ssize_t, copy, iov_iter_count(&ii));

/* go while there's data to be copied and no errors */
if (copy && !rc) {
pdata = kmap(page);
rc = memcpy_toiovecend(ii.iov, pdata, ii.iov_offset,
(int)copy);
kunmap(page);
if (!rc) {
*copied += copy;
remaining -= copy;
iov_iter_advance(&ii, copy);
}
}
size_t copy = min(remaining, PAGE_SIZE);
size_t written = copy_page_to_iter(page, 0, copy, iter);
remaining -= written;
if (written < copy && iov_iter_count(iter) > 0)
break;
}

return rc;
return remaining ? -EFAULT : 0;
}

static void
Expand Down Expand Up @@ -2851,6 +2822,7 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
struct cifsFileInfo *open_file;
struct cifs_readdata *rdata, *tmp;
struct list_head rdata_list;
struct iov_iter to;
pid_t pid;

if (!nr_segs)
Expand All @@ -2860,6 +2832,8 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
if (!len)
return 0;

iov_iter_init(&to, iov, nr_segs, len, 0);

INIT_LIST_HEAD(&rdata_list);
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
open_file = file->private_data;
Expand Down Expand Up @@ -2917,12 +2891,11 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
if (!list_empty(&rdata_list))
rc = 0;

len = iov_iter_count(&to);
/* the loop below should proceed in the order of increasing offsets */
list_for_each_entry_safe(rdata, tmp, &rdata_list, list) {
again:
if (!rc) {
ssize_t copied;

/* FIXME: freezable sleep too? */
rc = wait_for_completion_killable(&rdata->done);
if (rc)
Expand All @@ -2935,17 +2908,16 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
goto again;
}
} else {
rc = cifs_readdata_to_iov(rdata, iov,
nr_segs, *poffset,
&copied);
total_read += copied;
rc = cifs_readdata_to_iov(rdata, &to);
}

}
list_del_init(&rdata->list);
kref_put(&rdata->refcount, cifs_uncached_readdata_release);
}

total_read = len - iov_iter_count(&to);

cifs_stats_bytes_read(tcon, total_read);
*poffset += total_read;

Expand Down

0 comments on commit 7f25bba

Please sign in to comment.