mm: fix pagecache write deadlocks
[pandora-kernel.git] / mm / filemap.h
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>
15 #include <linux/uaccess.h>
16
17 size_t
18 __filemap_copy_from_user_iovec_inatomic(char *vaddr,
19                                         const struct iovec *iov,
20                                         size_t base,
21                                         size_t bytes);
22
23 /*
24  * Copy as much as we can into the page and return the number of bytes which
25  * were sucessfully copied.  If a fault is encountered then return the number of
26  * bytes which were copied.
27  */
28 static inline size_t
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)
32 {
33         char *kaddr;
34         size_t copied;
35
36         kaddr = kmap_atomic(page, KM_USER0);
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         }
47         kunmap_atomic(kaddr, KM_USER0);
48
49         return copied;
50 }
51
52 /*
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.
56  */
57 static inline size_t
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)
61 {
62         char *kaddr;
63         size_t copied;
64
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);
74         }
75         kunmap(page);
76         return copied;
77 }
78
79 static inline void
80 filemap_set_next_iovec(const struct iovec **iovp, unsigned long nr_segs,
81                                                  size_t *basep, size_t bytes)
82 {
83         if (likely(nr_segs == 1)) {
84                 *basep += bytes;
85         } else {
86                 const struct iovec *iov = *iovp;
87                 size_t base = *basep;
88
89                 while (bytes) {
90                         int copy = min(bytes, iov->iov_len - base);
91
92                         bytes -= copy;
93                         base += copy;
94                         if (iov->iov_len == base) {
95                                 iov++;
96                                 base = 0;
97                         }
98                 }
99                 *iovp = iov;
100                 *basep = base;
101         }
102 }
103 #endif