diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-13 05:28:42 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-13 05:28:42 -0400 |
commit | 77c688ac87183537ed0fb84ec2cb8fa8ec97c458 (patch) | |
tree | d18e117e05c0d71463823536165ddd9ad75b6bc5 /mm | |
parent | 5e40d331bd72447197f26525f21711c4a265b6a6 (diff) | |
parent | a457606a6f81cfddfc9da1ef2a8bf2c65a8eb35e (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs updates from Al Viro:
"The big thing in this pile is Eric's unmount-on-rmdir series; we
finally have everything we need for that. The final piece of prereqs
is delayed mntput() - now filesystem shutdown always happens on
shallow stack.
Other than that, we have several new primitives for iov_iter (Matt
Wilcox, culled from his XIP-related series) pushing the conversion to
->read_iter()/ ->write_iter() a bit more, a bunch of fs/dcache.c
cleanups and fixes (including the external name refcounting, which
gives consistent behaviour of d_move() wrt procfs symlinks for long
and short names alike) and assorted cleanups and fixes all over the
place.
This is just the first pile; there's a lot of stuff from various
people that ought to go in this window. Starting with
unionmount/overlayfs mess... ;-/"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (60 commits)
fs/file_table.c: Update alloc_file() comment
vfs: Deduplicate code shared by xattr system calls operating on paths
reiserfs: remove pointless forward declaration of struct nameidata
don't need that forward declaration of struct nameidata in dcache.h anymore
take dname_external() into fs/dcache.c
let path_init() failures treated the same way as subsequent link_path_walk()
fix misuses of f_count() in ppp and netlink
ncpfs: use list_for_each_entry() for d_subdirs walk
vfs: move getname() from callers to do_mount()
gfs2_atomic_open(): skip lookups on hashed dentry
[infiniband] remove pointless assignments
gadgetfs: saner API for gadgetfs_create_file()
f_fs: saner API for ffs_sb_create_file()
jfs: don't hash direct inode
[s390] remove pointless assignment of ->f_op in vmlogrdr ->open()
ecryptfs: ->f_op is never NULL
android: ->f_op is never NULL
nouveau: __iomem misannotations
missing annotation in fs/file.c
fs: namespace: suppress 'may be used uninitialized' warnings
...
Diffstat (limited to 'mm')
-rw-r--r-- | mm/iov_iter.c | 240 |
1 files changed, 226 insertions, 14 deletions
diff --git a/mm/iov_iter.c b/mm/iov_iter.c index 9a09f2034fcc..eafcf60f6b83 100644 --- a/mm/iov_iter.c +++ b/mm/iov_iter.c | |||
@@ -4,6 +4,96 @@ | |||
4 | #include <linux/slab.h> | 4 | #include <linux/slab.h> |
5 | #include <linux/vmalloc.h> | 5 | #include <linux/vmalloc.h> |
6 | 6 | ||
7 | static size_t copy_to_iter_iovec(void *from, size_t bytes, struct iov_iter *i) | ||
8 | { | ||
9 | size_t skip, copy, left, wanted; | ||
10 | const struct iovec *iov; | ||
11 | char __user *buf; | ||
12 | |||
13 | if (unlikely(bytes > i->count)) | ||
14 | bytes = i->count; | ||
15 | |||
16 | if (unlikely(!bytes)) | ||
17 | return 0; | ||
18 | |||
19 | wanted = bytes; | ||
20 | iov = i->iov; | ||
21 | skip = i->iov_offset; | ||
22 | buf = iov->iov_base + skip; | ||
23 | copy = min(bytes, iov->iov_len - skip); | ||
24 | |||
25 | left = __copy_to_user(buf, from, copy); | ||
26 | copy -= left; | ||
27 | skip += copy; | ||
28 | from += copy; | ||
29 | bytes -= copy; | ||
30 | while (unlikely(!left && bytes)) { | ||
31 | iov++; | ||
32 | buf = iov->iov_base; | ||
33 | copy = min(bytes, iov->iov_len); | ||
34 | left = __copy_to_user(buf, from, copy); | ||
35 | copy -= left; | ||
36 | skip = copy; | ||
37 | from += copy; | ||
38 | bytes -= copy; | ||
39 | } | ||
40 | |||
41 | if (skip == iov->iov_len) { | ||
42 | iov++; | ||
43 | skip = 0; | ||
44 | } | ||
45 | i->count -= wanted - bytes; | ||
46 | i->nr_segs -= iov - i->iov; | ||
47 | i->iov = iov; | ||
48 | i->iov_offset = skip; | ||
49 | return wanted - bytes; | ||
50 | } | ||
51 | |||
52 | static size_t copy_from_iter_iovec(void *to, size_t bytes, struct iov_iter *i) | ||
53 | { | ||
54 | size_t skip, copy, left, wanted; | ||
55 | const struct iovec *iov; | ||
56 | char __user *buf; | ||
57 | |||
58 | if (unlikely(bytes > i->count)) | ||
59 | bytes = i->count; | ||
60 | |||
61 | if (unlikely(!bytes)) | ||
62 | return 0; | ||
63 | |||
64 | wanted = bytes; | ||
65 | iov = i->iov; | ||
66 | skip = i->iov_offset; | ||
67 | buf = iov->iov_base + skip; | ||
68 | copy = min(bytes, iov->iov_len - skip); | ||
69 | |||
70 | left = __copy_from_user(to, buf, copy); | ||
71 | copy -= left; | ||
72 | skip += copy; | ||
73 | to += copy; | ||
74 | bytes -= copy; | ||
75 | while (unlikely(!left && bytes)) { | ||
76 | iov++; | ||
77 | buf = iov->iov_base; | ||
78 | copy = min(bytes, iov->iov_len); | ||
79 | left = __copy_from_user(to, buf, copy); | ||
80 | copy -= left; | ||
81 | skip = copy; | ||
82 | to += copy; | ||
83 | bytes -= copy; | ||
84 | } | ||
85 | |||
86 | if (skip == iov->iov_len) { | ||
87 | iov++; | ||
88 | skip = 0; | ||
89 | } | ||
90 | i->count -= wanted - bytes; | ||
91 | i->nr_segs -= iov - i->iov; | ||
92 | i->iov = iov; | ||
93 | i->iov_offset = skip; | ||
94 | return wanted - bytes; | ||
95 | } | ||
96 | |||
7 | static size_t copy_page_to_iter_iovec(struct page *page, size_t offset, size_t bytes, | 97 | static size_t copy_page_to_iter_iovec(struct page *page, size_t offset, size_t bytes, |
8 | struct iov_iter *i) | 98 | struct iov_iter *i) |
9 | { | 99 | { |
@@ -166,6 +256,50 @@ done: | |||
166 | return wanted - bytes; | 256 | return wanted - bytes; |
167 | } | 257 | } |
168 | 258 | ||
259 | static size_t zero_iovec(size_t bytes, struct iov_iter *i) | ||
260 | { | ||
261 | size_t skip, copy, left, wanted; | ||
262 | const struct iovec *iov; | ||
263 | char __user *buf; | ||
264 | |||
265 | if (unlikely(bytes > i->count)) | ||
266 | bytes = i->count; | ||
267 | |||
268 | if (unlikely(!bytes)) | ||
269 | return 0; | ||
270 | |||
271 | wanted = bytes; | ||
272 | iov = i->iov; | ||
273 | skip = i->iov_offset; | ||
274 | buf = iov->iov_base + skip; | ||
275 | copy = min(bytes, iov->iov_len - skip); | ||
276 | |||
277 | left = __clear_user(buf, copy); | ||
278 | copy -= left; | ||
279 | skip += copy; | ||
280 | bytes -= copy; | ||
281 | |||
282 | while (unlikely(!left && bytes)) { | ||
283 | iov++; | ||
284 | buf = iov->iov_base; | ||
285 | copy = min(bytes, iov->iov_len); | ||
286 | left = __clear_user(buf, copy); | ||
287 | copy -= left; | ||
288 | skip = copy; | ||
289 | bytes -= copy; | ||
290 | } | ||
291 | |||
292 | if (skip == iov->iov_len) { | ||
293 | iov++; | ||
294 | skip = 0; | ||
295 | } | ||
296 | i->count -= wanted - bytes; | ||
297 | i->nr_segs -= iov - i->iov; | ||
298 | i->iov = iov; | ||
299 | i->iov_offset = skip; | ||
300 | return wanted - bytes; | ||
301 | } | ||
302 | |||
169 | static size_t __iovec_copy_from_user_inatomic(char *vaddr, | 303 | static size_t __iovec_copy_from_user_inatomic(char *vaddr, |
170 | const struct iovec *iov, size_t base, size_t bytes) | 304 | const struct iovec *iov, size_t base, size_t bytes) |
171 | { | 305 | { |
@@ -414,12 +548,17 @@ static void memcpy_to_page(struct page *page, size_t offset, char *from, size_t | |||
414 | kunmap_atomic(to); | 548 | kunmap_atomic(to); |
415 | } | 549 | } |
416 | 550 | ||
417 | static size_t copy_page_to_iter_bvec(struct page *page, size_t offset, size_t bytes, | 551 | static void memzero_page(struct page *page, size_t offset, size_t len) |
418 | struct iov_iter *i) | 552 | { |
553 | char *addr = kmap_atomic(page); | ||
554 | memset(addr + offset, 0, len); | ||
555 | kunmap_atomic(addr); | ||
556 | } | ||
557 | |||
558 | static size_t copy_to_iter_bvec(void *from, size_t bytes, struct iov_iter *i) | ||
419 | { | 559 | { |
420 | size_t skip, copy, wanted; | 560 | size_t skip, copy, wanted; |
421 | const struct bio_vec *bvec; | 561 | const struct bio_vec *bvec; |
422 | void *kaddr, *from; | ||
423 | 562 | ||
424 | if (unlikely(bytes > i->count)) | 563 | if (unlikely(bytes > i->count)) |
425 | bytes = i->count; | 564 | bytes = i->count; |
@@ -432,8 +571,6 @@ static size_t copy_page_to_iter_bvec(struct page *page, size_t offset, size_t by | |||
432 | skip = i->iov_offset; | 571 | skip = i->iov_offset; |
433 | copy = min_t(size_t, bytes, bvec->bv_len - skip); | 572 | copy = min_t(size_t, bytes, bvec->bv_len - skip); |
434 | 573 | ||
435 | kaddr = kmap_atomic(page); | ||
436 | from = kaddr + offset; | ||
437 | memcpy_to_page(bvec->bv_page, skip + bvec->bv_offset, from, copy); | 574 | memcpy_to_page(bvec->bv_page, skip + bvec->bv_offset, from, copy); |
438 | skip += copy; | 575 | skip += copy; |
439 | from += copy; | 576 | from += copy; |
@@ -446,7 +583,6 @@ static size_t copy_page_to_iter_bvec(struct page *page, size_t offset, size_t by | |||
446 | from += copy; | 583 | from += copy; |
447 | bytes -= copy; | 584 | bytes -= copy; |
448 | } | 585 | } |
449 | kunmap_atomic(kaddr); | ||
450 | if (skip == bvec->bv_len) { | 586 | if (skip == bvec->bv_len) { |
451 | bvec++; | 587 | bvec++; |
452 | skip = 0; | 588 | skip = 0; |
@@ -458,12 +594,10 @@ static size_t copy_page_to_iter_bvec(struct page *page, size_t offset, size_t by | |||
458 | return wanted - bytes; | 594 | return wanted - bytes; |
459 | } | 595 | } |
460 | 596 | ||
461 | static size_t copy_page_from_iter_bvec(struct page *page, size_t offset, size_t bytes, | 597 | static size_t copy_from_iter_bvec(void *to, size_t bytes, struct iov_iter *i) |
462 | struct iov_iter *i) | ||
463 | { | 598 | { |
464 | size_t skip, copy, wanted; | 599 | size_t skip, copy, wanted; |
465 | const struct bio_vec *bvec; | 600 | const struct bio_vec *bvec; |
466 | void *kaddr, *to; | ||
467 | 601 | ||
468 | if (unlikely(bytes > i->count)) | 602 | if (unlikely(bytes > i->count)) |
469 | bytes = i->count; | 603 | bytes = i->count; |
@@ -475,10 +609,6 @@ static size_t copy_page_from_iter_bvec(struct page *page, size_t offset, size_t | |||
475 | bvec = i->bvec; | 609 | bvec = i->bvec; |
476 | skip = i->iov_offset; | 610 | skip = i->iov_offset; |
477 | 611 | ||
478 | kaddr = kmap_atomic(page); | ||
479 | |||
480 | to = kaddr + offset; | ||
481 | |||
482 | copy = min(bytes, bvec->bv_len - skip); | 612 | copy = min(bytes, bvec->bv_len - skip); |
483 | 613 | ||
484 | memcpy_from_page(to, bvec->bv_page, bvec->bv_offset + skip, copy); | 614 | memcpy_from_page(to, bvec->bv_page, bvec->bv_offset + skip, copy); |
@@ -495,7 +625,6 @@ static size_t copy_page_from_iter_bvec(struct page *page, size_t offset, size_t | |||
495 | to += copy; | 625 | to += copy; |
496 | bytes -= copy; | 626 | bytes -= copy; |
497 | } | 627 | } |
498 | kunmap_atomic(kaddr); | ||
499 | if (skip == bvec->bv_len) { | 628 | if (skip == bvec->bv_len) { |
500 | bvec++; | 629 | bvec++; |
501 | skip = 0; | 630 | skip = 0; |
@@ -507,6 +636,61 @@ static size_t copy_page_from_iter_bvec(struct page *page, size_t offset, size_t | |||
507 | return wanted; | 636 | return wanted; |
508 | } | 637 | } |
509 | 638 | ||
639 | static size_t copy_page_to_iter_bvec(struct page *page, size_t offset, | ||
640 | size_t bytes, struct iov_iter *i) | ||
641 | { | ||
642 | void *kaddr = kmap_atomic(page); | ||
643 | size_t wanted = copy_to_iter_bvec(kaddr + offset, bytes, i); | ||
644 | kunmap_atomic(kaddr); | ||
645 | return wanted; | ||
646 | } | ||
647 | |||
648 | static size_t copy_page_from_iter_bvec(struct page *page, size_t offset, | ||
649 | size_t bytes, struct iov_iter *i) | ||
650 | { | ||
651 | void *kaddr = kmap_atomic(page); | ||
652 | size_t wanted = copy_from_iter_bvec(kaddr + offset, bytes, i); | ||
653 | kunmap_atomic(kaddr); | ||
654 | return wanted; | ||
655 | } | ||
656 | |||
657 | static size_t zero_bvec(size_t bytes, struct iov_iter *i) | ||
658 | { | ||
659 | size_t skip, copy, wanted; | ||
660 | const struct bio_vec *bvec; | ||
661 | |||
662 | if (unlikely(bytes > i->count)) | ||
663 | bytes = i->count; | ||
664 | |||
665 | if (unlikely(!bytes)) | ||
666 | return 0; | ||
667 | |||
668 | wanted = bytes; | ||
669 | bvec = i->bvec; | ||
670 | skip = i->iov_offset; | ||
671 | copy = min_t(size_t, bytes, bvec->bv_len - skip); | ||
672 | |||
673 | memzero_page(bvec->bv_page, skip + bvec->bv_offset, copy); | ||
674 | skip += copy; | ||
675 | bytes -= copy; | ||
676 | while (bytes) { | ||
677 | bvec++; | ||
678 | copy = min(bytes, (size_t)bvec->bv_len); | ||
679 | memzero_page(bvec->bv_page, bvec->bv_offset, copy); | ||
680 | skip = copy; | ||
681 | bytes -= copy; | ||
682 | } | ||
683 | if (skip == bvec->bv_len) { | ||
684 | bvec++; | ||
685 | skip = 0; | ||
686 | } | ||
687 | i->count -= wanted - bytes; | ||
688 | i->nr_segs -= bvec - i->bvec; | ||
689 | i->bvec = bvec; | ||
690 | i->iov_offset = skip; | ||
691 | return wanted - bytes; | ||
692 | } | ||
693 | |||
510 | static size_t copy_from_user_bvec(struct page *page, | 694 | static size_t copy_from_user_bvec(struct page *page, |
511 | struct iov_iter *i, unsigned long offset, size_t bytes) | 695 | struct iov_iter *i, unsigned long offset, size_t bytes) |
512 | { | 696 | { |
@@ -672,6 +856,34 @@ size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes, | |||
672 | } | 856 | } |
673 | EXPORT_SYMBOL(copy_page_from_iter); | 857 | EXPORT_SYMBOL(copy_page_from_iter); |
674 | 858 | ||
859 | size_t copy_to_iter(void *addr, size_t bytes, struct iov_iter *i) | ||
860 | { | ||
861 | if (i->type & ITER_BVEC) | ||
862 | return copy_to_iter_bvec(addr, bytes, i); | ||
863 | else | ||
864 | return copy_to_iter_iovec(addr, bytes, i); | ||
865 | } | ||
866 | EXPORT_SYMBOL(copy_to_iter); | ||
867 | |||
868 | size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i) | ||
869 | { | ||
870 | if (i->type & ITER_BVEC) | ||
871 | return copy_from_iter_bvec(addr, bytes, i); | ||
872 | else | ||
873 | return copy_from_iter_iovec(addr, bytes, i); | ||
874 | } | ||
875 | EXPORT_SYMBOL(copy_from_iter); | ||
876 | |||
877 | size_t iov_iter_zero(size_t bytes, struct iov_iter *i) | ||
878 | { | ||
879 | if (i->type & ITER_BVEC) { | ||
880 | return zero_bvec(bytes, i); | ||
881 | } else { | ||
882 | return zero_iovec(bytes, i); | ||
883 | } | ||
884 | } | ||
885 | EXPORT_SYMBOL(iov_iter_zero); | ||
886 | |||
675 | size_t iov_iter_copy_from_user_atomic(struct page *page, | 887 | size_t iov_iter_copy_from_user_atomic(struct page *page, |
676 | struct iov_iter *i, unsigned long offset, size_t bytes) | 888 | struct iov_iter *i, unsigned long offset, size_t bytes) |
677 | { | 889 | { |