diff options
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r-- | fs/nfs/write.c | 616 |
1 files changed, 312 insertions, 304 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index f6675d2c386c..345492e78643 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -57,10 +57,13 @@ | |||
57 | #include <linux/nfs_fs.h> | 57 | #include <linux/nfs_fs.h> |
58 | #include <linux/nfs_mount.h> | 58 | #include <linux/nfs_mount.h> |
59 | #include <linux/nfs_page.h> | 59 | #include <linux/nfs_page.h> |
60 | #include <linux/backing-dev.h> | ||
61 | |||
60 | #include <asm/uaccess.h> | 62 | #include <asm/uaccess.h> |
61 | #include <linux/smp_lock.h> | 63 | #include <linux/smp_lock.h> |
62 | 64 | ||
63 | #include "delegation.h" | 65 | #include "delegation.h" |
66 | #include "internal.h" | ||
64 | #include "iostat.h" | 67 | #include "iostat.h" |
65 | 68 | ||
66 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 69 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
@@ -72,18 +75,17 @@ | |||
72 | * Local function declarations | 75 | * Local function declarations |
73 | */ | 76 | */ |
74 | static struct nfs_page * nfs_update_request(struct nfs_open_context*, | 77 | static struct nfs_page * nfs_update_request(struct nfs_open_context*, |
75 | struct inode *, | ||
76 | struct page *, | 78 | struct page *, |
77 | unsigned int, unsigned int); | 79 | unsigned int, unsigned int); |
80 | static void nfs_mark_request_dirty(struct nfs_page *req); | ||
78 | static int nfs_wait_on_write_congestion(struct address_space *, int); | 81 | static int nfs_wait_on_write_congestion(struct address_space *, int); |
79 | static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int); | 82 | static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int); |
80 | static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, | 83 | static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how); |
81 | unsigned int npages, int how); | ||
82 | static const struct rpc_call_ops nfs_write_partial_ops; | 84 | static const struct rpc_call_ops nfs_write_partial_ops; |
83 | static const struct rpc_call_ops nfs_write_full_ops; | 85 | static const struct rpc_call_ops nfs_write_full_ops; |
84 | static const struct rpc_call_ops nfs_commit_ops; | 86 | static const struct rpc_call_ops nfs_commit_ops; |
85 | 87 | ||
86 | static kmem_cache_t *nfs_wdata_cachep; | 88 | static struct kmem_cache *nfs_wdata_cachep; |
87 | static mempool_t *nfs_wdata_mempool; | 89 | static mempool_t *nfs_wdata_mempool; |
88 | static mempool_t *nfs_commit_mempool; | 90 | static mempool_t *nfs_commit_mempool; |
89 | 91 | ||
@@ -91,7 +93,7 @@ static DECLARE_WAIT_QUEUE_HEAD(nfs_write_congestion); | |||
91 | 93 | ||
92 | struct nfs_write_data *nfs_commit_alloc(void) | 94 | struct nfs_write_data *nfs_commit_alloc(void) |
93 | { | 95 | { |
94 | struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, SLAB_NOFS); | 96 | struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS); |
95 | 97 | ||
96 | if (p) { | 98 | if (p) { |
97 | memset(p, 0, sizeof(*p)); | 99 | memset(p, 0, sizeof(*p)); |
@@ -100,17 +102,23 @@ struct nfs_write_data *nfs_commit_alloc(void) | |||
100 | return p; | 102 | return p; |
101 | } | 103 | } |
102 | 104 | ||
103 | void nfs_commit_free(struct nfs_write_data *p) | 105 | void nfs_commit_rcu_free(struct rcu_head *head) |
104 | { | 106 | { |
107 | struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu); | ||
105 | if (p && (p->pagevec != &p->page_array[0])) | 108 | if (p && (p->pagevec != &p->page_array[0])) |
106 | kfree(p->pagevec); | 109 | kfree(p->pagevec); |
107 | mempool_free(p, nfs_commit_mempool); | 110 | mempool_free(p, nfs_commit_mempool); |
108 | } | 111 | } |
109 | 112 | ||
113 | void nfs_commit_free(struct nfs_write_data *wdata) | ||
114 | { | ||
115 | call_rcu_bh(&wdata->task.u.tk_rcu, nfs_commit_rcu_free); | ||
116 | } | ||
117 | |||
110 | struct nfs_write_data *nfs_writedata_alloc(size_t len) | 118 | struct nfs_write_data *nfs_writedata_alloc(size_t len) |
111 | { | 119 | { |
112 | unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | 120 | unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
113 | struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, SLAB_NOFS); | 121 | struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS); |
114 | 122 | ||
115 | if (p) { | 123 | if (p) { |
116 | memset(p, 0, sizeof(*p)); | 124 | memset(p, 0, sizeof(*p)); |
@@ -129,18 +137,47 @@ struct nfs_write_data *nfs_writedata_alloc(size_t len) | |||
129 | return p; | 137 | return p; |
130 | } | 138 | } |
131 | 139 | ||
132 | static void nfs_writedata_free(struct nfs_write_data *p) | 140 | static void nfs_writedata_rcu_free(struct rcu_head *head) |
133 | { | 141 | { |
142 | struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu); | ||
134 | if (p && (p->pagevec != &p->page_array[0])) | 143 | if (p && (p->pagevec != &p->page_array[0])) |
135 | kfree(p->pagevec); | 144 | kfree(p->pagevec); |
136 | mempool_free(p, nfs_wdata_mempool); | 145 | mempool_free(p, nfs_wdata_mempool); |
137 | } | 146 | } |
138 | 147 | ||
148 | static void nfs_writedata_free(struct nfs_write_data *wdata) | ||
149 | { | ||
150 | call_rcu_bh(&wdata->task.u.tk_rcu, nfs_writedata_rcu_free); | ||
151 | } | ||
152 | |||
139 | void nfs_writedata_release(void *wdata) | 153 | void nfs_writedata_release(void *wdata) |
140 | { | 154 | { |
141 | nfs_writedata_free(wdata); | 155 | nfs_writedata_free(wdata); |
142 | } | 156 | } |
143 | 157 | ||
158 | static struct nfs_page *nfs_page_find_request_locked(struct page *page) | ||
159 | { | ||
160 | struct nfs_page *req = NULL; | ||
161 | |||
162 | if (PagePrivate(page)) { | ||
163 | req = (struct nfs_page *)page_private(page); | ||
164 | if (req != NULL) | ||
165 | atomic_inc(&req->wb_count); | ||
166 | } | ||
167 | return req; | ||
168 | } | ||
169 | |||
170 | static struct nfs_page *nfs_page_find_request(struct page *page) | ||
171 | { | ||
172 | struct nfs_page *req = NULL; | ||
173 | spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock; | ||
174 | |||
175 | spin_lock(req_lock); | ||
176 | req = nfs_page_find_request_locked(page); | ||
177 | spin_unlock(req_lock); | ||
178 | return req; | ||
179 | } | ||
180 | |||
144 | /* Adjust the file length if we're writing beyond the end */ | 181 | /* Adjust the file length if we're writing beyond the end */ |
145 | static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count) | 182 | static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count) |
146 | { | 183 | { |
@@ -162,113 +199,34 @@ static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int c | |||
162 | */ | 199 | */ |
163 | static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int count) | 200 | static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int count) |
164 | { | 201 | { |
165 | loff_t end_offs; | ||
166 | |||
167 | if (PageUptodate(page)) | 202 | if (PageUptodate(page)) |
168 | return; | 203 | return; |
169 | if (base != 0) | 204 | if (base != 0) |
170 | return; | 205 | return; |
171 | if (count == PAGE_CACHE_SIZE) { | 206 | if (count != nfs_page_length(page)) |
172 | SetPageUptodate(page); | ||
173 | return; | 207 | return; |
174 | } | 208 | if (count != PAGE_CACHE_SIZE) |
175 | |||
176 | end_offs = i_size_read(page->mapping->host) - 1; | ||
177 | if (end_offs < 0) | ||
178 | return; | ||
179 | /* Is this the last page? */ | ||
180 | if (page->index != (unsigned long)(end_offs >> PAGE_CACHE_SHIFT)) | ||
181 | return; | ||
182 | /* This is the last page: set PG_uptodate if we cover the entire | ||
183 | * extent of the data, then zero the rest of the page. | ||
184 | */ | ||
185 | if (count == (unsigned int)(end_offs & (PAGE_CACHE_SIZE - 1)) + 1) { | ||
186 | memclear_highpage_flush(page, count, PAGE_CACHE_SIZE - count); | 209 | memclear_highpage_flush(page, count, PAGE_CACHE_SIZE - count); |
187 | SetPageUptodate(page); | 210 | SetPageUptodate(page); |
188 | } | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | * Write a page synchronously. | ||
193 | * Offset is the data offset within the page. | ||
194 | */ | ||
195 | static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode, | ||
196 | struct page *page, unsigned int offset, unsigned int count, | ||
197 | int how) | ||
198 | { | ||
199 | unsigned int wsize = NFS_SERVER(inode)->wsize; | ||
200 | int result, written = 0; | ||
201 | struct nfs_write_data *wdata; | ||
202 | |||
203 | wdata = nfs_writedata_alloc(wsize); | ||
204 | if (!wdata) | ||
205 | return -ENOMEM; | ||
206 | |||
207 | wdata->flags = how; | ||
208 | wdata->cred = ctx->cred; | ||
209 | wdata->inode = inode; | ||
210 | wdata->args.fh = NFS_FH(inode); | ||
211 | wdata->args.context = ctx; | ||
212 | wdata->args.pages = &page; | ||
213 | wdata->args.stable = NFS_FILE_SYNC; | ||
214 | wdata->args.pgbase = offset; | ||
215 | wdata->args.count = wsize; | ||
216 | wdata->res.fattr = &wdata->fattr; | ||
217 | wdata->res.verf = &wdata->verf; | ||
218 | |||
219 | dprintk("NFS: nfs_writepage_sync(%s/%Ld %d@%Ld)\n", | ||
220 | inode->i_sb->s_id, | ||
221 | (long long)NFS_FILEID(inode), | ||
222 | count, (long long)(page_offset(page) + offset)); | ||
223 | |||
224 | set_page_writeback(page); | ||
225 | nfs_begin_data_update(inode); | ||
226 | do { | ||
227 | if (count < wsize) | ||
228 | wdata->args.count = count; | ||
229 | wdata->args.offset = page_offset(page) + wdata->args.pgbase; | ||
230 | |||
231 | result = NFS_PROTO(inode)->write(wdata); | ||
232 | |||
233 | if (result < 0) { | ||
234 | /* Must mark the page invalid after I/O error */ | ||
235 | ClearPageUptodate(page); | ||
236 | goto io_error; | ||
237 | } | ||
238 | if (result < wdata->args.count) | ||
239 | printk(KERN_WARNING "NFS: short write, count=%u, result=%d\n", | ||
240 | wdata->args.count, result); | ||
241 | |||
242 | wdata->args.offset += result; | ||
243 | wdata->args.pgbase += result; | ||
244 | written += result; | ||
245 | count -= result; | ||
246 | nfs_add_stats(inode, NFSIOS_SERVERWRITTENBYTES, result); | ||
247 | } while (count); | ||
248 | /* Update file length */ | ||
249 | nfs_grow_file(page, offset, written); | ||
250 | /* Set the PG_uptodate flag? */ | ||
251 | nfs_mark_uptodate(page, offset, written); | ||
252 | |||
253 | if (PageError(page)) | ||
254 | ClearPageError(page); | ||
255 | |||
256 | io_error: | ||
257 | nfs_end_data_update(inode); | ||
258 | end_page_writeback(page); | ||
259 | nfs_writedata_free(wdata); | ||
260 | return written ? written : result; | ||
261 | } | 211 | } |
262 | 212 | ||
263 | static int nfs_writepage_async(struct nfs_open_context *ctx, | 213 | static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, |
264 | struct inode *inode, struct page *page, | ||
265 | unsigned int offset, unsigned int count) | 214 | unsigned int offset, unsigned int count) |
266 | { | 215 | { |
267 | struct nfs_page *req; | 216 | struct nfs_page *req; |
217 | int ret; | ||
268 | 218 | ||
269 | req = nfs_update_request(ctx, inode, page, offset, count); | 219 | for (;;) { |
270 | if (IS_ERR(req)) | 220 | req = nfs_update_request(ctx, page, offset, count); |
271 | return PTR_ERR(req); | 221 | if (!IS_ERR(req)) |
222 | break; | ||
223 | ret = PTR_ERR(req); | ||
224 | if (ret != -EBUSY) | ||
225 | return ret; | ||
226 | ret = nfs_wb_page(page->mapping->host, page); | ||
227 | if (ret != 0) | ||
228 | return ret; | ||
229 | } | ||
272 | /* Update file length */ | 230 | /* Update file length */ |
273 | nfs_grow_file(page, offset, count); | 231 | nfs_grow_file(page, offset, count); |
274 | /* Set the PG_uptodate flag? */ | 232 | /* Set the PG_uptodate flag? */ |
@@ -287,73 +245,94 @@ static int wb_priority(struct writeback_control *wbc) | |||
287 | } | 245 | } |
288 | 246 | ||
289 | /* | 247 | /* |
248 | * Find an associated nfs write request, and prepare to flush it out | ||
249 | * Returns 1 if there was no write request, or if the request was | ||
250 | * already tagged by nfs_set_page_dirty.Returns 0 if the request | ||
251 | * was not tagged. | ||
252 | * May also return an error if the user signalled nfs_wait_on_request(). | ||
253 | */ | ||
254 | static int nfs_page_mark_flush(struct page *page) | ||
255 | { | ||
256 | struct nfs_page *req; | ||
257 | spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock; | ||
258 | int ret; | ||
259 | |||
260 | spin_lock(req_lock); | ||
261 | for(;;) { | ||
262 | req = nfs_page_find_request_locked(page); | ||
263 | if (req == NULL) { | ||
264 | spin_unlock(req_lock); | ||
265 | return 1; | ||
266 | } | ||
267 | if (nfs_lock_request_dontget(req)) | ||
268 | break; | ||
269 | /* Note: If we hold the page lock, as is the case in nfs_writepage, | ||
270 | * then the call to nfs_lock_request_dontget() will always | ||
271 | * succeed provided that someone hasn't already marked the | ||
272 | * request as dirty (in which case we don't care). | ||
273 | */ | ||
274 | spin_unlock(req_lock); | ||
275 | ret = nfs_wait_on_request(req); | ||
276 | nfs_release_request(req); | ||
277 | if (ret != 0) | ||
278 | return ret; | ||
279 | spin_lock(req_lock); | ||
280 | } | ||
281 | spin_unlock(req_lock); | ||
282 | if (test_and_set_bit(PG_FLUSHING, &req->wb_flags) == 0) { | ||
283 | nfs_mark_request_dirty(req); | ||
284 | set_page_writeback(page); | ||
285 | } | ||
286 | ret = test_bit(PG_NEED_FLUSH, &req->wb_flags); | ||
287 | nfs_unlock_request(req); | ||
288 | return ret; | ||
289 | } | ||
290 | |||
291 | /* | ||
290 | * Write an mmapped page to the server. | 292 | * Write an mmapped page to the server. |
291 | */ | 293 | */ |
292 | int nfs_writepage(struct page *page, struct writeback_control *wbc) | 294 | static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc) |
293 | { | 295 | { |
294 | struct nfs_open_context *ctx; | 296 | struct nfs_open_context *ctx; |
295 | struct inode *inode = page->mapping->host; | 297 | struct inode *inode = page->mapping->host; |
296 | unsigned long end_index; | 298 | unsigned offset; |
297 | unsigned offset = PAGE_CACHE_SIZE; | ||
298 | loff_t i_size = i_size_read(inode); | ||
299 | int inode_referenced = 0; | ||
300 | int priority = wb_priority(wbc); | ||
301 | int err; | 299 | int err; |
302 | 300 | ||
303 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); | 301 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); |
304 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); | 302 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); |
305 | 303 | ||
306 | /* | 304 | err = nfs_page_mark_flush(page); |
307 | * Note: We need to ensure that we have a reference to the inode | 305 | if (err <= 0) |
308 | * if we are to do asynchronous writes. If not, waiting | 306 | goto out; |
309 | * in nfs_wait_on_request() may deadlock with clear_inode(). | 307 | err = 0; |
310 | * | 308 | offset = nfs_page_length(page); |
311 | * If igrab() fails here, then it is in any case safe to | 309 | if (!offset) |
312 | * call nfs_wb_page(), since there will be no pending writes. | ||
313 | */ | ||
314 | if (igrab(inode) != 0) | ||
315 | inode_referenced = 1; | ||
316 | end_index = i_size >> PAGE_CACHE_SHIFT; | ||
317 | |||
318 | /* Ensure we've flushed out any previous writes */ | ||
319 | nfs_wb_page_priority(inode, page, priority); | ||
320 | |||
321 | /* easy case */ | ||
322 | if (page->index < end_index) | ||
323 | goto do_it; | ||
324 | /* things got complicated... */ | ||
325 | offset = i_size & (PAGE_CACHE_SIZE-1); | ||
326 | |||
327 | /* OK, are we completely out? */ | ||
328 | err = 0; /* potential race with truncate - ignore */ | ||
329 | if (page->index >= end_index+1 || !offset) | ||
330 | goto out; | 310 | goto out; |
331 | do_it: | 311 | |
332 | ctx = nfs_find_open_context(inode, NULL, FMODE_WRITE); | 312 | ctx = nfs_find_open_context(inode, NULL, FMODE_WRITE); |
333 | if (ctx == NULL) { | 313 | if (ctx == NULL) { |
334 | err = -EBADF; | 314 | err = -EBADF; |
335 | goto out; | 315 | goto out; |
336 | } | 316 | } |
337 | lock_kernel(); | 317 | err = nfs_writepage_setup(ctx, page, 0, offset); |
338 | if (!IS_SYNC(inode) && inode_referenced) { | ||
339 | err = nfs_writepage_async(ctx, inode, page, 0, offset); | ||
340 | if (!wbc->for_writepages) | ||
341 | nfs_flush_inode(inode, 0, 0, wb_priority(wbc)); | ||
342 | } else { | ||
343 | err = nfs_writepage_sync(ctx, inode, page, 0, | ||
344 | offset, priority); | ||
345 | if (err >= 0) { | ||
346 | if (err != offset) | ||
347 | redirty_page_for_writepage(wbc, page); | ||
348 | err = 0; | ||
349 | } | ||
350 | } | ||
351 | unlock_kernel(); | ||
352 | put_nfs_open_context(ctx); | 318 | put_nfs_open_context(ctx); |
319 | if (err != 0) | ||
320 | goto out; | ||
321 | err = nfs_page_mark_flush(page); | ||
322 | if (err > 0) | ||
323 | err = 0; | ||
353 | out: | 324 | out: |
325 | if (!wbc->for_writepages) | ||
326 | nfs_flush_mapping(page->mapping, wbc, wb_priority(wbc)); | ||
327 | return err; | ||
328 | } | ||
329 | |||
330 | int nfs_writepage(struct page *page, struct writeback_control *wbc) | ||
331 | { | ||
332 | int err; | ||
333 | |||
334 | err = nfs_writepage_locked(page, wbc); | ||
354 | unlock_page(page); | 335 | unlock_page(page); |
355 | if (inode_referenced) | ||
356 | iput(inode); | ||
357 | return err; | 336 | return err; |
358 | } | 337 | } |
359 | 338 | ||
@@ -377,25 +356,22 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | |||
377 | return 0; | 356 | return 0; |
378 | nfs_wait_on_write_congestion(mapping, 0); | 357 | nfs_wait_on_write_congestion(mapping, 0); |
379 | } | 358 | } |
380 | err = nfs_flush_inode(inode, 0, 0, wb_priority(wbc)); | 359 | err = nfs_flush_mapping(mapping, wbc, wb_priority(wbc)); |
381 | if (err < 0) | 360 | if (err < 0) |
382 | goto out; | 361 | goto out; |
383 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, err); | 362 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, err); |
384 | wbc->nr_to_write -= err; | ||
385 | if (!wbc->nonblocking && wbc->sync_mode == WB_SYNC_ALL) { | 363 | if (!wbc->nonblocking && wbc->sync_mode == WB_SYNC_ALL) { |
386 | err = nfs_wait_on_requests(inode, 0, 0); | 364 | err = nfs_wait_on_requests(inode, 0, 0); |
387 | if (err < 0) | 365 | if (err < 0) |
388 | goto out; | 366 | goto out; |
389 | } | 367 | } |
390 | err = nfs_commit_inode(inode, wb_priority(wbc)); | 368 | err = nfs_commit_inode(inode, wb_priority(wbc)); |
391 | if (err > 0) { | 369 | if (err > 0) |
392 | wbc->nr_to_write -= err; | ||
393 | err = 0; | 370 | err = 0; |
394 | } | ||
395 | out: | 371 | out: |
396 | clear_bit(BDI_write_congested, &bdi->state); | 372 | clear_bit(BDI_write_congested, &bdi->state); |
397 | wake_up_all(&nfs_write_congestion); | 373 | wake_up_all(&nfs_write_congestion); |
398 | writeback_congestion_end(); | 374 | congestion_end(WRITE); |
399 | return err; | 375 | return err; |
400 | } | 376 | } |
401 | 377 | ||
@@ -418,6 +394,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | |||
418 | nfsi->change_attr++; | 394 | nfsi->change_attr++; |
419 | } | 395 | } |
420 | SetPagePrivate(req->wb_page); | 396 | SetPagePrivate(req->wb_page); |
397 | set_page_private(req->wb_page, (unsigned long)req); | ||
421 | nfsi->npages++; | 398 | nfsi->npages++; |
422 | atomic_inc(&req->wb_count); | 399 | atomic_inc(&req->wb_count); |
423 | return 0; | 400 | return 0; |
@@ -434,6 +411,7 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
434 | BUG_ON (!NFS_WBACK_BUSY(req)); | 411 | BUG_ON (!NFS_WBACK_BUSY(req)); |
435 | 412 | ||
436 | spin_lock(&nfsi->req_lock); | 413 | spin_lock(&nfsi->req_lock); |
414 | set_page_private(req->wb_page, 0); | ||
437 | ClearPagePrivate(req->wb_page); | 415 | ClearPagePrivate(req->wb_page); |
438 | radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); | 416 | radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); |
439 | nfsi->npages--; | 417 | nfsi->npages--; |
@@ -448,33 +426,6 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
448 | } | 426 | } |
449 | 427 | ||
450 | /* | 428 | /* |
451 | * Find a request | ||
452 | */ | ||
453 | static inline struct nfs_page * | ||
454 | _nfs_find_request(struct inode *inode, unsigned long index) | ||
455 | { | ||
456 | struct nfs_inode *nfsi = NFS_I(inode); | ||
457 | struct nfs_page *req; | ||
458 | |||
459 | req = (struct nfs_page*)radix_tree_lookup(&nfsi->nfs_page_tree, index); | ||
460 | if (req) | ||
461 | atomic_inc(&req->wb_count); | ||
462 | return req; | ||
463 | } | ||
464 | |||
465 | static struct nfs_page * | ||
466 | nfs_find_request(struct inode *inode, unsigned long index) | ||
467 | { | ||
468 | struct nfs_page *req; | ||
469 | struct nfs_inode *nfsi = NFS_I(inode); | ||
470 | |||
471 | spin_lock(&nfsi->req_lock); | ||
472 | req = _nfs_find_request(inode, index); | ||
473 | spin_unlock(&nfsi->req_lock); | ||
474 | return req; | ||
475 | } | ||
476 | |||
477 | /* | ||
478 | * Add a request to the inode's dirty list. | 429 | * Add a request to the inode's dirty list. |
479 | */ | 430 | */ |
480 | static void | 431 | static void |
@@ -489,8 +440,14 @@ nfs_mark_request_dirty(struct nfs_page *req) | |||
489 | nfs_list_add_request(req, &nfsi->dirty); | 440 | nfs_list_add_request(req, &nfsi->dirty); |
490 | nfsi->ndirty++; | 441 | nfsi->ndirty++; |
491 | spin_unlock(&nfsi->req_lock); | 442 | spin_unlock(&nfsi->req_lock); |
492 | inc_zone_page_state(req->wb_page, NR_FILE_DIRTY); | 443 | __mark_inode_dirty(inode, I_DIRTY_PAGES); |
493 | mark_inode_dirty(inode); | 444 | } |
445 | |||
446 | static void | ||
447 | nfs_redirty_request(struct nfs_page *req) | ||
448 | { | ||
449 | clear_bit(PG_FLUSHING, &req->wb_flags); | ||
450 | __set_page_dirty_nobuffers(req->wb_page); | ||
494 | } | 451 | } |
495 | 452 | ||
496 | /* | 453 | /* |
@@ -499,8 +456,7 @@ nfs_mark_request_dirty(struct nfs_page *req) | |||
499 | static inline int | 456 | static inline int |
500 | nfs_dirty_request(struct nfs_page *req) | 457 | nfs_dirty_request(struct nfs_page *req) |
501 | { | 458 | { |
502 | struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); | 459 | return test_bit(PG_FLUSHING, &req->wb_flags) == 0; |
503 | return !list_empty(&req->wb_list) && req->wb_list_head == &nfsi->dirty; | ||
504 | } | 460 | } |
505 | 461 | ||
506 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 462 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
@@ -518,7 +474,7 @@ nfs_mark_request_commit(struct nfs_page *req) | |||
518 | nfsi->ncommit++; | 474 | nfsi->ncommit++; |
519 | spin_unlock(&nfsi->req_lock); | 475 | spin_unlock(&nfsi->req_lock); |
520 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 476 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); |
521 | mark_inode_dirty(inode); | 477 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); |
522 | } | 478 | } |
523 | #endif | 479 | #endif |
524 | 480 | ||
@@ -588,36 +544,11 @@ static void nfs_cancel_commit_list(struct list_head *head) | |||
588 | 544 | ||
589 | while(!list_empty(head)) { | 545 | while(!list_empty(head)) { |
590 | req = nfs_list_entry(head->next); | 546 | req = nfs_list_entry(head->next); |
547 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | ||
591 | nfs_list_remove_request(req); | 548 | nfs_list_remove_request(req); |
592 | nfs_inode_remove_request(req); | 549 | nfs_inode_remove_request(req); |
593 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 550 | nfs_unlock_request(req); |
594 | nfs_clear_page_writeback(req); | ||
595 | } | ||
596 | } | ||
597 | |||
598 | /* | ||
599 | * nfs_scan_dirty - Scan an inode for dirty requests | ||
600 | * @inode: NFS inode to scan | ||
601 | * @dst: destination list | ||
602 | * @idx_start: lower bound of page->index to scan. | ||
603 | * @npages: idx_start + npages sets the upper bound to scan. | ||
604 | * | ||
605 | * Moves requests from the inode's dirty page list. | ||
606 | * The requests are *not* checked to ensure that they form a contiguous set. | ||
607 | */ | ||
608 | static int | ||
609 | nfs_scan_dirty(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) | ||
610 | { | ||
611 | struct nfs_inode *nfsi = NFS_I(inode); | ||
612 | int res = 0; | ||
613 | |||
614 | if (nfsi->ndirty != 0) { | ||
615 | res = nfs_scan_lock_dirty(nfsi, dst, idx_start, npages); | ||
616 | nfsi->ndirty -= res; | ||
617 | if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty)) | ||
618 | printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n"); | ||
619 | } | 551 | } |
620 | return res; | ||
621 | } | 552 | } |
622 | 553 | ||
623 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 554 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
@@ -696,27 +627,27 @@ static int nfs_wait_on_write_congestion(struct address_space *mapping, int intr) | |||
696 | * Note: Should always be called with the Page Lock held! | 627 | * Note: Should always be called with the Page Lock held! |
697 | */ | 628 | */ |
698 | static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | 629 | static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, |
699 | struct inode *inode, struct page *page, | 630 | struct page *page, unsigned int offset, unsigned int bytes) |
700 | unsigned int offset, unsigned int bytes) | ||
701 | { | 631 | { |
702 | struct nfs_server *server = NFS_SERVER(inode); | 632 | struct inode *inode = page->mapping->host; |
703 | struct nfs_inode *nfsi = NFS_I(inode); | 633 | struct nfs_inode *nfsi = NFS_I(inode); |
704 | struct nfs_page *req, *new = NULL; | 634 | struct nfs_page *req, *new = NULL; |
705 | unsigned long rqend, end; | 635 | unsigned long rqend, end; |
706 | 636 | ||
707 | end = offset + bytes; | 637 | end = offset + bytes; |
708 | 638 | ||
709 | if (nfs_wait_on_write_congestion(page->mapping, server->flags & NFS_MOUNT_INTR)) | 639 | if (nfs_wait_on_write_congestion(page->mapping, NFS_SERVER(inode)->flags & NFS_MOUNT_INTR)) |
710 | return ERR_PTR(-ERESTARTSYS); | 640 | return ERR_PTR(-ERESTARTSYS); |
711 | for (;;) { | 641 | for (;;) { |
712 | /* Loop over all inode entries and see if we find | 642 | /* Loop over all inode entries and see if we find |
713 | * A request for the page we wish to update | 643 | * A request for the page we wish to update |
714 | */ | 644 | */ |
715 | spin_lock(&nfsi->req_lock); | 645 | spin_lock(&nfsi->req_lock); |
716 | req = _nfs_find_request(inode, page->index); | 646 | req = nfs_page_find_request_locked(page); |
717 | if (req) { | 647 | if (req) { |
718 | if (!nfs_lock_request_dontget(req)) { | 648 | if (!nfs_lock_request_dontget(req)) { |
719 | int error; | 649 | int error; |
650 | |||
720 | spin_unlock(&nfsi->req_lock); | 651 | spin_unlock(&nfsi->req_lock); |
721 | error = nfs_wait_on_request(req); | 652 | error = nfs_wait_on_request(req); |
722 | nfs_release_request(req); | 653 | nfs_release_request(req); |
@@ -743,7 +674,6 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
743 | return ERR_PTR(error); | 674 | return ERR_PTR(error); |
744 | } | 675 | } |
745 | spin_unlock(&nfsi->req_lock); | 676 | spin_unlock(&nfsi->req_lock); |
746 | nfs_mark_request_dirty(new); | ||
747 | return new; | 677 | return new; |
748 | } | 678 | } |
749 | spin_unlock(&nfsi->req_lock); | 679 | spin_unlock(&nfsi->req_lock); |
@@ -784,9 +714,8 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
784 | int nfs_flush_incompatible(struct file *file, struct page *page) | 714 | int nfs_flush_incompatible(struct file *file, struct page *page) |
785 | { | 715 | { |
786 | struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; | 716 | struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; |
787 | struct inode *inode = page->mapping->host; | ||
788 | struct nfs_page *req; | 717 | struct nfs_page *req; |
789 | int status = 0; | 718 | int do_flush, status; |
790 | /* | 719 | /* |
791 | * Look for a request corresponding to this page. If there | 720 | * Look for a request corresponding to this page. If there |
792 | * is one, and it belongs to another file, we flush it out | 721 | * is one, and it belongs to another file, we flush it out |
@@ -795,13 +724,18 @@ int nfs_flush_incompatible(struct file *file, struct page *page) | |||
795 | * Also do the same if we find a request from an existing | 724 | * Also do the same if we find a request from an existing |
796 | * dropped page. | 725 | * dropped page. |
797 | */ | 726 | */ |
798 | req = nfs_find_request(inode, page->index); | 727 | do { |
799 | if (req) { | 728 | req = nfs_page_find_request(page); |
800 | if (req->wb_page != page || ctx != req->wb_context) | 729 | if (req == NULL) |
801 | status = nfs_wb_page(inode, page); | 730 | return 0; |
731 | do_flush = req->wb_page != page || req->wb_context != ctx | ||
732 | || !nfs_dirty_request(req); | ||
802 | nfs_release_request(req); | 733 | nfs_release_request(req); |
803 | } | 734 | if (!do_flush) |
804 | return (status < 0) ? status : 0; | 735 | return 0; |
736 | status = nfs_wb_page(page->mapping->host, page); | ||
737 | } while (status == 0); | ||
738 | return status; | ||
805 | } | 739 | } |
806 | 740 | ||
807 | /* | 741 | /* |
@@ -815,72 +749,27 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
815 | { | 749 | { |
816 | struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; | 750 | struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; |
817 | struct inode *inode = page->mapping->host; | 751 | struct inode *inode = page->mapping->host; |
818 | struct nfs_page *req; | ||
819 | int status = 0; | 752 | int status = 0; |
820 | 753 | ||
821 | nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE); | 754 | nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE); |
822 | 755 | ||
823 | dprintk("NFS: nfs_updatepage(%s/%s %d@%Ld)\n", | 756 | dprintk("NFS: nfs_updatepage(%s/%s %d@%Ld)\n", |
824 | file->f_dentry->d_parent->d_name.name, | 757 | file->f_path.dentry->d_parent->d_name.name, |
825 | file->f_dentry->d_name.name, count, | 758 | file->f_path.dentry->d_name.name, count, |
826 | (long long)(page_offset(page) +offset)); | 759 | (long long)(page_offset(page) +offset)); |
827 | 760 | ||
828 | if (IS_SYNC(inode)) { | ||
829 | status = nfs_writepage_sync(ctx, inode, page, offset, count, 0); | ||
830 | if (status > 0) { | ||
831 | if (offset == 0 && status == PAGE_CACHE_SIZE) | ||
832 | SetPageUptodate(page); | ||
833 | return 0; | ||
834 | } | ||
835 | return status; | ||
836 | } | ||
837 | |||
838 | /* If we're not using byte range locks, and we know the page | 761 | /* If we're not using byte range locks, and we know the page |
839 | * is entirely in cache, it may be more efficient to avoid | 762 | * is entirely in cache, it may be more efficient to avoid |
840 | * fragmenting write requests. | 763 | * fragmenting write requests. |
841 | */ | 764 | */ |
842 | if (PageUptodate(page) && inode->i_flock == NULL && !(file->f_mode & O_SYNC)) { | 765 | if (PageUptodate(page) && inode->i_flock == NULL && !(file->f_mode & O_SYNC)) { |
843 | loff_t end_offs = i_size_read(inode) - 1; | 766 | count = max(count + offset, nfs_page_length(page)); |
844 | unsigned long end_index = end_offs >> PAGE_CACHE_SHIFT; | ||
845 | |||
846 | count += offset; | ||
847 | offset = 0; | 767 | offset = 0; |
848 | if (unlikely(end_offs < 0)) { | ||
849 | /* Do nothing */ | ||
850 | } else if (page->index == end_index) { | ||
851 | unsigned int pglen; | ||
852 | pglen = (unsigned int)(end_offs & (PAGE_CACHE_SIZE-1)) + 1; | ||
853 | if (count < pglen) | ||
854 | count = pglen; | ||
855 | } else if (page->index < end_index) | ||
856 | count = PAGE_CACHE_SIZE; | ||
857 | } | 768 | } |
858 | 769 | ||
859 | /* | 770 | status = nfs_writepage_setup(ctx, page, offset, count); |
860 | * Try to find an NFS request corresponding to this page | 771 | __set_page_dirty_nobuffers(page); |
861 | * and update it. | ||
862 | * If the existing request cannot be updated, we must flush | ||
863 | * it out now. | ||
864 | */ | ||
865 | do { | ||
866 | req = nfs_update_request(ctx, inode, page, offset, count); | ||
867 | status = (IS_ERR(req)) ? PTR_ERR(req) : 0; | ||
868 | if (status != -EBUSY) | ||
869 | break; | ||
870 | /* Request could not be updated. Flush it out and try again */ | ||
871 | status = nfs_wb_page(inode, page); | ||
872 | } while (status >= 0); | ||
873 | if (status < 0) | ||
874 | goto done; | ||
875 | 772 | ||
876 | status = 0; | ||
877 | |||
878 | /* Update file length */ | ||
879 | nfs_grow_file(page, offset, count); | ||
880 | /* Set the PG_uptodate flag? */ | ||
881 | nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); | ||
882 | nfs_unlock_request(req); | ||
883 | done: | ||
884 | dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n", | 773 | dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n", |
885 | status, (long long)i_size_read(inode)); | 774 | status, (long long)i_size_read(inode)); |
886 | if (status < 0) | 775 | if (status < 0) |
@@ -895,7 +784,7 @@ static void nfs_writepage_release(struct nfs_page *req) | |||
895 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 784 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
896 | if (!PageError(req->wb_page)) { | 785 | if (!PageError(req->wb_page)) { |
897 | if (NFS_NEED_RESCHED(req)) { | 786 | if (NFS_NEED_RESCHED(req)) { |
898 | nfs_mark_request_dirty(req); | 787 | nfs_redirty_request(req); |
899 | goto out; | 788 | goto out; |
900 | } else if (NFS_NEED_COMMIT(req)) { | 789 | } else if (NFS_NEED_COMMIT(req)) { |
901 | nfs_mark_request_commit(req); | 790 | nfs_mark_request_commit(req); |
@@ -977,9 +866,7 @@ static void nfs_execute_write(struct nfs_write_data *data) | |||
977 | sigset_t oldset; | 866 | sigset_t oldset; |
978 | 867 | ||
979 | rpc_clnt_sigmask(clnt, &oldset); | 868 | rpc_clnt_sigmask(clnt, &oldset); |
980 | lock_kernel(); | ||
981 | rpc_execute(&data->task); | 869 | rpc_execute(&data->task); |
982 | unlock_kernel(); | ||
983 | rpc_clnt_sigunmask(clnt, &oldset); | 870 | rpc_clnt_sigunmask(clnt, &oldset); |
984 | } | 871 | } |
985 | 872 | ||
@@ -1013,7 +900,6 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, int how) | |||
1013 | atomic_set(&req->wb_complete, requests); | 900 | atomic_set(&req->wb_complete, requests); |
1014 | 901 | ||
1015 | ClearPageError(page); | 902 | ClearPageError(page); |
1016 | set_page_writeback(page); | ||
1017 | offset = 0; | 903 | offset = 0; |
1018 | nbytes = req->wb_bytes; | 904 | nbytes = req->wb_bytes; |
1019 | do { | 905 | do { |
@@ -1041,9 +927,9 @@ out_bad: | |||
1041 | while (!list_empty(&list)) { | 927 | while (!list_empty(&list)) { |
1042 | data = list_entry(list.next, struct nfs_write_data, pages); | 928 | data = list_entry(list.next, struct nfs_write_data, pages); |
1043 | list_del(&data->pages); | 929 | list_del(&data->pages); |
1044 | nfs_writedata_free(data); | 930 | nfs_writedata_release(data); |
1045 | } | 931 | } |
1046 | nfs_mark_request_dirty(req); | 932 | nfs_redirty_request(req); |
1047 | nfs_clear_page_writeback(req); | 933 | nfs_clear_page_writeback(req); |
1048 | return -ENOMEM; | 934 | return -ENOMEM; |
1049 | } | 935 | } |
@@ -1074,7 +960,6 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, int how) | |||
1074 | nfs_list_remove_request(req); | 960 | nfs_list_remove_request(req); |
1075 | nfs_list_add_request(req, &data->pages); | 961 | nfs_list_add_request(req, &data->pages); |
1076 | ClearPageError(req->wb_page); | 962 | ClearPageError(req->wb_page); |
1077 | set_page_writeback(req->wb_page); | ||
1078 | *pages++ = req->wb_page; | 963 | *pages++ = req->wb_page; |
1079 | count += req->wb_bytes; | 964 | count += req->wb_bytes; |
1080 | } | 965 | } |
@@ -1089,7 +974,7 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, int how) | |||
1089 | while (!list_empty(head)) { | 974 | while (!list_empty(head)) { |
1090 | struct nfs_page *req = nfs_list_entry(head->next); | 975 | struct nfs_page *req = nfs_list_entry(head->next); |
1091 | nfs_list_remove_request(req); | 976 | nfs_list_remove_request(req); |
1092 | nfs_mark_request_dirty(req); | 977 | nfs_redirty_request(req); |
1093 | nfs_clear_page_writeback(req); | 978 | nfs_clear_page_writeback(req); |
1094 | } | 979 | } |
1095 | return -ENOMEM; | 980 | return -ENOMEM; |
@@ -1124,7 +1009,7 @@ out_err: | |||
1124 | while (!list_empty(head)) { | 1009 | while (!list_empty(head)) { |
1125 | req = nfs_list_entry(head->next); | 1010 | req = nfs_list_entry(head->next); |
1126 | nfs_list_remove_request(req); | 1011 | nfs_list_remove_request(req); |
1127 | nfs_mark_request_dirty(req); | 1012 | nfs_redirty_request(req); |
1128 | nfs_clear_page_writeback(req); | 1013 | nfs_clear_page_writeback(req); |
1129 | } | 1014 | } |
1130 | return error; | 1015 | return error; |
@@ -1440,7 +1325,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1440 | } | 1325 | } |
1441 | /* We have a mismatch. Write the page again */ | 1326 | /* We have a mismatch. Write the page again */ |
1442 | dprintk(" mismatch\n"); | 1327 | dprintk(" mismatch\n"); |
1443 | nfs_mark_request_dirty(req); | 1328 | nfs_redirty_request(req); |
1444 | next: | 1329 | next: |
1445 | nfs_clear_page_writeback(req); | 1330 | nfs_clear_page_writeback(req); |
1446 | } | 1331 | } |
@@ -1457,18 +1342,17 @@ static inline int nfs_commit_list(struct inode *inode, struct list_head *head, i | |||
1457 | } | 1342 | } |
1458 | #endif | 1343 | #endif |
1459 | 1344 | ||
1460 | static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, | 1345 | static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how) |
1461 | unsigned int npages, int how) | ||
1462 | { | 1346 | { |
1463 | struct nfs_inode *nfsi = NFS_I(inode); | 1347 | struct nfs_inode *nfsi = NFS_I(mapping->host); |
1464 | LIST_HEAD(head); | 1348 | LIST_HEAD(head); |
1465 | int res; | 1349 | long res; |
1466 | 1350 | ||
1467 | spin_lock(&nfsi->req_lock); | 1351 | spin_lock(&nfsi->req_lock); |
1468 | res = nfs_scan_dirty(inode, &head, idx_start, npages); | 1352 | res = nfs_scan_dirty(mapping, wbc, &head); |
1469 | spin_unlock(&nfsi->req_lock); | 1353 | spin_unlock(&nfsi->req_lock); |
1470 | if (res) { | 1354 | if (res) { |
1471 | int error = nfs_flush_list(inode, &head, res, how); | 1355 | int error = nfs_flush_list(mapping->host, &head, res, how); |
1472 | if (error < 0) | 1356 | if (error < 0) |
1473 | return error; | 1357 | return error; |
1474 | } | 1358 | } |
@@ -1494,38 +1378,62 @@ int nfs_commit_inode(struct inode *inode, int how) | |||
1494 | } | 1378 | } |
1495 | #endif | 1379 | #endif |
1496 | 1380 | ||
1497 | int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start, | 1381 | long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_control *wbc, int how) |
1498 | unsigned int npages, int how) | ||
1499 | { | 1382 | { |
1383 | struct inode *inode = mapping->host; | ||
1500 | struct nfs_inode *nfsi = NFS_I(inode); | 1384 | struct nfs_inode *nfsi = NFS_I(inode); |
1385 | unsigned long idx_start, idx_end; | ||
1386 | unsigned int npages = 0; | ||
1501 | LIST_HEAD(head); | 1387 | LIST_HEAD(head); |
1502 | int nocommit = how & FLUSH_NOCOMMIT; | 1388 | int nocommit = how & FLUSH_NOCOMMIT; |
1503 | int pages, ret; | 1389 | long pages, ret; |
1504 | 1390 | ||
1391 | /* FIXME */ | ||
1392 | if (wbc->range_cyclic) | ||
1393 | idx_start = 0; | ||
1394 | else { | ||
1395 | idx_start = wbc->range_start >> PAGE_CACHE_SHIFT; | ||
1396 | idx_end = wbc->range_end >> PAGE_CACHE_SHIFT; | ||
1397 | if (idx_end > idx_start) { | ||
1398 | unsigned long l_npages = 1 + idx_end - idx_start; | ||
1399 | npages = l_npages; | ||
1400 | if (sizeof(npages) != sizeof(l_npages) && | ||
1401 | (unsigned long)npages != l_npages) | ||
1402 | npages = 0; | ||
1403 | } | ||
1404 | } | ||
1505 | how &= ~FLUSH_NOCOMMIT; | 1405 | how &= ~FLUSH_NOCOMMIT; |
1506 | spin_lock(&nfsi->req_lock); | 1406 | spin_lock(&nfsi->req_lock); |
1507 | do { | 1407 | do { |
1408 | wbc->pages_skipped = 0; | ||
1508 | ret = nfs_wait_on_requests_locked(inode, idx_start, npages); | 1409 | ret = nfs_wait_on_requests_locked(inode, idx_start, npages); |
1509 | if (ret != 0) | 1410 | if (ret != 0) |
1510 | continue; | 1411 | continue; |
1511 | pages = nfs_scan_dirty(inode, &head, idx_start, npages); | 1412 | pages = nfs_scan_dirty(mapping, wbc, &head); |
1512 | if (pages != 0) { | 1413 | if (pages != 0) { |
1513 | spin_unlock(&nfsi->req_lock); | 1414 | spin_unlock(&nfsi->req_lock); |
1514 | if (how & FLUSH_INVALIDATE) | 1415 | if (how & FLUSH_INVALIDATE) { |
1515 | nfs_cancel_dirty_list(&head); | 1416 | nfs_cancel_dirty_list(&head); |
1516 | else | 1417 | ret = pages; |
1418 | } else | ||
1517 | ret = nfs_flush_list(inode, &head, pages, how); | 1419 | ret = nfs_flush_list(inode, &head, pages, how); |
1518 | spin_lock(&nfsi->req_lock); | 1420 | spin_lock(&nfsi->req_lock); |
1519 | continue; | 1421 | continue; |
1520 | } | 1422 | } |
1423 | if (wbc->pages_skipped != 0) | ||
1424 | continue; | ||
1521 | if (nocommit) | 1425 | if (nocommit) |
1522 | break; | 1426 | break; |
1523 | pages = nfs_scan_commit(inode, &head, idx_start, npages); | 1427 | pages = nfs_scan_commit(inode, &head, idx_start, npages); |
1524 | if (pages == 0) | 1428 | if (pages == 0) { |
1429 | if (wbc->pages_skipped != 0) | ||
1430 | continue; | ||
1525 | break; | 1431 | break; |
1432 | } | ||
1526 | if (how & FLUSH_INVALIDATE) { | 1433 | if (how & FLUSH_INVALIDATE) { |
1527 | spin_unlock(&nfsi->req_lock); | 1434 | spin_unlock(&nfsi->req_lock); |
1528 | nfs_cancel_commit_list(&head); | 1435 | nfs_cancel_commit_list(&head); |
1436 | ret = pages; | ||
1529 | spin_lock(&nfsi->req_lock); | 1437 | spin_lock(&nfsi->req_lock); |
1530 | continue; | 1438 | continue; |
1531 | } | 1439 | } |
@@ -1538,6 +1446,106 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start, | |||
1538 | return ret; | 1446 | return ret; |
1539 | } | 1447 | } |
1540 | 1448 | ||
1449 | /* | ||
1450 | * flush the inode to disk. | ||
1451 | */ | ||
1452 | int nfs_wb_all(struct inode *inode) | ||
1453 | { | ||
1454 | struct address_space *mapping = inode->i_mapping; | ||
1455 | struct writeback_control wbc = { | ||
1456 | .bdi = mapping->backing_dev_info, | ||
1457 | .sync_mode = WB_SYNC_ALL, | ||
1458 | .nr_to_write = LONG_MAX, | ||
1459 | .for_writepages = 1, | ||
1460 | .range_cyclic = 1, | ||
1461 | }; | ||
1462 | int ret; | ||
1463 | |||
1464 | ret = generic_writepages(mapping, &wbc); | ||
1465 | if (ret < 0) | ||
1466 | goto out; | ||
1467 | ret = nfs_sync_mapping_wait(mapping, &wbc, 0); | ||
1468 | if (ret >= 0) | ||
1469 | return 0; | ||
1470 | out: | ||
1471 | __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); | ||
1472 | return ret; | ||
1473 | } | ||
1474 | |||
1475 | int nfs_sync_mapping_range(struct address_space *mapping, loff_t range_start, loff_t range_end, int how) | ||
1476 | { | ||
1477 | struct writeback_control wbc = { | ||
1478 | .bdi = mapping->backing_dev_info, | ||
1479 | .sync_mode = WB_SYNC_ALL, | ||
1480 | .nr_to_write = LONG_MAX, | ||
1481 | .range_start = range_start, | ||
1482 | .range_end = range_end, | ||
1483 | .for_writepages = 1, | ||
1484 | }; | ||
1485 | int ret; | ||
1486 | |||
1487 | if (!(how & FLUSH_NOWRITEPAGE)) { | ||
1488 | ret = generic_writepages(mapping, &wbc); | ||
1489 | if (ret < 0) | ||
1490 | goto out; | ||
1491 | } | ||
1492 | ret = nfs_sync_mapping_wait(mapping, &wbc, how); | ||
1493 | if (ret >= 0) | ||
1494 | return 0; | ||
1495 | out: | ||
1496 | __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); | ||
1497 | return ret; | ||
1498 | } | ||
1499 | |||
1500 | int nfs_wb_page_priority(struct inode *inode, struct page *page, int how) | ||
1501 | { | ||
1502 | loff_t range_start = page_offset(page); | ||
1503 | loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); | ||
1504 | struct writeback_control wbc = { | ||
1505 | .bdi = page->mapping->backing_dev_info, | ||
1506 | .sync_mode = WB_SYNC_ALL, | ||
1507 | .nr_to_write = LONG_MAX, | ||
1508 | .range_start = range_start, | ||
1509 | .range_end = range_end, | ||
1510 | }; | ||
1511 | int ret; | ||
1512 | |||
1513 | BUG_ON(!PageLocked(page)); | ||
1514 | if (!(how & FLUSH_NOWRITEPAGE) && clear_page_dirty_for_io(page)) { | ||
1515 | ret = nfs_writepage_locked(page, &wbc); | ||
1516 | if (ret < 0) | ||
1517 | goto out; | ||
1518 | } | ||
1519 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); | ||
1520 | if (ret >= 0) | ||
1521 | return 0; | ||
1522 | out: | ||
1523 | __mark_inode_dirty(inode, I_DIRTY_PAGES); | ||
1524 | return ret; | ||
1525 | } | ||
1526 | |||
1527 | /* | ||
1528 | * Write back all requests on one page - we do this before reading it. | ||
1529 | */ | ||
1530 | int nfs_wb_page(struct inode *inode, struct page* page) | ||
1531 | { | ||
1532 | return nfs_wb_page_priority(inode, page, FLUSH_STABLE); | ||
1533 | } | ||
1534 | |||
1535 | int nfs_set_page_dirty(struct page *page) | ||
1536 | { | ||
1537 | struct nfs_page *req; | ||
1538 | |||
1539 | req = nfs_page_find_request(page); | ||
1540 | if (req != NULL) { | ||
1541 | /* Mark any existing write requests for flushing */ | ||
1542 | set_bit(PG_NEED_FLUSH, &req->wb_flags); | ||
1543 | nfs_release_request(req); | ||
1544 | } | ||
1545 | return __set_page_dirty_nobuffers(page); | ||
1546 | } | ||
1547 | |||
1548 | |||
1541 | int __init nfs_init_writepagecache(void) | 1549 | int __init nfs_init_writepagecache(void) |
1542 | { | 1550 | { |
1543 | nfs_wdata_cachep = kmem_cache_create("nfs_write_data", | 1551 | nfs_wdata_cachep = kmem_cache_create("nfs_write_data", |