diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-04-11 22:28:58 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-04-11 22:28:58 -0400 |
commit | c48722c6364ec94738afa42e48b1e1f8f20e3192 (patch) | |
tree | b2abd188e9d7dac738e7d5ddad6b0bc022cd1db8 | |
parent | 34d0640e268923bb1fb9d244a047cdfcd3f77909 (diff) | |
parent | dcdbd7b269003bec7d729ca3fd143f93cf98f56e (diff) |
Merge branch '9p-iov_iter' into for-next
-rw-r--r-- | fs/9p/v9fs_vfs.h | 4 | ||||
-rw-r--r-- | fs/9p/vfs_addr.c | 80 | ||||
-rw-r--r-- | fs/9p/vfs_dir.c | 15 | ||||
-rw-r--r-- | fs/9p/vfs_file.c | 326 | ||||
-rw-r--r-- | fs/9p/xattr.c | 80 | ||||
-rw-r--r-- | include/net/9p/client.h | 8 | ||||
-rw-r--r-- | include/net/9p/transport.h | 2 | ||||
-rw-r--r-- | net/9p/client.c | 262 | ||||
-rw-r--r-- | net/9p/protocol.c | 24 | ||||
-rw-r--r-- | net/9p/trans_common.c | 42 | ||||
-rw-r--r-- | net/9p/trans_common.h | 2 | ||||
-rw-r--r-- | net/9p/trans_virtio.c | 137 |
12 files changed, 355 insertions, 627 deletions
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index b83ebfbf3fdc..5a0db6dec8d1 100644 --- a/fs/9p/v9fs_vfs.h +++ b/fs/9p/v9fs_vfs.h | |||
@@ -68,14 +68,10 @@ int v9fs_file_open(struct inode *inode, struct file *file); | |||
68 | void v9fs_inode2stat(struct inode *inode, struct p9_wstat *stat); | 68 | void v9fs_inode2stat(struct inode *inode, struct p9_wstat *stat); |
69 | int v9fs_uflags2omode(int uflags, int extended); | 69 | int v9fs_uflags2omode(int uflags, int extended); |
70 | 70 | ||
71 | ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64); | ||
72 | ssize_t v9fs_fid_readn(struct p9_fid *, char *, char __user *, u32, u64); | ||
73 | void v9fs_blank_wstat(struct p9_wstat *wstat); | 71 | void v9fs_blank_wstat(struct p9_wstat *wstat); |
74 | int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *); | 72 | int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *); |
75 | int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end, | 73 | int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end, |
76 | int datasync); | 74 | int datasync); |
77 | ssize_t v9fs_file_write_internal(struct inode *, struct p9_fid *, | ||
78 | const char __user *, size_t, loff_t *, int); | ||
79 | int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode); | 75 | int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode); |
80 | int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode); | 76 | int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode); |
81 | static inline void v9fs_invalidate_inode_attr(struct inode *inode) | 77 | static inline void v9fs_invalidate_inode_attr(struct inode *inode) |
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c index ff1a5bac4200..2e38f9a5b472 100644 --- a/fs/9p/vfs_addr.c +++ b/fs/9p/vfs_addr.c | |||
@@ -51,12 +51,11 @@ | |||
51 | */ | 51 | */ |
52 | static int v9fs_fid_readpage(struct p9_fid *fid, struct page *page) | 52 | static int v9fs_fid_readpage(struct p9_fid *fid, struct page *page) |
53 | { | 53 | { |
54 | int retval; | 54 | struct inode *inode = page->mapping->host; |
55 | loff_t offset; | 55 | struct bio_vec bvec = {.bv_page = page, .bv_len = PAGE_SIZE}; |
56 | char *buffer; | 56 | struct iov_iter to; |
57 | struct inode *inode; | 57 | int retval, err; |
58 | 58 | ||
59 | inode = page->mapping->host; | ||
60 | p9_debug(P9_DEBUG_VFS, "\n"); | 59 | p9_debug(P9_DEBUG_VFS, "\n"); |
61 | 60 | ||
62 | BUG_ON(!PageLocked(page)); | 61 | BUG_ON(!PageLocked(page)); |
@@ -65,16 +64,16 @@ static int v9fs_fid_readpage(struct p9_fid *fid, struct page *page) | |||
65 | if (retval == 0) | 64 | if (retval == 0) |
66 | return retval; | 65 | return retval; |
67 | 66 | ||
68 | buffer = kmap(page); | 67 | iov_iter_bvec(&to, ITER_BVEC | READ, &bvec, 1, PAGE_SIZE); |
69 | offset = page_offset(page); | ||
70 | 68 | ||
71 | retval = v9fs_fid_readn(fid, buffer, NULL, PAGE_CACHE_SIZE, offset); | 69 | retval = p9_client_read(fid, page_offset(page), &to, &err); |
72 | if (retval < 0) { | 70 | if (err) { |
73 | v9fs_uncache_page(inode, page); | 71 | v9fs_uncache_page(inode, page); |
72 | retval = err; | ||
74 | goto done; | 73 | goto done; |
75 | } | 74 | } |
76 | 75 | ||
77 | memset(buffer + retval, 0, PAGE_CACHE_SIZE - retval); | 76 | zero_user(page, retval, PAGE_SIZE - retval); |
78 | flush_dcache_page(page); | 77 | flush_dcache_page(page); |
79 | SetPageUptodate(page); | 78 | SetPageUptodate(page); |
80 | 79 | ||
@@ -82,7 +81,6 @@ static int v9fs_fid_readpage(struct p9_fid *fid, struct page *page) | |||
82 | retval = 0; | 81 | retval = 0; |
83 | 82 | ||
84 | done: | 83 | done: |
85 | kunmap(page); | ||
86 | unlock_page(page); | 84 | unlock_page(page); |
87 | return retval; | 85 | return retval; |
88 | } | 86 | } |
@@ -161,41 +159,32 @@ static void v9fs_invalidate_page(struct page *page, unsigned int offset, | |||
161 | 159 | ||
162 | static int v9fs_vfs_writepage_locked(struct page *page) | 160 | static int v9fs_vfs_writepage_locked(struct page *page) |
163 | { | 161 | { |
164 | char *buffer; | ||
165 | int retval, len; | ||
166 | loff_t offset, size; | ||
167 | mm_segment_t old_fs; | ||
168 | struct v9fs_inode *v9inode; | ||
169 | struct inode *inode = page->mapping->host; | 162 | struct inode *inode = page->mapping->host; |
163 | struct v9fs_inode *v9inode = V9FS_I(inode); | ||
164 | loff_t size = i_size_read(inode); | ||
165 | struct iov_iter from; | ||
166 | struct bio_vec bvec; | ||
167 | int err, len; | ||
170 | 168 | ||
171 | v9inode = V9FS_I(inode); | ||
172 | size = i_size_read(inode); | ||
173 | if (page->index == size >> PAGE_CACHE_SHIFT) | 169 | if (page->index == size >> PAGE_CACHE_SHIFT) |
174 | len = size & ~PAGE_CACHE_MASK; | 170 | len = size & ~PAGE_CACHE_MASK; |
175 | else | 171 | else |
176 | len = PAGE_CACHE_SIZE; | 172 | len = PAGE_CACHE_SIZE; |
177 | 173 | ||
178 | set_page_writeback(page); | 174 | bvec.bv_page = page; |
179 | 175 | bvec.bv_offset = 0; | |
180 | buffer = kmap(page); | 176 | bvec.bv_len = len; |
181 | offset = page_offset(page); | 177 | iov_iter_bvec(&from, ITER_BVEC | WRITE, &bvec, 1, len); |
182 | 178 | ||
183 | old_fs = get_fs(); | ||
184 | set_fs(get_ds()); | ||
185 | /* We should have writeback_fid always set */ | 179 | /* We should have writeback_fid always set */ |
186 | BUG_ON(!v9inode->writeback_fid); | 180 | BUG_ON(!v9inode->writeback_fid); |
187 | 181 | ||
188 | retval = v9fs_file_write_internal(inode, | 182 | set_page_writeback(page); |
189 | v9inode->writeback_fid, | 183 | |
190 | (__force const char __user *)buffer, | 184 | p9_client_write(v9inode->writeback_fid, page_offset(page), &from, &err); |
191 | len, &offset, 0); | ||
192 | if (retval > 0) | ||
193 | retval = 0; | ||
194 | 185 | ||
195 | set_fs(old_fs); | ||
196 | kunmap(page); | ||
197 | end_page_writeback(page); | 186 | end_page_writeback(page); |
198 | return retval; | 187 | return err; |
199 | } | 188 | } |
200 | 189 | ||
201 | static int v9fs_vfs_writepage(struct page *page, struct writeback_control *wbc) | 190 | static int v9fs_vfs_writepage(struct page *page, struct writeback_control *wbc) |
@@ -261,16 +250,21 @@ static int v9fs_launder_page(struct page *page) | |||
261 | static ssize_t | 250 | static ssize_t |
262 | v9fs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, loff_t pos) | 251 | v9fs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, loff_t pos) |
263 | { | 252 | { |
264 | /* | 253 | struct file *file = iocb->ki_filp; |
265 | * FIXME | 254 | ssize_t n; |
266 | * Now that we do caching with cache mode enabled, We need | 255 | int err = 0; |
267 | * to support direct IO | 256 | if (rw & WRITE) { |
268 | */ | 257 | n = p9_client_write(file->private_data, pos, iter, &err); |
269 | p9_debug(P9_DEBUG_VFS, "v9fs_direct_IO: v9fs_direct_IO (%pD) off/no(%lld/%lu) EINVAL\n", | 258 | if (n) { |
270 | iocb->ki_filp, | 259 | struct inode *inode = file_inode(file); |
271 | (long long)pos, iter->nr_segs); | 260 | loff_t i_size = i_size_read(inode); |
272 | 261 | if (pos + n > i_size) | |
273 | return -EINVAL; | 262 | inode_add_bytes(inode, pos + n - i_size); |
263 | } | ||
264 | } else { | ||
265 | n = p9_client_read(file->private_data, pos, iter, &err); | ||
266 | } | ||
267 | return n ? n : err; | ||
274 | } | 268 | } |
275 | 269 | ||
276 | static int v9fs_write_begin(struct file *filp, struct address_space *mapping, | 270 | static int v9fs_write_begin(struct file *filp, struct address_space *mapping, |
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index 4f1151088ebe..76c3b1ab6361 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/inet.h> | 33 | #include <linux/inet.h> |
34 | #include <linux/idr.h> | 34 | #include <linux/idr.h> |
35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/uio.h> | ||
36 | #include <net/9p/9p.h> | 37 | #include <net/9p/9p.h> |
37 | #include <net/9p/client.h> | 38 | #include <net/9p/client.h> |
38 | 39 | ||
@@ -115,6 +116,7 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx) | |||
115 | int buflen; | 116 | int buflen; |
116 | int reclen = 0; | 117 | int reclen = 0; |
117 | struct p9_rdir *rdir; | 118 | struct p9_rdir *rdir; |
119 | struct kvec kvec; | ||
118 | 120 | ||
119 | p9_debug(P9_DEBUG_VFS, "name %pD\n", file); | 121 | p9_debug(P9_DEBUG_VFS, "name %pD\n", file); |
120 | fid = file->private_data; | 122 | fid = file->private_data; |
@@ -124,16 +126,21 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx) | |||
124 | rdir = v9fs_alloc_rdir_buf(file, buflen); | 126 | rdir = v9fs_alloc_rdir_buf(file, buflen); |
125 | if (!rdir) | 127 | if (!rdir) |
126 | return -ENOMEM; | 128 | return -ENOMEM; |
129 | kvec.iov_base = rdir->buf; | ||
130 | kvec.iov_len = buflen; | ||
127 | 131 | ||
128 | while (1) { | 132 | while (1) { |
129 | if (rdir->tail == rdir->head) { | 133 | if (rdir->tail == rdir->head) { |
130 | err = v9fs_file_readn(file, rdir->buf, NULL, | 134 | struct iov_iter to; |
131 | buflen, ctx->pos); | 135 | int n; |
132 | if (err <= 0) | 136 | iov_iter_kvec(&to, READ | ITER_KVEC, &kvec, 1, buflen); |
137 | n = p9_client_read(file->private_data, ctx->pos, &to, | ||
138 | &err); | ||
139 | if (err) | ||
133 | return err; | 140 | return err; |
134 | 141 | ||
135 | rdir->head = 0; | 142 | rdir->head = 0; |
136 | rdir->tail = err; | 143 | rdir->tail = n; |
137 | } | 144 | } |
138 | while (rdir->head < rdir->tail) { | 145 | while (rdir->head < rdir->tail) { |
139 | p9stat_init(&st); | 146 | p9stat_init(&st); |
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index b40133796b87..55cc9c80e187 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c | |||
@@ -36,6 +36,8 @@ | |||
36 | #include <linux/utsname.h> | 36 | #include <linux/utsname.h> |
37 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
38 | #include <linux/idr.h> | 38 | #include <linux/idr.h> |
39 | #include <linux/uio.h> | ||
40 | #include <linux/slab.h> | ||
39 | #include <net/9p/9p.h> | 41 | #include <net/9p/9p.h> |
40 | #include <net/9p/client.h> | 42 | #include <net/9p/client.h> |
41 | 43 | ||
@@ -285,6 +287,7 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl) | |||
285 | fl->fl_end = glock.start + glock.length - 1; | 287 | fl->fl_end = glock.start + glock.length - 1; |
286 | fl->fl_pid = glock.proc_id; | 288 | fl->fl_pid = glock.proc_id; |
287 | } | 289 | } |
290 | kfree(glock.client_id); | ||
288 | return res; | 291 | return res; |
289 | } | 292 | } |
290 | 293 | ||
@@ -364,63 +367,6 @@ out_err: | |||
364 | } | 367 | } |
365 | 368 | ||
366 | /** | 369 | /** |
367 | * v9fs_fid_readn - read from a fid | ||
368 | * @fid: fid to read | ||
369 | * @data: data buffer to read data into | ||
370 | * @udata: user data buffer to read data into | ||
371 | * @count: size of buffer | ||
372 | * @offset: offset at which to read data | ||
373 | * | ||
374 | */ | ||
375 | ssize_t | ||
376 | v9fs_fid_readn(struct p9_fid *fid, char *data, char __user *udata, u32 count, | ||
377 | u64 offset) | ||
378 | { | ||
379 | int n, total, size; | ||
380 | |||
381 | p9_debug(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", | ||
382 | fid->fid, (long long unsigned)offset, count); | ||
383 | n = 0; | ||
384 | total = 0; | ||
385 | size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ; | ||
386 | do { | ||
387 | n = p9_client_read(fid, data, udata, offset, count); | ||
388 | if (n <= 0) | ||
389 | break; | ||
390 | |||
391 | if (data) | ||
392 | data += n; | ||
393 | if (udata) | ||
394 | udata += n; | ||
395 | |||
396 | offset += n; | ||
397 | count -= n; | ||
398 | total += n; | ||
399 | } while (count > 0 && n == size); | ||
400 | |||
401 | if (n < 0) | ||
402 | total = n; | ||
403 | |||
404 | return total; | ||
405 | } | ||
406 | |||
407 | /** | ||
408 | * v9fs_file_readn - read from a file | ||
409 | * @filp: file pointer to read | ||
410 | * @data: data buffer to read data into | ||
411 | * @udata: user data buffer to read data into | ||
412 | * @count: size of buffer | ||
413 | * @offset: offset at which to read data | ||
414 | * | ||
415 | */ | ||
416 | ssize_t | ||
417 | v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count, | ||
418 | u64 offset) | ||
419 | { | ||
420 | return v9fs_fid_readn(filp->private_data, data, udata, count, offset); | ||
421 | } | ||
422 | |||
423 | /** | ||
424 | * v9fs_file_read - read from a file | 370 | * v9fs_file_read - read from a file |
425 | * @filp: file pointer to read | 371 | * @filp: file pointer to read |
426 | * @udata: user data buffer to read data into | 372 | * @udata: user data buffer to read data into |
@@ -430,69 +376,22 @@ v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count, | |||
430 | */ | 376 | */ |
431 | 377 | ||
432 | static ssize_t | 378 | static ssize_t |
433 | v9fs_file_read(struct file *filp, char __user *udata, size_t count, | 379 | v9fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to) |
434 | loff_t * offset) | ||
435 | { | 380 | { |
436 | int ret; | 381 | struct p9_fid *fid = iocb->ki_filp->private_data; |
437 | struct p9_fid *fid; | 382 | int ret, err; |
438 | size_t size; | ||
439 | 383 | ||
440 | p9_debug(P9_DEBUG_VFS, "count %zu offset %lld\n", count, *offset); | 384 | p9_debug(P9_DEBUG_VFS, "count %zu offset %lld\n", |
441 | fid = filp->private_data; | 385 | iov_iter_count(to), iocb->ki_pos); |
442 | 386 | ||
443 | size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ; | 387 | ret = p9_client_read(fid, iocb->ki_pos, to, &err); |
444 | if (count > size) | 388 | if (!ret) |
445 | ret = v9fs_file_readn(filp, NULL, udata, count, *offset); | 389 | return err; |
446 | else | ||
447 | ret = p9_client_read(fid, NULL, udata, *offset, count); | ||
448 | |||
449 | if (ret > 0) | ||
450 | *offset += ret; | ||
451 | 390 | ||
391 | iocb->ki_pos += ret; | ||
452 | return ret; | 392 | return ret; |
453 | } | 393 | } |
454 | 394 | ||
455 | ssize_t | ||
456 | v9fs_file_write_internal(struct inode *inode, struct p9_fid *fid, | ||
457 | const char __user *data, size_t count, | ||
458 | loff_t *offset, int invalidate) | ||
459 | { | ||
460 | int n; | ||
461 | loff_t i_size; | ||
462 | size_t total = 0; | ||
463 | loff_t origin = *offset; | ||
464 | unsigned long pg_start, pg_end; | ||
465 | |||
466 | p9_debug(P9_DEBUG_VFS, "data %p count %d offset %x\n", | ||
467 | data, (int)count, (int)*offset); | ||
468 | |||
469 | do { | ||
470 | n = p9_client_write(fid, NULL, data+total, origin+total, count); | ||
471 | if (n <= 0) | ||
472 | break; | ||
473 | count -= n; | ||
474 | total += n; | ||
475 | } while (count > 0); | ||
476 | |||
477 | if (invalidate && (total > 0)) { | ||
478 | pg_start = origin >> PAGE_CACHE_SHIFT; | ||
479 | pg_end = (origin + total - 1) >> PAGE_CACHE_SHIFT; | ||
480 | if (inode->i_mapping && inode->i_mapping->nrpages) | ||
481 | invalidate_inode_pages2_range(inode->i_mapping, | ||
482 | pg_start, pg_end); | ||
483 | *offset += total; | ||
484 | i_size = i_size_read(inode); | ||
485 | if (*offset > i_size) { | ||
486 | inode_add_bytes(inode, *offset - i_size); | ||
487 | i_size_write(inode, *offset); | ||
488 | } | ||
489 | } | ||
490 | if (n < 0) | ||
491 | return n; | ||
492 | |||
493 | return total; | ||
494 | } | ||
495 | |||
496 | /** | 395 | /** |
497 | * v9fs_file_write - write to a file | 396 | * v9fs_file_write - write to a file |
498 | * @filp: file pointer to write | 397 | * @filp: file pointer to write |
@@ -502,35 +401,45 @@ v9fs_file_write_internal(struct inode *inode, struct p9_fid *fid, | |||
502 | * | 401 | * |
503 | */ | 402 | */ |
504 | static ssize_t | 403 | static ssize_t |
505 | v9fs_file_write(struct file *filp, const char __user * data, | 404 | v9fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) |
506 | size_t count, loff_t *offset) | ||
507 | { | 405 | { |
406 | struct file *file = iocb->ki_filp; | ||
508 | ssize_t retval = 0; | 407 | ssize_t retval = 0; |
509 | loff_t origin = *offset; | 408 | loff_t origin = iocb->ki_pos; |
409 | size_t count = iov_iter_count(from); | ||
410 | int err = 0; | ||
510 | 411 | ||
511 | 412 | retval = generic_write_checks(file, &origin, &count, 0); | |
512 | retval = generic_write_checks(filp, &origin, &count, 0); | ||
513 | if (retval) | 413 | if (retval) |
514 | goto out; | 414 | return retval; |
415 | |||
416 | iov_iter_truncate(from, count); | ||
515 | 417 | ||
516 | retval = -EINVAL; | ||
517 | if ((ssize_t) count < 0) | ||
518 | goto out; | ||
519 | retval = 0; | ||
520 | if (!count) | 418 | if (!count) |
521 | goto out; | 419 | return 0; |
522 | 420 | ||
523 | retval = v9fs_file_write_internal(file_inode(filp), | 421 | retval = p9_client_write(file->private_data, origin, from, &err); |
524 | filp->private_data, | 422 | if (retval > 0) { |
525 | data, count, &origin, 1); | 423 | struct inode *inode = file_inode(file); |
526 | /* update offset on successful write */ | 424 | loff_t i_size; |
527 | if (retval > 0) | 425 | unsigned long pg_start, pg_end; |
528 | *offset = origin; | 426 | pg_start = origin >> PAGE_CACHE_SHIFT; |
529 | out: | 427 | pg_end = (origin + retval - 1) >> PAGE_CACHE_SHIFT; |
530 | return retval; | 428 | if (inode->i_mapping && inode->i_mapping->nrpages) |
429 | invalidate_inode_pages2_range(inode->i_mapping, | ||
430 | pg_start, pg_end); | ||
431 | origin += retval; | ||
432 | i_size = i_size_read(inode); | ||
433 | iocb->ki_pos = origin; | ||
434 | if (origin > i_size) { | ||
435 | inode_add_bytes(inode, origin - i_size); | ||
436 | i_size_write(inode, origin); | ||
437 | } | ||
438 | return retval; | ||
439 | } | ||
440 | return err; | ||
531 | } | 441 | } |
532 | 442 | ||
533 | |||
534 | static int v9fs_file_fsync(struct file *filp, loff_t start, loff_t end, | 443 | static int v9fs_file_fsync(struct file *filp, loff_t start, loff_t end, |
535 | int datasync) | 444 | int datasync) |
536 | { | 445 | { |
@@ -657,44 +566,6 @@ out_unlock: | |||
657 | return VM_FAULT_NOPAGE; | 566 | return VM_FAULT_NOPAGE; |
658 | } | 567 | } |
659 | 568 | ||
660 | static ssize_t | ||
661 | v9fs_direct_read(struct file *filp, char __user *udata, size_t count, | ||
662 | loff_t *offsetp) | ||
663 | { | ||
664 | loff_t size, offset; | ||
665 | struct inode *inode; | ||
666 | struct address_space *mapping; | ||
667 | |||
668 | offset = *offsetp; | ||
669 | mapping = filp->f_mapping; | ||
670 | inode = mapping->host; | ||
671 | if (!count) | ||
672 | return 0; | ||
673 | size = i_size_read(inode); | ||
674 | if (offset < size) | ||
675 | filemap_write_and_wait_range(mapping, offset, | ||
676 | offset + count - 1); | ||
677 | |||
678 | return v9fs_file_read(filp, udata, count, offsetp); | ||
679 | } | ||
680 | |||
681 | /** | ||
682 | * v9fs_cached_file_read - read from a file | ||
683 | * @filp: file pointer to read | ||
684 | * @data: user data buffer to read data into | ||
685 | * @count: size of buffer | ||
686 | * @offset: offset at which to read data | ||
687 | * | ||
688 | */ | ||
689 | static ssize_t | ||
690 | v9fs_cached_file_read(struct file *filp, char __user *data, size_t count, | ||
691 | loff_t *offset) | ||
692 | { | ||
693 | if (filp->f_flags & O_DIRECT) | ||
694 | return v9fs_direct_read(filp, data, count, offset); | ||
695 | return new_sync_read(filp, data, count, offset); | ||
696 | } | ||
697 | |||
698 | /** | 569 | /** |
699 | * v9fs_mmap_file_read - read from a file | 570 | * v9fs_mmap_file_read - read from a file |
700 | * @filp: file pointer to read | 571 | * @filp: file pointer to read |
@@ -704,84 +575,12 @@ v9fs_cached_file_read(struct file *filp, char __user *data, size_t count, | |||
704 | * | 575 | * |
705 | */ | 576 | */ |
706 | static ssize_t | 577 | static ssize_t |
707 | v9fs_mmap_file_read(struct file *filp, char __user *data, size_t count, | 578 | v9fs_mmap_file_read_iter(struct kiocb *iocb, struct iov_iter *to) |
708 | loff_t *offset) | ||
709 | { | 579 | { |
710 | /* TODO: Check if there are dirty pages */ | 580 | /* TODO: Check if there are dirty pages */ |
711 | return v9fs_file_read(filp, data, count, offset); | 581 | return v9fs_file_read_iter(iocb, to); |
712 | } | 582 | } |
713 | 583 | ||
714 | static ssize_t | ||
715 | v9fs_direct_write(struct file *filp, const char __user * data, | ||
716 | size_t count, loff_t *offsetp) | ||
717 | { | ||
718 | loff_t offset; | ||
719 | ssize_t retval; | ||
720 | struct inode *inode; | ||
721 | struct address_space *mapping; | ||
722 | |||
723 | offset = *offsetp; | ||
724 | mapping = filp->f_mapping; | ||
725 | inode = mapping->host; | ||
726 | if (!count) | ||
727 | return 0; | ||
728 | |||
729 | mutex_lock(&inode->i_mutex); | ||
730 | retval = filemap_write_and_wait_range(mapping, offset, | ||
731 | offset + count - 1); | ||
732 | if (retval) | ||
733 | goto err_out; | ||
734 | /* | ||
735 | * After a write we want buffered reads to be sure to go to disk to get | ||
736 | * the new data. We invalidate clean cached page from the region we're | ||
737 | * about to write. We do this *before* the write so that if we fail | ||
738 | * here we fall back to buffered write | ||
739 | */ | ||
740 | if (mapping->nrpages) { | ||
741 | pgoff_t pg_start = offset >> PAGE_CACHE_SHIFT; | ||
742 | pgoff_t pg_end = (offset + count - 1) >> PAGE_CACHE_SHIFT; | ||
743 | |||
744 | retval = invalidate_inode_pages2_range(mapping, | ||
745 | pg_start, pg_end); | ||
746 | /* | ||
747 | * If a page can not be invalidated, fall back | ||
748 | * to buffered write. | ||
749 | */ | ||
750 | if (retval) { | ||
751 | if (retval == -EBUSY) | ||
752 | goto buff_write; | ||
753 | goto err_out; | ||
754 | } | ||
755 | } | ||
756 | retval = v9fs_file_write(filp, data, count, offsetp); | ||
757 | err_out: | ||
758 | mutex_unlock(&inode->i_mutex); | ||
759 | return retval; | ||
760 | |||
761 | buff_write: | ||
762 | mutex_unlock(&inode->i_mutex); | ||
763 | return new_sync_write(filp, data, count, offsetp); | ||
764 | } | ||
765 | |||
766 | /** | ||
767 | * v9fs_cached_file_write - write to a file | ||
768 | * @filp: file pointer to write | ||
769 | * @data: data buffer to write data from | ||
770 | * @count: size of buffer | ||
771 | * @offset: offset at which to write data | ||
772 | * | ||
773 | */ | ||
774 | static ssize_t | ||
775 | v9fs_cached_file_write(struct file *filp, const char __user * data, | ||
776 | size_t count, loff_t *offset) | ||
777 | { | ||
778 | |||
779 | if (filp->f_flags & O_DIRECT) | ||
780 | return v9fs_direct_write(filp, data, count, offset); | ||
781 | return new_sync_write(filp, data, count, offset); | ||
782 | } | ||
783 | |||
784 | |||
785 | /** | 584 | /** |
786 | * v9fs_mmap_file_write - write to a file | 585 | * v9fs_mmap_file_write - write to a file |
787 | * @filp: file pointer to write | 586 | * @filp: file pointer to write |
@@ -791,14 +590,13 @@ v9fs_cached_file_write(struct file *filp, const char __user * data, | |||
791 | * | 590 | * |
792 | */ | 591 | */ |
793 | static ssize_t | 592 | static ssize_t |
794 | v9fs_mmap_file_write(struct file *filp, const char __user *data, | 593 | v9fs_mmap_file_write_iter(struct kiocb *iocb, struct iov_iter *from) |
795 | size_t count, loff_t *offset) | ||
796 | { | 594 | { |
797 | /* | 595 | /* |
798 | * TODO: invalidate mmaps on filp's inode between | 596 | * TODO: invalidate mmaps on filp's inode between |
799 | * offset and offset+count | 597 | * offset and offset+count |
800 | */ | 598 | */ |
801 | return v9fs_file_write(filp, data, count, offset); | 599 | return v9fs_file_write_iter(iocb, from); |
802 | } | 600 | } |
803 | 601 | ||
804 | static void v9fs_mmap_vm_close(struct vm_area_struct *vma) | 602 | static void v9fs_mmap_vm_close(struct vm_area_struct *vma) |
@@ -843,8 +641,8 @@ static const struct vm_operations_struct v9fs_mmap_file_vm_ops = { | |||
843 | 641 | ||
844 | const struct file_operations v9fs_cached_file_operations = { | 642 | const struct file_operations v9fs_cached_file_operations = { |
845 | .llseek = generic_file_llseek, | 643 | .llseek = generic_file_llseek, |
846 | .read = v9fs_cached_file_read, | 644 | .read = new_sync_read, |
847 | .write = v9fs_cached_file_write, | 645 | .write = new_sync_write, |
848 | .read_iter = generic_file_read_iter, | 646 | .read_iter = generic_file_read_iter, |
849 | .write_iter = generic_file_write_iter, | 647 | .write_iter = generic_file_write_iter, |
850 | .open = v9fs_file_open, | 648 | .open = v9fs_file_open, |
@@ -856,8 +654,8 @@ const struct file_operations v9fs_cached_file_operations = { | |||
856 | 654 | ||
857 | const struct file_operations v9fs_cached_file_operations_dotl = { | 655 | const struct file_operations v9fs_cached_file_operations_dotl = { |
858 | .llseek = generic_file_llseek, | 656 | .llseek = generic_file_llseek, |
859 | .read = v9fs_cached_file_read, | 657 | .read = new_sync_read, |
860 | .write = v9fs_cached_file_write, | 658 | .write = new_sync_write, |
861 | .read_iter = generic_file_read_iter, | 659 | .read_iter = generic_file_read_iter, |
862 | .write_iter = generic_file_write_iter, | 660 | .write_iter = generic_file_write_iter, |
863 | .open = v9fs_file_open, | 661 | .open = v9fs_file_open, |
@@ -870,8 +668,10 @@ const struct file_operations v9fs_cached_file_operations_dotl = { | |||
870 | 668 | ||
871 | const struct file_operations v9fs_file_operations = { | 669 | const struct file_operations v9fs_file_operations = { |
872 | .llseek = generic_file_llseek, | 670 | .llseek = generic_file_llseek, |
873 | .read = v9fs_file_read, | 671 | .read = new_sync_read, |
874 | .write = v9fs_file_write, | 672 | .write = new_sync_write, |
673 | .read_iter = v9fs_file_read_iter, | ||
674 | .write_iter = v9fs_file_write_iter, | ||
875 | .open = v9fs_file_open, | 675 | .open = v9fs_file_open, |
876 | .release = v9fs_dir_release, | 676 | .release = v9fs_dir_release, |
877 | .lock = v9fs_file_lock, | 677 | .lock = v9fs_file_lock, |
@@ -881,8 +681,10 @@ const struct file_operations v9fs_file_operations = { | |||
881 | 681 | ||
882 | const struct file_operations v9fs_file_operations_dotl = { | 682 | const struct file_operations v9fs_file_operations_dotl = { |
883 | .llseek = generic_file_llseek, | 683 | .llseek = generic_file_llseek, |
884 | .read = v9fs_file_read, | 684 | .read = new_sync_read, |
885 | .write = v9fs_file_write, | 685 | .write = new_sync_write, |
686 | .read_iter = v9fs_file_read_iter, | ||
687 | .write_iter = v9fs_file_write_iter, | ||
886 | .open = v9fs_file_open, | 688 | .open = v9fs_file_open, |
887 | .release = v9fs_dir_release, | 689 | .release = v9fs_dir_release, |
888 | .lock = v9fs_file_lock_dotl, | 690 | .lock = v9fs_file_lock_dotl, |
@@ -893,8 +695,10 @@ const struct file_operations v9fs_file_operations_dotl = { | |||
893 | 695 | ||
894 | const struct file_operations v9fs_mmap_file_operations = { | 696 | const struct file_operations v9fs_mmap_file_operations = { |
895 | .llseek = generic_file_llseek, | 697 | .llseek = generic_file_llseek, |
896 | .read = v9fs_mmap_file_read, | 698 | .read = new_sync_read, |
897 | .write = v9fs_mmap_file_write, | 699 | .write = new_sync_write, |
700 | .read_iter = v9fs_mmap_file_read_iter, | ||
701 | .write_iter = v9fs_mmap_file_write_iter, | ||
898 | .open = v9fs_file_open, | 702 | .open = v9fs_file_open, |
899 | .release = v9fs_dir_release, | 703 | .release = v9fs_dir_release, |
900 | .lock = v9fs_file_lock, | 704 | .lock = v9fs_file_lock, |
@@ -904,8 +708,10 @@ const struct file_operations v9fs_mmap_file_operations = { | |||
904 | 708 | ||
905 | const struct file_operations v9fs_mmap_file_operations_dotl = { | 709 | const struct file_operations v9fs_mmap_file_operations_dotl = { |
906 | .llseek = generic_file_llseek, | 710 | .llseek = generic_file_llseek, |
907 | .read = v9fs_mmap_file_read, | 711 | .read = new_sync_read, |
908 | .write = v9fs_mmap_file_write, | 712 | .write = new_sync_write, |
713 | .read_iter = v9fs_mmap_file_read_iter, | ||
714 | .write_iter = v9fs_mmap_file_write_iter, | ||
909 | .open = v9fs_file_open, | 715 | .open = v9fs_file_open, |
910 | .release = v9fs_dir_release, | 716 | .release = v9fs_dir_release, |
911 | .lock = v9fs_file_lock_dotl, | 717 | .lock = v9fs_file_lock_dotl, |
diff --git a/fs/9p/xattr.c b/fs/9p/xattr.c index f95e01e058e4..0cf44b6cccd6 100644 --- a/fs/9p/xattr.c +++ b/fs/9p/xattr.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
17 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
18 | #include <linux/uio.h> | ||
18 | #include <net/9p/9p.h> | 19 | #include <net/9p/9p.h> |
19 | #include <net/9p/client.h> | 20 | #include <net/9p/client.h> |
20 | 21 | ||
@@ -25,50 +26,34 @@ ssize_t v9fs_fid_xattr_get(struct p9_fid *fid, const char *name, | |||
25 | void *buffer, size_t buffer_size) | 26 | void *buffer, size_t buffer_size) |
26 | { | 27 | { |
27 | ssize_t retval; | 28 | ssize_t retval; |
28 | int msize, read_count; | 29 | u64 attr_size; |
29 | u64 offset = 0, attr_size; | ||
30 | struct p9_fid *attr_fid; | 30 | struct p9_fid *attr_fid; |
31 | struct kvec kvec = {.iov_base = buffer, .iov_len = buffer_size}; | ||
32 | struct iov_iter to; | ||
33 | int err; | ||
34 | |||
35 | iov_iter_kvec(&to, READ | ITER_KVEC, &kvec, 1, buffer_size); | ||
31 | 36 | ||
32 | attr_fid = p9_client_xattrwalk(fid, name, &attr_size); | 37 | attr_fid = p9_client_xattrwalk(fid, name, &attr_size); |
33 | if (IS_ERR(attr_fid)) { | 38 | if (IS_ERR(attr_fid)) { |
34 | retval = PTR_ERR(attr_fid); | 39 | retval = PTR_ERR(attr_fid); |
35 | p9_debug(P9_DEBUG_VFS, "p9_client_attrwalk failed %zd\n", | 40 | p9_debug(P9_DEBUG_VFS, "p9_client_attrwalk failed %zd\n", |
36 | retval); | 41 | retval); |
37 | attr_fid = NULL; | 42 | return retval; |
38 | goto error; | ||
39 | } | ||
40 | if (!buffer_size) { | ||
41 | /* request to get the attr_size */ | ||
42 | retval = attr_size; | ||
43 | goto error; | ||
44 | } | 43 | } |
45 | if (attr_size > buffer_size) { | 44 | if (attr_size > buffer_size) { |
46 | retval = -ERANGE; | 45 | if (!buffer_size) /* request to get the attr_size */ |
47 | goto error; | 46 | retval = attr_size; |
48 | } | ||
49 | msize = attr_fid->clnt->msize; | ||
50 | while (attr_size) { | ||
51 | if (attr_size > (msize - P9_IOHDRSZ)) | ||
52 | read_count = msize - P9_IOHDRSZ; | ||
53 | else | 47 | else |
54 | read_count = attr_size; | 48 | retval = -ERANGE; |
55 | read_count = p9_client_read(attr_fid, ((char *)buffer)+offset, | 49 | } else { |
56 | NULL, offset, read_count); | 50 | iov_iter_truncate(&to, attr_size); |
57 | if (read_count < 0) { | 51 | retval = p9_client_read(attr_fid, 0, &to, &err); |
58 | /* error in xattr read */ | 52 | if (err) |
59 | retval = read_count; | 53 | retval = err; |
60 | goto error; | ||
61 | } | ||
62 | offset += read_count; | ||
63 | attr_size -= read_count; | ||
64 | } | 54 | } |
65 | /* Total read xattr bytes */ | 55 | p9_client_clunk(attr_fid); |
66 | retval = offset; | ||
67 | error: | ||
68 | if (attr_fid) | ||
69 | p9_client_clunk(attr_fid); | ||
70 | return retval; | 56 | return retval; |
71 | |||
72 | } | 57 | } |
73 | 58 | ||
74 | 59 | ||
@@ -120,8 +105,11 @@ int v9fs_xattr_set(struct dentry *dentry, const char *name, | |||
120 | int v9fs_fid_xattr_set(struct p9_fid *fid, const char *name, | 105 | int v9fs_fid_xattr_set(struct p9_fid *fid, const char *name, |
121 | const void *value, size_t value_len, int flags) | 106 | const void *value, size_t value_len, int flags) |
122 | { | 107 | { |
123 | u64 offset = 0; | 108 | struct kvec kvec = {.iov_base = (void *)value, .iov_len = value_len}; |
124 | int retval, msize, write_count; | 109 | struct iov_iter from; |
110 | int retval; | ||
111 | |||
112 | iov_iter_kvec(&from, WRITE | ITER_KVEC, &kvec, 1, value_len); | ||
125 | 113 | ||
126 | p9_debug(P9_DEBUG_VFS, "name = %s value_len = %zu flags = %d\n", | 114 | p9_debug(P9_DEBUG_VFS, "name = %s value_len = %zu flags = %d\n", |
127 | name, value_len, flags); | 115 | name, value_len, flags); |
@@ -135,29 +123,11 @@ int v9fs_fid_xattr_set(struct p9_fid *fid, const char *name, | |||
135 | * On success fid points to xattr | 123 | * On success fid points to xattr |
136 | */ | 124 | */ |
137 | retval = p9_client_xattrcreate(fid, name, value_len, flags); | 125 | retval = p9_client_xattrcreate(fid, name, value_len, flags); |
138 | if (retval < 0) { | 126 | if (retval < 0) |
139 | p9_debug(P9_DEBUG_VFS, "p9_client_xattrcreate failed %d\n", | 127 | p9_debug(P9_DEBUG_VFS, "p9_client_xattrcreate failed %d\n", |
140 | retval); | 128 | retval); |
141 | goto err; | 129 | else |
142 | } | 130 | p9_client_write(fid, 0, &from, &retval); |
143 | msize = fid->clnt->msize; | ||
144 | while (value_len) { | ||
145 | if (value_len > (msize - P9_IOHDRSZ)) | ||
146 | write_count = msize - P9_IOHDRSZ; | ||
147 | else | ||
148 | write_count = value_len; | ||
149 | write_count = p9_client_write(fid, ((char *)value)+offset, | ||
150 | NULL, offset, write_count); | ||
151 | if (write_count < 0) { | ||
152 | /* error in xattr write */ | ||
153 | retval = write_count; | ||
154 | goto err; | ||
155 | } | ||
156 | offset += write_count; | ||
157 | value_len -= write_count; | ||
158 | } | ||
159 | retval = 0; | ||
160 | err: | ||
161 | p9_client_clunk(fid); | 131 | p9_client_clunk(fid); |
162 | return retval; | 132 | return retval; |
163 | } | 133 | } |
diff --git a/include/net/9p/client.h b/include/net/9p/client.h index 6fab66c5c5af..c6b97e58cf84 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h | |||
@@ -211,6 +211,8 @@ struct p9_dirent { | |||
211 | char d_name[256]; | 211 | char d_name[256]; |
212 | }; | 212 | }; |
213 | 213 | ||
214 | struct iov_iter; | ||
215 | |||
214 | int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb); | 216 | int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb); |
215 | int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, | 217 | int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, |
216 | const char *name); | 218 | const char *name); |
@@ -236,10 +238,8 @@ int p9_client_clunk(struct p9_fid *fid); | |||
236 | int p9_client_fsync(struct p9_fid *fid, int datasync); | 238 | int p9_client_fsync(struct p9_fid *fid, int datasync); |
237 | int p9_client_remove(struct p9_fid *fid); | 239 | int p9_client_remove(struct p9_fid *fid); |
238 | int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags); | 240 | int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags); |
239 | int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, | 241 | int p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err); |
240 | u64 offset, u32 count); | 242 | int p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err); |
241 | int p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, | ||
242 | u64 offset, u32 count); | ||
243 | int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset); | 243 | int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset); |
244 | int p9dirent_read(struct p9_client *clnt, char *buf, int len, | 244 | int p9dirent_read(struct p9_client *clnt, char *buf, int len, |
245 | struct p9_dirent *dirent); | 245 | struct p9_dirent *dirent); |
diff --git a/include/net/9p/transport.h b/include/net/9p/transport.h index 2a25dec30211..5122b5e40f78 100644 --- a/include/net/9p/transport.h +++ b/include/net/9p/transport.h | |||
@@ -61,7 +61,7 @@ struct p9_trans_module { | |||
61 | int (*cancel) (struct p9_client *, struct p9_req_t *req); | 61 | int (*cancel) (struct p9_client *, struct p9_req_t *req); |
62 | int (*cancelled)(struct p9_client *, struct p9_req_t *req); | 62 | int (*cancelled)(struct p9_client *, struct p9_req_t *req); |
63 | int (*zc_request)(struct p9_client *, struct p9_req_t *, | 63 | int (*zc_request)(struct p9_client *, struct p9_req_t *, |
64 | char *, char *, int , int, int, int); | 64 | struct iov_iter *, struct iov_iter *, int , int, int); |
65 | }; | 65 | }; |
66 | 66 | ||
67 | void v9fs_register_trans(struct p9_trans_module *m); | 67 | void v9fs_register_trans(struct p9_trans_module *m); |
diff --git a/net/9p/client.c b/net/9p/client.c index e86a9bea1d16..6f4c4c88db84 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
35 | #include <linux/sched.h> | 35 | #include <linux/sched.h> |
36 | #include <linux/uaccess.h> | 36 | #include <linux/uaccess.h> |
37 | #include <linux/uio.h> | ||
37 | #include <net/9p/9p.h> | 38 | #include <net/9p/9p.h> |
38 | #include <linux/parser.h> | 39 | #include <linux/parser.h> |
39 | #include <net/9p/client.h> | 40 | #include <net/9p/client.h> |
@@ -555,7 +556,7 @@ out_err: | |||
555 | */ | 556 | */ |
556 | 557 | ||
557 | static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req, | 558 | static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req, |
558 | char *uidata, int in_hdrlen, int kern_buf) | 559 | struct iov_iter *uidata, int in_hdrlen) |
559 | { | 560 | { |
560 | int err; | 561 | int err; |
561 | int ecode; | 562 | int ecode; |
@@ -591,16 +592,11 @@ static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req, | |||
591 | ename = &req->rc->sdata[req->rc->offset]; | 592 | ename = &req->rc->sdata[req->rc->offset]; |
592 | if (len > inline_len) { | 593 | if (len > inline_len) { |
593 | /* We have error in external buffer */ | 594 | /* We have error in external buffer */ |
594 | if (kern_buf) { | 595 | err = copy_from_iter(ename + inline_len, |
595 | memcpy(ename + inline_len, uidata, | 596 | len - inline_len, uidata); |
596 | len - inline_len); | 597 | if (err != len - inline_len) { |
597 | } else { | 598 | err = -EFAULT; |
598 | err = copy_from_user(ename + inline_len, | 599 | goto out_err; |
599 | uidata, len - inline_len); | ||
600 | if (err) { | ||
601 | err = -EFAULT; | ||
602 | goto out_err; | ||
603 | } | ||
604 | } | 600 | } |
605 | } | 601 | } |
606 | ename = NULL; | 602 | ename = NULL; |
@@ -806,8 +802,8 @@ reterr: | |||
806 | * p9_client_zc_rpc - issue a request and wait for a response | 802 | * p9_client_zc_rpc - issue a request and wait for a response |
807 | * @c: client session | 803 | * @c: client session |
808 | * @type: type of request | 804 | * @type: type of request |
809 | * @uidata: user bffer that should be ued for zero copy read | 805 | * @uidata: destination for zero copy read |
810 | * @uodata: user buffer that shoud be user for zero copy write | 806 | * @uodata: source for zero copy write |
811 | * @inlen: read buffer size | 807 | * @inlen: read buffer size |
812 | * @olen: write buffer size | 808 | * @olen: write buffer size |
813 | * @hdrlen: reader header size, This is the size of response protocol data | 809 | * @hdrlen: reader header size, This is the size of response protocol data |
@@ -816,9 +812,10 @@ reterr: | |||
816 | * Returns request structure (which client must free using p9_free_req) | 812 | * Returns request structure (which client must free using p9_free_req) |
817 | */ | 813 | */ |
818 | static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type, | 814 | static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type, |
819 | char *uidata, char *uodata, | 815 | struct iov_iter *uidata, |
816 | struct iov_iter *uodata, | ||
820 | int inlen, int olen, int in_hdrlen, | 817 | int inlen, int olen, int in_hdrlen, |
821 | int kern_buf, const char *fmt, ...) | 818 | const char *fmt, ...) |
822 | { | 819 | { |
823 | va_list ap; | 820 | va_list ap; |
824 | int sigpending, err; | 821 | int sigpending, err; |
@@ -841,12 +838,8 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type, | |||
841 | } else | 838 | } else |
842 | sigpending = 0; | 839 | sigpending = 0; |
843 | 840 | ||
844 | /* If we are called with KERNEL_DS force kern_buf */ | ||
845 | if (segment_eq(get_fs(), KERNEL_DS)) | ||
846 | kern_buf = 1; | ||
847 | |||
848 | err = c->trans_mod->zc_request(c, req, uidata, uodata, | 841 | err = c->trans_mod->zc_request(c, req, uidata, uodata, |
849 | inlen, olen, in_hdrlen, kern_buf); | 842 | inlen, olen, in_hdrlen); |
850 | if (err < 0) { | 843 | if (err < 0) { |
851 | if (err == -EIO) | 844 | if (err == -EIO) |
852 | c->status = Disconnected; | 845 | c->status = Disconnected; |
@@ -876,7 +869,7 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type, | |||
876 | if (err < 0) | 869 | if (err < 0) |
877 | goto reterr; | 870 | goto reterr; |
878 | 871 | ||
879 | err = p9_check_zc_errors(c, req, uidata, in_hdrlen, kern_buf); | 872 | err = p9_check_zc_errors(c, req, uidata, in_hdrlen); |
880 | trace_9p_client_res(c, type, req->rc->tag, err); | 873 | trace_9p_client_res(c, type, req->rc->tag, err); |
881 | if (!err) | 874 | if (!err) |
882 | return req; | 875 | return req; |
@@ -1123,6 +1116,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, | |||
1123 | fid = NULL; | 1116 | fid = NULL; |
1124 | goto error; | 1117 | goto error; |
1125 | } | 1118 | } |
1119 | fid->uid = n_uname; | ||
1126 | 1120 | ||
1127 | req = p9_client_rpc(clnt, P9_TATTACH, "ddss?u", fid->fid, | 1121 | req = p9_client_rpc(clnt, P9_TATTACH, "ddss?u", fid->fid, |
1128 | afid ? afid->fid : P9_NOFID, uname, aname, n_uname); | 1122 | afid ? afid->fid : P9_NOFID, uname, aname, n_uname); |
@@ -1541,142 +1535,128 @@ error: | |||
1541 | EXPORT_SYMBOL(p9_client_unlinkat); | 1535 | EXPORT_SYMBOL(p9_client_unlinkat); |
1542 | 1536 | ||
1543 | int | 1537 | int |
1544 | p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | 1538 | p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err) |
1545 | u32 count) | ||
1546 | { | 1539 | { |
1547 | char *dataptr; | 1540 | struct p9_client *clnt = fid->clnt; |
1548 | int kernel_buf = 0; | ||
1549 | struct p9_req_t *req; | 1541 | struct p9_req_t *req; |
1550 | struct p9_client *clnt; | 1542 | int total = 0; |
1551 | int err, rsize, non_zc = 0; | ||
1552 | |||
1553 | 1543 | ||
1554 | p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", | 1544 | p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", |
1555 | fid->fid, (unsigned long long) offset, count); | 1545 | fid->fid, (unsigned long long) offset, (int)iov_iter_count(to)); |
1556 | err = 0; | 1546 | |
1557 | clnt = fid->clnt; | 1547 | while (iov_iter_count(to)) { |
1558 | 1548 | int count = iov_iter_count(to); | |
1559 | rsize = fid->iounit; | 1549 | int rsize, non_zc = 0; |
1560 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) | 1550 | char *dataptr; |
1561 | rsize = clnt->msize - P9_IOHDRSZ; | 1551 | |
1562 | 1552 | rsize = fid->iounit; | |
1563 | if (count < rsize) | 1553 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) |
1564 | rsize = count; | 1554 | rsize = clnt->msize - P9_IOHDRSZ; |
1565 | 1555 | ||
1566 | /* Don't bother zerocopy for small IO (< 1024) */ | 1556 | if (count < rsize) |
1567 | if (clnt->trans_mod->zc_request && rsize > 1024) { | 1557 | rsize = count; |
1568 | char *indata; | 1558 | |
1569 | if (data) { | 1559 | /* Don't bother zerocopy for small IO (< 1024) */ |
1570 | kernel_buf = 1; | 1560 | if (clnt->trans_mod->zc_request && rsize > 1024) { |
1571 | indata = data; | 1561 | /* |
1572 | } else | 1562 | * response header len is 11 |
1573 | indata = (__force char *)udata; | 1563 | * PDU Header(7) + IO Size (4) |
1574 | /* | 1564 | */ |
1575 | * response header len is 11 | 1565 | req = p9_client_zc_rpc(clnt, P9_TREAD, to, NULL, rsize, |
1576 | * PDU Header(7) + IO Size (4) | 1566 | 0, 11, "dqd", fid->fid, |
1577 | */ | 1567 | offset, rsize); |
1578 | req = p9_client_zc_rpc(clnt, P9_TREAD, indata, NULL, rsize, 0, | 1568 | } else { |
1579 | 11, kernel_buf, "dqd", fid->fid, | 1569 | non_zc = 1; |
1580 | offset, rsize); | 1570 | req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, |
1581 | } else { | 1571 | rsize); |
1582 | non_zc = 1; | 1572 | } |
1583 | req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, | 1573 | if (IS_ERR(req)) { |
1584 | rsize); | 1574 | *err = PTR_ERR(req); |
1585 | } | 1575 | break; |
1586 | if (IS_ERR(req)) { | 1576 | } |
1587 | err = PTR_ERR(req); | ||
1588 | goto error; | ||
1589 | } | ||
1590 | 1577 | ||
1591 | err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr); | 1578 | *err = p9pdu_readf(req->rc, clnt->proto_version, |
1592 | if (err) { | 1579 | "D", &count, &dataptr); |
1593 | trace_9p_protocol_dump(clnt, req->rc); | 1580 | if (*err) { |
1594 | goto free_and_error; | 1581 | trace_9p_protocol_dump(clnt, req->rc); |
1595 | } | 1582 | p9_free_req(clnt, req); |
1583 | break; | ||
1584 | } | ||
1596 | 1585 | ||
1597 | p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count); | 1586 | p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count); |
1587 | if (!count) { | ||
1588 | p9_free_req(clnt, req); | ||
1589 | break; | ||
1590 | } | ||
1598 | 1591 | ||
1599 | if (non_zc) { | 1592 | if (non_zc) { |
1600 | if (data) { | 1593 | int n = copy_to_iter(dataptr, count, to); |
1601 | memmove(data, dataptr, count); | 1594 | total += n; |
1602 | } else { | 1595 | offset += n; |
1603 | err = copy_to_user(udata, dataptr, count); | 1596 | if (n != count) { |
1604 | if (err) { | 1597 | *err = -EFAULT; |
1605 | err = -EFAULT; | 1598 | p9_free_req(clnt, req); |
1606 | goto free_and_error; | 1599 | break; |
1607 | } | 1600 | } |
1601 | } else { | ||
1602 | iov_iter_advance(to, count); | ||
1603 | total += count; | ||
1604 | offset += count; | ||
1608 | } | 1605 | } |
1606 | p9_free_req(clnt, req); | ||
1609 | } | 1607 | } |
1610 | p9_free_req(clnt, req); | 1608 | return total; |
1611 | return count; | ||
1612 | |||
1613 | free_and_error: | ||
1614 | p9_free_req(clnt, req); | ||
1615 | error: | ||
1616 | return err; | ||
1617 | } | 1609 | } |
1618 | EXPORT_SYMBOL(p9_client_read); | 1610 | EXPORT_SYMBOL(p9_client_read); |
1619 | 1611 | ||
1620 | int | 1612 | int |
1621 | p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, | 1613 | p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err) |
1622 | u64 offset, u32 count) | ||
1623 | { | 1614 | { |
1624 | int err, rsize; | 1615 | struct p9_client *clnt = fid->clnt; |
1625 | int kernel_buf = 0; | ||
1626 | struct p9_client *clnt; | ||
1627 | struct p9_req_t *req; | 1616 | struct p9_req_t *req; |
1617 | int total = 0; | ||
1618 | |||
1619 | p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %zd\n", | ||
1620 | fid->fid, (unsigned long long) offset, | ||
1621 | iov_iter_count(from)); | ||
1622 | |||
1623 | while (iov_iter_count(from)) { | ||
1624 | int count = iov_iter_count(from); | ||
1625 | int rsize = fid->iounit; | ||
1626 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) | ||
1627 | rsize = clnt->msize - P9_IOHDRSZ; | ||
1628 | |||
1629 | if (count < rsize) | ||
1630 | rsize = count; | ||
1631 | |||
1632 | /* Don't bother zerocopy for small IO (< 1024) */ | ||
1633 | if (clnt->trans_mod->zc_request && rsize > 1024) { | ||
1634 | req = p9_client_zc_rpc(clnt, P9_TWRITE, NULL, from, 0, | ||
1635 | rsize, P9_ZC_HDR_SZ, "dqd", | ||
1636 | fid->fid, offset, rsize); | ||
1637 | } else { | ||
1638 | req = p9_client_rpc(clnt, P9_TWRITE, "dqV", fid->fid, | ||
1639 | offset, rsize, from); | ||
1640 | } | ||
1641 | if (IS_ERR(req)) { | ||
1642 | *err = PTR_ERR(req); | ||
1643 | break; | ||
1644 | } | ||
1628 | 1645 | ||
1629 | p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d\n", | 1646 | *err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count); |
1630 | fid->fid, (unsigned long long) offset, count); | 1647 | if (*err) { |
1631 | err = 0; | 1648 | trace_9p_protocol_dump(clnt, req->rc); |
1632 | clnt = fid->clnt; | 1649 | p9_free_req(clnt, req); |
1633 | 1650 | } | |
1634 | rsize = fid->iounit; | ||
1635 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) | ||
1636 | rsize = clnt->msize - P9_IOHDRSZ; | ||
1637 | 1651 | ||
1638 | if (count < rsize) | 1652 | p9_debug(P9_DEBUG_9P, "<<< RWRITE count %d\n", count); |
1639 | rsize = count; | ||
1640 | 1653 | ||
1641 | /* Don't bother zerocopy for small IO (< 1024) */ | 1654 | p9_free_req(clnt, req); |
1642 | if (clnt->trans_mod->zc_request && rsize > 1024) { | 1655 | iov_iter_advance(from, count); |
1643 | char *odata; | 1656 | total += count; |
1644 | if (data) { | 1657 | offset += count; |
1645 | kernel_buf = 1; | ||
1646 | odata = data; | ||
1647 | } else | ||
1648 | odata = (char *)udata; | ||
1649 | req = p9_client_zc_rpc(clnt, P9_TWRITE, NULL, odata, 0, rsize, | ||
1650 | P9_ZC_HDR_SZ, kernel_buf, "dqd", | ||
1651 | fid->fid, offset, rsize); | ||
1652 | } else { | ||
1653 | if (data) | ||
1654 | req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, | ||
1655 | offset, rsize, data); | ||
1656 | else | ||
1657 | req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, | ||
1658 | offset, rsize, udata); | ||
1659 | } | ||
1660 | if (IS_ERR(req)) { | ||
1661 | err = PTR_ERR(req); | ||
1662 | goto error; | ||
1663 | } | ||
1664 | |||
1665 | err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count); | ||
1666 | if (err) { | ||
1667 | trace_9p_protocol_dump(clnt, req->rc); | ||
1668 | goto free_and_error; | ||
1669 | } | 1658 | } |
1670 | 1659 | return total; | |
1671 | p9_debug(P9_DEBUG_9P, "<<< RWRITE count %d\n", count); | ||
1672 | |||
1673 | p9_free_req(clnt, req); | ||
1674 | return count; | ||
1675 | |||
1676 | free_and_error: | ||
1677 | p9_free_req(clnt, req); | ||
1678 | error: | ||
1679 | return err; | ||
1680 | } | 1660 | } |
1681 | EXPORT_SYMBOL(p9_client_write); | 1661 | EXPORT_SYMBOL(p9_client_write); |
1682 | 1662 | ||
@@ -2068,6 +2048,10 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | |||
2068 | struct p9_client *clnt; | 2048 | struct p9_client *clnt; |
2069 | struct p9_req_t *req; | 2049 | struct p9_req_t *req; |
2070 | char *dataptr; | 2050 | char *dataptr; |
2051 | struct kvec kv = {.iov_base = data, .iov_len = count}; | ||
2052 | struct iov_iter to; | ||
2053 | |||
2054 | iov_iter_kvec(&to, READ | ITER_KVEC, &kv, 1, count); | ||
2071 | 2055 | ||
2072 | p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n", | 2056 | p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n", |
2073 | fid->fid, (unsigned long long) offset, count); | 2057 | fid->fid, (unsigned long long) offset, count); |
@@ -2088,8 +2072,8 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | |||
2088 | * response header len is 11 | 2072 | * response header len is 11 |
2089 | * PDU Header(7) + IO Size (4) | 2073 | * PDU Header(7) + IO Size (4) |
2090 | */ | 2074 | */ |
2091 | req = p9_client_zc_rpc(clnt, P9_TREADDIR, data, NULL, rsize, 0, | 2075 | req = p9_client_zc_rpc(clnt, P9_TREADDIR, &to, NULL, rsize, 0, |
2092 | 11, 1, "dqd", fid->fid, offset, rsize); | 2076 | 11, "dqd", fid->fid, offset, rsize); |
2093 | } else { | 2077 | } else { |
2094 | non_zc = 1; | 2078 | non_zc = 1; |
2095 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, | 2079 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, |
diff --git a/net/9p/protocol.c b/net/9p/protocol.c index ab9127ec5b7a..e9d0f0c1a048 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/sched.h> | 33 | #include <linux/sched.h> |
34 | #include <linux/stddef.h> | 34 | #include <linux/stddef.h> |
35 | #include <linux/types.h> | 35 | #include <linux/types.h> |
36 | #include <linux/uio.h> | ||
36 | #include <net/9p/9p.h> | 37 | #include <net/9p/9p.h> |
37 | #include <net/9p/client.h> | 38 | #include <net/9p/client.h> |
38 | #include "protocol.h" | 39 | #include "protocol.h" |
@@ -69,10 +70,11 @@ static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size) | |||
69 | } | 70 | } |
70 | 71 | ||
71 | static size_t | 72 | static size_t |
72 | pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size) | 73 | pdu_write_u(struct p9_fcall *pdu, struct iov_iter *from, size_t size) |
73 | { | 74 | { |
74 | size_t len = min(pdu->capacity - pdu->size, size); | 75 | size_t len = min(pdu->capacity - pdu->size, size); |
75 | if (copy_from_user(&pdu->sdata[pdu->size], udata, len)) | 76 | struct iov_iter i = *from; |
77 | if (copy_from_iter(&pdu->sdata[pdu->size], len, &i) != len) | ||
76 | len = 0; | 78 | len = 0; |
77 | 79 | ||
78 | pdu->size += len; | 80 | pdu->size += len; |
@@ -437,23 +439,13 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt, | |||
437 | stbuf->extension, stbuf->n_uid, | 439 | stbuf->extension, stbuf->n_uid, |
438 | stbuf->n_gid, stbuf->n_muid); | 440 | stbuf->n_gid, stbuf->n_muid); |
439 | } break; | 441 | } break; |
440 | case 'D':{ | 442 | case 'V':{ |
441 | uint32_t count = va_arg(ap, uint32_t); | ||
442 | const void *data = va_arg(ap, const void *); | ||
443 | |||
444 | errcode = p9pdu_writef(pdu, proto_version, "d", | ||
445 | count); | ||
446 | if (!errcode && pdu_write(pdu, data, count)) | ||
447 | errcode = -EFAULT; | ||
448 | } | ||
449 | break; | ||
450 | case 'U':{ | ||
451 | int32_t count = va_arg(ap, int32_t); | 443 | int32_t count = va_arg(ap, int32_t); |
452 | const char __user *udata = | 444 | struct iov_iter *from = |
453 | va_arg(ap, const void __user *); | 445 | va_arg(ap, struct iov_iter *); |
454 | errcode = p9pdu_writef(pdu, proto_version, "d", | 446 | errcode = p9pdu_writef(pdu, proto_version, "d", |
455 | count); | 447 | count); |
456 | if (!errcode && pdu_write_u(pdu, udata, count)) | 448 | if (!errcode && pdu_write_u(pdu, from, count)) |
457 | errcode = -EFAULT; | 449 | errcode = -EFAULT; |
458 | } | 450 | } |
459 | break; | 451 | break; |
diff --git a/net/9p/trans_common.c b/net/9p/trans_common.c index 2ee3879161b1..38aa6345bdfa 100644 --- a/net/9p/trans_common.c +++ b/net/9p/trans_common.c | |||
@@ -12,12 +12,8 @@ | |||
12 | * | 12 | * |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/slab.h> | 15 | #include <linux/mm.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <net/9p/9p.h> | ||
18 | #include <net/9p/client.h> | ||
19 | #include <linux/scatterlist.h> | ||
20 | #include "trans_common.h" | ||
21 | 17 | ||
22 | /** | 18 | /** |
23 | * p9_release_req_pages - Release pages after the transaction. | 19 | * p9_release_req_pages - Release pages after the transaction. |
@@ -31,39 +27,3 @@ void p9_release_pages(struct page **pages, int nr_pages) | |||
31 | put_page(pages[i]); | 27 | put_page(pages[i]); |
32 | } | 28 | } |
33 | EXPORT_SYMBOL(p9_release_pages); | 29 | EXPORT_SYMBOL(p9_release_pages); |
34 | |||
35 | /** | ||
36 | * p9_nr_pages - Return number of pages needed to accommodate the payload. | ||
37 | */ | ||
38 | int p9_nr_pages(char *data, int len) | ||
39 | { | ||
40 | unsigned long start_page, end_page; | ||
41 | start_page = (unsigned long)data >> PAGE_SHIFT; | ||
42 | end_page = ((unsigned long)data + len + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
43 | return end_page - start_page; | ||
44 | } | ||
45 | EXPORT_SYMBOL(p9_nr_pages); | ||
46 | |||
47 | /** | ||
48 | * payload_gup - Translates user buffer into kernel pages and | ||
49 | * pins them either for read/write through get_user_pages_fast(). | ||
50 | * @req: Request to be sent to server. | ||
51 | * @pdata_off: data offset into the first page after translation (gup). | ||
52 | * @pdata_len: Total length of the IO. gup may not return requested # of pages. | ||
53 | * @nr_pages: number of pages to accommodate the payload | ||
54 | * @rw: Indicates if the pages are for read or write. | ||
55 | */ | ||
56 | |||
57 | int p9_payload_gup(char *data, int *nr_pages, struct page **pages, int write) | ||
58 | { | ||
59 | int nr_mapped_pages; | ||
60 | |||
61 | nr_mapped_pages = get_user_pages_fast((unsigned long)data, | ||
62 | *nr_pages, write, pages); | ||
63 | if (nr_mapped_pages <= 0) | ||
64 | return nr_mapped_pages; | ||
65 | |||
66 | *nr_pages = nr_mapped_pages; | ||
67 | return 0; | ||
68 | } | ||
69 | EXPORT_SYMBOL(p9_payload_gup); | ||
diff --git a/net/9p/trans_common.h b/net/9p/trans_common.h index 173bb550a9eb..c43babb3f635 100644 --- a/net/9p/trans_common.h +++ b/net/9p/trans_common.h | |||
@@ -13,5 +13,3 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | void p9_release_pages(struct page **, int); | 15 | void p9_release_pages(struct page **, int); |
16 | int p9_payload_gup(char *, int *, struct page **, int); | ||
17 | int p9_nr_pages(char *, int); | ||
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 36a1a739ad68..e62bcbbabb5e 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c | |||
@@ -217,15 +217,15 @@ static int p9_virtio_cancel(struct p9_client *client, struct p9_req_t *req) | |||
217 | * @start: which segment of the sg_list to start at | 217 | * @start: which segment of the sg_list to start at |
218 | * @pdata: a list of pages to add into sg. | 218 | * @pdata: a list of pages to add into sg. |
219 | * @nr_pages: number of pages to pack into the scatter/gather list | 219 | * @nr_pages: number of pages to pack into the scatter/gather list |
220 | * @data: data to pack into scatter/gather list | 220 | * @offs: amount of data in the beginning of first page _not_ to pack |
221 | * @count: amount of data to pack into the scatter/gather list | 221 | * @count: amount of data to pack into the scatter/gather list |
222 | */ | 222 | */ |
223 | static int | 223 | static int |
224 | pack_sg_list_p(struct scatterlist *sg, int start, int limit, | 224 | pack_sg_list_p(struct scatterlist *sg, int start, int limit, |
225 | struct page **pdata, int nr_pages, char *data, int count) | 225 | struct page **pdata, int nr_pages, size_t offs, int count) |
226 | { | 226 | { |
227 | int i = 0, s; | 227 | int i = 0, s; |
228 | int data_off; | 228 | int data_off = offs; |
229 | int index = start; | 229 | int index = start; |
230 | 230 | ||
231 | BUG_ON(nr_pages > (limit - start)); | 231 | BUG_ON(nr_pages > (limit - start)); |
@@ -233,16 +233,14 @@ pack_sg_list_p(struct scatterlist *sg, int start, int limit, | |||
233 | * if the first page doesn't start at | 233 | * if the first page doesn't start at |
234 | * page boundary find the offset | 234 | * page boundary find the offset |
235 | */ | 235 | */ |
236 | data_off = offset_in_page(data); | ||
237 | while (nr_pages) { | 236 | while (nr_pages) { |
238 | s = rest_of_page(data); | 237 | s = PAGE_SIZE - data_off; |
239 | if (s > count) | 238 | if (s > count) |
240 | s = count; | 239 | s = count; |
241 | /* Make sure we don't terminate early. */ | 240 | /* Make sure we don't terminate early. */ |
242 | sg_unmark_end(&sg[index]); | 241 | sg_unmark_end(&sg[index]); |
243 | sg_set_page(&sg[index++], pdata[i++], s, data_off); | 242 | sg_set_page(&sg[index++], pdata[i++], s, data_off); |
244 | data_off = 0; | 243 | data_off = 0; |
245 | data += s; | ||
246 | count -= s; | 244 | count -= s; |
247 | nr_pages--; | 245 | nr_pages--; |
248 | } | 246 | } |
@@ -314,11 +312,20 @@ req_retry: | |||
314 | } | 312 | } |
315 | 313 | ||
316 | static int p9_get_mapped_pages(struct virtio_chan *chan, | 314 | static int p9_get_mapped_pages(struct virtio_chan *chan, |
317 | struct page **pages, char *data, | 315 | struct page ***pages, |
318 | int nr_pages, int write, int kern_buf) | 316 | struct iov_iter *data, |
317 | int count, | ||
318 | size_t *offs, | ||
319 | int *need_drop) | ||
319 | { | 320 | { |
321 | int nr_pages; | ||
320 | int err; | 322 | int err; |
321 | if (!kern_buf) { | 323 | |
324 | if (!iov_iter_count(data)) | ||
325 | return 0; | ||
326 | |||
327 | if (!(data->type & ITER_KVEC)) { | ||
328 | int n; | ||
322 | /* | 329 | /* |
323 | * We allow only p9_max_pages pinned. We wait for the | 330 | * We allow only p9_max_pages pinned. We wait for the |
324 | * Other zc request to finish here | 331 | * Other zc request to finish here |
@@ -329,26 +336,49 @@ static int p9_get_mapped_pages(struct virtio_chan *chan, | |||
329 | if (err == -ERESTARTSYS) | 336 | if (err == -ERESTARTSYS) |
330 | return err; | 337 | return err; |
331 | } | 338 | } |
332 | err = p9_payload_gup(data, &nr_pages, pages, write); | 339 | n = iov_iter_get_pages_alloc(data, pages, count, offs); |
333 | if (err < 0) | 340 | if (n < 0) |
334 | return err; | 341 | return n; |
342 | *need_drop = 1; | ||
343 | nr_pages = DIV_ROUND_UP(n + *offs, PAGE_SIZE); | ||
335 | atomic_add(nr_pages, &vp_pinned); | 344 | atomic_add(nr_pages, &vp_pinned); |
345 | return n; | ||
336 | } else { | 346 | } else { |
337 | /* kernel buffer, no need to pin pages */ | 347 | /* kernel buffer, no need to pin pages */ |
338 | int s, index = 0; | 348 | int index; |
339 | int count = nr_pages; | 349 | size_t len; |
340 | while (nr_pages) { | 350 | void *p; |
341 | s = rest_of_page(data); | 351 | |
342 | if (is_vmalloc_addr(data)) | 352 | /* we'd already checked that it's non-empty */ |
343 | pages[index++] = vmalloc_to_page(data); | 353 | while (1) { |
354 | len = iov_iter_single_seg_count(data); | ||
355 | if (likely(len)) { | ||
356 | p = data->kvec->iov_base + data->iov_offset; | ||
357 | break; | ||
358 | } | ||
359 | iov_iter_advance(data, 0); | ||
360 | } | ||
361 | if (len > count) | ||
362 | len = count; | ||
363 | |||
364 | nr_pages = DIV_ROUND_UP((unsigned long)p + len, PAGE_SIZE) - | ||
365 | (unsigned long)p / PAGE_SIZE; | ||
366 | |||
367 | *pages = kmalloc(sizeof(struct page *) * nr_pages, GFP_NOFS); | ||
368 | if (!*pages) | ||
369 | return -ENOMEM; | ||
370 | |||
371 | *need_drop = 0; | ||
372 | p -= (*offs = (unsigned long)p % PAGE_SIZE); | ||
373 | for (index = 0; index < nr_pages; index++) { | ||
374 | if (is_vmalloc_addr(p)) | ||
375 | (*pages)[index] = vmalloc_to_page(p); | ||
344 | else | 376 | else |
345 | pages[index++] = kmap_to_page(data); | 377 | (*pages)[index] = kmap_to_page(p); |
346 | data += s; | 378 | p += PAGE_SIZE; |
347 | nr_pages--; | ||
348 | } | 379 | } |
349 | nr_pages = count; | 380 | return len; |
350 | } | 381 | } |
351 | return nr_pages; | ||
352 | } | 382 | } |
353 | 383 | ||
354 | /** | 384 | /** |
@@ -364,8 +394,8 @@ static int p9_get_mapped_pages(struct virtio_chan *chan, | |||
364 | */ | 394 | */ |
365 | static int | 395 | static int |
366 | p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req, | 396 | p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req, |
367 | char *uidata, char *uodata, int inlen, | 397 | struct iov_iter *uidata, struct iov_iter *uodata, |
368 | int outlen, int in_hdr_len, int kern_buf) | 398 | int inlen, int outlen, int in_hdr_len) |
369 | { | 399 | { |
370 | int in, out, err, out_sgs, in_sgs; | 400 | int in, out, err, out_sgs, in_sgs; |
371 | unsigned long flags; | 401 | unsigned long flags; |
@@ -373,41 +403,32 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req, | |||
373 | struct page **in_pages = NULL, **out_pages = NULL; | 403 | struct page **in_pages = NULL, **out_pages = NULL; |
374 | struct virtio_chan *chan = client->trans; | 404 | struct virtio_chan *chan = client->trans; |
375 | struct scatterlist *sgs[4]; | 405 | struct scatterlist *sgs[4]; |
406 | size_t offs; | ||
407 | int need_drop = 0; | ||
376 | 408 | ||
377 | p9_debug(P9_DEBUG_TRANS, "virtio request\n"); | 409 | p9_debug(P9_DEBUG_TRANS, "virtio request\n"); |
378 | 410 | ||
379 | if (uodata) { | 411 | if (uodata) { |
380 | out_nr_pages = p9_nr_pages(uodata, outlen); | 412 | int n = p9_get_mapped_pages(chan, &out_pages, uodata, |
381 | out_pages = kmalloc(sizeof(struct page *) * out_nr_pages, | 413 | outlen, &offs, &need_drop); |
382 | GFP_NOFS); | 414 | if (n < 0) |
383 | if (!out_pages) { | 415 | return n; |
384 | err = -ENOMEM; | 416 | out_nr_pages = DIV_ROUND_UP(n + offs, PAGE_SIZE); |
385 | goto err_out; | 417 | if (n != outlen) { |
386 | } | 418 | __le32 v = cpu_to_le32(n); |
387 | out_nr_pages = p9_get_mapped_pages(chan, out_pages, uodata, | 419 | memcpy(&req->tc->sdata[req->tc->size - 4], &v, 4); |
388 | out_nr_pages, 0, kern_buf); | 420 | outlen = n; |
389 | if (out_nr_pages < 0) { | ||
390 | err = out_nr_pages; | ||
391 | kfree(out_pages); | ||
392 | out_pages = NULL; | ||
393 | goto err_out; | ||
394 | } | 421 | } |
395 | } | 422 | } else if (uidata) { |
396 | if (uidata) { | 423 | int n = p9_get_mapped_pages(chan, &in_pages, uidata, |
397 | in_nr_pages = p9_nr_pages(uidata, inlen); | 424 | inlen, &offs, &need_drop); |
398 | in_pages = kmalloc(sizeof(struct page *) * in_nr_pages, | 425 | if (n < 0) |
399 | GFP_NOFS); | 426 | return n; |
400 | if (!in_pages) { | 427 | in_nr_pages = DIV_ROUND_UP(n + offs, PAGE_SIZE); |
401 | err = -ENOMEM; | 428 | if (n != inlen) { |
402 | goto err_out; | 429 | __le32 v = cpu_to_le32(n); |
403 | } | 430 | memcpy(&req->tc->sdata[req->tc->size - 4], &v, 4); |
404 | in_nr_pages = p9_get_mapped_pages(chan, in_pages, uidata, | 431 | inlen = n; |
405 | in_nr_pages, 1, kern_buf); | ||
406 | if (in_nr_pages < 0) { | ||
407 | err = in_nr_pages; | ||
408 | kfree(in_pages); | ||
409 | in_pages = NULL; | ||
410 | goto err_out; | ||
411 | } | 432 | } |
412 | } | 433 | } |
413 | req->status = REQ_STATUS_SENT; | 434 | req->status = REQ_STATUS_SENT; |
@@ -426,7 +447,7 @@ req_retry_pinned: | |||
426 | if (out_pages) { | 447 | if (out_pages) { |
427 | sgs[out_sgs++] = chan->sg + out; | 448 | sgs[out_sgs++] = chan->sg + out; |
428 | out += pack_sg_list_p(chan->sg, out, VIRTQUEUE_NUM, | 449 | out += pack_sg_list_p(chan->sg, out, VIRTQUEUE_NUM, |
429 | out_pages, out_nr_pages, uodata, outlen); | 450 | out_pages, out_nr_pages, offs, outlen); |
430 | } | 451 | } |
431 | 452 | ||
432 | /* | 453 | /* |
@@ -444,7 +465,7 @@ req_retry_pinned: | |||
444 | if (in_pages) { | 465 | if (in_pages) { |
445 | sgs[out_sgs + in_sgs++] = chan->sg + out + in; | 466 | sgs[out_sgs + in_sgs++] = chan->sg + out + in; |
446 | in += pack_sg_list_p(chan->sg, out + in, VIRTQUEUE_NUM, | 467 | in += pack_sg_list_p(chan->sg, out + in, VIRTQUEUE_NUM, |
447 | in_pages, in_nr_pages, uidata, inlen); | 468 | in_pages, in_nr_pages, offs, inlen); |
448 | } | 469 | } |
449 | 470 | ||
450 | BUG_ON(out_sgs + in_sgs > ARRAY_SIZE(sgs)); | 471 | BUG_ON(out_sgs + in_sgs > ARRAY_SIZE(sgs)); |
@@ -478,7 +499,7 @@ req_retry_pinned: | |||
478 | * Non kernel buffers are pinned, unpin them | 499 | * Non kernel buffers are pinned, unpin them |
479 | */ | 500 | */ |
480 | err_out: | 501 | err_out: |
481 | if (!kern_buf) { | 502 | if (need_drop) { |
482 | if (in_pages) { | 503 | if (in_pages) { |
483 | p9_release_pages(in_pages, in_nr_pages); | 504 | p9_release_pages(in_pages, in_nr_pages); |
484 | atomic_sub(in_nr_pages, &vp_pinned); | 505 | atomic_sub(in_nr_pages, &vp_pinned); |