Commit | Line | Data |
---|---|---|
ceffc078 CO |
1 | /* |
2 | * linux/mm/filemap.h | |
3 | * | |
4 | * Copyright (C) 1994-1999 Linus Torvalds | |
5 | */ | |
6 | ||
7 | #ifndef __FILEMAP_H | |
8 | #define __FILEMAP_H | |
9 | ||
10 | #include <linux/types.h> | |
11 | #include <linux/fs.h> | |
12 | #include <linux/mm.h> | |
13 | #include <linux/highmem.h> | |
14 | #include <linux/uio.h> | |
c22ce143 | 15 | #include <linux/uaccess.h> |
ceffc078 | 16 | |
eb6fe0c3 | 17 | size_t |
01408c49 N |
18 | __filemap_copy_from_user_iovec_inatomic(char *vaddr, |
19 | const struct iovec *iov, | |
20 | size_t base, | |
21 | size_t bytes); | |
ceffc078 CO |
22 | |
23 | /* | |
24 | * Copy as much as we can into the page and return the number of bytes which | |
4a9e5ef1 NP |
25 | * were sucessfully copied. If a fault is encountered then return the number of |
26 | * bytes which were copied. | |
ceffc078 CO |
27 | */ |
28 | static inline size_t | |
4a9e5ef1 NP |
29 | filemap_copy_from_user_atomic(struct page *page, unsigned long offset, |
30 | const struct iovec *iov, unsigned long nr_segs, | |
31 | size_t base, size_t bytes) | |
ceffc078 CO |
32 | { |
33 | char *kaddr; | |
4a9e5ef1 | 34 | size_t copied; |
ceffc078 CO |
35 | |
36 | kaddr = kmap_atomic(page, KM_USER0); | |
4a9e5ef1 NP |
37 | if (likely(nr_segs == 1)) { |
38 | int left; | |
39 | char __user *buf = iov->iov_base + base; | |
40 | left = __copy_from_user_inatomic_nocache(kaddr + offset, | |
41 | buf, bytes); | |
42 | copied = bytes - left; | |
43 | } else { | |
44 | copied = __filemap_copy_from_user_iovec_inatomic(kaddr + offset, | |
45 | iov, base, bytes); | |
46 | } | |
ceffc078 CO |
47 | kunmap_atomic(kaddr, KM_USER0); |
48 | ||
4a9e5ef1 | 49 | return copied; |
ceffc078 CO |
50 | } |
51 | ||
52 | /* | |
4a9e5ef1 NP |
53 | * This has the same sideeffects and return value as |
54 | * filemap_copy_from_user_atomic(). | |
55 | * The difference is that it attempts to resolve faults. | |
ceffc078 CO |
56 | */ |
57 | static inline size_t | |
4a9e5ef1 NP |
58 | filemap_copy_from_user(struct page *page, unsigned long offset, |
59 | const struct iovec *iov, unsigned long nr_segs, | |
60 | size_t base, size_t bytes) | |
ceffc078 CO |
61 | { |
62 | char *kaddr; | |
63 | size_t copied; | |
64 | ||
4a9e5ef1 NP |
65 | kaddr = kmap(page); |
66 | if (likely(nr_segs == 1)) { | |
67 | int left; | |
68 | char __user *buf = iov->iov_base + base; | |
69 | left = __copy_from_user_nocache(kaddr + offset, buf, bytes); | |
70 | copied = bytes - left; | |
71 | } else { | |
72 | copied = __filemap_copy_from_user_iovec_inatomic(kaddr + offset, | |
73 | iov, base, bytes); | |
ceffc078 | 74 | } |
4a9e5ef1 | 75 | kunmap(page); |
ceffc078 CO |
76 | return copied; |
77 | } | |
78 | ||
79 | static inline void | |
4a9e5ef1 NP |
80 | filemap_set_next_iovec(const struct iovec **iovp, unsigned long nr_segs, |
81 | size_t *basep, size_t bytes) | |
ceffc078 | 82 | { |
4a9e5ef1 NP |
83 | if (likely(nr_segs == 1)) { |
84 | *basep += bytes; | |
85 | } else { | |
86 | const struct iovec *iov = *iovp; | |
87 | size_t base = *basep; | |
ceffc078 | 88 | |
4a9e5ef1 NP |
89 | while (bytes) { |
90 | int copy = min(bytes, iov->iov_len - base); | |
ceffc078 | 91 | |
4a9e5ef1 NP |
92 | bytes -= copy; |
93 | base += copy; | |
94 | if (iov->iov_len == base) { | |
95 | iov++; | |
96 | base = 0; | |
97 | } | |
ceffc078 | 98 | } |
4a9e5ef1 NP |
99 | *iovp = iov; |
100 | *basep = base; | |
4b49643f | 101 | } |
ceffc078 CO |
102 | } |
103 | #endif |