Commit 60945cb7c8377b727288275f21791914fe65311c
Committed by
Trond Myklebust
1 parent
550facd138
Exists in
master
and in
7 other branches
NFS: use zero_user_page
Use zero_user_page() instead of the newly deprecated memclear_highpage_flush(). Signed-off-by: Nate Diller <nate.diller@gmail.com> Cc: Trond Myklebust <trond.myklebust@fys.uio.no> Cc: "J. Bruce Fields" <bfields@fieldses.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Showing 2 changed files with 6 additions and 6 deletions Inline Diff
fs/nfs/read.c
1 | /* | 1 | /* |
2 | * linux/fs/nfs/read.c | 2 | * linux/fs/nfs/read.c |
3 | * | 3 | * |
4 | * Block I/O for NFS | 4 | * Block I/O for NFS |
5 | * | 5 | * |
6 | * Partial copy of Linus' read cache modifications to fs/nfs/file.c | 6 | * Partial copy of Linus' read cache modifications to fs/nfs/file.c |
7 | * modified for async RPC by okir@monad.swb.de | 7 | * modified for async RPC by okir@monad.swb.de |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/time.h> | 10 | #include <linux/time.h> |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
13 | #include <linux/fcntl.h> | 13 | #include <linux/fcntl.h> |
14 | #include <linux/stat.h> | 14 | #include <linux/stat.h> |
15 | #include <linux/mm.h> | 15 | #include <linux/mm.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/pagemap.h> | 17 | #include <linux/pagemap.h> |
18 | #include <linux/sunrpc/clnt.h> | 18 | #include <linux/sunrpc/clnt.h> |
19 | #include <linux/nfs_fs.h> | 19 | #include <linux/nfs_fs.h> |
20 | #include <linux/nfs_page.h> | 20 | #include <linux/nfs_page.h> |
21 | #include <linux/smp_lock.h> | 21 | #include <linux/smp_lock.h> |
22 | 22 | ||
23 | #include <asm/system.h> | 23 | #include <asm/system.h> |
24 | 24 | ||
25 | #include "internal.h" | 25 | #include "internal.h" |
26 | #include "iostat.h" | 26 | #include "iostat.h" |
27 | 27 | ||
28 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 28 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
29 | 29 | ||
30 | static int nfs_pagein_multi(struct inode *, struct list_head *, unsigned int, size_t, int); | 30 | static int nfs_pagein_multi(struct inode *, struct list_head *, unsigned int, size_t, int); |
31 | static int nfs_pagein_one(struct inode *, struct list_head *, unsigned int, size_t, int); | 31 | static int nfs_pagein_one(struct inode *, struct list_head *, unsigned int, size_t, int); |
32 | static const struct rpc_call_ops nfs_read_partial_ops; | 32 | static const struct rpc_call_ops nfs_read_partial_ops; |
33 | static const struct rpc_call_ops nfs_read_full_ops; | 33 | static const struct rpc_call_ops nfs_read_full_ops; |
34 | 34 | ||
35 | static struct kmem_cache *nfs_rdata_cachep; | 35 | static struct kmem_cache *nfs_rdata_cachep; |
36 | static mempool_t *nfs_rdata_mempool; | 36 | static mempool_t *nfs_rdata_mempool; |
37 | 37 | ||
38 | #define MIN_POOL_READ (32) | 38 | #define MIN_POOL_READ (32) |
39 | 39 | ||
40 | struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) | 40 | struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) |
41 | { | 41 | { |
42 | struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, GFP_NOFS); | 42 | struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, GFP_NOFS); |
43 | 43 | ||
44 | if (p) { | 44 | if (p) { |
45 | memset(p, 0, sizeof(*p)); | 45 | memset(p, 0, sizeof(*p)); |
46 | INIT_LIST_HEAD(&p->pages); | 46 | INIT_LIST_HEAD(&p->pages); |
47 | p->npages = pagecount; | 47 | p->npages = pagecount; |
48 | if (pagecount <= ARRAY_SIZE(p->page_array)) | 48 | if (pagecount <= ARRAY_SIZE(p->page_array)) |
49 | p->pagevec = p->page_array; | 49 | p->pagevec = p->page_array; |
50 | else { | 50 | else { |
51 | p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS); | 51 | p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS); |
52 | if (!p->pagevec) { | 52 | if (!p->pagevec) { |
53 | mempool_free(p, nfs_rdata_mempool); | 53 | mempool_free(p, nfs_rdata_mempool); |
54 | p = NULL; | 54 | p = NULL; |
55 | } | 55 | } |
56 | } | 56 | } |
57 | } | 57 | } |
58 | return p; | 58 | return p; |
59 | } | 59 | } |
60 | 60 | ||
61 | static void nfs_readdata_rcu_free(struct rcu_head *head) | 61 | static void nfs_readdata_rcu_free(struct rcu_head *head) |
62 | { | 62 | { |
63 | struct nfs_read_data *p = container_of(head, struct nfs_read_data, task.u.tk_rcu); | 63 | struct nfs_read_data *p = container_of(head, struct nfs_read_data, task.u.tk_rcu); |
64 | if (p && (p->pagevec != &p->page_array[0])) | 64 | if (p && (p->pagevec != &p->page_array[0])) |
65 | kfree(p->pagevec); | 65 | kfree(p->pagevec); |
66 | mempool_free(p, nfs_rdata_mempool); | 66 | mempool_free(p, nfs_rdata_mempool); |
67 | } | 67 | } |
68 | 68 | ||
69 | static void nfs_readdata_free(struct nfs_read_data *rdata) | 69 | static void nfs_readdata_free(struct nfs_read_data *rdata) |
70 | { | 70 | { |
71 | call_rcu_bh(&rdata->task.u.tk_rcu, nfs_readdata_rcu_free); | 71 | call_rcu_bh(&rdata->task.u.tk_rcu, nfs_readdata_rcu_free); |
72 | } | 72 | } |
73 | 73 | ||
74 | void nfs_readdata_release(void *data) | 74 | void nfs_readdata_release(void *data) |
75 | { | 75 | { |
76 | nfs_readdata_free(data); | 76 | nfs_readdata_free(data); |
77 | } | 77 | } |
78 | 78 | ||
79 | static | 79 | static |
80 | int nfs_return_empty_page(struct page *page) | 80 | int nfs_return_empty_page(struct page *page) |
81 | { | 81 | { |
82 | memclear_highpage_flush(page, 0, PAGE_CACHE_SIZE); | 82 | zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0); |
83 | SetPageUptodate(page); | 83 | SetPageUptodate(page); |
84 | unlock_page(page); | 84 | unlock_page(page); |
85 | return 0; | 85 | return 0; |
86 | } | 86 | } |
87 | 87 | ||
88 | static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data) | 88 | static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data) |
89 | { | 89 | { |
90 | unsigned int remainder = data->args.count - data->res.count; | 90 | unsigned int remainder = data->args.count - data->res.count; |
91 | unsigned int base = data->args.pgbase + data->res.count; | 91 | unsigned int base = data->args.pgbase + data->res.count; |
92 | unsigned int pglen; | 92 | unsigned int pglen; |
93 | struct page **pages; | 93 | struct page **pages; |
94 | 94 | ||
95 | if (data->res.eof == 0 || remainder == 0) | 95 | if (data->res.eof == 0 || remainder == 0) |
96 | return; | 96 | return; |
97 | /* | 97 | /* |
98 | * Note: "remainder" can never be negative, since we check for | 98 | * Note: "remainder" can never be negative, since we check for |
99 | * this in the XDR code. | 99 | * this in the XDR code. |
100 | */ | 100 | */ |
101 | pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; | 101 | pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; |
102 | base &= ~PAGE_CACHE_MASK; | 102 | base &= ~PAGE_CACHE_MASK; |
103 | pglen = PAGE_CACHE_SIZE - base; | 103 | pglen = PAGE_CACHE_SIZE - base; |
104 | for (;;) { | 104 | for (;;) { |
105 | if (remainder <= pglen) { | 105 | if (remainder <= pglen) { |
106 | memclear_highpage_flush(*pages, base, remainder); | 106 | zero_user_page(*pages, base, remainder, KM_USER0); |
107 | break; | 107 | break; |
108 | } | 108 | } |
109 | memclear_highpage_flush(*pages, base, pglen); | 109 | zero_user_page(*pages, base, pglen, KM_USER0); |
110 | pages++; | 110 | pages++; |
111 | remainder -= pglen; | 111 | remainder -= pglen; |
112 | pglen = PAGE_CACHE_SIZE; | 112 | pglen = PAGE_CACHE_SIZE; |
113 | base = 0; | 113 | base = 0; |
114 | } | 114 | } |
115 | } | 115 | } |
116 | 116 | ||
117 | static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, | 117 | static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, |
118 | struct page *page) | 118 | struct page *page) |
119 | { | 119 | { |
120 | LIST_HEAD(one_request); | 120 | LIST_HEAD(one_request); |
121 | struct nfs_page *new; | 121 | struct nfs_page *new; |
122 | unsigned int len; | 122 | unsigned int len; |
123 | 123 | ||
124 | len = nfs_page_length(page); | 124 | len = nfs_page_length(page); |
125 | if (len == 0) | 125 | if (len == 0) |
126 | return nfs_return_empty_page(page); | 126 | return nfs_return_empty_page(page); |
127 | new = nfs_create_request(ctx, inode, page, 0, len); | 127 | new = nfs_create_request(ctx, inode, page, 0, len); |
128 | if (IS_ERR(new)) { | 128 | if (IS_ERR(new)) { |
129 | unlock_page(page); | 129 | unlock_page(page); |
130 | return PTR_ERR(new); | 130 | return PTR_ERR(new); |
131 | } | 131 | } |
132 | if (len < PAGE_CACHE_SIZE) | 132 | if (len < PAGE_CACHE_SIZE) |
133 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); | 133 | zero_user_page(page, len, PAGE_CACHE_SIZE - len, KM_USER0); |
134 | 134 | ||
135 | nfs_list_add_request(new, &one_request); | 135 | nfs_list_add_request(new, &one_request); |
136 | if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) | 136 | if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) |
137 | nfs_pagein_multi(inode, &one_request, 1, len, 0); | 137 | nfs_pagein_multi(inode, &one_request, 1, len, 0); |
138 | else | 138 | else |
139 | nfs_pagein_one(inode, &one_request, 1, len, 0); | 139 | nfs_pagein_one(inode, &one_request, 1, len, 0); |
140 | return 0; | 140 | return 0; |
141 | } | 141 | } |
142 | 142 | ||
143 | static void nfs_readpage_release(struct nfs_page *req) | 143 | static void nfs_readpage_release(struct nfs_page *req) |
144 | { | 144 | { |
145 | unlock_page(req->wb_page); | 145 | unlock_page(req->wb_page); |
146 | 146 | ||
147 | dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", | 147 | dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", |
148 | req->wb_context->dentry->d_inode->i_sb->s_id, | 148 | req->wb_context->dentry->d_inode->i_sb->s_id, |
149 | (long long)NFS_FILEID(req->wb_context->dentry->d_inode), | 149 | (long long)NFS_FILEID(req->wb_context->dentry->d_inode), |
150 | req->wb_bytes, | 150 | req->wb_bytes, |
151 | (long long)req_offset(req)); | 151 | (long long)req_offset(req)); |
152 | nfs_clear_request(req); | 152 | nfs_clear_request(req); |
153 | nfs_release_request(req); | 153 | nfs_release_request(req); |
154 | } | 154 | } |
155 | 155 | ||
156 | /* | 156 | /* |
157 | * Set up the NFS read request struct | 157 | * Set up the NFS read request struct |
158 | */ | 158 | */ |
159 | static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | 159 | static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, |
160 | const struct rpc_call_ops *call_ops, | 160 | const struct rpc_call_ops *call_ops, |
161 | unsigned int count, unsigned int offset) | 161 | unsigned int count, unsigned int offset) |
162 | { | 162 | { |
163 | struct inode *inode; | 163 | struct inode *inode; |
164 | int flags; | 164 | int flags; |
165 | 165 | ||
166 | data->req = req; | 166 | data->req = req; |
167 | data->inode = inode = req->wb_context->dentry->d_inode; | 167 | data->inode = inode = req->wb_context->dentry->d_inode; |
168 | data->cred = req->wb_context->cred; | 168 | data->cred = req->wb_context->cred; |
169 | 169 | ||
170 | data->args.fh = NFS_FH(inode); | 170 | data->args.fh = NFS_FH(inode); |
171 | data->args.offset = req_offset(req) + offset; | 171 | data->args.offset = req_offset(req) + offset; |
172 | data->args.pgbase = req->wb_pgbase + offset; | 172 | data->args.pgbase = req->wb_pgbase + offset; |
173 | data->args.pages = data->pagevec; | 173 | data->args.pages = data->pagevec; |
174 | data->args.count = count; | 174 | data->args.count = count; |
175 | data->args.context = req->wb_context; | 175 | data->args.context = req->wb_context; |
176 | 176 | ||
177 | data->res.fattr = &data->fattr; | 177 | data->res.fattr = &data->fattr; |
178 | data->res.count = count; | 178 | data->res.count = count; |
179 | data->res.eof = 0; | 179 | data->res.eof = 0; |
180 | nfs_fattr_init(&data->fattr); | 180 | nfs_fattr_init(&data->fattr); |
181 | 181 | ||
182 | /* Set up the initial task struct. */ | 182 | /* Set up the initial task struct. */ |
183 | flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); | 183 | flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); |
184 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, call_ops, data); | 184 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, call_ops, data); |
185 | NFS_PROTO(inode)->read_setup(data); | 185 | NFS_PROTO(inode)->read_setup(data); |
186 | 186 | ||
187 | data->task.tk_cookie = (unsigned long)inode; | 187 | data->task.tk_cookie = (unsigned long)inode; |
188 | 188 | ||
189 | dprintk("NFS: %5u initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n", | 189 | dprintk("NFS: %5u initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n", |
190 | data->task.tk_pid, | 190 | data->task.tk_pid, |
191 | inode->i_sb->s_id, | 191 | inode->i_sb->s_id, |
192 | (long long)NFS_FILEID(inode), | 192 | (long long)NFS_FILEID(inode), |
193 | count, | 193 | count, |
194 | (unsigned long long)data->args.offset); | 194 | (unsigned long long)data->args.offset); |
195 | } | 195 | } |
196 | 196 | ||
197 | static void | 197 | static void |
198 | nfs_async_read_error(struct list_head *head) | 198 | nfs_async_read_error(struct list_head *head) |
199 | { | 199 | { |
200 | struct nfs_page *req; | 200 | struct nfs_page *req; |
201 | 201 | ||
202 | while (!list_empty(head)) { | 202 | while (!list_empty(head)) { |
203 | req = nfs_list_entry(head->next); | 203 | req = nfs_list_entry(head->next); |
204 | nfs_list_remove_request(req); | 204 | nfs_list_remove_request(req); |
205 | SetPageError(req->wb_page); | 205 | SetPageError(req->wb_page); |
206 | nfs_readpage_release(req); | 206 | nfs_readpage_release(req); |
207 | } | 207 | } |
208 | } | 208 | } |
209 | 209 | ||
210 | /* | 210 | /* |
211 | * Start an async read operation | 211 | * Start an async read operation |
212 | */ | 212 | */ |
213 | static void nfs_execute_read(struct nfs_read_data *data) | 213 | static void nfs_execute_read(struct nfs_read_data *data) |
214 | { | 214 | { |
215 | struct rpc_clnt *clnt = NFS_CLIENT(data->inode); | 215 | struct rpc_clnt *clnt = NFS_CLIENT(data->inode); |
216 | sigset_t oldset; | 216 | sigset_t oldset; |
217 | 217 | ||
218 | rpc_clnt_sigmask(clnt, &oldset); | 218 | rpc_clnt_sigmask(clnt, &oldset); |
219 | rpc_execute(&data->task); | 219 | rpc_execute(&data->task); |
220 | rpc_clnt_sigunmask(clnt, &oldset); | 220 | rpc_clnt_sigunmask(clnt, &oldset); |
221 | } | 221 | } |
222 | 222 | ||
223 | /* | 223 | /* |
224 | * Generate multiple requests to fill a single page. | 224 | * Generate multiple requests to fill a single page. |
225 | * | 225 | * |
226 | * We optimize to reduce the number of read operations on the wire. If we | 226 | * We optimize to reduce the number of read operations on the wire. If we |
227 | * detect that we're reading a page, or an area of a page, that is past the | 227 | * detect that we're reading a page, or an area of a page, that is past the |
228 | * end of file, we do not generate NFS read operations but just clear the | 228 | * end of file, we do not generate NFS read operations but just clear the |
229 | * parts of the page that would have come back zero from the server anyway. | 229 | * parts of the page that would have come back zero from the server anyway. |
230 | * | 230 | * |
231 | * We rely on the cached value of i_size to make this determination; another | 231 | * We rely on the cached value of i_size to make this determination; another |
232 | * client can fill pages on the server past our cached end-of-file, but we | 232 | * client can fill pages on the server past our cached end-of-file, but we |
233 | * won't see the new data until our attribute cache is updated. This is more | 233 | * won't see the new data until our attribute cache is updated. This is more |
234 | * or less conventional NFS client behavior. | 234 | * or less conventional NFS client behavior. |
235 | */ | 235 | */ |
236 | static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags) | 236 | static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags) |
237 | { | 237 | { |
238 | struct nfs_page *req = nfs_list_entry(head->next); | 238 | struct nfs_page *req = nfs_list_entry(head->next); |
239 | struct page *page = req->wb_page; | 239 | struct page *page = req->wb_page; |
240 | struct nfs_read_data *data; | 240 | struct nfs_read_data *data; |
241 | size_t rsize = NFS_SERVER(inode)->rsize, nbytes; | 241 | size_t rsize = NFS_SERVER(inode)->rsize, nbytes; |
242 | unsigned int offset; | 242 | unsigned int offset; |
243 | int requests = 0; | 243 | int requests = 0; |
244 | LIST_HEAD(list); | 244 | LIST_HEAD(list); |
245 | 245 | ||
246 | nfs_list_remove_request(req); | 246 | nfs_list_remove_request(req); |
247 | 247 | ||
248 | nbytes = count; | 248 | nbytes = count; |
249 | do { | 249 | do { |
250 | size_t len = min(nbytes,rsize); | 250 | size_t len = min(nbytes,rsize); |
251 | 251 | ||
252 | data = nfs_readdata_alloc(1); | 252 | data = nfs_readdata_alloc(1); |
253 | if (!data) | 253 | if (!data) |
254 | goto out_bad; | 254 | goto out_bad; |
255 | INIT_LIST_HEAD(&data->pages); | 255 | INIT_LIST_HEAD(&data->pages); |
256 | list_add(&data->pages, &list); | 256 | list_add(&data->pages, &list); |
257 | requests++; | 257 | requests++; |
258 | nbytes -= len; | 258 | nbytes -= len; |
259 | } while(nbytes != 0); | 259 | } while(nbytes != 0); |
260 | atomic_set(&req->wb_complete, requests); | 260 | atomic_set(&req->wb_complete, requests); |
261 | 261 | ||
262 | ClearPageError(page); | 262 | ClearPageError(page); |
263 | offset = 0; | 263 | offset = 0; |
264 | nbytes = count; | 264 | nbytes = count; |
265 | do { | 265 | do { |
266 | data = list_entry(list.next, struct nfs_read_data, pages); | 266 | data = list_entry(list.next, struct nfs_read_data, pages); |
267 | list_del_init(&data->pages); | 267 | list_del_init(&data->pages); |
268 | 268 | ||
269 | data->pagevec[0] = page; | 269 | data->pagevec[0] = page; |
270 | 270 | ||
271 | if (nbytes < rsize) | 271 | if (nbytes < rsize) |
272 | rsize = nbytes; | 272 | rsize = nbytes; |
273 | nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, | 273 | nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, |
274 | rsize, offset); | 274 | rsize, offset); |
275 | offset += rsize; | 275 | offset += rsize; |
276 | nbytes -= rsize; | 276 | nbytes -= rsize; |
277 | nfs_execute_read(data); | 277 | nfs_execute_read(data); |
278 | } while (nbytes != 0); | 278 | } while (nbytes != 0); |
279 | 279 | ||
280 | return 0; | 280 | return 0; |
281 | 281 | ||
282 | out_bad: | 282 | out_bad: |
283 | while (!list_empty(&list)) { | 283 | while (!list_empty(&list)) { |
284 | data = list_entry(list.next, struct nfs_read_data, pages); | 284 | data = list_entry(list.next, struct nfs_read_data, pages); |
285 | list_del(&data->pages); | 285 | list_del(&data->pages); |
286 | nfs_readdata_free(data); | 286 | nfs_readdata_free(data); |
287 | } | 287 | } |
288 | SetPageError(page); | 288 | SetPageError(page); |
289 | nfs_readpage_release(req); | 289 | nfs_readpage_release(req); |
290 | return -ENOMEM; | 290 | return -ENOMEM; |
291 | } | 291 | } |
292 | 292 | ||
293 | static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags) | 293 | static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags) |
294 | { | 294 | { |
295 | struct nfs_page *req; | 295 | struct nfs_page *req; |
296 | struct page **pages; | 296 | struct page **pages; |
297 | struct nfs_read_data *data; | 297 | struct nfs_read_data *data; |
298 | 298 | ||
299 | data = nfs_readdata_alloc(npages); | 299 | data = nfs_readdata_alloc(npages); |
300 | if (!data) | 300 | if (!data) |
301 | goto out_bad; | 301 | goto out_bad; |
302 | 302 | ||
303 | INIT_LIST_HEAD(&data->pages); | 303 | INIT_LIST_HEAD(&data->pages); |
304 | pages = data->pagevec; | 304 | pages = data->pagevec; |
305 | while (!list_empty(head)) { | 305 | while (!list_empty(head)) { |
306 | req = nfs_list_entry(head->next); | 306 | req = nfs_list_entry(head->next); |
307 | nfs_list_remove_request(req); | 307 | nfs_list_remove_request(req); |
308 | nfs_list_add_request(req, &data->pages); | 308 | nfs_list_add_request(req, &data->pages); |
309 | ClearPageError(req->wb_page); | 309 | ClearPageError(req->wb_page); |
310 | *pages++ = req->wb_page; | 310 | *pages++ = req->wb_page; |
311 | } | 311 | } |
312 | req = nfs_list_entry(data->pages.next); | 312 | req = nfs_list_entry(data->pages.next); |
313 | 313 | ||
314 | nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0); | 314 | nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0); |
315 | 315 | ||
316 | nfs_execute_read(data); | 316 | nfs_execute_read(data); |
317 | return 0; | 317 | return 0; |
318 | out_bad: | 318 | out_bad: |
319 | nfs_async_read_error(head); | 319 | nfs_async_read_error(head); |
320 | return -ENOMEM; | 320 | return -ENOMEM; |
321 | } | 321 | } |
322 | 322 | ||
323 | /* | 323 | /* |
324 | * This is the callback from RPC telling us whether a reply was | 324 | * This is the callback from RPC telling us whether a reply was |
325 | * received or some error occurred (timeout or socket shutdown). | 325 | * received or some error occurred (timeout or socket shutdown). |
326 | */ | 326 | */ |
327 | int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) | 327 | int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) |
328 | { | 328 | { |
329 | int status; | 329 | int status; |
330 | 330 | ||
331 | dprintk("NFS: %s: %5u, (status %d)\n", __FUNCTION__, task->tk_pid, | 331 | dprintk("NFS: %s: %5u, (status %d)\n", __FUNCTION__, task->tk_pid, |
332 | task->tk_status); | 332 | task->tk_status); |
333 | 333 | ||
334 | status = NFS_PROTO(data->inode)->read_done(task, data); | 334 | status = NFS_PROTO(data->inode)->read_done(task, data); |
335 | if (status != 0) | 335 | if (status != 0) |
336 | return status; | 336 | return status; |
337 | 337 | ||
338 | nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, data->res.count); | 338 | nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, data->res.count); |
339 | 339 | ||
340 | if (task->tk_status == -ESTALE) { | 340 | if (task->tk_status == -ESTALE) { |
341 | set_bit(NFS_INO_STALE, &NFS_FLAGS(data->inode)); | 341 | set_bit(NFS_INO_STALE, &NFS_FLAGS(data->inode)); |
342 | nfs_mark_for_revalidate(data->inode); | 342 | nfs_mark_for_revalidate(data->inode); |
343 | } | 343 | } |
344 | spin_lock(&data->inode->i_lock); | 344 | spin_lock(&data->inode->i_lock); |
345 | NFS_I(data->inode)->cache_validity |= NFS_INO_INVALID_ATIME; | 345 | NFS_I(data->inode)->cache_validity |= NFS_INO_INVALID_ATIME; |
346 | spin_unlock(&data->inode->i_lock); | 346 | spin_unlock(&data->inode->i_lock); |
347 | return 0; | 347 | return 0; |
348 | } | 348 | } |
349 | 349 | ||
350 | static int nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data) | 350 | static int nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data) |
351 | { | 351 | { |
352 | struct nfs_readargs *argp = &data->args; | 352 | struct nfs_readargs *argp = &data->args; |
353 | struct nfs_readres *resp = &data->res; | 353 | struct nfs_readres *resp = &data->res; |
354 | 354 | ||
355 | if (resp->eof || resp->count == argp->count) | 355 | if (resp->eof || resp->count == argp->count) |
356 | return 0; | 356 | return 0; |
357 | 357 | ||
358 | /* This is a short read! */ | 358 | /* This is a short read! */ |
359 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); | 359 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); |
360 | /* Has the server at least made some progress? */ | 360 | /* Has the server at least made some progress? */ |
361 | if (resp->count == 0) | 361 | if (resp->count == 0) |
362 | return 0; | 362 | return 0; |
363 | 363 | ||
364 | /* Yes, so retry the read at the end of the data */ | 364 | /* Yes, so retry the read at the end of the data */ |
365 | argp->offset += resp->count; | 365 | argp->offset += resp->count; |
366 | argp->pgbase += resp->count; | 366 | argp->pgbase += resp->count; |
367 | argp->count -= resp->count; | 367 | argp->count -= resp->count; |
368 | rpc_restart_call(task); | 368 | rpc_restart_call(task); |
369 | return -EAGAIN; | 369 | return -EAGAIN; |
370 | } | 370 | } |
371 | 371 | ||
372 | /* | 372 | /* |
373 | * Handle a read reply that fills part of a page. | 373 | * Handle a read reply that fills part of a page. |
374 | */ | 374 | */ |
375 | static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata) | 375 | static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata) |
376 | { | 376 | { |
377 | struct nfs_read_data *data = calldata; | 377 | struct nfs_read_data *data = calldata; |
378 | struct nfs_page *req = data->req; | 378 | struct nfs_page *req = data->req; |
379 | struct page *page = req->wb_page; | 379 | struct page *page = req->wb_page; |
380 | 380 | ||
381 | if (nfs_readpage_result(task, data) != 0) | 381 | if (nfs_readpage_result(task, data) != 0) |
382 | return; | 382 | return; |
383 | 383 | ||
384 | if (likely(task->tk_status >= 0)) { | 384 | if (likely(task->tk_status >= 0)) { |
385 | nfs_readpage_truncate_uninitialised_page(data); | 385 | nfs_readpage_truncate_uninitialised_page(data); |
386 | if (nfs_readpage_retry(task, data) != 0) | 386 | if (nfs_readpage_retry(task, data) != 0) |
387 | return; | 387 | return; |
388 | } | 388 | } |
389 | if (unlikely(task->tk_status < 0)) | 389 | if (unlikely(task->tk_status < 0)) |
390 | SetPageError(page); | 390 | SetPageError(page); |
391 | if (atomic_dec_and_test(&req->wb_complete)) { | 391 | if (atomic_dec_and_test(&req->wb_complete)) { |
392 | if (!PageError(page)) | 392 | if (!PageError(page)) |
393 | SetPageUptodate(page); | 393 | SetPageUptodate(page); |
394 | nfs_readpage_release(req); | 394 | nfs_readpage_release(req); |
395 | } | 395 | } |
396 | } | 396 | } |
397 | 397 | ||
398 | static const struct rpc_call_ops nfs_read_partial_ops = { | 398 | static const struct rpc_call_ops nfs_read_partial_ops = { |
399 | .rpc_call_done = nfs_readpage_result_partial, | 399 | .rpc_call_done = nfs_readpage_result_partial, |
400 | .rpc_release = nfs_readdata_release, | 400 | .rpc_release = nfs_readdata_release, |
401 | }; | 401 | }; |
402 | 402 | ||
403 | static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data) | 403 | static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data) |
404 | { | 404 | { |
405 | unsigned int count = data->res.count; | 405 | unsigned int count = data->res.count; |
406 | unsigned int base = data->args.pgbase; | 406 | unsigned int base = data->args.pgbase; |
407 | struct page **pages; | 407 | struct page **pages; |
408 | 408 | ||
409 | if (data->res.eof) | 409 | if (data->res.eof) |
410 | count = data->args.count; | 410 | count = data->args.count; |
411 | if (unlikely(count == 0)) | 411 | if (unlikely(count == 0)) |
412 | return; | 412 | return; |
413 | pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; | 413 | pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; |
414 | base &= ~PAGE_CACHE_MASK; | 414 | base &= ~PAGE_CACHE_MASK; |
415 | count += base; | 415 | count += base; |
416 | for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) | 416 | for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) |
417 | SetPageUptodate(*pages); | 417 | SetPageUptodate(*pages); |
418 | if (count == 0) | 418 | if (count == 0) |
419 | return; | 419 | return; |
420 | /* Was this a short read? */ | 420 | /* Was this a short read? */ |
421 | if (data->res.eof || data->res.count == data->args.count) | 421 | if (data->res.eof || data->res.count == data->args.count) |
422 | SetPageUptodate(*pages); | 422 | SetPageUptodate(*pages); |
423 | } | 423 | } |
424 | 424 | ||
425 | /* | 425 | /* |
426 | * This is the callback from RPC telling us whether a reply was | 426 | * This is the callback from RPC telling us whether a reply was |
427 | * received or some error occurred (timeout or socket shutdown). | 427 | * received or some error occurred (timeout or socket shutdown). |
428 | */ | 428 | */ |
429 | static void nfs_readpage_result_full(struct rpc_task *task, void *calldata) | 429 | static void nfs_readpage_result_full(struct rpc_task *task, void *calldata) |
430 | { | 430 | { |
431 | struct nfs_read_data *data = calldata; | 431 | struct nfs_read_data *data = calldata; |
432 | 432 | ||
433 | if (nfs_readpage_result(task, data) != 0) | 433 | if (nfs_readpage_result(task, data) != 0) |
434 | return; | 434 | return; |
435 | /* | 435 | /* |
436 | * Note: nfs_readpage_retry may change the values of | 436 | * Note: nfs_readpage_retry may change the values of |
437 | * data->args. In the multi-page case, we therefore need | 437 | * data->args. In the multi-page case, we therefore need |
438 | * to ensure that we call nfs_readpage_set_pages_uptodate() | 438 | * to ensure that we call nfs_readpage_set_pages_uptodate() |
439 | * first. | 439 | * first. |
440 | */ | 440 | */ |
441 | if (likely(task->tk_status >= 0)) { | 441 | if (likely(task->tk_status >= 0)) { |
442 | nfs_readpage_truncate_uninitialised_page(data); | 442 | nfs_readpage_truncate_uninitialised_page(data); |
443 | nfs_readpage_set_pages_uptodate(data); | 443 | nfs_readpage_set_pages_uptodate(data); |
444 | if (nfs_readpage_retry(task, data) != 0) | 444 | if (nfs_readpage_retry(task, data) != 0) |
445 | return; | 445 | return; |
446 | } | 446 | } |
447 | while (!list_empty(&data->pages)) { | 447 | while (!list_empty(&data->pages)) { |
448 | struct nfs_page *req = nfs_list_entry(data->pages.next); | 448 | struct nfs_page *req = nfs_list_entry(data->pages.next); |
449 | 449 | ||
450 | nfs_list_remove_request(req); | 450 | nfs_list_remove_request(req); |
451 | nfs_readpage_release(req); | 451 | nfs_readpage_release(req); |
452 | } | 452 | } |
453 | } | 453 | } |
454 | 454 | ||
455 | static const struct rpc_call_ops nfs_read_full_ops = { | 455 | static const struct rpc_call_ops nfs_read_full_ops = { |
456 | .rpc_call_done = nfs_readpage_result_full, | 456 | .rpc_call_done = nfs_readpage_result_full, |
457 | .rpc_release = nfs_readdata_release, | 457 | .rpc_release = nfs_readdata_release, |
458 | }; | 458 | }; |
459 | 459 | ||
460 | /* | 460 | /* |
461 | * Read a page over NFS. | 461 | * Read a page over NFS. |
462 | * We read the page synchronously in the following case: | 462 | * We read the page synchronously in the following case: |
463 | * - The error flag is set for this page. This happens only when a | 463 | * - The error flag is set for this page. This happens only when a |
464 | * previous async read operation failed. | 464 | * previous async read operation failed. |
465 | */ | 465 | */ |
466 | int nfs_readpage(struct file *file, struct page *page) | 466 | int nfs_readpage(struct file *file, struct page *page) |
467 | { | 467 | { |
468 | struct nfs_open_context *ctx; | 468 | struct nfs_open_context *ctx; |
469 | struct inode *inode = page->mapping->host; | 469 | struct inode *inode = page->mapping->host; |
470 | int error; | 470 | int error; |
471 | 471 | ||
472 | dprintk("NFS: nfs_readpage (%p %ld@%lu)\n", | 472 | dprintk("NFS: nfs_readpage (%p %ld@%lu)\n", |
473 | page, PAGE_CACHE_SIZE, page->index); | 473 | page, PAGE_CACHE_SIZE, page->index); |
474 | nfs_inc_stats(inode, NFSIOS_VFSREADPAGE); | 474 | nfs_inc_stats(inode, NFSIOS_VFSREADPAGE); |
475 | nfs_add_stats(inode, NFSIOS_READPAGES, 1); | 475 | nfs_add_stats(inode, NFSIOS_READPAGES, 1); |
476 | 476 | ||
477 | /* | 477 | /* |
478 | * Try to flush any pending writes to the file.. | 478 | * Try to flush any pending writes to the file.. |
479 | * | 479 | * |
480 | * NOTE! Because we own the page lock, there cannot | 480 | * NOTE! Because we own the page lock, there cannot |
481 | * be any new pending writes generated at this point | 481 | * be any new pending writes generated at this point |
482 | * for this page (other pages can be written to). | 482 | * for this page (other pages can be written to). |
483 | */ | 483 | */ |
484 | error = nfs_wb_page(inode, page); | 484 | error = nfs_wb_page(inode, page); |
485 | if (error) | 485 | if (error) |
486 | goto out_error; | 486 | goto out_error; |
487 | 487 | ||
488 | error = -ESTALE; | 488 | error = -ESTALE; |
489 | if (NFS_STALE(inode)) | 489 | if (NFS_STALE(inode)) |
490 | goto out_error; | 490 | goto out_error; |
491 | 491 | ||
492 | if (file == NULL) { | 492 | if (file == NULL) { |
493 | error = -EBADF; | 493 | error = -EBADF; |
494 | ctx = nfs_find_open_context(inode, NULL, FMODE_READ); | 494 | ctx = nfs_find_open_context(inode, NULL, FMODE_READ); |
495 | if (ctx == NULL) | 495 | if (ctx == NULL) |
496 | goto out_error; | 496 | goto out_error; |
497 | } else | 497 | } else |
498 | ctx = get_nfs_open_context((struct nfs_open_context *) | 498 | ctx = get_nfs_open_context((struct nfs_open_context *) |
499 | file->private_data); | 499 | file->private_data); |
500 | 500 | ||
501 | error = nfs_readpage_async(ctx, inode, page); | 501 | error = nfs_readpage_async(ctx, inode, page); |
502 | 502 | ||
503 | put_nfs_open_context(ctx); | 503 | put_nfs_open_context(ctx); |
504 | return error; | 504 | return error; |
505 | 505 | ||
506 | out_error: | 506 | out_error: |
507 | unlock_page(page); | 507 | unlock_page(page); |
508 | return error; | 508 | return error; |
509 | } | 509 | } |
510 | 510 | ||
511 | struct nfs_readdesc { | 511 | struct nfs_readdesc { |
512 | struct nfs_pageio_descriptor *pgio; | 512 | struct nfs_pageio_descriptor *pgio; |
513 | struct nfs_open_context *ctx; | 513 | struct nfs_open_context *ctx; |
514 | }; | 514 | }; |
515 | 515 | ||
516 | static int | 516 | static int |
517 | readpage_async_filler(void *data, struct page *page) | 517 | readpage_async_filler(void *data, struct page *page) |
518 | { | 518 | { |
519 | struct nfs_readdesc *desc = (struct nfs_readdesc *)data; | 519 | struct nfs_readdesc *desc = (struct nfs_readdesc *)data; |
520 | struct inode *inode = page->mapping->host; | 520 | struct inode *inode = page->mapping->host; |
521 | struct nfs_page *new; | 521 | struct nfs_page *new; |
522 | unsigned int len; | 522 | unsigned int len; |
523 | 523 | ||
524 | nfs_wb_page(inode, page); | 524 | nfs_wb_page(inode, page); |
525 | len = nfs_page_length(page); | 525 | len = nfs_page_length(page); |
526 | if (len == 0) | 526 | if (len == 0) |
527 | return nfs_return_empty_page(page); | 527 | return nfs_return_empty_page(page); |
528 | new = nfs_create_request(desc->ctx, inode, page, 0, len); | 528 | new = nfs_create_request(desc->ctx, inode, page, 0, len); |
529 | if (IS_ERR(new)) { | 529 | if (IS_ERR(new)) { |
530 | SetPageError(page); | 530 | SetPageError(page); |
531 | unlock_page(page); | 531 | unlock_page(page); |
532 | return PTR_ERR(new); | 532 | return PTR_ERR(new); |
533 | } | 533 | } |
534 | if (len < PAGE_CACHE_SIZE) | 534 | if (len < PAGE_CACHE_SIZE) |
535 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); | 535 | zero_user_page(page, len, PAGE_CACHE_SIZE - len, KM_USER0); |
536 | nfs_pageio_add_request(desc->pgio, new); | 536 | nfs_pageio_add_request(desc->pgio, new); |
537 | return 0; | 537 | return 0; |
538 | } | 538 | } |
539 | 539 | ||
540 | int nfs_readpages(struct file *filp, struct address_space *mapping, | 540 | int nfs_readpages(struct file *filp, struct address_space *mapping, |
541 | struct list_head *pages, unsigned nr_pages) | 541 | struct list_head *pages, unsigned nr_pages) |
542 | { | 542 | { |
543 | struct nfs_pageio_descriptor pgio; | 543 | struct nfs_pageio_descriptor pgio; |
544 | struct nfs_readdesc desc = { | 544 | struct nfs_readdesc desc = { |
545 | .pgio = &pgio, | 545 | .pgio = &pgio, |
546 | }; | 546 | }; |
547 | struct inode *inode = mapping->host; | 547 | struct inode *inode = mapping->host; |
548 | struct nfs_server *server = NFS_SERVER(inode); | 548 | struct nfs_server *server = NFS_SERVER(inode); |
549 | size_t rsize = server->rsize; | 549 | size_t rsize = server->rsize; |
550 | unsigned long npages; | 550 | unsigned long npages; |
551 | int ret = -ESTALE; | 551 | int ret = -ESTALE; |
552 | 552 | ||
553 | dprintk("NFS: nfs_readpages (%s/%Ld %d)\n", | 553 | dprintk("NFS: nfs_readpages (%s/%Ld %d)\n", |
554 | inode->i_sb->s_id, | 554 | inode->i_sb->s_id, |
555 | (long long)NFS_FILEID(inode), | 555 | (long long)NFS_FILEID(inode), |
556 | nr_pages); | 556 | nr_pages); |
557 | nfs_inc_stats(inode, NFSIOS_VFSREADPAGES); | 557 | nfs_inc_stats(inode, NFSIOS_VFSREADPAGES); |
558 | 558 | ||
559 | if (NFS_STALE(inode)) | 559 | if (NFS_STALE(inode)) |
560 | goto out; | 560 | goto out; |
561 | 561 | ||
562 | if (filp == NULL) { | 562 | if (filp == NULL) { |
563 | desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ); | 563 | desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ); |
564 | if (desc.ctx == NULL) | 564 | if (desc.ctx == NULL) |
565 | return -EBADF; | 565 | return -EBADF; |
566 | } else | 566 | } else |
567 | desc.ctx = get_nfs_open_context((struct nfs_open_context *) | 567 | desc.ctx = get_nfs_open_context((struct nfs_open_context *) |
568 | filp->private_data); | 568 | filp->private_data); |
569 | if (rsize < PAGE_CACHE_SIZE) | 569 | if (rsize < PAGE_CACHE_SIZE) |
570 | nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0); | 570 | nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0); |
571 | else | 571 | else |
572 | nfs_pageio_init(&pgio, inode, nfs_pagein_one, rsize, 0); | 572 | nfs_pageio_init(&pgio, inode, nfs_pagein_one, rsize, 0); |
573 | 573 | ||
574 | ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); | 574 | ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); |
575 | 575 | ||
576 | nfs_pageio_complete(&pgio); | 576 | nfs_pageio_complete(&pgio); |
577 | npages = (pgio.pg_bytes_written + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 577 | npages = (pgio.pg_bytes_written + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
578 | nfs_add_stats(inode, NFSIOS_READPAGES, npages); | 578 | nfs_add_stats(inode, NFSIOS_READPAGES, npages); |
579 | put_nfs_open_context(desc.ctx); | 579 | put_nfs_open_context(desc.ctx); |
580 | out: | 580 | out: |
581 | return ret; | 581 | return ret; |
582 | } | 582 | } |
583 | 583 | ||
584 | int __init nfs_init_readpagecache(void) | 584 | int __init nfs_init_readpagecache(void) |
585 | { | 585 | { |
586 | nfs_rdata_cachep = kmem_cache_create("nfs_read_data", | 586 | nfs_rdata_cachep = kmem_cache_create("nfs_read_data", |
587 | sizeof(struct nfs_read_data), | 587 | sizeof(struct nfs_read_data), |
588 | 0, SLAB_HWCACHE_ALIGN, | 588 | 0, SLAB_HWCACHE_ALIGN, |
589 | NULL, NULL); | 589 | NULL, NULL); |
590 | if (nfs_rdata_cachep == NULL) | 590 | if (nfs_rdata_cachep == NULL) |
591 | return -ENOMEM; | 591 | return -ENOMEM; |
592 | 592 | ||
593 | nfs_rdata_mempool = mempool_create_slab_pool(MIN_POOL_READ, | 593 | nfs_rdata_mempool = mempool_create_slab_pool(MIN_POOL_READ, |
594 | nfs_rdata_cachep); | 594 | nfs_rdata_cachep); |
595 | if (nfs_rdata_mempool == NULL) | 595 | if (nfs_rdata_mempool == NULL) |
596 | return -ENOMEM; | 596 | return -ENOMEM; |
597 | 597 | ||
598 | return 0; | 598 | return 0; |
599 | } | 599 | } |
600 | 600 | ||
601 | void nfs_destroy_readpagecache(void) | 601 | void nfs_destroy_readpagecache(void) |
602 | { | 602 | { |
603 | mempool_destroy(nfs_rdata_mempool); | 603 | mempool_destroy(nfs_rdata_mempool); |
604 | kmem_cache_destroy(nfs_rdata_cachep); | 604 | kmem_cache_destroy(nfs_rdata_cachep); |
605 | } | 605 | } |
606 | 606 |
fs/nfs/write.c
1 | /* | 1 | /* |
2 | * linux/fs/nfs/write.c | 2 | * linux/fs/nfs/write.c |
3 | * | 3 | * |
4 | * Write file data over NFS. | 4 | * Write file data over NFS. |
5 | * | 5 | * |
6 | * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de> | 6 | * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de> |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
10 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
11 | #include <linux/mm.h> | 11 | #include <linux/mm.h> |
12 | #include <linux/pagemap.h> | 12 | #include <linux/pagemap.h> |
13 | #include <linux/file.h> | 13 | #include <linux/file.h> |
14 | #include <linux/writeback.h> | 14 | #include <linux/writeback.h> |
15 | #include <linux/swap.h> | 15 | #include <linux/swap.h> |
16 | 16 | ||
17 | #include <linux/sunrpc/clnt.h> | 17 | #include <linux/sunrpc/clnt.h> |
18 | #include <linux/nfs_fs.h> | 18 | #include <linux/nfs_fs.h> |
19 | #include <linux/nfs_mount.h> | 19 | #include <linux/nfs_mount.h> |
20 | #include <linux/nfs_page.h> | 20 | #include <linux/nfs_page.h> |
21 | #include <linux/backing-dev.h> | 21 | #include <linux/backing-dev.h> |
22 | 22 | ||
23 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
24 | 24 | ||
25 | #include "delegation.h" | 25 | #include "delegation.h" |
26 | #include "internal.h" | 26 | #include "internal.h" |
27 | #include "iostat.h" | 27 | #include "iostat.h" |
28 | 28 | ||
29 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 29 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
30 | 30 | ||
31 | #define MIN_POOL_WRITE (32) | 31 | #define MIN_POOL_WRITE (32) |
32 | #define MIN_POOL_COMMIT (4) | 32 | #define MIN_POOL_COMMIT (4) |
33 | 33 | ||
34 | /* | 34 | /* |
35 | * Local function declarations | 35 | * Local function declarations |
36 | */ | 36 | */ |
37 | static struct nfs_page * nfs_update_request(struct nfs_open_context*, | 37 | static struct nfs_page * nfs_update_request(struct nfs_open_context*, |
38 | struct page *, | 38 | struct page *, |
39 | unsigned int, unsigned int); | 39 | unsigned int, unsigned int); |
40 | static void nfs_pageio_init_write(struct nfs_pageio_descriptor *desc, | 40 | static void nfs_pageio_init_write(struct nfs_pageio_descriptor *desc, |
41 | struct inode *inode, int ioflags); | 41 | struct inode *inode, int ioflags); |
42 | static const struct rpc_call_ops nfs_write_partial_ops; | 42 | static const struct rpc_call_ops nfs_write_partial_ops; |
43 | static const struct rpc_call_ops nfs_write_full_ops; | 43 | static const struct rpc_call_ops nfs_write_full_ops; |
44 | static const struct rpc_call_ops nfs_commit_ops; | 44 | static const struct rpc_call_ops nfs_commit_ops; |
45 | 45 | ||
46 | static struct kmem_cache *nfs_wdata_cachep; | 46 | static struct kmem_cache *nfs_wdata_cachep; |
47 | static mempool_t *nfs_wdata_mempool; | 47 | static mempool_t *nfs_wdata_mempool; |
48 | static mempool_t *nfs_commit_mempool; | 48 | static mempool_t *nfs_commit_mempool; |
49 | 49 | ||
50 | struct nfs_write_data *nfs_commit_alloc(void) | 50 | struct nfs_write_data *nfs_commit_alloc(void) |
51 | { | 51 | { |
52 | struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS); | 52 | struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS); |
53 | 53 | ||
54 | if (p) { | 54 | if (p) { |
55 | memset(p, 0, sizeof(*p)); | 55 | memset(p, 0, sizeof(*p)); |
56 | INIT_LIST_HEAD(&p->pages); | 56 | INIT_LIST_HEAD(&p->pages); |
57 | } | 57 | } |
58 | return p; | 58 | return p; |
59 | } | 59 | } |
60 | 60 | ||
61 | void nfs_commit_rcu_free(struct rcu_head *head) | 61 | void nfs_commit_rcu_free(struct rcu_head *head) |
62 | { | 62 | { |
63 | struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu); | 63 | struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu); |
64 | if (p && (p->pagevec != &p->page_array[0])) | 64 | if (p && (p->pagevec != &p->page_array[0])) |
65 | kfree(p->pagevec); | 65 | kfree(p->pagevec); |
66 | mempool_free(p, nfs_commit_mempool); | 66 | mempool_free(p, nfs_commit_mempool); |
67 | } | 67 | } |
68 | 68 | ||
69 | void nfs_commit_free(struct nfs_write_data *wdata) | 69 | void nfs_commit_free(struct nfs_write_data *wdata) |
70 | { | 70 | { |
71 | call_rcu_bh(&wdata->task.u.tk_rcu, nfs_commit_rcu_free); | 71 | call_rcu_bh(&wdata->task.u.tk_rcu, nfs_commit_rcu_free); |
72 | } | 72 | } |
73 | 73 | ||
74 | struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | 74 | struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) |
75 | { | 75 | { |
76 | struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS); | 76 | struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS); |
77 | 77 | ||
78 | if (p) { | 78 | if (p) { |
79 | memset(p, 0, sizeof(*p)); | 79 | memset(p, 0, sizeof(*p)); |
80 | INIT_LIST_HEAD(&p->pages); | 80 | INIT_LIST_HEAD(&p->pages); |
81 | p->npages = pagecount; | 81 | p->npages = pagecount; |
82 | if (pagecount <= ARRAY_SIZE(p->page_array)) | 82 | if (pagecount <= ARRAY_SIZE(p->page_array)) |
83 | p->pagevec = p->page_array; | 83 | p->pagevec = p->page_array; |
84 | else { | 84 | else { |
85 | p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS); | 85 | p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS); |
86 | if (!p->pagevec) { | 86 | if (!p->pagevec) { |
87 | mempool_free(p, nfs_wdata_mempool); | 87 | mempool_free(p, nfs_wdata_mempool); |
88 | p = NULL; | 88 | p = NULL; |
89 | } | 89 | } |
90 | } | 90 | } |
91 | } | 91 | } |
92 | return p; | 92 | return p; |
93 | } | 93 | } |
94 | 94 | ||
95 | static void nfs_writedata_rcu_free(struct rcu_head *head) | 95 | static void nfs_writedata_rcu_free(struct rcu_head *head) |
96 | { | 96 | { |
97 | struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu); | 97 | struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu); |
98 | if (p && (p->pagevec != &p->page_array[0])) | 98 | if (p && (p->pagevec != &p->page_array[0])) |
99 | kfree(p->pagevec); | 99 | kfree(p->pagevec); |
100 | mempool_free(p, nfs_wdata_mempool); | 100 | mempool_free(p, nfs_wdata_mempool); |
101 | } | 101 | } |
102 | 102 | ||
103 | static void nfs_writedata_free(struct nfs_write_data *wdata) | 103 | static void nfs_writedata_free(struct nfs_write_data *wdata) |
104 | { | 104 | { |
105 | call_rcu_bh(&wdata->task.u.tk_rcu, nfs_writedata_rcu_free); | 105 | call_rcu_bh(&wdata->task.u.tk_rcu, nfs_writedata_rcu_free); |
106 | } | 106 | } |
107 | 107 | ||
108 | void nfs_writedata_release(void *wdata) | 108 | void nfs_writedata_release(void *wdata) |
109 | { | 109 | { |
110 | nfs_writedata_free(wdata); | 110 | nfs_writedata_free(wdata); |
111 | } | 111 | } |
112 | 112 | ||
113 | static struct nfs_page *nfs_page_find_request_locked(struct page *page) | 113 | static struct nfs_page *nfs_page_find_request_locked(struct page *page) |
114 | { | 114 | { |
115 | struct nfs_page *req = NULL; | 115 | struct nfs_page *req = NULL; |
116 | 116 | ||
117 | if (PagePrivate(page)) { | 117 | if (PagePrivate(page)) { |
118 | req = (struct nfs_page *)page_private(page); | 118 | req = (struct nfs_page *)page_private(page); |
119 | if (req != NULL) | 119 | if (req != NULL) |
120 | atomic_inc(&req->wb_count); | 120 | atomic_inc(&req->wb_count); |
121 | } | 121 | } |
122 | return req; | 122 | return req; |
123 | } | 123 | } |
124 | 124 | ||
125 | static struct nfs_page *nfs_page_find_request(struct page *page) | 125 | static struct nfs_page *nfs_page_find_request(struct page *page) |
126 | { | 126 | { |
127 | struct nfs_page *req = NULL; | 127 | struct nfs_page *req = NULL; |
128 | spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock; | 128 | spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock; |
129 | 129 | ||
130 | spin_lock(req_lock); | 130 | spin_lock(req_lock); |
131 | req = nfs_page_find_request_locked(page); | 131 | req = nfs_page_find_request_locked(page); |
132 | spin_unlock(req_lock); | 132 | spin_unlock(req_lock); |
133 | return req; | 133 | return req; |
134 | } | 134 | } |
135 | 135 | ||
136 | /* Adjust the file length if we're writing beyond the end */ | 136 | /* Adjust the file length if we're writing beyond the end */ |
137 | static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count) | 137 | static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count) |
138 | { | 138 | { |
139 | struct inode *inode = page->mapping->host; | 139 | struct inode *inode = page->mapping->host; |
140 | loff_t end, i_size = i_size_read(inode); | 140 | loff_t end, i_size = i_size_read(inode); |
141 | pgoff_t end_index = (i_size - 1) >> PAGE_CACHE_SHIFT; | 141 | pgoff_t end_index = (i_size - 1) >> PAGE_CACHE_SHIFT; |
142 | 142 | ||
143 | if (i_size > 0 && page->index < end_index) | 143 | if (i_size > 0 && page->index < end_index) |
144 | return; | 144 | return; |
145 | end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + ((loff_t)offset+count); | 145 | end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + ((loff_t)offset+count); |
146 | if (i_size >= end) | 146 | if (i_size >= end) |
147 | return; | 147 | return; |
148 | nfs_inc_stats(inode, NFSIOS_EXTENDWRITE); | 148 | nfs_inc_stats(inode, NFSIOS_EXTENDWRITE); |
149 | i_size_write(inode, end); | 149 | i_size_write(inode, end); |
150 | } | 150 | } |
151 | 151 | ||
152 | /* A writeback failed: mark the page as bad, and invalidate the page cache */ | 152 | /* A writeback failed: mark the page as bad, and invalidate the page cache */ |
153 | static void nfs_set_pageerror(struct page *page) | 153 | static void nfs_set_pageerror(struct page *page) |
154 | { | 154 | { |
155 | SetPageError(page); | 155 | SetPageError(page); |
156 | nfs_zap_mapping(page->mapping->host, page->mapping); | 156 | nfs_zap_mapping(page->mapping->host, page->mapping); |
157 | } | 157 | } |
158 | 158 | ||
159 | /* We can set the PG_uptodate flag if we see that a write request | 159 | /* We can set the PG_uptodate flag if we see that a write request |
160 | * covers the full page. | 160 | * covers the full page. |
161 | */ | 161 | */ |
162 | static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int count) | 162 | static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int count) |
163 | { | 163 | { |
164 | if (PageUptodate(page)) | 164 | if (PageUptodate(page)) |
165 | return; | 165 | return; |
166 | if (base != 0) | 166 | if (base != 0) |
167 | return; | 167 | return; |
168 | if (count != nfs_page_length(page)) | 168 | if (count != nfs_page_length(page)) |
169 | return; | 169 | return; |
170 | if (count != PAGE_CACHE_SIZE) | 170 | if (count != PAGE_CACHE_SIZE) |
171 | memclear_highpage_flush(page, count, PAGE_CACHE_SIZE - count); | 171 | zero_user_page(page, count, PAGE_CACHE_SIZE - count, KM_USER0); |
172 | SetPageUptodate(page); | 172 | SetPageUptodate(page); |
173 | } | 173 | } |
174 | 174 | ||
175 | static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, | 175 | static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, |
176 | unsigned int offset, unsigned int count) | 176 | unsigned int offset, unsigned int count) |
177 | { | 177 | { |
178 | struct nfs_page *req; | 178 | struct nfs_page *req; |
179 | int ret; | 179 | int ret; |
180 | 180 | ||
181 | for (;;) { | 181 | for (;;) { |
182 | req = nfs_update_request(ctx, page, offset, count); | 182 | req = nfs_update_request(ctx, page, offset, count); |
183 | if (!IS_ERR(req)) | 183 | if (!IS_ERR(req)) |
184 | break; | 184 | break; |
185 | ret = PTR_ERR(req); | 185 | ret = PTR_ERR(req); |
186 | if (ret != -EBUSY) | 186 | if (ret != -EBUSY) |
187 | return ret; | 187 | return ret; |
188 | ret = nfs_wb_page(page->mapping->host, page); | 188 | ret = nfs_wb_page(page->mapping->host, page); |
189 | if (ret != 0) | 189 | if (ret != 0) |
190 | return ret; | 190 | return ret; |
191 | } | 191 | } |
192 | /* Update file length */ | 192 | /* Update file length */ |
193 | nfs_grow_file(page, offset, count); | 193 | nfs_grow_file(page, offset, count); |
194 | /* Set the PG_uptodate flag? */ | 194 | /* Set the PG_uptodate flag? */ |
195 | nfs_mark_uptodate(page, offset, count); | 195 | nfs_mark_uptodate(page, offset, count); |
196 | nfs_unlock_request(req); | 196 | nfs_unlock_request(req); |
197 | return 0; | 197 | return 0; |
198 | } | 198 | } |
199 | 199 | ||
200 | static int wb_priority(struct writeback_control *wbc) | 200 | static int wb_priority(struct writeback_control *wbc) |
201 | { | 201 | { |
202 | if (wbc->for_reclaim) | 202 | if (wbc->for_reclaim) |
203 | return FLUSH_HIGHPRI | FLUSH_STABLE; | 203 | return FLUSH_HIGHPRI | FLUSH_STABLE; |
204 | if (wbc->for_kupdate) | 204 | if (wbc->for_kupdate) |
205 | return FLUSH_LOWPRI; | 205 | return FLUSH_LOWPRI; |
206 | return 0; | 206 | return 0; |
207 | } | 207 | } |
208 | 208 | ||
209 | /* | 209 | /* |
210 | * NFS congestion control | 210 | * NFS congestion control |
211 | */ | 211 | */ |
212 | 212 | ||
213 | int nfs_congestion_kb; | 213 | int nfs_congestion_kb; |
214 | 214 | ||
215 | #define NFS_CONGESTION_ON_THRESH (nfs_congestion_kb >> (PAGE_SHIFT-10)) | 215 | #define NFS_CONGESTION_ON_THRESH (nfs_congestion_kb >> (PAGE_SHIFT-10)) |
216 | #define NFS_CONGESTION_OFF_THRESH \ | 216 | #define NFS_CONGESTION_OFF_THRESH \ |
217 | (NFS_CONGESTION_ON_THRESH - (NFS_CONGESTION_ON_THRESH >> 2)) | 217 | (NFS_CONGESTION_ON_THRESH - (NFS_CONGESTION_ON_THRESH >> 2)) |
218 | 218 | ||
219 | static int nfs_set_page_writeback(struct page *page) | 219 | static int nfs_set_page_writeback(struct page *page) |
220 | { | 220 | { |
221 | int ret = test_set_page_writeback(page); | 221 | int ret = test_set_page_writeback(page); |
222 | 222 | ||
223 | if (!ret) { | 223 | if (!ret) { |
224 | struct inode *inode = page->mapping->host; | 224 | struct inode *inode = page->mapping->host; |
225 | struct nfs_server *nfss = NFS_SERVER(inode); | 225 | struct nfs_server *nfss = NFS_SERVER(inode); |
226 | 226 | ||
227 | if (atomic_long_inc_return(&nfss->writeback) > | 227 | if (atomic_long_inc_return(&nfss->writeback) > |
228 | NFS_CONGESTION_ON_THRESH) | 228 | NFS_CONGESTION_ON_THRESH) |
229 | set_bdi_congested(&nfss->backing_dev_info, WRITE); | 229 | set_bdi_congested(&nfss->backing_dev_info, WRITE); |
230 | } | 230 | } |
231 | return ret; | 231 | return ret; |
232 | } | 232 | } |
233 | 233 | ||
234 | static void nfs_end_page_writeback(struct page *page) | 234 | static void nfs_end_page_writeback(struct page *page) |
235 | { | 235 | { |
236 | struct inode *inode = page->mapping->host; | 236 | struct inode *inode = page->mapping->host; |
237 | struct nfs_server *nfss = NFS_SERVER(inode); | 237 | struct nfs_server *nfss = NFS_SERVER(inode); |
238 | 238 | ||
239 | end_page_writeback(page); | 239 | end_page_writeback(page); |
240 | if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) { | 240 | if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) { |
241 | clear_bdi_congested(&nfss->backing_dev_info, WRITE); | 241 | clear_bdi_congested(&nfss->backing_dev_info, WRITE); |
242 | congestion_end(WRITE); | 242 | congestion_end(WRITE); |
243 | } | 243 | } |
244 | } | 244 | } |
245 | 245 | ||
246 | /* | 246 | /* |
247 | * Find an associated nfs write request, and prepare to flush it out | 247 | * Find an associated nfs write request, and prepare to flush it out |
248 | * Returns 1 if there was no write request, or if the request was | 248 | * Returns 1 if there was no write request, or if the request was |
249 | * already tagged by nfs_set_page_dirty.Returns 0 if the request | 249 | * already tagged by nfs_set_page_dirty.Returns 0 if the request |
250 | * was not tagged. | 250 | * was not tagged. |
251 | * May also return an error if the user signalled nfs_wait_on_request(). | 251 | * May also return an error if the user signalled nfs_wait_on_request(). |
252 | */ | 252 | */ |
253 | static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | 253 | static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, |
254 | struct page *page) | 254 | struct page *page) |
255 | { | 255 | { |
256 | struct nfs_page *req; | 256 | struct nfs_page *req; |
257 | struct nfs_inode *nfsi = NFS_I(page->mapping->host); | 257 | struct nfs_inode *nfsi = NFS_I(page->mapping->host); |
258 | spinlock_t *req_lock = &nfsi->req_lock; | 258 | spinlock_t *req_lock = &nfsi->req_lock; |
259 | int ret; | 259 | int ret; |
260 | 260 | ||
261 | spin_lock(req_lock); | 261 | spin_lock(req_lock); |
262 | for(;;) { | 262 | for(;;) { |
263 | req = nfs_page_find_request_locked(page); | 263 | req = nfs_page_find_request_locked(page); |
264 | if (req == NULL) { | 264 | if (req == NULL) { |
265 | spin_unlock(req_lock); | 265 | spin_unlock(req_lock); |
266 | return 1; | 266 | return 1; |
267 | } | 267 | } |
268 | if (nfs_lock_request_dontget(req)) | 268 | if (nfs_lock_request_dontget(req)) |
269 | break; | 269 | break; |
270 | /* Note: If we hold the page lock, as is the case in nfs_writepage, | 270 | /* Note: If we hold the page lock, as is the case in nfs_writepage, |
271 | * then the call to nfs_lock_request_dontget() will always | 271 | * then the call to nfs_lock_request_dontget() will always |
272 | * succeed provided that someone hasn't already marked the | 272 | * succeed provided that someone hasn't already marked the |
273 | * request as dirty (in which case we don't care). | 273 | * request as dirty (in which case we don't care). |
274 | */ | 274 | */ |
275 | spin_unlock(req_lock); | 275 | spin_unlock(req_lock); |
276 | /* Prevent deadlock! */ | 276 | /* Prevent deadlock! */ |
277 | nfs_pageio_complete(pgio); | 277 | nfs_pageio_complete(pgio); |
278 | ret = nfs_wait_on_request(req); | 278 | ret = nfs_wait_on_request(req); |
279 | nfs_release_request(req); | 279 | nfs_release_request(req); |
280 | if (ret != 0) | 280 | if (ret != 0) |
281 | return ret; | 281 | return ret; |
282 | spin_lock(req_lock); | 282 | spin_lock(req_lock); |
283 | } | 283 | } |
284 | if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { | 284 | if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { |
285 | /* This request is marked for commit */ | 285 | /* This request is marked for commit */ |
286 | spin_unlock(req_lock); | 286 | spin_unlock(req_lock); |
287 | nfs_unlock_request(req); | 287 | nfs_unlock_request(req); |
288 | nfs_pageio_complete(pgio); | 288 | nfs_pageio_complete(pgio); |
289 | return 1; | 289 | return 1; |
290 | } | 290 | } |
291 | if (nfs_set_page_writeback(page) != 0) { | 291 | if (nfs_set_page_writeback(page) != 0) { |
292 | spin_unlock(req_lock); | 292 | spin_unlock(req_lock); |
293 | BUG(); | 293 | BUG(); |
294 | } | 294 | } |
295 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, | 295 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, |
296 | NFS_PAGE_TAG_WRITEBACK); | 296 | NFS_PAGE_TAG_WRITEBACK); |
297 | ret = test_bit(PG_NEED_FLUSH, &req->wb_flags); | 297 | ret = test_bit(PG_NEED_FLUSH, &req->wb_flags); |
298 | spin_unlock(req_lock); | 298 | spin_unlock(req_lock); |
299 | nfs_pageio_add_request(pgio, req); | 299 | nfs_pageio_add_request(pgio, req); |
300 | return ret; | 300 | return ret; |
301 | } | 301 | } |
302 | 302 | ||
303 | /* | 303 | /* |
304 | * Write an mmapped page to the server. | 304 | * Write an mmapped page to the server. |
305 | */ | 305 | */ |
306 | static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc) | 306 | static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc) |
307 | { | 307 | { |
308 | struct nfs_pageio_descriptor mypgio, *pgio; | 308 | struct nfs_pageio_descriptor mypgio, *pgio; |
309 | struct nfs_open_context *ctx; | 309 | struct nfs_open_context *ctx; |
310 | struct inode *inode = page->mapping->host; | 310 | struct inode *inode = page->mapping->host; |
311 | unsigned offset; | 311 | unsigned offset; |
312 | int err; | 312 | int err; |
313 | 313 | ||
314 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); | 314 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); |
315 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); | 315 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); |
316 | 316 | ||
317 | if (wbc->for_writepages) | 317 | if (wbc->for_writepages) |
318 | pgio = wbc->fs_private; | 318 | pgio = wbc->fs_private; |
319 | else { | 319 | else { |
320 | nfs_pageio_init_write(&mypgio, inode, wb_priority(wbc)); | 320 | nfs_pageio_init_write(&mypgio, inode, wb_priority(wbc)); |
321 | pgio = &mypgio; | 321 | pgio = &mypgio; |
322 | } | 322 | } |
323 | 323 | ||
324 | err = nfs_page_async_flush(pgio, page); | 324 | err = nfs_page_async_flush(pgio, page); |
325 | if (err <= 0) | 325 | if (err <= 0) |
326 | goto out; | 326 | goto out; |
327 | err = 0; | 327 | err = 0; |
328 | offset = nfs_page_length(page); | 328 | offset = nfs_page_length(page); |
329 | if (!offset) | 329 | if (!offset) |
330 | goto out; | 330 | goto out; |
331 | 331 | ||
332 | ctx = nfs_find_open_context(inode, NULL, FMODE_WRITE); | 332 | ctx = nfs_find_open_context(inode, NULL, FMODE_WRITE); |
333 | if (ctx == NULL) { | 333 | if (ctx == NULL) { |
334 | err = -EBADF; | 334 | err = -EBADF; |
335 | goto out; | 335 | goto out; |
336 | } | 336 | } |
337 | err = nfs_writepage_setup(ctx, page, 0, offset); | 337 | err = nfs_writepage_setup(ctx, page, 0, offset); |
338 | put_nfs_open_context(ctx); | 338 | put_nfs_open_context(ctx); |
339 | if (err != 0) | 339 | if (err != 0) |
340 | goto out; | 340 | goto out; |
341 | err = nfs_page_async_flush(pgio, page); | 341 | err = nfs_page_async_flush(pgio, page); |
342 | if (err > 0) | 342 | if (err > 0) |
343 | err = 0; | 343 | err = 0; |
344 | out: | 344 | out: |
345 | if (!wbc->for_writepages) | 345 | if (!wbc->for_writepages) |
346 | nfs_pageio_complete(pgio); | 346 | nfs_pageio_complete(pgio); |
347 | return err; | 347 | return err; |
348 | } | 348 | } |
349 | 349 | ||
350 | int nfs_writepage(struct page *page, struct writeback_control *wbc) | 350 | int nfs_writepage(struct page *page, struct writeback_control *wbc) |
351 | { | 351 | { |
352 | int err; | 352 | int err; |
353 | 353 | ||
354 | err = nfs_writepage_locked(page, wbc); | 354 | err = nfs_writepage_locked(page, wbc); |
355 | unlock_page(page); | 355 | unlock_page(page); |
356 | return err; | 356 | return err; |
357 | } | 357 | } |
358 | 358 | ||
359 | int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | 359 | int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) |
360 | { | 360 | { |
361 | struct inode *inode = mapping->host; | 361 | struct inode *inode = mapping->host; |
362 | struct nfs_pageio_descriptor pgio; | 362 | struct nfs_pageio_descriptor pgio; |
363 | int err; | 363 | int err; |
364 | 364 | ||
365 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES); | 365 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES); |
366 | 366 | ||
367 | nfs_pageio_init_write(&pgio, inode, wb_priority(wbc)); | 367 | nfs_pageio_init_write(&pgio, inode, wb_priority(wbc)); |
368 | wbc->fs_private = &pgio; | 368 | wbc->fs_private = &pgio; |
369 | err = generic_writepages(mapping, wbc); | 369 | err = generic_writepages(mapping, wbc); |
370 | nfs_pageio_complete(&pgio); | 370 | nfs_pageio_complete(&pgio); |
371 | if (err) | 371 | if (err) |
372 | return err; | 372 | return err; |
373 | if (pgio.pg_error) | 373 | if (pgio.pg_error) |
374 | return pgio.pg_error; | 374 | return pgio.pg_error; |
375 | return 0; | 375 | return 0; |
376 | } | 376 | } |
377 | 377 | ||
378 | /* | 378 | /* |
379 | * Insert a write request into an inode | 379 | * Insert a write request into an inode |
380 | */ | 380 | */ |
381 | static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | 381 | static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) |
382 | { | 382 | { |
383 | struct nfs_inode *nfsi = NFS_I(inode); | 383 | struct nfs_inode *nfsi = NFS_I(inode); |
384 | int error; | 384 | int error; |
385 | 385 | ||
386 | error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); | 386 | error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); |
387 | BUG_ON(error == -EEXIST); | 387 | BUG_ON(error == -EEXIST); |
388 | if (error) | 388 | if (error) |
389 | return error; | 389 | return error; |
390 | if (!nfsi->npages) { | 390 | if (!nfsi->npages) { |
391 | igrab(inode); | 391 | igrab(inode); |
392 | nfs_begin_data_update(inode); | 392 | nfs_begin_data_update(inode); |
393 | if (nfs_have_delegation(inode, FMODE_WRITE)) | 393 | if (nfs_have_delegation(inode, FMODE_WRITE)) |
394 | nfsi->change_attr++; | 394 | nfsi->change_attr++; |
395 | } | 395 | } |
396 | SetPagePrivate(req->wb_page); | 396 | SetPagePrivate(req->wb_page); |
397 | set_page_private(req->wb_page, (unsigned long)req); | 397 | set_page_private(req->wb_page, (unsigned long)req); |
398 | if (PageDirty(req->wb_page)) | 398 | if (PageDirty(req->wb_page)) |
399 | set_bit(PG_NEED_FLUSH, &req->wb_flags); | 399 | set_bit(PG_NEED_FLUSH, &req->wb_flags); |
400 | nfsi->npages++; | 400 | nfsi->npages++; |
401 | atomic_inc(&req->wb_count); | 401 | atomic_inc(&req->wb_count); |
402 | return 0; | 402 | return 0; |
403 | } | 403 | } |
404 | 404 | ||
405 | /* | 405 | /* |
406 | * Remove a write request from an inode | 406 | * Remove a write request from an inode |
407 | */ | 407 | */ |
408 | static void nfs_inode_remove_request(struct nfs_page *req) | 408 | static void nfs_inode_remove_request(struct nfs_page *req) |
409 | { | 409 | { |
410 | struct inode *inode = req->wb_context->dentry->d_inode; | 410 | struct inode *inode = req->wb_context->dentry->d_inode; |
411 | struct nfs_inode *nfsi = NFS_I(inode); | 411 | struct nfs_inode *nfsi = NFS_I(inode); |
412 | 412 | ||
413 | BUG_ON (!NFS_WBACK_BUSY(req)); | 413 | BUG_ON (!NFS_WBACK_BUSY(req)); |
414 | 414 | ||
415 | spin_lock(&nfsi->req_lock); | 415 | spin_lock(&nfsi->req_lock); |
416 | set_page_private(req->wb_page, 0); | 416 | set_page_private(req->wb_page, 0); |
417 | ClearPagePrivate(req->wb_page); | 417 | ClearPagePrivate(req->wb_page); |
418 | radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); | 418 | radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); |
419 | if (test_and_clear_bit(PG_NEED_FLUSH, &req->wb_flags)) | 419 | if (test_and_clear_bit(PG_NEED_FLUSH, &req->wb_flags)) |
420 | __set_page_dirty_nobuffers(req->wb_page); | 420 | __set_page_dirty_nobuffers(req->wb_page); |
421 | nfsi->npages--; | 421 | nfsi->npages--; |
422 | if (!nfsi->npages) { | 422 | if (!nfsi->npages) { |
423 | spin_unlock(&nfsi->req_lock); | 423 | spin_unlock(&nfsi->req_lock); |
424 | nfs_end_data_update(inode); | 424 | nfs_end_data_update(inode); |
425 | iput(inode); | 425 | iput(inode); |
426 | } else | 426 | } else |
427 | spin_unlock(&nfsi->req_lock); | 427 | spin_unlock(&nfsi->req_lock); |
428 | nfs_clear_request(req); | 428 | nfs_clear_request(req); |
429 | nfs_release_request(req); | 429 | nfs_release_request(req); |
430 | } | 430 | } |
431 | 431 | ||
432 | static void | 432 | static void |
433 | nfs_redirty_request(struct nfs_page *req) | 433 | nfs_redirty_request(struct nfs_page *req) |
434 | { | 434 | { |
435 | __set_page_dirty_nobuffers(req->wb_page); | 435 | __set_page_dirty_nobuffers(req->wb_page); |
436 | } | 436 | } |
437 | 437 | ||
438 | /* | 438 | /* |
439 | * Check if a request is dirty | 439 | * Check if a request is dirty |
440 | */ | 440 | */ |
441 | static inline int | 441 | static inline int |
442 | nfs_dirty_request(struct nfs_page *req) | 442 | nfs_dirty_request(struct nfs_page *req) |
443 | { | 443 | { |
444 | struct page *page = req->wb_page; | 444 | struct page *page = req->wb_page; |
445 | 445 | ||
446 | if (page == NULL || test_bit(PG_NEED_COMMIT, &req->wb_flags)) | 446 | if (page == NULL || test_bit(PG_NEED_COMMIT, &req->wb_flags)) |
447 | return 0; | 447 | return 0; |
448 | return !PageWriteback(req->wb_page); | 448 | return !PageWriteback(req->wb_page); |
449 | } | 449 | } |
450 | 450 | ||
451 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 451 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
452 | /* | 452 | /* |
453 | * Add a request to the inode's commit list. | 453 | * Add a request to the inode's commit list. |
454 | */ | 454 | */ |
455 | static void | 455 | static void |
456 | nfs_mark_request_commit(struct nfs_page *req) | 456 | nfs_mark_request_commit(struct nfs_page *req) |
457 | { | 457 | { |
458 | struct inode *inode = req->wb_context->dentry->d_inode; | 458 | struct inode *inode = req->wb_context->dentry->d_inode; |
459 | struct nfs_inode *nfsi = NFS_I(inode); | 459 | struct nfs_inode *nfsi = NFS_I(inode); |
460 | 460 | ||
461 | spin_lock(&nfsi->req_lock); | 461 | spin_lock(&nfsi->req_lock); |
462 | nfs_list_add_request(req, &nfsi->commit); | 462 | nfs_list_add_request(req, &nfsi->commit); |
463 | nfsi->ncommit++; | 463 | nfsi->ncommit++; |
464 | set_bit(PG_NEED_COMMIT, &(req)->wb_flags); | 464 | set_bit(PG_NEED_COMMIT, &(req)->wb_flags); |
465 | spin_unlock(&nfsi->req_lock); | 465 | spin_unlock(&nfsi->req_lock); |
466 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 466 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); |
467 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | 467 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); |
468 | } | 468 | } |
469 | 469 | ||
470 | static inline | 470 | static inline |
471 | int nfs_write_need_commit(struct nfs_write_data *data) | 471 | int nfs_write_need_commit(struct nfs_write_data *data) |
472 | { | 472 | { |
473 | return data->verf.committed != NFS_FILE_SYNC; | 473 | return data->verf.committed != NFS_FILE_SYNC; |
474 | } | 474 | } |
475 | 475 | ||
476 | static inline | 476 | static inline |
477 | int nfs_reschedule_unstable_write(struct nfs_page *req) | 477 | int nfs_reschedule_unstable_write(struct nfs_page *req) |
478 | { | 478 | { |
479 | if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { | 479 | if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { |
480 | nfs_mark_request_commit(req); | 480 | nfs_mark_request_commit(req); |
481 | return 1; | 481 | return 1; |
482 | } | 482 | } |
483 | if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) { | 483 | if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) { |
484 | nfs_redirty_request(req); | 484 | nfs_redirty_request(req); |
485 | return 1; | 485 | return 1; |
486 | } | 486 | } |
487 | return 0; | 487 | return 0; |
488 | } | 488 | } |
489 | #else | 489 | #else |
490 | static inline void | 490 | static inline void |
491 | nfs_mark_request_commit(struct nfs_page *req) | 491 | nfs_mark_request_commit(struct nfs_page *req) |
492 | { | 492 | { |
493 | } | 493 | } |
494 | 494 | ||
495 | static inline | 495 | static inline |
496 | int nfs_write_need_commit(struct nfs_write_data *data) | 496 | int nfs_write_need_commit(struct nfs_write_data *data) |
497 | { | 497 | { |
498 | return 0; | 498 | return 0; |
499 | } | 499 | } |
500 | 500 | ||
501 | static inline | 501 | static inline |
502 | int nfs_reschedule_unstable_write(struct nfs_page *req) | 502 | int nfs_reschedule_unstable_write(struct nfs_page *req) |
503 | { | 503 | { |
504 | return 0; | 504 | return 0; |
505 | } | 505 | } |
506 | #endif | 506 | #endif |
507 | 507 | ||
508 | /* | 508 | /* |
509 | * Wait for a request to complete. | 509 | * Wait for a request to complete. |
510 | * | 510 | * |
511 | * Interruptible by signals only if mounted with intr flag. | 511 | * Interruptible by signals only if mounted with intr flag. |
512 | */ | 512 | */ |
513 | static int nfs_wait_on_requests_locked(struct inode *inode, pgoff_t idx_start, unsigned int npages) | 513 | static int nfs_wait_on_requests_locked(struct inode *inode, pgoff_t idx_start, unsigned int npages) |
514 | { | 514 | { |
515 | struct nfs_inode *nfsi = NFS_I(inode); | 515 | struct nfs_inode *nfsi = NFS_I(inode); |
516 | struct nfs_page *req; | 516 | struct nfs_page *req; |
517 | pgoff_t idx_end, next; | 517 | pgoff_t idx_end, next; |
518 | unsigned int res = 0; | 518 | unsigned int res = 0; |
519 | int error; | 519 | int error; |
520 | 520 | ||
521 | if (npages == 0) | 521 | if (npages == 0) |
522 | idx_end = ~0; | 522 | idx_end = ~0; |
523 | else | 523 | else |
524 | idx_end = idx_start + npages - 1; | 524 | idx_end = idx_start + npages - 1; |
525 | 525 | ||
526 | next = idx_start; | 526 | next = idx_start; |
527 | while (radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&req, next, 1, NFS_PAGE_TAG_WRITEBACK)) { | 527 | while (radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&req, next, 1, NFS_PAGE_TAG_WRITEBACK)) { |
528 | if (req->wb_index > idx_end) | 528 | if (req->wb_index > idx_end) |
529 | break; | 529 | break; |
530 | 530 | ||
531 | next = req->wb_index + 1; | 531 | next = req->wb_index + 1; |
532 | BUG_ON(!NFS_WBACK_BUSY(req)); | 532 | BUG_ON(!NFS_WBACK_BUSY(req)); |
533 | 533 | ||
534 | atomic_inc(&req->wb_count); | 534 | atomic_inc(&req->wb_count); |
535 | spin_unlock(&nfsi->req_lock); | 535 | spin_unlock(&nfsi->req_lock); |
536 | error = nfs_wait_on_request(req); | 536 | error = nfs_wait_on_request(req); |
537 | nfs_release_request(req); | 537 | nfs_release_request(req); |
538 | spin_lock(&nfsi->req_lock); | 538 | spin_lock(&nfsi->req_lock); |
539 | if (error < 0) | 539 | if (error < 0) |
540 | return error; | 540 | return error; |
541 | res++; | 541 | res++; |
542 | } | 542 | } |
543 | return res; | 543 | return res; |
544 | } | 544 | } |
545 | 545 | ||
546 | static void nfs_cancel_commit_list(struct list_head *head) | 546 | static void nfs_cancel_commit_list(struct list_head *head) |
547 | { | 547 | { |
548 | struct nfs_page *req; | 548 | struct nfs_page *req; |
549 | 549 | ||
550 | while(!list_empty(head)) { | 550 | while(!list_empty(head)) { |
551 | req = nfs_list_entry(head->next); | 551 | req = nfs_list_entry(head->next); |
552 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 552 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); |
553 | nfs_list_remove_request(req); | 553 | nfs_list_remove_request(req); |
554 | clear_bit(PG_NEED_COMMIT, &(req)->wb_flags); | 554 | clear_bit(PG_NEED_COMMIT, &(req)->wb_flags); |
555 | nfs_inode_remove_request(req); | 555 | nfs_inode_remove_request(req); |
556 | nfs_unlock_request(req); | 556 | nfs_unlock_request(req); |
557 | } | 557 | } |
558 | } | 558 | } |
559 | 559 | ||
560 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 560 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
561 | /* | 561 | /* |
562 | * nfs_scan_commit - Scan an inode for commit requests | 562 | * nfs_scan_commit - Scan an inode for commit requests |
563 | * @inode: NFS inode to scan | 563 | * @inode: NFS inode to scan |
564 | * @dst: destination list | 564 | * @dst: destination list |
565 | * @idx_start: lower bound of page->index to scan. | 565 | * @idx_start: lower bound of page->index to scan. |
566 | * @npages: idx_start + npages sets the upper bound to scan. | 566 | * @npages: idx_start + npages sets the upper bound to scan. |
567 | * | 567 | * |
568 | * Moves requests from the inode's 'commit' request list. | 568 | * Moves requests from the inode's 'commit' request list. |
569 | * The requests are *not* checked to ensure that they form a contiguous set. | 569 | * The requests are *not* checked to ensure that they form a contiguous set. |
570 | */ | 570 | */ |
571 | static int | 571 | static int |
572 | nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages) | 572 | nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages) |
573 | { | 573 | { |
574 | struct nfs_inode *nfsi = NFS_I(inode); | 574 | struct nfs_inode *nfsi = NFS_I(inode); |
575 | int res = 0; | 575 | int res = 0; |
576 | 576 | ||
577 | if (nfsi->ncommit != 0) { | 577 | if (nfsi->ncommit != 0) { |
578 | res = nfs_scan_list(nfsi, &nfsi->commit, dst, idx_start, npages); | 578 | res = nfs_scan_list(nfsi, &nfsi->commit, dst, idx_start, npages); |
579 | nfsi->ncommit -= res; | 579 | nfsi->ncommit -= res; |
580 | if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit)) | 580 | if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit)) |
581 | printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n"); | 581 | printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n"); |
582 | } | 582 | } |
583 | return res; | 583 | return res; |
584 | } | 584 | } |
585 | #else | 585 | #else |
586 | static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages) | 586 | static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages) |
587 | { | 587 | { |
588 | return 0; | 588 | return 0; |
589 | } | 589 | } |
590 | #endif | 590 | #endif |
591 | 591 | ||
592 | /* | 592 | /* |
593 | * Try to update any existing write request, or create one if there is none. | 593 | * Try to update any existing write request, or create one if there is none. |
594 | * In order to match, the request's credentials must match those of | 594 | * In order to match, the request's credentials must match those of |
595 | * the calling process. | 595 | * the calling process. |
596 | * | 596 | * |
597 | * Note: Should always be called with the Page Lock held! | 597 | * Note: Should always be called with the Page Lock held! |
598 | */ | 598 | */ |
599 | static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | 599 | static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, |
600 | struct page *page, unsigned int offset, unsigned int bytes) | 600 | struct page *page, unsigned int offset, unsigned int bytes) |
601 | { | 601 | { |
602 | struct address_space *mapping = page->mapping; | 602 | struct address_space *mapping = page->mapping; |
603 | struct inode *inode = mapping->host; | 603 | struct inode *inode = mapping->host; |
604 | struct nfs_inode *nfsi = NFS_I(inode); | 604 | struct nfs_inode *nfsi = NFS_I(inode); |
605 | struct nfs_page *req, *new = NULL; | 605 | struct nfs_page *req, *new = NULL; |
606 | pgoff_t rqend, end; | 606 | pgoff_t rqend, end; |
607 | 607 | ||
608 | end = offset + bytes; | 608 | end = offset + bytes; |
609 | 609 | ||
610 | for (;;) { | 610 | for (;;) { |
611 | /* Loop over all inode entries and see if we find | 611 | /* Loop over all inode entries and see if we find |
612 | * A request for the page we wish to update | 612 | * A request for the page we wish to update |
613 | */ | 613 | */ |
614 | spin_lock(&nfsi->req_lock); | 614 | spin_lock(&nfsi->req_lock); |
615 | req = nfs_page_find_request_locked(page); | 615 | req = nfs_page_find_request_locked(page); |
616 | if (req) { | 616 | if (req) { |
617 | if (!nfs_lock_request_dontget(req)) { | 617 | if (!nfs_lock_request_dontget(req)) { |
618 | int error; | 618 | int error; |
619 | 619 | ||
620 | spin_unlock(&nfsi->req_lock); | 620 | spin_unlock(&nfsi->req_lock); |
621 | error = nfs_wait_on_request(req); | 621 | error = nfs_wait_on_request(req); |
622 | nfs_release_request(req); | 622 | nfs_release_request(req); |
623 | if (error < 0) { | 623 | if (error < 0) { |
624 | if (new) | 624 | if (new) |
625 | nfs_release_request(new); | 625 | nfs_release_request(new); |
626 | return ERR_PTR(error); | 626 | return ERR_PTR(error); |
627 | } | 627 | } |
628 | continue; | 628 | continue; |
629 | } | 629 | } |
630 | spin_unlock(&nfsi->req_lock); | 630 | spin_unlock(&nfsi->req_lock); |
631 | if (new) | 631 | if (new) |
632 | nfs_release_request(new); | 632 | nfs_release_request(new); |
633 | break; | 633 | break; |
634 | } | 634 | } |
635 | 635 | ||
636 | if (new) { | 636 | if (new) { |
637 | int error; | 637 | int error; |
638 | nfs_lock_request_dontget(new); | 638 | nfs_lock_request_dontget(new); |
639 | error = nfs_inode_add_request(inode, new); | 639 | error = nfs_inode_add_request(inode, new); |
640 | if (error) { | 640 | if (error) { |
641 | spin_unlock(&nfsi->req_lock); | 641 | spin_unlock(&nfsi->req_lock); |
642 | nfs_unlock_request(new); | 642 | nfs_unlock_request(new); |
643 | return ERR_PTR(error); | 643 | return ERR_PTR(error); |
644 | } | 644 | } |
645 | spin_unlock(&nfsi->req_lock); | 645 | spin_unlock(&nfsi->req_lock); |
646 | return new; | 646 | return new; |
647 | } | 647 | } |
648 | spin_unlock(&nfsi->req_lock); | 648 | spin_unlock(&nfsi->req_lock); |
649 | 649 | ||
650 | new = nfs_create_request(ctx, inode, page, offset, bytes); | 650 | new = nfs_create_request(ctx, inode, page, offset, bytes); |
651 | if (IS_ERR(new)) | 651 | if (IS_ERR(new)) |
652 | return new; | 652 | return new; |
653 | } | 653 | } |
654 | 654 | ||
655 | /* We have a request for our page. | 655 | /* We have a request for our page. |
656 | * If the creds don't match, or the | 656 | * If the creds don't match, or the |
657 | * page addresses don't match, | 657 | * page addresses don't match, |
658 | * tell the caller to wait on the conflicting | 658 | * tell the caller to wait on the conflicting |
659 | * request. | 659 | * request. |
660 | */ | 660 | */ |
661 | rqend = req->wb_offset + req->wb_bytes; | 661 | rqend = req->wb_offset + req->wb_bytes; |
662 | if (req->wb_context != ctx | 662 | if (req->wb_context != ctx |
663 | || req->wb_page != page | 663 | || req->wb_page != page |
664 | || !nfs_dirty_request(req) | 664 | || !nfs_dirty_request(req) |
665 | || offset > rqend || end < req->wb_offset) { | 665 | || offset > rqend || end < req->wb_offset) { |
666 | nfs_unlock_request(req); | 666 | nfs_unlock_request(req); |
667 | return ERR_PTR(-EBUSY); | 667 | return ERR_PTR(-EBUSY); |
668 | } | 668 | } |
669 | 669 | ||
670 | /* Okay, the request matches. Update the region */ | 670 | /* Okay, the request matches. Update the region */ |
671 | if (offset < req->wb_offset) { | 671 | if (offset < req->wb_offset) { |
672 | req->wb_offset = offset; | 672 | req->wb_offset = offset; |
673 | req->wb_pgbase = offset; | 673 | req->wb_pgbase = offset; |
674 | req->wb_bytes = rqend - req->wb_offset; | 674 | req->wb_bytes = rqend - req->wb_offset; |
675 | } | 675 | } |
676 | 676 | ||
677 | if (end > rqend) | 677 | if (end > rqend) |
678 | req->wb_bytes = end - req->wb_offset; | 678 | req->wb_bytes = end - req->wb_offset; |
679 | 679 | ||
680 | return req; | 680 | return req; |
681 | } | 681 | } |
682 | 682 | ||
683 | int nfs_flush_incompatible(struct file *file, struct page *page) | 683 | int nfs_flush_incompatible(struct file *file, struct page *page) |
684 | { | 684 | { |
685 | struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; | 685 | struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; |
686 | struct nfs_page *req; | 686 | struct nfs_page *req; |
687 | int do_flush, status; | 687 | int do_flush, status; |
688 | /* | 688 | /* |
689 | * Look for a request corresponding to this page. If there | 689 | * Look for a request corresponding to this page. If there |
690 | * is one, and it belongs to another file, we flush it out | 690 | * is one, and it belongs to another file, we flush it out |
691 | * before we try to copy anything into the page. Do this | 691 | * before we try to copy anything into the page. Do this |
692 | * due to the lack of an ACCESS-type call in NFSv2. | 692 | * due to the lack of an ACCESS-type call in NFSv2. |
693 | * Also do the same if we find a request from an existing | 693 | * Also do the same if we find a request from an existing |
694 | * dropped page. | 694 | * dropped page. |
695 | */ | 695 | */ |
696 | do { | 696 | do { |
697 | req = nfs_page_find_request(page); | 697 | req = nfs_page_find_request(page); |
698 | if (req == NULL) | 698 | if (req == NULL) |
699 | return 0; | 699 | return 0; |
700 | do_flush = req->wb_page != page || req->wb_context != ctx | 700 | do_flush = req->wb_page != page || req->wb_context != ctx |
701 | || !nfs_dirty_request(req); | 701 | || !nfs_dirty_request(req); |
702 | nfs_release_request(req); | 702 | nfs_release_request(req); |
703 | if (!do_flush) | 703 | if (!do_flush) |
704 | return 0; | 704 | return 0; |
705 | status = nfs_wb_page(page->mapping->host, page); | 705 | status = nfs_wb_page(page->mapping->host, page); |
706 | } while (status == 0); | 706 | } while (status == 0); |
707 | return status; | 707 | return status; |
708 | } | 708 | } |
709 | 709 | ||
710 | /* | 710 | /* |
711 | * Update and possibly write a cached page of an NFS file. | 711 | * Update and possibly write a cached page of an NFS file. |
712 | * | 712 | * |
713 | * XXX: Keep an eye on generic_file_read to make sure it doesn't do bad | 713 | * XXX: Keep an eye on generic_file_read to make sure it doesn't do bad |
714 | * things with a page scheduled for an RPC call (e.g. invalidate it). | 714 | * things with a page scheduled for an RPC call (e.g. invalidate it). |
715 | */ | 715 | */ |
716 | int nfs_updatepage(struct file *file, struct page *page, | 716 | int nfs_updatepage(struct file *file, struct page *page, |
717 | unsigned int offset, unsigned int count) | 717 | unsigned int offset, unsigned int count) |
718 | { | 718 | { |
719 | struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; | 719 | struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; |
720 | struct inode *inode = page->mapping->host; | 720 | struct inode *inode = page->mapping->host; |
721 | int status = 0; | 721 | int status = 0; |
722 | 722 | ||
723 | nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE); | 723 | nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE); |
724 | 724 | ||
725 | dprintk("NFS: nfs_updatepage(%s/%s %d@%Ld)\n", | 725 | dprintk("NFS: nfs_updatepage(%s/%s %d@%Ld)\n", |
726 | file->f_path.dentry->d_parent->d_name.name, | 726 | file->f_path.dentry->d_parent->d_name.name, |
727 | file->f_path.dentry->d_name.name, count, | 727 | file->f_path.dentry->d_name.name, count, |
728 | (long long)(page_offset(page) +offset)); | 728 | (long long)(page_offset(page) +offset)); |
729 | 729 | ||
730 | /* If we're not using byte range locks, and we know the page | 730 | /* If we're not using byte range locks, and we know the page |
731 | * is entirely in cache, it may be more efficient to avoid | 731 | * is entirely in cache, it may be more efficient to avoid |
732 | * fragmenting write requests. | 732 | * fragmenting write requests. |
733 | */ | 733 | */ |
734 | if (PageUptodate(page) && inode->i_flock == NULL && !(file->f_mode & O_SYNC)) { | 734 | if (PageUptodate(page) && inode->i_flock == NULL && !(file->f_mode & O_SYNC)) { |
735 | count = max(count + offset, nfs_page_length(page)); | 735 | count = max(count + offset, nfs_page_length(page)); |
736 | offset = 0; | 736 | offset = 0; |
737 | } | 737 | } |
738 | 738 | ||
739 | status = nfs_writepage_setup(ctx, page, offset, count); | 739 | status = nfs_writepage_setup(ctx, page, offset, count); |
740 | __set_page_dirty_nobuffers(page); | 740 | __set_page_dirty_nobuffers(page); |
741 | 741 | ||
742 | dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n", | 742 | dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n", |
743 | status, (long long)i_size_read(inode)); | 743 | status, (long long)i_size_read(inode)); |
744 | if (status < 0) | 744 | if (status < 0) |
745 | nfs_set_pageerror(page); | 745 | nfs_set_pageerror(page); |
746 | return status; | 746 | return status; |
747 | } | 747 | } |
748 | 748 | ||
749 | static void nfs_writepage_release(struct nfs_page *req) | 749 | static void nfs_writepage_release(struct nfs_page *req) |
750 | { | 750 | { |
751 | 751 | ||
752 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) { | 752 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) { |
753 | nfs_end_page_writeback(req->wb_page); | 753 | nfs_end_page_writeback(req->wb_page); |
754 | nfs_inode_remove_request(req); | 754 | nfs_inode_remove_request(req); |
755 | } else | 755 | } else |
756 | nfs_end_page_writeback(req->wb_page); | 756 | nfs_end_page_writeback(req->wb_page); |
757 | nfs_clear_page_writeback(req); | 757 | nfs_clear_page_writeback(req); |
758 | } | 758 | } |
759 | 759 | ||
760 | static inline int flush_task_priority(int how) | 760 | static inline int flush_task_priority(int how) |
761 | { | 761 | { |
762 | switch (how & (FLUSH_HIGHPRI|FLUSH_LOWPRI)) { | 762 | switch (how & (FLUSH_HIGHPRI|FLUSH_LOWPRI)) { |
763 | case FLUSH_HIGHPRI: | 763 | case FLUSH_HIGHPRI: |
764 | return RPC_PRIORITY_HIGH; | 764 | return RPC_PRIORITY_HIGH; |
765 | case FLUSH_LOWPRI: | 765 | case FLUSH_LOWPRI: |
766 | return RPC_PRIORITY_LOW; | 766 | return RPC_PRIORITY_LOW; |
767 | } | 767 | } |
768 | return RPC_PRIORITY_NORMAL; | 768 | return RPC_PRIORITY_NORMAL; |
769 | } | 769 | } |
770 | 770 | ||
771 | /* | 771 | /* |
772 | * Set up the argument/result storage required for the RPC call. | 772 | * Set up the argument/result storage required for the RPC call. |
773 | */ | 773 | */ |
774 | static void nfs_write_rpcsetup(struct nfs_page *req, | 774 | static void nfs_write_rpcsetup(struct nfs_page *req, |
775 | struct nfs_write_data *data, | 775 | struct nfs_write_data *data, |
776 | const struct rpc_call_ops *call_ops, | 776 | const struct rpc_call_ops *call_ops, |
777 | unsigned int count, unsigned int offset, | 777 | unsigned int count, unsigned int offset, |
778 | int how) | 778 | int how) |
779 | { | 779 | { |
780 | struct inode *inode; | 780 | struct inode *inode; |
781 | int flags; | 781 | int flags; |
782 | 782 | ||
783 | /* Set up the RPC argument and reply structs | 783 | /* Set up the RPC argument and reply structs |
784 | * NB: take care not to mess about with data->commit et al. */ | 784 | * NB: take care not to mess about with data->commit et al. */ |
785 | 785 | ||
786 | data->req = req; | 786 | data->req = req; |
787 | data->inode = inode = req->wb_context->dentry->d_inode; | 787 | data->inode = inode = req->wb_context->dentry->d_inode; |
788 | data->cred = req->wb_context->cred; | 788 | data->cred = req->wb_context->cred; |
789 | 789 | ||
790 | data->args.fh = NFS_FH(inode); | 790 | data->args.fh = NFS_FH(inode); |
791 | data->args.offset = req_offset(req) + offset; | 791 | data->args.offset = req_offset(req) + offset; |
792 | data->args.pgbase = req->wb_pgbase + offset; | 792 | data->args.pgbase = req->wb_pgbase + offset; |
793 | data->args.pages = data->pagevec; | 793 | data->args.pages = data->pagevec; |
794 | data->args.count = count; | 794 | data->args.count = count; |
795 | data->args.context = req->wb_context; | 795 | data->args.context = req->wb_context; |
796 | 796 | ||
797 | data->res.fattr = &data->fattr; | 797 | data->res.fattr = &data->fattr; |
798 | data->res.count = count; | 798 | data->res.count = count; |
799 | data->res.verf = &data->verf; | 799 | data->res.verf = &data->verf; |
800 | nfs_fattr_init(&data->fattr); | 800 | nfs_fattr_init(&data->fattr); |
801 | 801 | ||
802 | /* Set up the initial task struct. */ | 802 | /* Set up the initial task struct. */ |
803 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | 803 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; |
804 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, call_ops, data); | 804 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, call_ops, data); |
805 | NFS_PROTO(inode)->write_setup(data, how); | 805 | NFS_PROTO(inode)->write_setup(data, how); |
806 | 806 | ||
807 | data->task.tk_priority = flush_task_priority(how); | 807 | data->task.tk_priority = flush_task_priority(how); |
808 | data->task.tk_cookie = (unsigned long)inode; | 808 | data->task.tk_cookie = (unsigned long)inode; |
809 | 809 | ||
810 | dprintk("NFS: %5u initiated write call " | 810 | dprintk("NFS: %5u initiated write call " |
811 | "(req %s/%Ld, %u bytes @ offset %Lu)\n", | 811 | "(req %s/%Ld, %u bytes @ offset %Lu)\n", |
812 | data->task.tk_pid, | 812 | data->task.tk_pid, |
813 | inode->i_sb->s_id, | 813 | inode->i_sb->s_id, |
814 | (long long)NFS_FILEID(inode), | 814 | (long long)NFS_FILEID(inode), |
815 | count, | 815 | count, |
816 | (unsigned long long)data->args.offset); | 816 | (unsigned long long)data->args.offset); |
817 | } | 817 | } |
818 | 818 | ||
819 | static void nfs_execute_write(struct nfs_write_data *data) | 819 | static void nfs_execute_write(struct nfs_write_data *data) |
820 | { | 820 | { |
821 | struct rpc_clnt *clnt = NFS_CLIENT(data->inode); | 821 | struct rpc_clnt *clnt = NFS_CLIENT(data->inode); |
822 | sigset_t oldset; | 822 | sigset_t oldset; |
823 | 823 | ||
824 | rpc_clnt_sigmask(clnt, &oldset); | 824 | rpc_clnt_sigmask(clnt, &oldset); |
825 | rpc_execute(&data->task); | 825 | rpc_execute(&data->task); |
826 | rpc_clnt_sigunmask(clnt, &oldset); | 826 | rpc_clnt_sigunmask(clnt, &oldset); |
827 | } | 827 | } |
828 | 828 | ||
829 | /* | 829 | /* |
830 | * Generate multiple small requests to write out a single | 830 | * Generate multiple small requests to write out a single |
831 | * contiguous dirty area on one page. | 831 | * contiguous dirty area on one page. |
832 | */ | 832 | */ |
833 | static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how) | 833 | static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how) |
834 | { | 834 | { |
835 | struct nfs_page *req = nfs_list_entry(head->next); | 835 | struct nfs_page *req = nfs_list_entry(head->next); |
836 | struct page *page = req->wb_page; | 836 | struct page *page = req->wb_page; |
837 | struct nfs_write_data *data; | 837 | struct nfs_write_data *data; |
838 | size_t wsize = NFS_SERVER(inode)->wsize, nbytes; | 838 | size_t wsize = NFS_SERVER(inode)->wsize, nbytes; |
839 | unsigned int offset; | 839 | unsigned int offset; |
840 | int requests = 0; | 840 | int requests = 0; |
841 | LIST_HEAD(list); | 841 | LIST_HEAD(list); |
842 | 842 | ||
843 | nfs_list_remove_request(req); | 843 | nfs_list_remove_request(req); |
844 | 844 | ||
845 | nbytes = count; | 845 | nbytes = count; |
846 | do { | 846 | do { |
847 | size_t len = min(nbytes, wsize); | 847 | size_t len = min(nbytes, wsize); |
848 | 848 | ||
849 | data = nfs_writedata_alloc(1); | 849 | data = nfs_writedata_alloc(1); |
850 | if (!data) | 850 | if (!data) |
851 | goto out_bad; | 851 | goto out_bad; |
852 | list_add(&data->pages, &list); | 852 | list_add(&data->pages, &list); |
853 | requests++; | 853 | requests++; |
854 | nbytes -= len; | 854 | nbytes -= len; |
855 | } while (nbytes != 0); | 855 | } while (nbytes != 0); |
856 | atomic_set(&req->wb_complete, requests); | 856 | atomic_set(&req->wb_complete, requests); |
857 | 857 | ||
858 | ClearPageError(page); | 858 | ClearPageError(page); |
859 | offset = 0; | 859 | offset = 0; |
860 | nbytes = count; | 860 | nbytes = count; |
861 | do { | 861 | do { |
862 | data = list_entry(list.next, struct nfs_write_data, pages); | 862 | data = list_entry(list.next, struct nfs_write_data, pages); |
863 | list_del_init(&data->pages); | 863 | list_del_init(&data->pages); |
864 | 864 | ||
865 | data->pagevec[0] = page; | 865 | data->pagevec[0] = page; |
866 | 866 | ||
867 | if (nbytes < wsize) | 867 | if (nbytes < wsize) |
868 | wsize = nbytes; | 868 | wsize = nbytes; |
869 | nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, | 869 | nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, |
870 | wsize, offset, how); | 870 | wsize, offset, how); |
871 | offset += wsize; | 871 | offset += wsize; |
872 | nbytes -= wsize; | 872 | nbytes -= wsize; |
873 | nfs_execute_write(data); | 873 | nfs_execute_write(data); |
874 | } while (nbytes != 0); | 874 | } while (nbytes != 0); |
875 | 875 | ||
876 | return 0; | 876 | return 0; |
877 | 877 | ||
878 | out_bad: | 878 | out_bad: |
879 | while (!list_empty(&list)) { | 879 | while (!list_empty(&list)) { |
880 | data = list_entry(list.next, struct nfs_write_data, pages); | 880 | data = list_entry(list.next, struct nfs_write_data, pages); |
881 | list_del(&data->pages); | 881 | list_del(&data->pages); |
882 | nfs_writedata_release(data); | 882 | nfs_writedata_release(data); |
883 | } | 883 | } |
884 | nfs_redirty_request(req); | 884 | nfs_redirty_request(req); |
885 | nfs_end_page_writeback(req->wb_page); | 885 | nfs_end_page_writeback(req->wb_page); |
886 | nfs_clear_page_writeback(req); | 886 | nfs_clear_page_writeback(req); |
887 | return -ENOMEM; | 887 | return -ENOMEM; |
888 | } | 888 | } |
889 | 889 | ||
890 | /* | 890 | /* |
891 | * Create an RPC task for the given write request and kick it. | 891 | * Create an RPC task for the given write request and kick it. |
892 | * The page must have been locked by the caller. | 892 | * The page must have been locked by the caller. |
893 | * | 893 | * |
894 | * It may happen that the page we're passed is not marked dirty. | 894 | * It may happen that the page we're passed is not marked dirty. |
895 | * This is the case if nfs_updatepage detects a conflicting request | 895 | * This is the case if nfs_updatepage detects a conflicting request |
896 | * that has been written but not committed. | 896 | * that has been written but not committed. |
897 | */ | 897 | */ |
898 | static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how) | 898 | static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how) |
899 | { | 899 | { |
900 | struct nfs_page *req; | 900 | struct nfs_page *req; |
901 | struct page **pages; | 901 | struct page **pages; |
902 | struct nfs_write_data *data; | 902 | struct nfs_write_data *data; |
903 | 903 | ||
904 | data = nfs_writedata_alloc(npages); | 904 | data = nfs_writedata_alloc(npages); |
905 | if (!data) | 905 | if (!data) |
906 | goto out_bad; | 906 | goto out_bad; |
907 | 907 | ||
908 | pages = data->pagevec; | 908 | pages = data->pagevec; |
909 | while (!list_empty(head)) { | 909 | while (!list_empty(head)) { |
910 | req = nfs_list_entry(head->next); | 910 | req = nfs_list_entry(head->next); |
911 | nfs_list_remove_request(req); | 911 | nfs_list_remove_request(req); |
912 | nfs_list_add_request(req, &data->pages); | 912 | nfs_list_add_request(req, &data->pages); |
913 | ClearPageError(req->wb_page); | 913 | ClearPageError(req->wb_page); |
914 | *pages++ = req->wb_page; | 914 | *pages++ = req->wb_page; |
915 | } | 915 | } |
916 | req = nfs_list_entry(data->pages.next); | 916 | req = nfs_list_entry(data->pages.next); |
917 | 917 | ||
918 | /* Set up the argument struct */ | 918 | /* Set up the argument struct */ |
919 | nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); | 919 | nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); |
920 | 920 | ||
921 | nfs_execute_write(data); | 921 | nfs_execute_write(data); |
922 | return 0; | 922 | return 0; |
923 | out_bad: | 923 | out_bad: |
924 | while (!list_empty(head)) { | 924 | while (!list_empty(head)) { |
925 | struct nfs_page *req = nfs_list_entry(head->next); | 925 | struct nfs_page *req = nfs_list_entry(head->next); |
926 | nfs_list_remove_request(req); | 926 | nfs_list_remove_request(req); |
927 | nfs_redirty_request(req); | 927 | nfs_redirty_request(req); |
928 | nfs_end_page_writeback(req->wb_page); | 928 | nfs_end_page_writeback(req->wb_page); |
929 | nfs_clear_page_writeback(req); | 929 | nfs_clear_page_writeback(req); |
930 | } | 930 | } |
931 | return -ENOMEM; | 931 | return -ENOMEM; |
932 | } | 932 | } |
933 | 933 | ||
934 | static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, | 934 | static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, |
935 | struct inode *inode, int ioflags) | 935 | struct inode *inode, int ioflags) |
936 | { | 936 | { |
937 | int wsize = NFS_SERVER(inode)->wsize; | 937 | int wsize = NFS_SERVER(inode)->wsize; |
938 | 938 | ||
939 | if (wsize < PAGE_CACHE_SIZE) | 939 | if (wsize < PAGE_CACHE_SIZE) |
940 | nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags); | 940 | nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags); |
941 | else | 941 | else |
942 | nfs_pageio_init(pgio, inode, nfs_flush_one, wsize, ioflags); | 942 | nfs_pageio_init(pgio, inode, nfs_flush_one, wsize, ioflags); |
943 | } | 943 | } |
944 | 944 | ||
945 | /* | 945 | /* |
946 | * Handle a write reply that flushed part of a page. | 946 | * Handle a write reply that flushed part of a page. |
947 | */ | 947 | */ |
948 | static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) | 948 | static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) |
949 | { | 949 | { |
950 | struct nfs_write_data *data = calldata; | 950 | struct nfs_write_data *data = calldata; |
951 | struct nfs_page *req = data->req; | 951 | struct nfs_page *req = data->req; |
952 | struct page *page = req->wb_page; | 952 | struct page *page = req->wb_page; |
953 | 953 | ||
954 | dprintk("NFS: write (%s/%Ld %d@%Ld)", | 954 | dprintk("NFS: write (%s/%Ld %d@%Ld)", |
955 | req->wb_context->dentry->d_inode->i_sb->s_id, | 955 | req->wb_context->dentry->d_inode->i_sb->s_id, |
956 | (long long)NFS_FILEID(req->wb_context->dentry->d_inode), | 956 | (long long)NFS_FILEID(req->wb_context->dentry->d_inode), |
957 | req->wb_bytes, | 957 | req->wb_bytes, |
958 | (long long)req_offset(req)); | 958 | (long long)req_offset(req)); |
959 | 959 | ||
960 | if (nfs_writeback_done(task, data) != 0) | 960 | if (nfs_writeback_done(task, data) != 0) |
961 | return; | 961 | return; |
962 | 962 | ||
963 | if (task->tk_status < 0) { | 963 | if (task->tk_status < 0) { |
964 | nfs_set_pageerror(page); | 964 | nfs_set_pageerror(page); |
965 | req->wb_context->error = task->tk_status; | 965 | req->wb_context->error = task->tk_status; |
966 | dprintk(", error = %d\n", task->tk_status); | 966 | dprintk(", error = %d\n", task->tk_status); |
967 | goto out; | 967 | goto out; |
968 | } | 968 | } |
969 | 969 | ||
970 | if (nfs_write_need_commit(data)) { | 970 | if (nfs_write_need_commit(data)) { |
971 | spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock; | 971 | spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock; |
972 | 972 | ||
973 | spin_lock(req_lock); | 973 | spin_lock(req_lock); |
974 | if (test_bit(PG_NEED_RESCHED, &req->wb_flags)) { | 974 | if (test_bit(PG_NEED_RESCHED, &req->wb_flags)) { |
975 | /* Do nothing we need to resend the writes */ | 975 | /* Do nothing we need to resend the writes */ |
976 | } else if (!test_and_set_bit(PG_NEED_COMMIT, &req->wb_flags)) { | 976 | } else if (!test_and_set_bit(PG_NEED_COMMIT, &req->wb_flags)) { |
977 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); | 977 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); |
978 | dprintk(" defer commit\n"); | 978 | dprintk(" defer commit\n"); |
979 | } else if (memcmp(&req->wb_verf, &data->verf, sizeof(req->wb_verf))) { | 979 | } else if (memcmp(&req->wb_verf, &data->verf, sizeof(req->wb_verf))) { |
980 | set_bit(PG_NEED_RESCHED, &req->wb_flags); | 980 | set_bit(PG_NEED_RESCHED, &req->wb_flags); |
981 | clear_bit(PG_NEED_COMMIT, &req->wb_flags); | 981 | clear_bit(PG_NEED_COMMIT, &req->wb_flags); |
982 | dprintk(" server reboot detected\n"); | 982 | dprintk(" server reboot detected\n"); |
983 | } | 983 | } |
984 | spin_unlock(req_lock); | 984 | spin_unlock(req_lock); |
985 | } else | 985 | } else |
986 | dprintk(" OK\n"); | 986 | dprintk(" OK\n"); |
987 | 987 | ||
988 | out: | 988 | out: |
989 | if (atomic_dec_and_test(&req->wb_complete)) | 989 | if (atomic_dec_and_test(&req->wb_complete)) |
990 | nfs_writepage_release(req); | 990 | nfs_writepage_release(req); |
991 | } | 991 | } |
992 | 992 | ||
993 | static const struct rpc_call_ops nfs_write_partial_ops = { | 993 | static const struct rpc_call_ops nfs_write_partial_ops = { |
994 | .rpc_call_done = nfs_writeback_done_partial, | 994 | .rpc_call_done = nfs_writeback_done_partial, |
995 | .rpc_release = nfs_writedata_release, | 995 | .rpc_release = nfs_writedata_release, |
996 | }; | 996 | }; |
997 | 997 | ||
998 | /* | 998 | /* |
999 | * Handle a write reply that flushes a whole page. | 999 | * Handle a write reply that flushes a whole page. |
1000 | * | 1000 | * |
1001 | * FIXME: There is an inherent race with invalidate_inode_pages and | 1001 | * FIXME: There is an inherent race with invalidate_inode_pages and |
1002 | * writebacks since the page->count is kept > 1 for as long | 1002 | * writebacks since the page->count is kept > 1 for as long |
1003 | * as the page has a write request pending. | 1003 | * as the page has a write request pending. |
1004 | */ | 1004 | */ |
1005 | static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) | 1005 | static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) |
1006 | { | 1006 | { |
1007 | struct nfs_write_data *data = calldata; | 1007 | struct nfs_write_data *data = calldata; |
1008 | struct nfs_page *req; | 1008 | struct nfs_page *req; |
1009 | struct page *page; | 1009 | struct page *page; |
1010 | 1010 | ||
1011 | if (nfs_writeback_done(task, data) != 0) | 1011 | if (nfs_writeback_done(task, data) != 0) |
1012 | return; | 1012 | return; |
1013 | 1013 | ||
1014 | /* Update attributes as result of writeback. */ | 1014 | /* Update attributes as result of writeback. */ |
1015 | while (!list_empty(&data->pages)) { | 1015 | while (!list_empty(&data->pages)) { |
1016 | req = nfs_list_entry(data->pages.next); | 1016 | req = nfs_list_entry(data->pages.next); |
1017 | nfs_list_remove_request(req); | 1017 | nfs_list_remove_request(req); |
1018 | page = req->wb_page; | 1018 | page = req->wb_page; |
1019 | 1019 | ||
1020 | dprintk("NFS: write (%s/%Ld %d@%Ld)", | 1020 | dprintk("NFS: write (%s/%Ld %d@%Ld)", |
1021 | req->wb_context->dentry->d_inode->i_sb->s_id, | 1021 | req->wb_context->dentry->d_inode->i_sb->s_id, |
1022 | (long long)NFS_FILEID(req->wb_context->dentry->d_inode), | 1022 | (long long)NFS_FILEID(req->wb_context->dentry->d_inode), |
1023 | req->wb_bytes, | 1023 | req->wb_bytes, |
1024 | (long long)req_offset(req)); | 1024 | (long long)req_offset(req)); |
1025 | 1025 | ||
1026 | if (task->tk_status < 0) { | 1026 | if (task->tk_status < 0) { |
1027 | nfs_set_pageerror(page); | 1027 | nfs_set_pageerror(page); |
1028 | req->wb_context->error = task->tk_status; | 1028 | req->wb_context->error = task->tk_status; |
1029 | dprintk(", error = %d\n", task->tk_status); | 1029 | dprintk(", error = %d\n", task->tk_status); |
1030 | goto remove_request; | 1030 | goto remove_request; |
1031 | } | 1031 | } |
1032 | 1032 | ||
1033 | if (nfs_write_need_commit(data)) { | 1033 | if (nfs_write_need_commit(data)) { |
1034 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); | 1034 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); |
1035 | nfs_mark_request_commit(req); | 1035 | nfs_mark_request_commit(req); |
1036 | nfs_end_page_writeback(page); | 1036 | nfs_end_page_writeback(page); |
1037 | dprintk(" marked for commit\n"); | 1037 | dprintk(" marked for commit\n"); |
1038 | goto next; | 1038 | goto next; |
1039 | } | 1039 | } |
1040 | dprintk(" OK\n"); | 1040 | dprintk(" OK\n"); |
1041 | remove_request: | 1041 | remove_request: |
1042 | nfs_end_page_writeback(page); | 1042 | nfs_end_page_writeback(page); |
1043 | nfs_inode_remove_request(req); | 1043 | nfs_inode_remove_request(req); |
1044 | next: | 1044 | next: |
1045 | nfs_clear_page_writeback(req); | 1045 | nfs_clear_page_writeback(req); |
1046 | } | 1046 | } |
1047 | } | 1047 | } |
1048 | 1048 | ||
1049 | static const struct rpc_call_ops nfs_write_full_ops = { | 1049 | static const struct rpc_call_ops nfs_write_full_ops = { |
1050 | .rpc_call_done = nfs_writeback_done_full, | 1050 | .rpc_call_done = nfs_writeback_done_full, |
1051 | .rpc_release = nfs_writedata_release, | 1051 | .rpc_release = nfs_writedata_release, |
1052 | }; | 1052 | }; |
1053 | 1053 | ||
1054 | 1054 | ||
1055 | /* | 1055 | /* |
1056 | * This function is called when the WRITE call is complete. | 1056 | * This function is called when the WRITE call is complete. |
1057 | */ | 1057 | */ |
1058 | int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | 1058 | int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) |
1059 | { | 1059 | { |
1060 | struct nfs_writeargs *argp = &data->args; | 1060 | struct nfs_writeargs *argp = &data->args; |
1061 | struct nfs_writeres *resp = &data->res; | 1061 | struct nfs_writeres *resp = &data->res; |
1062 | int status; | 1062 | int status; |
1063 | 1063 | ||
1064 | dprintk("NFS: %5u nfs_writeback_done (status %d)\n", | 1064 | dprintk("NFS: %5u nfs_writeback_done (status %d)\n", |
1065 | task->tk_pid, task->tk_status); | 1065 | task->tk_pid, task->tk_status); |
1066 | 1066 | ||
1067 | /* | 1067 | /* |
1068 | * ->write_done will attempt to use post-op attributes to detect | 1068 | * ->write_done will attempt to use post-op attributes to detect |
1069 | * conflicting writes by other clients. A strict interpretation | 1069 | * conflicting writes by other clients. A strict interpretation |
1070 | * of close-to-open would allow us to continue caching even if | 1070 | * of close-to-open would allow us to continue caching even if |
1071 | * another writer had changed the file, but some applications | 1071 | * another writer had changed the file, but some applications |
1072 | * depend on tighter cache coherency when writing. | 1072 | * depend on tighter cache coherency when writing. |
1073 | */ | 1073 | */ |
1074 | status = NFS_PROTO(data->inode)->write_done(task, data); | 1074 | status = NFS_PROTO(data->inode)->write_done(task, data); |
1075 | if (status != 0) | 1075 | if (status != 0) |
1076 | return status; | 1076 | return status; |
1077 | nfs_add_stats(data->inode, NFSIOS_SERVERWRITTENBYTES, resp->count); | 1077 | nfs_add_stats(data->inode, NFSIOS_SERVERWRITTENBYTES, resp->count); |
1078 | 1078 | ||
1079 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1079 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1080 | if (resp->verf->committed < argp->stable && task->tk_status >= 0) { | 1080 | if (resp->verf->committed < argp->stable && task->tk_status >= 0) { |
1081 | /* We tried a write call, but the server did not | 1081 | /* We tried a write call, but the server did not |
1082 | * commit data to stable storage even though we | 1082 | * commit data to stable storage even though we |
1083 | * requested it. | 1083 | * requested it. |
1084 | * Note: There is a known bug in Tru64 < 5.0 in which | 1084 | * Note: There is a known bug in Tru64 < 5.0 in which |
1085 | * the server reports NFS_DATA_SYNC, but performs | 1085 | * the server reports NFS_DATA_SYNC, but performs |
1086 | * NFS_FILE_SYNC. We therefore implement this checking | 1086 | * NFS_FILE_SYNC. We therefore implement this checking |
1087 | * as a dprintk() in order to avoid filling syslog. | 1087 | * as a dprintk() in order to avoid filling syslog. |
1088 | */ | 1088 | */ |
1089 | static unsigned long complain; | 1089 | static unsigned long complain; |
1090 | 1090 | ||
1091 | if (time_before(complain, jiffies)) { | 1091 | if (time_before(complain, jiffies)) { |
1092 | dprintk("NFS: faulty NFS server %s:" | 1092 | dprintk("NFS: faulty NFS server %s:" |
1093 | " (committed = %d) != (stable = %d)\n", | 1093 | " (committed = %d) != (stable = %d)\n", |
1094 | NFS_SERVER(data->inode)->nfs_client->cl_hostname, | 1094 | NFS_SERVER(data->inode)->nfs_client->cl_hostname, |
1095 | resp->verf->committed, argp->stable); | 1095 | resp->verf->committed, argp->stable); |
1096 | complain = jiffies + 300 * HZ; | 1096 | complain = jiffies + 300 * HZ; |
1097 | } | 1097 | } |
1098 | } | 1098 | } |
1099 | #endif | 1099 | #endif |
1100 | /* Is this a short write? */ | 1100 | /* Is this a short write? */ |
1101 | if (task->tk_status >= 0 && resp->count < argp->count) { | 1101 | if (task->tk_status >= 0 && resp->count < argp->count) { |
1102 | static unsigned long complain; | 1102 | static unsigned long complain; |
1103 | 1103 | ||
1104 | nfs_inc_stats(data->inode, NFSIOS_SHORTWRITE); | 1104 | nfs_inc_stats(data->inode, NFSIOS_SHORTWRITE); |
1105 | 1105 | ||
1106 | /* Has the server at least made some progress? */ | 1106 | /* Has the server at least made some progress? */ |
1107 | if (resp->count != 0) { | 1107 | if (resp->count != 0) { |
1108 | /* Was this an NFSv2 write or an NFSv3 stable write? */ | 1108 | /* Was this an NFSv2 write or an NFSv3 stable write? */ |
1109 | if (resp->verf->committed != NFS_UNSTABLE) { | 1109 | if (resp->verf->committed != NFS_UNSTABLE) { |
1110 | /* Resend from where the server left off */ | 1110 | /* Resend from where the server left off */ |
1111 | argp->offset += resp->count; | 1111 | argp->offset += resp->count; |
1112 | argp->pgbase += resp->count; | 1112 | argp->pgbase += resp->count; |
1113 | argp->count -= resp->count; | 1113 | argp->count -= resp->count; |
1114 | } else { | 1114 | } else { |
1115 | /* Resend as a stable write in order to avoid | 1115 | /* Resend as a stable write in order to avoid |
1116 | * headaches in the case of a server crash. | 1116 | * headaches in the case of a server crash. |
1117 | */ | 1117 | */ |
1118 | argp->stable = NFS_FILE_SYNC; | 1118 | argp->stable = NFS_FILE_SYNC; |
1119 | } | 1119 | } |
1120 | rpc_restart_call(task); | 1120 | rpc_restart_call(task); |
1121 | return -EAGAIN; | 1121 | return -EAGAIN; |
1122 | } | 1122 | } |
1123 | if (time_before(complain, jiffies)) { | 1123 | if (time_before(complain, jiffies)) { |
1124 | printk(KERN_WARNING | 1124 | printk(KERN_WARNING |
1125 | "NFS: Server wrote zero bytes, expected %u.\n", | 1125 | "NFS: Server wrote zero bytes, expected %u.\n", |
1126 | argp->count); | 1126 | argp->count); |
1127 | complain = jiffies + 300 * HZ; | 1127 | complain = jiffies + 300 * HZ; |
1128 | } | 1128 | } |
1129 | /* Can't do anything about it except throw an error. */ | 1129 | /* Can't do anything about it except throw an error. */ |
1130 | task->tk_status = -EIO; | 1130 | task->tk_status = -EIO; |
1131 | } | 1131 | } |
1132 | return 0; | 1132 | return 0; |
1133 | } | 1133 | } |
1134 | 1134 | ||
1135 | 1135 | ||
1136 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1136 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1137 | void nfs_commit_release(void *wdata) | 1137 | void nfs_commit_release(void *wdata) |
1138 | { | 1138 | { |
1139 | nfs_commit_free(wdata); | 1139 | nfs_commit_free(wdata); |
1140 | } | 1140 | } |
1141 | 1141 | ||
1142 | /* | 1142 | /* |
1143 | * Set up the argument/result storage required for the RPC call. | 1143 | * Set up the argument/result storage required for the RPC call. |
1144 | */ | 1144 | */ |
1145 | static void nfs_commit_rpcsetup(struct list_head *head, | 1145 | static void nfs_commit_rpcsetup(struct list_head *head, |
1146 | struct nfs_write_data *data, | 1146 | struct nfs_write_data *data, |
1147 | int how) | 1147 | int how) |
1148 | { | 1148 | { |
1149 | struct nfs_page *first; | 1149 | struct nfs_page *first; |
1150 | struct inode *inode; | 1150 | struct inode *inode; |
1151 | int flags; | 1151 | int flags; |
1152 | 1152 | ||
1153 | /* Set up the RPC argument and reply structs | 1153 | /* Set up the RPC argument and reply structs |
1154 | * NB: take care not to mess about with data->commit et al. */ | 1154 | * NB: take care not to mess about with data->commit et al. */ |
1155 | 1155 | ||
1156 | list_splice_init(head, &data->pages); | 1156 | list_splice_init(head, &data->pages); |
1157 | first = nfs_list_entry(data->pages.next); | 1157 | first = nfs_list_entry(data->pages.next); |
1158 | inode = first->wb_context->dentry->d_inode; | 1158 | inode = first->wb_context->dentry->d_inode; |
1159 | 1159 | ||
1160 | data->inode = inode; | 1160 | data->inode = inode; |
1161 | data->cred = first->wb_context->cred; | 1161 | data->cred = first->wb_context->cred; |
1162 | 1162 | ||
1163 | data->args.fh = NFS_FH(data->inode); | 1163 | data->args.fh = NFS_FH(data->inode); |
1164 | /* Note: we always request a commit of the entire inode */ | 1164 | /* Note: we always request a commit of the entire inode */ |
1165 | data->args.offset = 0; | 1165 | data->args.offset = 0; |
1166 | data->args.count = 0; | 1166 | data->args.count = 0; |
1167 | data->res.count = 0; | 1167 | data->res.count = 0; |
1168 | data->res.fattr = &data->fattr; | 1168 | data->res.fattr = &data->fattr; |
1169 | data->res.verf = &data->verf; | 1169 | data->res.verf = &data->verf; |
1170 | nfs_fattr_init(&data->fattr); | 1170 | nfs_fattr_init(&data->fattr); |
1171 | 1171 | ||
1172 | /* Set up the initial task struct. */ | 1172 | /* Set up the initial task struct. */ |
1173 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | 1173 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; |
1174 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, &nfs_commit_ops, data); | 1174 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, &nfs_commit_ops, data); |
1175 | NFS_PROTO(inode)->commit_setup(data, how); | 1175 | NFS_PROTO(inode)->commit_setup(data, how); |
1176 | 1176 | ||
1177 | data->task.tk_priority = flush_task_priority(how); | 1177 | data->task.tk_priority = flush_task_priority(how); |
1178 | data->task.tk_cookie = (unsigned long)inode; | 1178 | data->task.tk_cookie = (unsigned long)inode; |
1179 | 1179 | ||
1180 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); | 1180 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); |
1181 | } | 1181 | } |
1182 | 1182 | ||
1183 | /* | 1183 | /* |
1184 | * Commit dirty pages | 1184 | * Commit dirty pages |
1185 | */ | 1185 | */ |
1186 | static int | 1186 | static int |
1187 | nfs_commit_list(struct inode *inode, struct list_head *head, int how) | 1187 | nfs_commit_list(struct inode *inode, struct list_head *head, int how) |
1188 | { | 1188 | { |
1189 | struct nfs_write_data *data; | 1189 | struct nfs_write_data *data; |
1190 | struct nfs_page *req; | 1190 | struct nfs_page *req; |
1191 | 1191 | ||
1192 | data = nfs_commit_alloc(); | 1192 | data = nfs_commit_alloc(); |
1193 | 1193 | ||
1194 | if (!data) | 1194 | if (!data) |
1195 | goto out_bad; | 1195 | goto out_bad; |
1196 | 1196 | ||
1197 | /* Set up the argument struct */ | 1197 | /* Set up the argument struct */ |
1198 | nfs_commit_rpcsetup(head, data, how); | 1198 | nfs_commit_rpcsetup(head, data, how); |
1199 | 1199 | ||
1200 | nfs_execute_write(data); | 1200 | nfs_execute_write(data); |
1201 | return 0; | 1201 | return 0; |
1202 | out_bad: | 1202 | out_bad: |
1203 | while (!list_empty(head)) { | 1203 | while (!list_empty(head)) { |
1204 | req = nfs_list_entry(head->next); | 1204 | req = nfs_list_entry(head->next); |
1205 | nfs_list_remove_request(req); | 1205 | nfs_list_remove_request(req); |
1206 | nfs_mark_request_commit(req); | 1206 | nfs_mark_request_commit(req); |
1207 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 1207 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); |
1208 | nfs_clear_page_writeback(req); | 1208 | nfs_clear_page_writeback(req); |
1209 | } | 1209 | } |
1210 | return -ENOMEM; | 1210 | return -ENOMEM; |
1211 | } | 1211 | } |
1212 | 1212 | ||
1213 | /* | 1213 | /* |
1214 | * COMMIT call returned | 1214 | * COMMIT call returned |
1215 | */ | 1215 | */ |
1216 | static void nfs_commit_done(struct rpc_task *task, void *calldata) | 1216 | static void nfs_commit_done(struct rpc_task *task, void *calldata) |
1217 | { | 1217 | { |
1218 | struct nfs_write_data *data = calldata; | 1218 | struct nfs_write_data *data = calldata; |
1219 | struct nfs_page *req; | 1219 | struct nfs_page *req; |
1220 | 1220 | ||
1221 | dprintk("NFS: %5u nfs_commit_done (status %d)\n", | 1221 | dprintk("NFS: %5u nfs_commit_done (status %d)\n", |
1222 | task->tk_pid, task->tk_status); | 1222 | task->tk_pid, task->tk_status); |
1223 | 1223 | ||
1224 | /* Call the NFS version-specific code */ | 1224 | /* Call the NFS version-specific code */ |
1225 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) | 1225 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) |
1226 | return; | 1226 | return; |
1227 | 1227 | ||
1228 | while (!list_empty(&data->pages)) { | 1228 | while (!list_empty(&data->pages)) { |
1229 | req = nfs_list_entry(data->pages.next); | 1229 | req = nfs_list_entry(data->pages.next); |
1230 | nfs_list_remove_request(req); | 1230 | nfs_list_remove_request(req); |
1231 | clear_bit(PG_NEED_COMMIT, &(req)->wb_flags); | 1231 | clear_bit(PG_NEED_COMMIT, &(req)->wb_flags); |
1232 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 1232 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); |
1233 | 1233 | ||
1234 | dprintk("NFS: commit (%s/%Ld %d@%Ld)", | 1234 | dprintk("NFS: commit (%s/%Ld %d@%Ld)", |
1235 | req->wb_context->dentry->d_inode->i_sb->s_id, | 1235 | req->wb_context->dentry->d_inode->i_sb->s_id, |
1236 | (long long)NFS_FILEID(req->wb_context->dentry->d_inode), | 1236 | (long long)NFS_FILEID(req->wb_context->dentry->d_inode), |
1237 | req->wb_bytes, | 1237 | req->wb_bytes, |
1238 | (long long)req_offset(req)); | 1238 | (long long)req_offset(req)); |
1239 | if (task->tk_status < 0) { | 1239 | if (task->tk_status < 0) { |
1240 | req->wb_context->error = task->tk_status; | 1240 | req->wb_context->error = task->tk_status; |
1241 | nfs_inode_remove_request(req); | 1241 | nfs_inode_remove_request(req); |
1242 | dprintk(", error = %d\n", task->tk_status); | 1242 | dprintk(", error = %d\n", task->tk_status); |
1243 | goto next; | 1243 | goto next; |
1244 | } | 1244 | } |
1245 | 1245 | ||
1246 | /* Okay, COMMIT succeeded, apparently. Check the verifier | 1246 | /* Okay, COMMIT succeeded, apparently. Check the verifier |
1247 | * returned by the server against all stored verfs. */ | 1247 | * returned by the server against all stored verfs. */ |
1248 | if (!memcmp(req->wb_verf.verifier, data->verf.verifier, sizeof(data->verf.verifier))) { | 1248 | if (!memcmp(req->wb_verf.verifier, data->verf.verifier, sizeof(data->verf.verifier))) { |
1249 | /* We have a match */ | 1249 | /* We have a match */ |
1250 | nfs_inode_remove_request(req); | 1250 | nfs_inode_remove_request(req); |
1251 | dprintk(" OK\n"); | 1251 | dprintk(" OK\n"); |
1252 | goto next; | 1252 | goto next; |
1253 | } | 1253 | } |
1254 | /* We have a mismatch. Write the page again */ | 1254 | /* We have a mismatch. Write the page again */ |
1255 | dprintk(" mismatch\n"); | 1255 | dprintk(" mismatch\n"); |
1256 | nfs_redirty_request(req); | 1256 | nfs_redirty_request(req); |
1257 | next: | 1257 | next: |
1258 | nfs_clear_page_writeback(req); | 1258 | nfs_clear_page_writeback(req); |
1259 | } | 1259 | } |
1260 | } | 1260 | } |
1261 | 1261 | ||
1262 | static const struct rpc_call_ops nfs_commit_ops = { | 1262 | static const struct rpc_call_ops nfs_commit_ops = { |
1263 | .rpc_call_done = nfs_commit_done, | 1263 | .rpc_call_done = nfs_commit_done, |
1264 | .rpc_release = nfs_commit_release, | 1264 | .rpc_release = nfs_commit_release, |
1265 | }; | 1265 | }; |
1266 | 1266 | ||
1267 | int nfs_commit_inode(struct inode *inode, int how) | 1267 | int nfs_commit_inode(struct inode *inode, int how) |
1268 | { | 1268 | { |
1269 | struct nfs_inode *nfsi = NFS_I(inode); | 1269 | struct nfs_inode *nfsi = NFS_I(inode); |
1270 | LIST_HEAD(head); | 1270 | LIST_HEAD(head); |
1271 | int res; | 1271 | int res; |
1272 | 1272 | ||
1273 | spin_lock(&nfsi->req_lock); | 1273 | spin_lock(&nfsi->req_lock); |
1274 | res = nfs_scan_commit(inode, &head, 0, 0); | 1274 | res = nfs_scan_commit(inode, &head, 0, 0); |
1275 | spin_unlock(&nfsi->req_lock); | 1275 | spin_unlock(&nfsi->req_lock); |
1276 | if (res) { | 1276 | if (res) { |
1277 | int error = nfs_commit_list(inode, &head, how); | 1277 | int error = nfs_commit_list(inode, &head, how); |
1278 | if (error < 0) | 1278 | if (error < 0) |
1279 | return error; | 1279 | return error; |
1280 | } | 1280 | } |
1281 | return res; | 1281 | return res; |
1282 | } | 1282 | } |
1283 | #else | 1283 | #else |
1284 | static inline int nfs_commit_list(struct inode *inode, struct list_head *head, int how) | 1284 | static inline int nfs_commit_list(struct inode *inode, struct list_head *head, int how) |
1285 | { | 1285 | { |
1286 | return 0; | 1286 | return 0; |
1287 | } | 1287 | } |
1288 | #endif | 1288 | #endif |
1289 | 1289 | ||
1290 | long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_control *wbc, int how) | 1290 | long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_control *wbc, int how) |
1291 | { | 1291 | { |
1292 | struct inode *inode = mapping->host; | 1292 | struct inode *inode = mapping->host; |
1293 | struct nfs_inode *nfsi = NFS_I(inode); | 1293 | struct nfs_inode *nfsi = NFS_I(inode); |
1294 | pgoff_t idx_start, idx_end; | 1294 | pgoff_t idx_start, idx_end; |
1295 | unsigned int npages = 0; | 1295 | unsigned int npages = 0; |
1296 | LIST_HEAD(head); | 1296 | LIST_HEAD(head); |
1297 | int nocommit = how & FLUSH_NOCOMMIT; | 1297 | int nocommit = how & FLUSH_NOCOMMIT; |
1298 | long pages, ret; | 1298 | long pages, ret; |
1299 | 1299 | ||
1300 | /* FIXME */ | 1300 | /* FIXME */ |
1301 | if (wbc->range_cyclic) | 1301 | if (wbc->range_cyclic) |
1302 | idx_start = 0; | 1302 | idx_start = 0; |
1303 | else { | 1303 | else { |
1304 | idx_start = wbc->range_start >> PAGE_CACHE_SHIFT; | 1304 | idx_start = wbc->range_start >> PAGE_CACHE_SHIFT; |
1305 | idx_end = wbc->range_end >> PAGE_CACHE_SHIFT; | 1305 | idx_end = wbc->range_end >> PAGE_CACHE_SHIFT; |
1306 | if (idx_end > idx_start) { | 1306 | if (idx_end > idx_start) { |
1307 | pgoff_t l_npages = 1 + idx_end - idx_start; | 1307 | pgoff_t l_npages = 1 + idx_end - idx_start; |
1308 | npages = l_npages; | 1308 | npages = l_npages; |
1309 | if (sizeof(npages) != sizeof(l_npages) && | 1309 | if (sizeof(npages) != sizeof(l_npages) && |
1310 | (pgoff_t)npages != l_npages) | 1310 | (pgoff_t)npages != l_npages) |
1311 | npages = 0; | 1311 | npages = 0; |
1312 | } | 1312 | } |
1313 | } | 1313 | } |
1314 | how &= ~FLUSH_NOCOMMIT; | 1314 | how &= ~FLUSH_NOCOMMIT; |
1315 | spin_lock(&nfsi->req_lock); | 1315 | spin_lock(&nfsi->req_lock); |
1316 | do { | 1316 | do { |
1317 | ret = nfs_wait_on_requests_locked(inode, idx_start, npages); | 1317 | ret = nfs_wait_on_requests_locked(inode, idx_start, npages); |
1318 | if (ret != 0) | 1318 | if (ret != 0) |
1319 | continue; | 1319 | continue; |
1320 | if (nocommit) | 1320 | if (nocommit) |
1321 | break; | 1321 | break; |
1322 | pages = nfs_scan_commit(inode, &head, idx_start, npages); | 1322 | pages = nfs_scan_commit(inode, &head, idx_start, npages); |
1323 | if (pages == 0) | 1323 | if (pages == 0) |
1324 | break; | 1324 | break; |
1325 | if (how & FLUSH_INVALIDATE) { | 1325 | if (how & FLUSH_INVALIDATE) { |
1326 | spin_unlock(&nfsi->req_lock); | 1326 | spin_unlock(&nfsi->req_lock); |
1327 | nfs_cancel_commit_list(&head); | 1327 | nfs_cancel_commit_list(&head); |
1328 | ret = pages; | 1328 | ret = pages; |
1329 | spin_lock(&nfsi->req_lock); | 1329 | spin_lock(&nfsi->req_lock); |
1330 | continue; | 1330 | continue; |
1331 | } | 1331 | } |
1332 | pages += nfs_scan_commit(inode, &head, 0, 0); | 1332 | pages += nfs_scan_commit(inode, &head, 0, 0); |
1333 | spin_unlock(&nfsi->req_lock); | 1333 | spin_unlock(&nfsi->req_lock); |
1334 | ret = nfs_commit_list(inode, &head, how); | 1334 | ret = nfs_commit_list(inode, &head, how); |
1335 | spin_lock(&nfsi->req_lock); | 1335 | spin_lock(&nfsi->req_lock); |
1336 | } while (ret >= 0); | 1336 | } while (ret >= 0); |
1337 | spin_unlock(&nfsi->req_lock); | 1337 | spin_unlock(&nfsi->req_lock); |
1338 | return ret; | 1338 | return ret; |
1339 | } | 1339 | } |
1340 | 1340 | ||
1341 | /* | 1341 | /* |
1342 | * flush the inode to disk. | 1342 | * flush the inode to disk. |
1343 | */ | 1343 | */ |
1344 | int nfs_wb_all(struct inode *inode) | 1344 | int nfs_wb_all(struct inode *inode) |
1345 | { | 1345 | { |
1346 | struct address_space *mapping = inode->i_mapping; | 1346 | struct address_space *mapping = inode->i_mapping; |
1347 | struct writeback_control wbc = { | 1347 | struct writeback_control wbc = { |
1348 | .bdi = mapping->backing_dev_info, | 1348 | .bdi = mapping->backing_dev_info, |
1349 | .sync_mode = WB_SYNC_ALL, | 1349 | .sync_mode = WB_SYNC_ALL, |
1350 | .nr_to_write = LONG_MAX, | 1350 | .nr_to_write = LONG_MAX, |
1351 | .for_writepages = 1, | 1351 | .for_writepages = 1, |
1352 | .range_cyclic = 1, | 1352 | .range_cyclic = 1, |
1353 | }; | 1353 | }; |
1354 | int ret; | 1354 | int ret; |
1355 | 1355 | ||
1356 | ret = nfs_writepages(mapping, &wbc); | 1356 | ret = nfs_writepages(mapping, &wbc); |
1357 | if (ret < 0) | 1357 | if (ret < 0) |
1358 | goto out; | 1358 | goto out; |
1359 | ret = nfs_sync_mapping_wait(mapping, &wbc, 0); | 1359 | ret = nfs_sync_mapping_wait(mapping, &wbc, 0); |
1360 | if (ret >= 0) | 1360 | if (ret >= 0) |
1361 | return 0; | 1361 | return 0; |
1362 | out: | 1362 | out: |
1363 | __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); | 1363 | __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); |
1364 | return ret; | 1364 | return ret; |
1365 | } | 1365 | } |
1366 | 1366 | ||
1367 | int nfs_sync_mapping_range(struct address_space *mapping, loff_t range_start, loff_t range_end, int how) | 1367 | int nfs_sync_mapping_range(struct address_space *mapping, loff_t range_start, loff_t range_end, int how) |
1368 | { | 1368 | { |
1369 | struct writeback_control wbc = { | 1369 | struct writeback_control wbc = { |
1370 | .bdi = mapping->backing_dev_info, | 1370 | .bdi = mapping->backing_dev_info, |
1371 | .sync_mode = WB_SYNC_ALL, | 1371 | .sync_mode = WB_SYNC_ALL, |
1372 | .nr_to_write = LONG_MAX, | 1372 | .nr_to_write = LONG_MAX, |
1373 | .range_start = range_start, | 1373 | .range_start = range_start, |
1374 | .range_end = range_end, | 1374 | .range_end = range_end, |
1375 | .for_writepages = 1, | 1375 | .for_writepages = 1, |
1376 | }; | 1376 | }; |
1377 | int ret; | 1377 | int ret; |
1378 | 1378 | ||
1379 | ret = nfs_writepages(mapping, &wbc); | 1379 | ret = nfs_writepages(mapping, &wbc); |
1380 | if (ret < 0) | 1380 | if (ret < 0) |
1381 | goto out; | 1381 | goto out; |
1382 | ret = nfs_sync_mapping_wait(mapping, &wbc, how); | 1382 | ret = nfs_sync_mapping_wait(mapping, &wbc, how); |
1383 | if (ret >= 0) | 1383 | if (ret >= 0) |
1384 | return 0; | 1384 | return 0; |
1385 | out: | 1385 | out: |
1386 | __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); | 1386 | __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); |
1387 | return ret; | 1387 | return ret; |
1388 | } | 1388 | } |
1389 | 1389 | ||
1390 | int nfs_wb_page_priority(struct inode *inode, struct page *page, int how) | 1390 | int nfs_wb_page_priority(struct inode *inode, struct page *page, int how) |
1391 | { | 1391 | { |
1392 | loff_t range_start = page_offset(page); | 1392 | loff_t range_start = page_offset(page); |
1393 | loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); | 1393 | loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); |
1394 | struct writeback_control wbc = { | 1394 | struct writeback_control wbc = { |
1395 | .bdi = page->mapping->backing_dev_info, | 1395 | .bdi = page->mapping->backing_dev_info, |
1396 | .sync_mode = WB_SYNC_ALL, | 1396 | .sync_mode = WB_SYNC_ALL, |
1397 | .nr_to_write = LONG_MAX, | 1397 | .nr_to_write = LONG_MAX, |
1398 | .range_start = range_start, | 1398 | .range_start = range_start, |
1399 | .range_end = range_end, | 1399 | .range_end = range_end, |
1400 | }; | 1400 | }; |
1401 | int ret; | 1401 | int ret; |
1402 | 1402 | ||
1403 | BUG_ON(!PageLocked(page)); | 1403 | BUG_ON(!PageLocked(page)); |
1404 | if (clear_page_dirty_for_io(page)) { | 1404 | if (clear_page_dirty_for_io(page)) { |
1405 | ret = nfs_writepage_locked(page, &wbc); | 1405 | ret = nfs_writepage_locked(page, &wbc); |
1406 | if (ret < 0) | 1406 | if (ret < 0) |
1407 | goto out; | 1407 | goto out; |
1408 | } | 1408 | } |
1409 | if (!PagePrivate(page)) | 1409 | if (!PagePrivate(page)) |
1410 | return 0; | 1410 | return 0; |
1411 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); | 1411 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); |
1412 | if (ret >= 0) | 1412 | if (ret >= 0) |
1413 | return 0; | 1413 | return 0; |
1414 | out: | 1414 | out: |
1415 | __mark_inode_dirty(inode, I_DIRTY_PAGES); | 1415 | __mark_inode_dirty(inode, I_DIRTY_PAGES); |
1416 | return ret; | 1416 | return ret; |
1417 | } | 1417 | } |
1418 | 1418 | ||
1419 | /* | 1419 | /* |
1420 | * Write back all requests on one page - we do this before reading it. | 1420 | * Write back all requests on one page - we do this before reading it. |
1421 | */ | 1421 | */ |
1422 | int nfs_wb_page(struct inode *inode, struct page* page) | 1422 | int nfs_wb_page(struct inode *inode, struct page* page) |
1423 | { | 1423 | { |
1424 | return nfs_wb_page_priority(inode, page, FLUSH_STABLE); | 1424 | return nfs_wb_page_priority(inode, page, FLUSH_STABLE); |
1425 | } | 1425 | } |
1426 | 1426 | ||
1427 | int nfs_set_page_dirty(struct page *page) | 1427 | int nfs_set_page_dirty(struct page *page) |
1428 | { | 1428 | { |
1429 | struct address_space *mapping = page->mapping; | 1429 | struct address_space *mapping = page->mapping; |
1430 | struct inode *inode; | 1430 | struct inode *inode; |
1431 | spinlock_t *req_lock; | 1431 | spinlock_t *req_lock; |
1432 | struct nfs_page *req; | 1432 | struct nfs_page *req; |
1433 | int ret; | 1433 | int ret; |
1434 | 1434 | ||
1435 | if (!mapping) | 1435 | if (!mapping) |
1436 | goto out_raced; | 1436 | goto out_raced; |
1437 | inode = mapping->host; | 1437 | inode = mapping->host; |
1438 | if (!inode) | 1438 | if (!inode) |
1439 | goto out_raced; | 1439 | goto out_raced; |
1440 | req_lock = &NFS_I(inode)->req_lock; | 1440 | req_lock = &NFS_I(inode)->req_lock; |
1441 | spin_lock(req_lock); | 1441 | spin_lock(req_lock); |
1442 | req = nfs_page_find_request_locked(page); | 1442 | req = nfs_page_find_request_locked(page); |
1443 | if (req != NULL) { | 1443 | if (req != NULL) { |
1444 | /* Mark any existing write requests for flushing */ | 1444 | /* Mark any existing write requests for flushing */ |
1445 | ret = !test_and_set_bit(PG_NEED_FLUSH, &req->wb_flags); | 1445 | ret = !test_and_set_bit(PG_NEED_FLUSH, &req->wb_flags); |
1446 | spin_unlock(req_lock); | 1446 | spin_unlock(req_lock); |
1447 | nfs_release_request(req); | 1447 | nfs_release_request(req); |
1448 | return ret; | 1448 | return ret; |
1449 | } | 1449 | } |
1450 | ret = __set_page_dirty_nobuffers(page); | 1450 | ret = __set_page_dirty_nobuffers(page); |
1451 | spin_unlock(req_lock); | 1451 | spin_unlock(req_lock); |
1452 | return ret; | 1452 | return ret; |
1453 | out_raced: | 1453 | out_raced: |
1454 | return !TestSetPageDirty(page); | 1454 | return !TestSetPageDirty(page); |
1455 | } | 1455 | } |
1456 | 1456 | ||
1457 | 1457 | ||
1458 | int __init nfs_init_writepagecache(void) | 1458 | int __init nfs_init_writepagecache(void) |
1459 | { | 1459 | { |
1460 | nfs_wdata_cachep = kmem_cache_create("nfs_write_data", | 1460 | nfs_wdata_cachep = kmem_cache_create("nfs_write_data", |
1461 | sizeof(struct nfs_write_data), | 1461 | sizeof(struct nfs_write_data), |
1462 | 0, SLAB_HWCACHE_ALIGN, | 1462 | 0, SLAB_HWCACHE_ALIGN, |
1463 | NULL, NULL); | 1463 | NULL, NULL); |
1464 | if (nfs_wdata_cachep == NULL) | 1464 | if (nfs_wdata_cachep == NULL) |
1465 | return -ENOMEM; | 1465 | return -ENOMEM; |
1466 | 1466 | ||
1467 | nfs_wdata_mempool = mempool_create_slab_pool(MIN_POOL_WRITE, | 1467 | nfs_wdata_mempool = mempool_create_slab_pool(MIN_POOL_WRITE, |
1468 | nfs_wdata_cachep); | 1468 | nfs_wdata_cachep); |
1469 | if (nfs_wdata_mempool == NULL) | 1469 | if (nfs_wdata_mempool == NULL) |
1470 | return -ENOMEM; | 1470 | return -ENOMEM; |
1471 | 1471 | ||
1472 | nfs_commit_mempool = mempool_create_slab_pool(MIN_POOL_COMMIT, | 1472 | nfs_commit_mempool = mempool_create_slab_pool(MIN_POOL_COMMIT, |
1473 | nfs_wdata_cachep); | 1473 | nfs_wdata_cachep); |
1474 | if (nfs_commit_mempool == NULL) | 1474 | if (nfs_commit_mempool == NULL) |
1475 | return -ENOMEM; | 1475 | return -ENOMEM; |
1476 | 1476 | ||
1477 | /* | 1477 | /* |
1478 | * NFS congestion size, scale with available memory. | 1478 | * NFS congestion size, scale with available memory. |
1479 | * | 1479 | * |
1480 | * 64MB: 8192k | 1480 | * 64MB: 8192k |
1481 | * 128MB: 11585k | 1481 | * 128MB: 11585k |
1482 | * 256MB: 16384k | 1482 | * 256MB: 16384k |
1483 | * 512MB: 23170k | 1483 | * 512MB: 23170k |
1484 | * 1GB: 32768k | 1484 | * 1GB: 32768k |
1485 | * 2GB: 46340k | 1485 | * 2GB: 46340k |
1486 | * 4GB: 65536k | 1486 | * 4GB: 65536k |
1487 | * 8GB: 92681k | 1487 | * 8GB: 92681k |
1488 | * 16GB: 131072k | 1488 | * 16GB: 131072k |
1489 | * | 1489 | * |
1490 | * This allows larger machines to have larger/more transfers. | 1490 | * This allows larger machines to have larger/more transfers. |
1491 | * Limit the default to 256M | 1491 | * Limit the default to 256M |
1492 | */ | 1492 | */ |
1493 | nfs_congestion_kb = (16*int_sqrt(totalram_pages)) << (PAGE_SHIFT-10); | 1493 | nfs_congestion_kb = (16*int_sqrt(totalram_pages)) << (PAGE_SHIFT-10); |
1494 | if (nfs_congestion_kb > 256*1024) | 1494 | if (nfs_congestion_kb > 256*1024) |
1495 | nfs_congestion_kb = 256*1024; | 1495 | nfs_congestion_kb = 256*1024; |
1496 | 1496 | ||
1497 | return 0; | 1497 | return 0; |
1498 | } | 1498 | } |
1499 | 1499 | ||
1500 | void nfs_destroy_writepagecache(void) | 1500 | void nfs_destroy_writepagecache(void) |
1501 | { | 1501 | { |
1502 | mempool_destroy(nfs_commit_mempool); | 1502 | mempool_destroy(nfs_commit_mempool); |
1503 | mempool_destroy(nfs_wdata_mempool); | 1503 | mempool_destroy(nfs_wdata_mempool); |
1504 | kmem_cache_destroy(nfs_wdata_cachep); | 1504 | kmem_cache_destroy(nfs_wdata_cachep); |
1505 | } | 1505 | } |
1506 | 1506 | ||
1507 | 1507 |