Blame view

fs/nfs/write.c 44.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   * linux/fs/nfs/write.c
   *
7c85d9007   Trond Myklebust   NFS: Fixup some o...
4
   * Write file data over NFS.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
   *
   * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de>
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
11
12
  #include <linux/types.h>
  #include <linux/slab.h>
  #include <linux/mm.h>
  #include <linux/pagemap.h>
  #include <linux/file.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
  #include <linux/writeback.h>
89a09141d   Peter Zijlstra   [PATCH] nfs: fix ...
14
  #include <linux/swap.h>
074cc1dee   Trond Myklebust   NFS: Add a ->migr...
15
  #include <linux/migrate.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
18
19
20
  
  #include <linux/sunrpc/clnt.h>
  #include <linux/nfs_fs.h>
  #include <linux/nfs_mount.h>
  #include <linux/nfs_page.h>
3fcfab16c   Andrew Morton   [PATCH] separate ...
21
  #include <linux/backing-dev.h>
afeacc8c1   Paul Gortmaker   fs: add export.h ...
22
  #include <linux/export.h>
3fcfab16c   Andrew Morton   [PATCH] separate ...
23

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
  #include <asm/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
  
  #include "delegation.h"
49a70f278   Trond Myklebust   NFS: Cleanup: add...
27
  #include "internal.h"
91d5b4702   Chuck Lever   NFS: add I/O perf...
28
  #include "iostat.h"
def6ed7ef   Andy Adamson   nfs41 write seque...
29
  #include "nfs4_fs.h"
074cc1dee   Trond Myklebust   NFS: Add a ->migr...
30
  #include "fscache.h"
94ad1c80e   Fred Isaman   NFSv4.1: coelesce...
31
  #include "pnfs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
35
36
37
38
39
40
  
  #define NFSDBG_FACILITY		NFSDBG_PAGECACHE
  
  #define MIN_POOL_WRITE		(32)
  #define MIN_POOL_COMMIT		(4)
  
  /*
   * Local function declarations
   */
c63c7b051   Trond Myklebust   NFS: Fix a race w...
41
42
  static void nfs_pageio_init_write(struct nfs_pageio_descriptor *desc,
  				  struct inode *inode, int ioflags);
f8512ad0d   Fred Isaman   nfs: don't ignore...
43
  static void nfs_redirty_request(struct nfs_page *req);
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
44
45
46
  static const struct rpc_call_ops nfs_write_partial_ops;
  static const struct rpc_call_ops nfs_write_full_ops;
  static const struct rpc_call_ops nfs_commit_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47

e18b890bb   Christoph Lameter   [PATCH] slab: rem...
48
  static struct kmem_cache *nfs_wdata_cachep;
3feb2d493   Trond Myklebust   NFS: Uninline nfs...
49
  static mempool_t *nfs_wdata_mempool;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  static mempool_t *nfs_commit_mempool;
c9d8f89d9   Trond Myklebust   NFS: Ensure that ...
51
  struct nfs_write_data *nfs_commitdata_alloc(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
  {
e6b4f8da3   Christoph Lameter   [PATCH] slab: rem...
53
  	struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS);
40859d7ee   Chuck Lever   NFS: support larg...
54

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
59
60
  	if (p) {
  		memset(p, 0, sizeof(*p));
  		INIT_LIST_HEAD(&p->pages);
  	}
  	return p;
  }
e0c2b3801   Fred Isaman   NFSv4.1: filelayo...
61
  EXPORT_SYMBOL_GPL(nfs_commitdata_alloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62

5e4424af9   Trond Myklebust   SUNRPC: Remove no...
63
  void nfs_commit_free(struct nfs_write_data *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  {
40859d7ee   Chuck Lever   NFS: support larg...
65
66
  	if (p && (p->pagevec != &p->page_array[0]))
  		kfree(p->pagevec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
  	mempool_free(p, nfs_commit_mempool);
  }
e0c2b3801   Fred Isaman   NFSv4.1: filelayo...
69
  EXPORT_SYMBOL_GPL(nfs_commit_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70

8d5658c94   Trond Myklebust   NFS: Fix a buffer...
71
  struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
3feb2d493   Trond Myklebust   NFS: Uninline nfs...
72
  {
e6b4f8da3   Christoph Lameter   [PATCH] slab: rem...
73
  	struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS);
3feb2d493   Trond Myklebust   NFS: Uninline nfs...
74
75
76
77
  
  	if (p) {
  		memset(p, 0, sizeof(*p));
  		INIT_LIST_HEAD(&p->pages);
e9f7bee1d   Trond Myklebust   [PATCH] NFS: larg...
78
  		p->npages = pagecount;
0d0b5cb36   Chuck Lever   NFS: Optimize all...
79
80
  		if (pagecount <= ARRAY_SIZE(p->page_array))
  			p->pagevec = p->page_array;
3feb2d493   Trond Myklebust   NFS: Uninline nfs...
81
  		else {
0d0b5cb36   Chuck Lever   NFS: Optimize all...
82
83
  			p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS);
  			if (!p->pagevec) {
3feb2d493   Trond Myklebust   NFS: Uninline nfs...
84
85
86
87
88
89
90
  				mempool_free(p, nfs_wdata_mempool);
  				p = NULL;
  			}
  		}
  	}
  	return p;
  }
1ae88b2e4   Trond Myklebust   NFS: Fix an O_DIR...
91
  void nfs_writedata_free(struct nfs_write_data *p)
3feb2d493   Trond Myklebust   NFS: Uninline nfs...
92
93
94
95
96
  {
  	if (p && (p->pagevec != &p->page_array[0]))
  		kfree(p->pagevec);
  	mempool_free(p, nfs_wdata_mempool);
  }
dce81290e   Trond Myklebust   NFS: Move the pnf...
97
  void nfs_writedata_release(struct nfs_write_data *wdata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  {
5053aa568   Fred Isaman   NFSv4.1: Send lse...
99
  	put_lseg(wdata->lseg);
383ba7193   Trond Myklebust   NFS: Fix a deadlo...
100
  	put_nfs_open_context(wdata->args.context);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
  	nfs_writedata_free(wdata);
  }
7b159fc18   Trond Myklebust   NFS: Fall back to...
103
104
105
106
107
108
  static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error)
  {
  	ctx->error = error;
  	smp_wmb();
  	set_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
  }
277459d2e   Trond Myklebust   NFS: Store pointe...
109
110
111
112
113
114
115
  static struct nfs_page *nfs_page_find_request_locked(struct page *page)
  {
  	struct nfs_page *req = NULL;
  
  	if (PagePrivate(page)) {
  		req = (struct nfs_page *)page_private(page);
  		if (req != NULL)
c03b40246   Trond Myklebust   NFS: Convert stru...
116
  			kref_get(&req->wb_kref);
277459d2e   Trond Myklebust   NFS: Store pointe...
117
118
119
120
121
122
  	}
  	return req;
  }
  
  static struct nfs_page *nfs_page_find_request(struct page *page)
  {
587142f85   Trond Myklebust   NFS: Replace NFS_...
123
  	struct inode *inode = page->mapping->host;
277459d2e   Trond Myklebust   NFS: Store pointe...
124
  	struct nfs_page *req = NULL;
277459d2e   Trond Myklebust   NFS: Store pointe...
125

587142f85   Trond Myklebust   NFS: Replace NFS_...
126
  	spin_lock(&inode->i_lock);
277459d2e   Trond Myklebust   NFS: Store pointe...
127
  	req = nfs_page_find_request_locked(page);
587142f85   Trond Myklebust   NFS: Replace NFS_...
128
  	spin_unlock(&inode->i_lock);
277459d2e   Trond Myklebust   NFS: Store pointe...
129
130
  	return req;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
134
  /* Adjust the file length if we're writing beyond the end */
  static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count)
  {
  	struct inode *inode = page->mapping->host;
a3d01454b   Trond Myklebust   NFS: Remove BKL r...
135
136
  	loff_t end, i_size;
  	pgoff_t end_index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137

a3d01454b   Trond Myklebust   NFS: Remove BKL r...
138
139
140
  	spin_lock(&inode->i_lock);
  	i_size = i_size_read(inode);
  	end_index = (i_size - 1) >> PAGE_CACHE_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
  	if (i_size > 0 && page->index < end_index)
a3d01454b   Trond Myklebust   NFS: Remove BKL r...
142
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
  	end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + ((loff_t)offset+count);
  	if (i_size >= end)
a3d01454b   Trond Myklebust   NFS: Remove BKL r...
145
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  	i_size_write(inode, end);
a3d01454b   Trond Myklebust   NFS: Remove BKL r...
147
148
149
  	nfs_inc_stats(inode, NFSIOS_EXTENDWRITE);
  out:
  	spin_unlock(&inode->i_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
  }
a301b7777   Trond Myklebust   NFS: Don't use Cl...
151
152
153
154
155
156
  /* A writeback failed: mark the page as bad, and invalidate the page cache */
  static void nfs_set_pageerror(struct page *page)
  {
  	SetPageError(page);
  	nfs_zap_mapping(page->mapping->host, page->mapping);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
161
  /* We can set the PG_uptodate flag if we see that a write request
   * covers the full page.
   */
  static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int count)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
164
165
  	if (PageUptodate(page))
  		return;
  	if (base != 0)
  		return;
49a70f278   Trond Myklebust   NFS: Cleanup: add...
166
  	if (count != nfs_page_length(page))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  		return;
49a70f278   Trond Myklebust   NFS: Cleanup: add...
168
  	SetPageUptodate(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
172
  static int wb_priority(struct writeback_control *wbc)
  {
  	if (wbc->for_reclaim)
c63c7b051   Trond Myklebust   NFS: Fix a race w...
173
  		return FLUSH_HIGHPRI | FLUSH_STABLE;
b17621fed   Wu Fengguang   writeback: introd...
174
  	if (wbc->for_kupdate || wbc->for_background)
b31268ac7   Trond Myklebust   FS: Use stable wr...
175
176
  		return FLUSH_LOWPRI | FLUSH_COND_STABLE;
  	return FLUSH_COND_STABLE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
178
179
  }
  
  /*
89a09141d   Peter Zijlstra   [PATCH] nfs: fix ...
180
181
182
183
184
185
186
187
   * NFS congestion control
   */
  
  int nfs_congestion_kb;
  
  #define NFS_CONGESTION_ON_THRESH 	(nfs_congestion_kb >> (PAGE_SHIFT-10))
  #define NFS_CONGESTION_OFF_THRESH	\
  	(NFS_CONGESTION_ON_THRESH - (NFS_CONGESTION_ON_THRESH >> 2))
5a6d41b32   Trond Myklebust   NFS: Ensure PG_wr...
188
  static int nfs_set_page_writeback(struct page *page)
89a09141d   Peter Zijlstra   [PATCH] nfs: fix ...
189
  {
5a6d41b32   Trond Myklebust   NFS: Ensure PG_wr...
190
191
192
  	int ret = test_set_page_writeback(page);
  
  	if (!ret) {
89a09141d   Peter Zijlstra   [PATCH] nfs: fix ...
193
194
  		struct inode *inode = page->mapping->host;
  		struct nfs_server *nfss = NFS_SERVER(inode);
a6305ddb0   Trond Myklebust   NFS: Fix a race w...
195
  		page_cache_get(page);
277866a0e   Peter Zijlstra   nfs: fix congesti...
196
  		if (atomic_long_inc_return(&nfss->writeback) >
8aa7e847d   Jens Axboe   Fix congestion_wa...
197
198
199
200
  				NFS_CONGESTION_ON_THRESH) {
  			set_bdi_congested(&nfss->backing_dev_info,
  						BLK_RW_ASYNC);
  		}
89a09141d   Peter Zijlstra   [PATCH] nfs: fix ...
201
  	}
5a6d41b32   Trond Myklebust   NFS: Ensure PG_wr...
202
  	return ret;
89a09141d   Peter Zijlstra   [PATCH] nfs: fix ...
203
204
205
206
207
208
209
210
  }
  
  static void nfs_end_page_writeback(struct page *page)
  {
  	struct inode *inode = page->mapping->host;
  	struct nfs_server *nfss = NFS_SERVER(inode);
  
  	end_page_writeback(page);
a6305ddb0   Trond Myklebust   NFS: Fix a race w...
211
  	page_cache_release(page);
c4dc4beed   Peter Zijlstra   nfs: remove conge...
212
  	if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH)
8aa7e847d   Jens Axboe   Fix congestion_wa...
213
  		clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC);
89a09141d   Peter Zijlstra   [PATCH] nfs: fix ...
214
  }
cfb506e1d   Trond Myklebust   NFS: Ensure that ...
215
  static struct nfs_page *nfs_find_and_lock_request(struct page *page, bool nonblock)
e261f51f2   Trond Myklebust   NFS: Make nfs_upd...
216
  {
587142f85   Trond Myklebust   NFS: Replace NFS_...
217
  	struct inode *inode = page->mapping->host;
e261f51f2   Trond Myklebust   NFS: Make nfs_upd...
218
  	struct nfs_page *req;
e261f51f2   Trond Myklebust   NFS: Make nfs_upd...
219
  	int ret;
587142f85   Trond Myklebust   NFS: Replace NFS_...
220
  	spin_lock(&inode->i_lock);
074cc1dee   Trond Myklebust   NFS: Add a ->migr...
221
  	for (;;) {
e261f51f2   Trond Myklebust   NFS: Make nfs_upd...
222
  		req = nfs_page_find_request_locked(page);
074cc1dee   Trond Myklebust   NFS: Add a ->migr...
223
224
  		if (req == NULL)
  			break;
acee478af   Trond Myklebust   NFS: Clean up the...
225
  		if (nfs_set_page_tag_locked(req))
e261f51f2   Trond Myklebust   NFS: Make nfs_upd...
226
227
  			break;
  		/* Note: If we hold the page lock, as is the case in nfs_writepage,
acee478af   Trond Myklebust   NFS: Clean up the...
228
  		 *	 then the call to nfs_set_page_tag_locked() will always
e261f51f2   Trond Myklebust   NFS: Make nfs_upd...
229
230
231
  		 *	 succeed provided that someone hasn't already marked the
  		 *	 request as dirty (in which case we don't care).
  		 */
587142f85   Trond Myklebust   NFS: Replace NFS_...
232
  		spin_unlock(&inode->i_lock);
cfb506e1d   Trond Myklebust   NFS: Ensure that ...
233
234
235
236
  		if (!nonblock)
  			ret = nfs_wait_on_request(req);
  		else
  			ret = -EAGAIN;
e261f51f2   Trond Myklebust   NFS: Make nfs_upd...
237
238
  		nfs_release_request(req);
  		if (ret != 0)
074cc1dee   Trond Myklebust   NFS: Add a ->migr...
239
  			return ERR_PTR(ret);
587142f85   Trond Myklebust   NFS: Replace NFS_...
240
  		spin_lock(&inode->i_lock);
e261f51f2   Trond Myklebust   NFS: Make nfs_upd...
241
  	}
587142f85   Trond Myklebust   NFS: Replace NFS_...
242
  	spin_unlock(&inode->i_lock);
074cc1dee   Trond Myklebust   NFS: Add a ->migr...
243
244
245
246
247
248
249
250
  	return req;
  }
  
  /*
   * Find an associated nfs write request, and prepare to flush it out
   * May return an error if the user signalled nfs_wait_on_request().
   */
  static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
cfb506e1d   Trond Myklebust   NFS: Ensure that ...
251
  				struct page *page, bool nonblock)
074cc1dee   Trond Myklebust   NFS: Add a ->migr...
252
253
254
  {
  	struct nfs_page *req;
  	int ret = 0;
cfb506e1d   Trond Myklebust   NFS: Ensure that ...
255
  	req = nfs_find_and_lock_request(page, nonblock);
074cc1dee   Trond Myklebust   NFS: Add a ->migr...
256
257
258
259
260
261
262
263
264
  	if (!req)
  		goto out;
  	ret = PTR_ERR(req);
  	if (IS_ERR(req))
  		goto out;
  
  	ret = nfs_set_page_writeback(page);
  	BUG_ON(ret != 0);
  	BUG_ON(test_bit(PG_CLEAN, &req->wb_flags));
f8512ad0d   Fred Isaman   nfs: don't ignore...
265
266
  	if (!nfs_pageio_add_request(pgio, req)) {
  		nfs_redirty_request(req);
074cc1dee   Trond Myklebust   NFS: Add a ->migr...
267
  		ret = pgio->pg_error;
f8512ad0d   Fred Isaman   nfs: don't ignore...
268
  	}
074cc1dee   Trond Myklebust   NFS: Add a ->migr...
269
270
  out:
  	return ret;
e261f51f2   Trond Myklebust   NFS: Make nfs_upd...
271
  }
f758c8851   Trond Myklebust   NFS: Clean up nfs...
272
  static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  	struct inode *inode = page->mapping->host;
cfb506e1d   Trond Myklebust   NFS: Ensure that ...
275
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276

91d5b4702   Chuck Lever   NFS: add I/O perf...
277
278
  	nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE);
  	nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1);
7fe7f8487   Trond Myklebust   NFS: Avoid a dead...
279
  	nfs_pageio_cond_complete(pgio, page->index);
1b430beee   Wu Fengguang   writeback: remove...
280
  	ret = nfs_page_async_flush(pgio, page, wbc->sync_mode == WB_SYNC_NONE);
cfb506e1d   Trond Myklebust   NFS: Ensure that ...
281
282
283
284
285
  	if (ret == -EAGAIN) {
  		redirty_page_for_writepage(wbc, page);
  		ret = 0;
  	}
  	return ret;
f758c8851   Trond Myklebust   NFS: Clean up nfs...
286
  }
7fe7f8487   Trond Myklebust   NFS: Avoid a dead...
287

f758c8851   Trond Myklebust   NFS: Clean up nfs...
288
289
290
291
292
293
294
  /*
   * Write an mmapped page to the server.
   */
  static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc)
  {
  	struct nfs_pageio_descriptor pgio;
  	int err;
49a70f278   Trond Myklebust   NFS: Cleanup: add...
295

f758c8851   Trond Myklebust   NFS: Clean up nfs...
296
297
298
299
300
301
302
303
  	nfs_pageio_init_write(&pgio, page->mapping->host, wb_priority(wbc));
  	err = nfs_do_writepage(page, wbc, &pgio);
  	nfs_pageio_complete(&pgio);
  	if (err < 0)
  		return err;
  	if (pgio.pg_error < 0)
  		return pgio.pg_error;
  	return 0;
4d770ccf4   Trond Myklebust   NFS: Ensure that ...
304
305
306
307
  }
  
  int nfs_writepage(struct page *page, struct writeback_control *wbc)
  {
f758c8851   Trond Myklebust   NFS: Clean up nfs...
308
  	int ret;
4d770ccf4   Trond Myklebust   NFS: Ensure that ...
309

f758c8851   Trond Myklebust   NFS: Clean up nfs...
310
  	ret = nfs_writepage_locked(page, wbc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
  	unlock_page(page);
f758c8851   Trond Myklebust   NFS: Clean up nfs...
312
313
314
315
316
317
318
319
320
321
  	return ret;
  }
  
  static int nfs_writepages_callback(struct page *page, struct writeback_control *wbc, void *data)
  {
  	int ret;
  
  	ret = nfs_do_writepage(page, wbc, data);
  	unlock_page(page);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
  int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
  	struct inode *inode = mapping->host;
72cb77f4a   Trond Myklebust   NFS: Throttle pag...
326
  	unsigned long *bitlock = &NFS_I(inode)->flags;
c63c7b051   Trond Myklebust   NFS: Fix a race w...
327
  	struct nfs_pageio_descriptor pgio;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
  	int err;
72cb77f4a   Trond Myklebust   NFS: Throttle pag...
329
330
331
332
333
  	/* Stop dirtying of new pages while we sync */
  	err = wait_on_bit_lock(bitlock, NFS_INO_FLUSHING,
  			nfs_wait_bit_killable, TASK_KILLABLE);
  	if (err)
  		goto out_err;
91d5b4702   Chuck Lever   NFS: add I/O perf...
334
  	nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES);
c63c7b051   Trond Myklebust   NFS: Fix a race w...
335
  	nfs_pageio_init_write(&pgio, inode, wb_priority(wbc));
f758c8851   Trond Myklebust   NFS: Clean up nfs...
336
  	err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio);
c63c7b051   Trond Myklebust   NFS: Fix a race w...
337
  	nfs_pageio_complete(&pgio);
72cb77f4a   Trond Myklebust   NFS: Throttle pag...
338
339
340
341
  
  	clear_bit_unlock(NFS_INO_FLUSHING, bitlock);
  	smp_mb__after_clear_bit();
  	wake_up_bit(bitlock, NFS_INO_FLUSHING);
f758c8851   Trond Myklebust   NFS: Clean up nfs...
342
  	if (err < 0)
72cb77f4a   Trond Myklebust   NFS: Throttle pag...
343
344
345
346
  		goto out_err;
  	err = pgio.pg_error;
  	if (err < 0)
  		goto out_err;
c63c7b051   Trond Myklebust   NFS: Fix a race w...
347
  	return 0;
72cb77f4a   Trond Myklebust   NFS: Throttle pag...
348
349
  out_err:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
352
353
354
  }
  
  /*
   * Insert a write request into an inode
   */
e7d39069e   Trond Myklebust   NFS: Clean up nfs...
355
  static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
357
358
  {
  	struct nfs_inode *nfsi = NFS_I(inode);
  	int error;
e7d39069e   Trond Myklebust   NFS: Clean up nfs...
359
360
361
362
363
364
365
366
  	error = radix_tree_preload(GFP_NOFS);
  	if (error != 0)
  		goto out;
  
  	/* Lock the request! */
  	nfs_lock_request_dontget(req);
  
  	spin_lock(&inode->i_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
  	error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req);
278525963   Nick Piggin   nfs: use GFP_NOFS...
368
  	BUG_ON(error);
4d65c520f   Trond Myklebust   NFS: Fix a hang i...
369
  	if (!nfsi->npages && nfs_have_delegation(inode, FMODE_WRITE))
a9a4a87a5   Trond Myklebust   NFS: Use the inod...
370
  		inode->i_version++;
2df485a77   Trond Myklebust   nfs: remove extra...
371
  	set_bit(PG_MAPPED, &req->wb_flags);
deb7d6382   Trond Myklebust   NFS: Fix a race w...
372
  	SetPagePrivate(req->wb_page);
277459d2e   Trond Myklebust   NFS: Store pointe...
373
  	set_page_private(req->wb_page, (unsigned long)req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
  	nfsi->npages++;
c03b40246   Trond Myklebust   NFS: Convert stru...
375
  	kref_get(&req->wb_kref);
278525963   Nick Piggin   nfs: use GFP_NOFS...
376
377
  	radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index,
  				NFS_PAGE_TAG_LOCKED);
e7d39069e   Trond Myklebust   NFS: Clean up nfs...
378
379
380
381
  	spin_unlock(&inode->i_lock);
  	radix_tree_preload_end();
  out:
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
383
384
  }
  
  /*
89a09141d   Peter Zijlstra   [PATCH] nfs: fix ...
385
   * Remove a write request from an inode
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
387
388
   */
  static void nfs_inode_remove_request(struct nfs_page *req)
  {
3d4ff43d8   Al Viro   nfs_open_context ...
389
  	struct inode *inode = req->wb_context->dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
392
  	struct nfs_inode *nfsi = NFS_I(inode);
  
  	BUG_ON (!NFS_WBACK_BUSY(req));
587142f85   Trond Myklebust   NFS: Replace NFS_...
393
  	spin_lock(&inode->i_lock);
277459d2e   Trond Myklebust   NFS: Store pointe...
394
  	set_page_private(req->wb_page, 0);
deb7d6382   Trond Myklebust   NFS: Fix a race w...
395
  	ClearPagePrivate(req->wb_page);
2df485a77   Trond Myklebust   nfs: remove extra...
396
  	clear_bit(PG_MAPPED, &req->wb_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
  	radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
  	nfsi->npages--;
4d65c520f   Trond Myklebust   NFS: Fix a hang i...
399
  	spin_unlock(&inode->i_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
  	nfs_release_request(req);
  }
61822ab5e   Trond Myklebust   NFS: Ensure we on...
402
  static void
6d884e8fc   Fred   nfs: nfs_redirty_...
403
  nfs_mark_request_dirty(struct nfs_page *req)
61822ab5e   Trond Myklebust   NFS: Ensure we on...
404
  {
61822ab5e   Trond Myklebust   NFS: Ensure we on...
405
406
  	__set_page_dirty_nobuffers(req->wb_page);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
410
411
  #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
  /*
   * Add a request to the inode's commit list.
   */
  static void
a861a1e1c   Fred Isaman   NFSv4.1: add gene...
412
  nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
  {
3d4ff43d8   Al Viro   nfs_open_context ...
414
  	struct inode *inode = req->wb_context->dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
  	struct nfs_inode *nfsi = NFS_I(inode);
587142f85   Trond Myklebust   NFS: Replace NFS_...
416
  	spin_lock(&inode->i_lock);
e468bae97   Trond Myklebust   NFS: Allow redirt...
417
  	set_bit(PG_CLEAN, &(req)->wb_flags);
5c3696834   Trond Myklebust   NFS cleanup: spee...
418
419
420
  	radix_tree_tag_set(&nfsi->nfs_page_tree,
  			req->wb_index,
  			NFS_PAGE_TAG_COMMIT);
ff778d02b   Trond Myklebust   NFS: Add a count ...
421
  	nfsi->ncommit++;
587142f85   Trond Myklebust   NFS: Replace NFS_...
422
  	spin_unlock(&inode->i_lock);
a861a1e1c   Fred Isaman   NFSv4.1: add gene...
423
  	pnfs_mark_request_commit(req, lseg);
fd39fc856   Christoph Lameter   [PATCH] zoned vm ...
424
  	inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
c9e51e418   Peter Zijlstra   mm: count reclaim...
425
  	inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE);
a18030445   Trond Myklebust   NFS: Clean up cal...
426
  	__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
  }
8e821cad1   Trond Myklebust   NFS: clean up the...
428

e468bae97   Trond Myklebust   NFS: Allow redirt...
429
430
431
432
433
434
435
436
437
438
439
440
  static int
  nfs_clear_request_commit(struct nfs_page *req)
  {
  	struct page *page = req->wb_page;
  
  	if (test_and_clear_bit(PG_CLEAN, &(req)->wb_flags)) {
  		dec_zone_page_state(page, NR_UNSTABLE_NFS);
  		dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE);
  		return 1;
  	}
  	return 0;
  }
8e821cad1   Trond Myklebust   NFS: clean up the...
441
442
443
  static inline
  int nfs_write_need_commit(struct nfs_write_data *data)
  {
465d52437   Fred Isaman   NFSv4.1: don't se...
444
445
446
447
  	if (data->verf.committed == NFS_DATA_SYNC)
  		return data->lseg == NULL;
  	else
  		return data->verf.committed != NFS_FILE_SYNC;
8e821cad1   Trond Myklebust   NFS: clean up the...
448
449
450
  }
  
  static inline
a861a1e1c   Fred Isaman   NFSv4.1: add gene...
451
452
  int nfs_reschedule_unstable_write(struct nfs_page *req,
  				  struct nfs_write_data *data)
8e821cad1   Trond Myklebust   NFS: clean up the...
453
  {
e468bae97   Trond Myklebust   NFS: Allow redirt...
454
  	if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) {
a861a1e1c   Fred Isaman   NFSv4.1: add gene...
455
  		nfs_mark_request_commit(req, data->lseg);
8e821cad1   Trond Myklebust   NFS: clean up the...
456
457
458
  		return 1;
  	}
  	if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) {
6d884e8fc   Fred   nfs: nfs_redirty_...
459
  		nfs_mark_request_dirty(req);
8e821cad1   Trond Myklebust   NFS: clean up the...
460
461
462
463
464
465
  		return 1;
  	}
  	return 0;
  }
  #else
  static inline void
a861a1e1c   Fred Isaman   NFSv4.1: add gene...
466
  nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
8e821cad1   Trond Myklebust   NFS: clean up the...
467
468
  {
  }
e468bae97   Trond Myklebust   NFS: Allow redirt...
469
470
471
472
473
  static inline int
  nfs_clear_request_commit(struct nfs_page *req)
  {
  	return 0;
  }
8e821cad1   Trond Myklebust   NFS: clean up the...
474
475
476
477
478
479
480
  static inline
  int nfs_write_need_commit(struct nfs_write_data *data)
  {
  	return 0;
  }
  
  static inline
a861a1e1c   Fred Isaman   NFSv4.1: add gene...
481
482
  int nfs_reschedule_unstable_write(struct nfs_page *req,
  				  struct nfs_write_data *data)
8e821cad1   Trond Myklebust   NFS: clean up the...
483
484
485
  {
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
  #endif
47c625642   Trond Myklebust   NFS: Fix up a mis...
487
  #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
fb8a1f11b   Trond Myklebust   NFS: cleanup - re...
488
489
490
491
492
  static int
  nfs_need_commit(struct nfs_inode *nfsi)
  {
  	return radix_tree_tagged(&nfsi->nfs_page_tree, NFS_PAGE_TAG_COMMIT);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
495
496
497
498
499
500
501
502
503
  /*
   * nfs_scan_commit - Scan an inode for commit requests
   * @inode: NFS inode to scan
   * @dst: destination list
   * @idx_start: lower bound of page->index to scan.
   * @npages: idx_start + npages sets the upper bound to scan.
   *
   * Moves requests from the inode's 'commit' request list.
   * The requests are *not* checked to ensure that they form a contiguous set.
   */
  static int
ca52fec15   Trond Myklebust   NFS: Use pgoff_t ...
504
  nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
506
  {
  	struct nfs_inode *nfsi = NFS_I(inode);
ff778d02b   Trond Myklebust   NFS: Add a count ...
507
  	int ret;
3da28eb1c   Trond Myklebust   [PATCH] NFS: Repl...
508

fb8a1f11b   Trond Myklebust   NFS: cleanup - re...
509
510
  	if (!nfs_need_commit(nfsi))
  		return 0;
0d88f6e80   Dave Chinner   nfs: don't call _...
511
  	spin_lock(&inode->i_lock);
ff778d02b   Trond Myklebust   NFS: Add a count ...
512
513
514
  	ret = nfs_scan_list(nfsi, dst, idx_start, npages, NFS_PAGE_TAG_COMMIT);
  	if (ret > 0)
  		nfsi->ncommit -= ret;
0d88f6e80   Dave Chinner   nfs: don't call _...
515
  	spin_unlock(&inode->i_lock);
2928db1ff   Trond Myklebust   NFS: Ensure inode...
516
517
  	if (nfs_need_commit(NFS_I(inode)))
  		__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
0d88f6e80   Dave Chinner   nfs: don't call _...
518

ff778d02b   Trond Myklebust   NFS: Add a count ...
519
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
  }
c42de9dd6   Trond Myklebust   NFS: Fix a race i...
521
  #else
fb8a1f11b   Trond Myklebust   NFS: cleanup - re...
522
523
524
525
  static inline int nfs_need_commit(struct nfs_inode *nfsi)
  {
  	return 0;
  }
ca52fec15   Trond Myklebust   NFS: Use pgoff_t ...
526
  static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
c42de9dd6   Trond Myklebust   NFS: Fix a race i...
527
528
529
  {
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
  /*
e7d39069e   Trond Myklebust   NFS: Clean up nfs...
532
533
   * Search for an existing write request, and attempt to update
   * it to reflect a new dirty region on a given page.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
   *
e7d39069e   Trond Myklebust   NFS: Clean up nfs...
535
536
   * If the attempt fails, then the existing request is flushed out
   * to disk.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
   */
e7d39069e   Trond Myklebust   NFS: Clean up nfs...
538
539
540
541
  static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
  		struct page *page,
  		unsigned int offset,
  		unsigned int bytes)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
  {
e7d39069e   Trond Myklebust   NFS: Clean up nfs...
543
544
545
546
547
548
549
  	struct nfs_page *req;
  	unsigned int rqend;
  	unsigned int end;
  	int error;
  
  	if (!PagePrivate(page))
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
551
  
  	end = offset + bytes;
e7d39069e   Trond Myklebust   NFS: Clean up nfs...
552
  	spin_lock(&inode->i_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
  	for (;;) {
277459d2e   Trond Myklebust   NFS: Store pointe...
555
  		req = nfs_page_find_request_locked(page);
e7d39069e   Trond Myklebust   NFS: Clean up nfs...
556
557
558
559
560
561
562
563
564
565
  		if (req == NULL)
  			goto out_unlock;
  
  		rqend = req->wb_offset + req->wb_bytes;
  		/*
  		 * Tell the caller to flush out the request if
  		 * the offsets are non-contiguous.
  		 * Note: nfs_flush_incompatible() will already
  		 * have flushed out requests having wrong owners.
  		 */
e468bae97   Trond Myklebust   NFS: Allow redirt...
566
  		if (offset > rqend
e7d39069e   Trond Myklebust   NFS: Clean up nfs...
567
568
569
570
  		    || end < req->wb_offset)
  			goto out_flushme;
  
  		if (nfs_set_page_tag_locked(req))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572

e7d39069e   Trond Myklebust   NFS: Clean up nfs...
573
  		/* The request is locked, so wait and then retry */
587142f85   Trond Myklebust   NFS: Replace NFS_...
574
  		spin_unlock(&inode->i_lock);
e7d39069e   Trond Myklebust   NFS: Clean up nfs...
575
576
577
578
579
  		error = nfs_wait_on_request(req);
  		nfs_release_request(req);
  		if (error != 0)
  			goto out_err;
  		spin_lock(&inode->i_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  	}
ff778d02b   Trond Myklebust   NFS: Add a count ...
581
  	if (nfs_clear_request_commit(req) &&
a861a1e1c   Fred Isaman   NFSv4.1: add gene...
582
583
  	    radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree,
  				 req->wb_index, NFS_PAGE_TAG_COMMIT) != NULL) {
ff778d02b   Trond Myklebust   NFS: Add a count ...
584
  		NFS_I(inode)->ncommit--;
a861a1e1c   Fred Isaman   NFSv4.1: add gene...
585
586
  		pnfs_clear_request_commit(req);
  	}
e468bae97   Trond Myklebust   NFS: Allow redirt...
587

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
589
590
591
  	/* Okay, the request matches. Update the region */
  	if (offset < req->wb_offset) {
  		req->wb_offset = offset;
  		req->wb_pgbase = offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
594
  	if (end > rqend)
  		req->wb_bytes = end - req->wb_offset;
e7d39069e   Trond Myklebust   NFS: Clean up nfs...
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
  	else
  		req->wb_bytes = rqend - req->wb_offset;
  out_unlock:
  	spin_unlock(&inode->i_lock);
  	return req;
  out_flushme:
  	spin_unlock(&inode->i_lock);
  	nfs_release_request(req);
  	error = nfs_wb_page(inode, page);
  out_err:
  	return ERR_PTR(error);
  }
  
  /*
   * Try to update an existing write request, or create one if there is none.
   *
   * Note: Should always be called with the Page Lock held to prevent races
   * if we have to add a new request. Also assumes that the caller has
   * already called nfs_flush_incompatible() if necessary.
   */
  static struct nfs_page * nfs_setup_write_request(struct nfs_open_context* ctx,
  		struct page *page, unsigned int offset, unsigned int bytes)
  {
  	struct inode *inode = page->mapping->host;
  	struct nfs_page	*req;
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621

e7d39069e   Trond Myklebust   NFS: Clean up nfs...
622
623
624
625
626
627
628
629
630
631
632
  	req = nfs_try_to_update_request(inode, page, offset, bytes);
  	if (req != NULL)
  		goto out;
  	req = nfs_create_request(ctx, inode, page, offset, bytes);
  	if (IS_ERR(req))
  		goto out;
  	error = nfs_inode_add_request(inode, req);
  	if (error != 0) {
  		nfs_release_request(req);
  		req = ERR_PTR(error);
  	}
efc91ed01   Trond Myklebust   NFS: Optimise app...
633
  out:
61e930a90   Trond Myklebust   NFS: Fix a writeb...
634
  	return req;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
  }
e7d39069e   Trond Myklebust   NFS: Clean up nfs...
636
637
638
639
640
641
642
643
644
645
646
  static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page,
  		unsigned int offset, unsigned int count)
  {
  	struct nfs_page	*req;
  
  	req = nfs_setup_write_request(ctx, page, offset, count);
  	if (IS_ERR(req))
  		return PTR_ERR(req);
  	/* Update file length */
  	nfs_grow_file(page, offset, count);
  	nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes);
a6305ddb0   Trond Myklebust   NFS: Fix a race w...
647
  	nfs_mark_request_dirty(req);
e7d39069e   Trond Myklebust   NFS: Clean up nfs...
648
649
650
  	nfs_clear_page_tag_locked(req);
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
  int nfs_flush_incompatible(struct file *file, struct page *page)
  {
cd3758e37   Trond Myklebust   NFS: Replace file...
653
  	struct nfs_open_context *ctx = nfs_file_open_context(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
  	struct nfs_page	*req;
1a54533ec   Trond Myklebust   NFS: Add nfs_set_...
655
  	int do_flush, status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
657
658
659
660
661
662
663
  	/*
  	 * Look for a request corresponding to this page. If there
  	 * is one, and it belongs to another file, we flush it out
  	 * before we try to copy anything into the page. Do this
  	 * due to the lack of an ACCESS-type call in NFSv2.
  	 * Also do the same if we find a request from an existing
  	 * dropped page.
  	 */
1a54533ec   Trond Myklebust   NFS: Add nfs_set_...
664
665
666
667
  	do {
  		req = nfs_page_find_request(page);
  		if (req == NULL)
  			return 0;
f11ac8db5   Trond Myklebust   NFSv4: Ensure tha...
668
669
670
  		do_flush = req->wb_page != page || req->wb_context != ctx ||
  			req->wb_lock_context->lockowner != current->files ||
  			req->wb_lock_context->pid != current->tgid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
  		nfs_release_request(req);
1a54533ec   Trond Myklebust   NFS: Add nfs_set_...
672
673
674
675
676
  		if (!do_flush)
  			return 0;
  		status = nfs_wb_page(page->mapping->host, page);
  	} while (status == 0);
  	return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
678
679
  }
  
  /*
5d47a3560   Trond Myklebust   NFS: Fix a potent...
680
681
682
683
684
685
686
687
688
689
690
   * If the page cache is marked as unsafe or invalid, then we can't rely on
   * the PageUptodate() flag. In this case, we will need to turn off
   * write optimisations that depend on the page contents being correct.
   */
  static int nfs_write_pageuptodate(struct page *page, struct inode *inode)
  {
  	return PageUptodate(page) &&
  		!(NFS_I(inode)->cache_validity & (NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA));
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691
692
693
694
695
696
697
698
   * Update and possibly write a cached page of an NFS file.
   *
   * XXX: Keep an eye on generic_file_read to make sure it doesn't do bad
   * things with a page scheduled for an RPC call (e.g. invalidate it).
   */
  int nfs_updatepage(struct file *file, struct page *page,
  		unsigned int offset, unsigned int count)
  {
cd3758e37   Trond Myklebust   NFS: Replace file...
699
  	struct nfs_open_context *ctx = nfs_file_open_context(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
  	struct inode	*inode = page->mapping->host;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
  	int		status = 0;
91d5b4702   Chuck Lever   NFS: add I/O perf...
702
  	nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE);
48186c7d5   Chuck Lever   NFS: Fix trace de...
703
704
  	dprintk("NFS:       nfs_updatepage(%s/%s %d@%lld)
  ",
01cce933d   Josef "Jeff" Sipek   [PATCH] nfs: chan...
705
706
  		file->f_path.dentry->d_parent->d_name.name,
  		file->f_path.dentry->d_name.name, count,
48186c7d5   Chuck Lever   NFS: Fix trace de...
707
  		(long long)(page_offset(page) + offset));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
  	/* If we're not using byte range locks, and we know the page
5d47a3560   Trond Myklebust   NFS: Fix a potent...
710
711
712
  	 * is up to date, it may be more efficient to extend the write
  	 * to cover the entire page in order to avoid fragmentation
  	 * inefficiencies.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
  	 */
5d47a3560   Trond Myklebust   NFS: Fix a potent...
714
715
  	if (nfs_write_pageuptodate(page, inode) &&
  			inode->i_flock == NULL &&
6b2f3d1f7   Christoph Hellwig   vfs: Implement pr...
716
  			!(file->f_flags & O_DSYNC)) {
49a70f278   Trond Myklebust   NFS: Cleanup: add...
717
  		count = max(count + offset, nfs_page_length(page));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718
  		offset = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
  	}
e21195a74   Trond Myklebust   NFS: More cleanup...
720
  	status = nfs_writepage_setup(ctx, page, offset, count);
03fa9e84e   Trond Myklebust   NFS: nfs_updatepa...
721
722
  	if (status < 0)
  		nfs_set_pageerror(page);
59b7c05ff   Trond Myklebust   Revert "NFS: Ensu...
723
724
  	else
  		__set_page_dirty_nobuffers(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725

48186c7d5   Chuck Lever   NFS: Fix trace de...
726
727
  	dprintk("NFS:       nfs_updatepage returns %d (isize %lld)
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
  			status, (long long)i_size_read(inode));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
729
730
  	return status;
  }
a861a1e1c   Fred Isaman   NFSv4.1: add gene...
731
732
  static void nfs_writepage_release(struct nfs_page *req,
  				  struct nfs_write_data *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
  {
a6305ddb0   Trond Myklebust   NFS: Fix a race w...
734
  	struct page *page = req->wb_page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735

a861a1e1c   Fred Isaman   NFSv4.1: add gene...
736
  	if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req, data))
8e821cad1   Trond Myklebust   NFS: clean up the...
737
  		nfs_inode_remove_request(req);
9fd367f0f   Trond Myklebust   NFS cleanup: Rena...
738
  	nfs_clear_page_tag_locked(req);
a6305ddb0   Trond Myklebust   NFS: Fix a race w...
739
  	nfs_end_page_writeback(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
  }
3ff7576dd   Trond Myklebust   SUNRPC: Clean up ...
741
  static int flush_task_priority(int how)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
743
744
745
746
747
748
749
750
  {
  	switch (how & (FLUSH_HIGHPRI|FLUSH_LOWPRI)) {
  		case FLUSH_HIGHPRI:
  			return RPC_PRIORITY_HIGH;
  		case FLUSH_LOWPRI:
  			return RPC_PRIORITY_LOW;
  	}
  	return RPC_PRIORITY_NORMAL;
  }
a69aef149   Fred Isaman   NFSv4.1: pnfs fil...
751
  int nfs_initiate_write(struct nfs_write_data *data,
d138d5d17   Andy Adamson   NFSv4.1: rearrang...
752
753
754
  		       struct rpc_clnt *clnt,
  		       const struct rpc_call_ops *call_ops,
  		       int how)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
  {
d138d5d17   Andy Adamson   NFSv4.1: rearrang...
756
  	struct inode *inode = data->inode;
3ff7576dd   Trond Myklebust   SUNRPC: Clean up ...
757
  	int priority = flush_task_priority(how);
077376919   Trond Myklebust   NFS/SUNRPC: Conve...
758
  	struct rpc_task *task;
bdc7f021f   Trond Myklebust   NFS: Clean up the...
759
760
761
  	struct rpc_message msg = {
  		.rpc_argp = &data->args,
  		.rpc_resp = &data->res,
d138d5d17   Andy Adamson   NFSv4.1: rearrang...
762
  		.rpc_cred = data->cred,
bdc7f021f   Trond Myklebust   NFS: Clean up the...
763
  	};
84115e1cd   Trond Myklebust   SUNRPC: Cleanup o...
764
  	struct rpc_task_setup task_setup_data = {
d138d5d17   Andy Adamson   NFSv4.1: rearrang...
765
  		.rpc_client = clnt,
077376919   Trond Myklebust   NFS/SUNRPC: Conve...
766
  		.task = &data->task,
bdc7f021f   Trond Myklebust   NFS: Clean up the...
767
  		.rpc_message = &msg,
84115e1cd   Trond Myklebust   SUNRPC: Cleanup o...
768
769
  		.callback_ops = call_ops,
  		.callback_data = data,
101070ca2   Trond Myklebust   NFS: Ensure that ...
770
  		.workqueue = nfsiod_workqueue,
2c61be0a9   Trond Myklebust   NFS: Ensure that ...
771
  		.flags = RPC_TASK_ASYNC,
3ff7576dd   Trond Myklebust   SUNRPC: Clean up ...
772
  		.priority = priority,
84115e1cd   Trond Myklebust   SUNRPC: Cleanup o...
773
  	};
2c61be0a9   Trond Myklebust   NFS: Ensure that ...
774
  	int ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775

d138d5d17   Andy Adamson   NFSv4.1: rearrang...
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
  	/* Set up the initial task struct.  */
  	NFS_PROTO(inode)->write_setup(data, &msg);
  
  	dprintk("NFS: %5u initiated write call "
  		"(req %s/%lld, %u bytes @ offset %llu)
  ",
  		data->task.tk_pid,
  		inode->i_sb->s_id,
  		(long long)NFS_FILEID(inode),
  		data->args.count,
  		(unsigned long long)data->args.offset);
  
  	task = rpc_run_task(&task_setup_data);
  	if (IS_ERR(task)) {
  		ret = PTR_ERR(task);
  		goto out;
  	}
  	if (how & FLUSH_SYNC) {
  		ret = rpc_wait_for_completion_task(task);
  		if (ret == 0)
  			ret = task->tk_status;
  	}
  	rpc_put_task(task);
  out:
  	return ret;
  }
a69aef149   Fred Isaman   NFSv4.1: pnfs fil...
802
  EXPORT_SYMBOL_GPL(nfs_initiate_write);
d138d5d17   Andy Adamson   NFSv4.1: rearrang...
803
804
805
806
  
  /*
   * Set up the argument/result storage required for the RPC call.
   */
6e4efd568   Trond Myklebust   NFS: Clean up nfs...
807
  static void nfs_write_rpcsetup(struct nfs_page *req,
d138d5d17   Andy Adamson   NFSv4.1: rearrang...
808
  		struct nfs_write_data *data,
d138d5d17   Andy Adamson   NFSv4.1: rearrang...
809
810
811
  		unsigned int count, unsigned int offset,
  		int how)
  {
3d4ff43d8   Al Viro   nfs_open_context ...
812
  	struct inode *inode = req->wb_context->dentry->d_inode;
d138d5d17   Andy Adamson   NFSv4.1: rearrang...
813

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
815
816
817
  	/* Set up the RPC argument and reply structs
  	 * NB: take care not to mess about with data->commit et al. */
  
  	data->req = req;
3d4ff43d8   Al Viro   nfs_open_context ...
818
  	data->inode = inode = req->wb_context->dentry->d_inode;
d138d5d17   Andy Adamson   NFSv4.1: rearrang...
819
  	data->cred = req->wb_context->cred;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820
821
822
  
  	data->args.fh     = NFS_FH(inode);
  	data->args.offset = req_offset(req) + offset;
2bea038c5   Boaz Harrosh   pnfs: write: Set ...
823
824
  	/* pnfs_set_layoutcommit needs this */
  	data->mds_offset = data->args.offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
826
827
  	data->args.pgbase = req->wb_pgbase + offset;
  	data->args.pages  = data->pagevec;
  	data->args.count  = count;
383ba7193   Trond Myklebust   NFS: Fix a deadlo...
828
  	data->args.context = get_nfs_open_context(req->wb_context);
f11ac8db5   Trond Myklebust   NFSv4: Ensure tha...
829
  	data->args.lock_context = req->wb_lock_context;
bdc7f021f   Trond Myklebust   NFS: Clean up the...
830
  	data->args.stable  = NFS_UNSTABLE;
87ed5eb44   Trond Myklebust   NFS: Don't use DA...
831
832
833
834
835
836
837
838
  	switch (how & (FLUSH_STABLE | FLUSH_COND_STABLE)) {
  	case 0:
  		break;
  	case FLUSH_COND_STABLE:
  		if (nfs_need_commit(NFS_I(inode)))
  			break;
  	default:
  		data->args.stable = NFS_FILE_SYNC;
bdc7f021f   Trond Myklebust   NFS: Clean up the...
839
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
840
841
842
843
  
  	data->res.fattr   = &data->fattr;
  	data->res.count   = count;
  	data->res.verf    = &data->verf;
0e574af1b   Trond Myklebust   NFS: Cleanup init...
844
  	nfs_fattr_init(&data->fattr);
6e4efd568   Trond Myklebust   NFS: Clean up nfs...
845
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846

6e4efd568   Trond Myklebust   NFS: Clean up nfs...
847
848
  static int nfs_do_write(struct nfs_write_data *data,
  		const struct rpc_call_ops *call_ops,
6e4efd568   Trond Myklebust   NFS: Clean up nfs...
849
850
  		int how)
  {
5f00bcb38   Stephen Rothwell   Merge branch 'mas...
851
  	struct inode *inode = data->args.context->dentry->d_inode;
0382b7440   Andy Adamson   NFSv4.1: implemen...
852

d138d5d17   Andy Adamson   NFSv4.1: rearrang...
853
  	return nfs_initiate_write(data, NFS_CLIENT(inode), call_ops, how);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
854
  }
275acaafd   Trond Myklebust   NFS: Clean up: sp...
855
856
  static int nfs_do_multiple_writes(struct list_head *head,
  		const struct rpc_call_ops *call_ops,
275acaafd   Trond Myklebust   NFS: Clean up: sp...
857
858
859
860
861
862
863
864
865
866
867
  		int how)
  {
  	struct nfs_write_data *data;
  	int ret = 0;
  
  	while (!list_empty(head)) {
  		int ret2;
  
  		data = list_entry(head->next, struct nfs_write_data, list);
  		list_del_init(&data->list);
  		
dce81290e   Trond Myklebust   NFS: Move the pnf...
868
  		ret2 = nfs_do_write(data, call_ops, how);
275acaafd   Trond Myklebust   NFS: Clean up: sp...
869
870
871
872
873
  		 if (ret == 0)
  			 ret = ret2;
  	}
  	return ret;
  }
6d884e8fc   Fred   nfs: nfs_redirty_...
874
875
876
877
878
879
  /* If a nfs_flush_* function fails, it should remove reqs from @head and
   * call this on each, which will prepare them to be retried on next
   * writeback using standard nfs.
   */
  static void nfs_redirty_request(struct nfs_page *req)
  {
a6305ddb0   Trond Myklebust   NFS: Fix a race w...
880
  	struct page *page = req->wb_page;
6d884e8fc   Fred   nfs: nfs_redirty_...
881
  	nfs_mark_request_dirty(req);
6d884e8fc   Fred   nfs: nfs_redirty_...
882
  	nfs_clear_page_tag_locked(req);
a6305ddb0   Trond Myklebust   NFS: Fix a race w...
883
  	nfs_end_page_writeback(page);
6d884e8fc   Fred   nfs: nfs_redirty_...
884
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
885
886
887
888
  /*
   * Generate multiple small requests to write out a single
   * contiguous dirty area on one page.
   */
275acaafd   Trond Myklebust   NFS: Clean up: sp...
889
  static int nfs_flush_multi(struct nfs_pageio_descriptor *desc, struct list_head *res)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
890
  {
c76069bda   Fred Isaman   NFSv4.1: rearrang...
891
  	struct nfs_page *req = nfs_list_entry(desc->pg_list.next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
893
  	struct page *page = req->wb_page;
  	struct nfs_write_data *data;
d097971d8   Trond Myklebust   NFS: Use the nfs_...
894
  	size_t wsize = desc->pg_bsize, nbytes;
e9f7bee1d   Trond Myklebust   [PATCH] NFS: larg...
895
  	unsigned int offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
  	int requests = 0;
dbae4c73f   Trond Myklebust   NFS: Ensure that ...
897
  	int ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
899
  
  	nfs_list_remove_request(req);
b31268ac7   Trond Myklebust   FS: Use stable wr...
900
901
902
903
  	if ((desc->pg_ioflags & FLUSH_COND_STABLE) &&
  	    (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit ||
  	     desc->pg_count > wsize))
  		desc->pg_ioflags &= ~FLUSH_COND_STABLE;
275acaafd   Trond Myklebust   NFS: Clean up: sp...
904
  	offset = 0;
c76069bda   Fred Isaman   NFSv4.1: rearrang...
905
  	nbytes = desc->pg_count;
e9f7bee1d   Trond Myklebust   [PATCH] NFS: larg...
906
907
  	do {
  		size_t len = min(nbytes, wsize);
8d5658c94   Trond Myklebust   NFS: Fix a buffer...
908
  		data = nfs_writedata_alloc(1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
910
  		if (!data)
  			goto out_bad;
275acaafd   Trond Myklebust   NFS: Clean up: sp...
911
  		data->pagevec[0] = page;
f13c3620a   Trond Myklebust   NFS: Fix a typo i...
912
  		nfs_write_rpcsetup(req, data, len, offset, desc->pg_ioflags);
275acaafd   Trond Myklebust   NFS: Clean up: sp...
913
  		list_add(&data->list, res);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
  		requests++;
e9f7bee1d   Trond Myklebust   [PATCH] NFS: larg...
915
  		nbytes -= len;
275acaafd   Trond Myklebust   NFS: Clean up: sp...
916
  		offset += len;
e9f7bee1d   Trond Myklebust   [PATCH] NFS: larg...
917
  	} while (nbytes != 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
918
  	atomic_set(&req->wb_complete, requests);
50828d7e6   Trond Myklebust   NFS: Cache rpc_op...
919
  	desc->pg_rpc_callops = &nfs_write_partial_ops;
dbae4c73f   Trond Myklebust   NFS: Ensure that ...
920
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921
922
  
  out_bad:
275acaafd   Trond Myklebust   NFS: Clean up: sp...
923
924
  	while (!list_empty(res)) {
  		data = list_entry(res->next, struct nfs_write_data, list);
6e4efd568   Trond Myklebust   NFS: Clean up nfs...
925
  		list_del(&data->list);
0da2a4ac3   Fred Isaman   NFS: fix handling...
926
  		nfs_writedata_free(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
  	}
61822ab5e   Trond Myklebust   NFS: Ensure we on...
928
  	nfs_redirty_request(req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
930
931
932
933
934
935
936
937
938
939
  	return -ENOMEM;
  }
  
  /*
   * Create an RPC task for the given write request and kick it.
   * The page must have been locked by the caller.
   *
   * It may happen that the page we're passed is not marked dirty.
   * This is the case if nfs_updatepage detects a conflicting request
   * that has been written but not committed.
   */
275acaafd   Trond Myklebust   NFS: Clean up: sp...
940
  static int nfs_flush_one(struct nfs_pageio_descriptor *desc, struct list_head *res)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
941
942
943
944
  {
  	struct nfs_page		*req;
  	struct page		**pages;
  	struct nfs_write_data	*data;
c76069bda   Fred Isaman   NFSv4.1: rearrang...
945
  	struct list_head *head = &desc->pg_list;
3b6091846   Peng Tao   NFS: fix return v...
946
  	int ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947

c76069bda   Fred Isaman   NFSv4.1: rearrang...
948
949
  	data = nfs_writedata_alloc(nfs_page_array_len(desc->pg_base,
  						      desc->pg_count));
44b83799a   Fred Isaman   NFSv4.1: trigger ...
950
951
952
953
954
955
956
957
958
  	if (!data) {
  		while (!list_empty(head)) {
  			req = nfs_list_entry(head->next);
  			nfs_list_remove_request(req);
  			nfs_redirty_request(req);
  		}
  		ret = -ENOMEM;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
959
  	pages = data->pagevec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
961
962
963
  	while (!list_empty(head)) {
  		req = nfs_list_entry(head->next);
  		nfs_list_remove_request(req);
  		nfs_list_add_request(req, &data->pages);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
964
  		*pages++ = req->wb_page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965
966
  	}
  	req = nfs_list_entry(data->pages.next);
b31268ac7   Trond Myklebust   FS: Use stable wr...
967
968
969
  	if ((desc->pg_ioflags & FLUSH_COND_STABLE) &&
  	    (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit))
  		desc->pg_ioflags &= ~FLUSH_COND_STABLE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
970
  	/* Set up the argument struct */
6e4efd568   Trond Myklebust   NFS: Clean up nfs...
971
  	nfs_write_rpcsetup(req, data, desc->pg_count, 0, desc->pg_ioflags);
275acaafd   Trond Myklebust   NFS: Clean up: sp...
972
  	list_add(&data->list, res);
50828d7e6   Trond Myklebust   NFS: Cache rpc_op...
973
  	desc->pg_rpc_callops = &nfs_write_full_ops;
44b83799a   Fred Isaman   NFSv4.1: trigger ...
974
  out:
44b83799a   Fred Isaman   NFSv4.1: trigger ...
975
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
  }
dce81290e   Trond Myklebust   NFS: Move the pnf...
977
978
979
980
981
982
983
984
  int nfs_generic_flush(struct nfs_pageio_descriptor *desc, struct list_head *head)
  {
  	if (desc->pg_bsize < PAGE_CACHE_SIZE)
  		return nfs_flush_multi(desc, head);
  	return nfs_flush_one(desc, head);
  }
  
  static int nfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc)
1751c3638   Trond Myklebust   NFS: Cleanup of t...
985
  {
275acaafd   Trond Myklebust   NFS: Clean up: sp...
986
987
  	LIST_HEAD(head);
  	int ret;
dce81290e   Trond Myklebust   NFS: Move the pnf...
988
  	ret = nfs_generic_flush(desc, &head);
50828d7e6   Trond Myklebust   NFS: Cache rpc_op...
989
990
  	if (ret == 0)
  		ret = nfs_do_multiple_writes(&head, desc->pg_rpc_callops,
dce81290e   Trond Myklebust   NFS: Move the pnf...
991
  				desc->pg_ioflags);
275acaafd   Trond Myklebust   NFS: Clean up: sp...
992
  	return ret;
1751c3638   Trond Myklebust   NFS: Cleanup of t...
993
  }
1751c3638   Trond Myklebust   NFS: Cleanup of t...
994
995
996
997
998
  
  static const struct nfs_pageio_ops nfs_pageio_write_ops = {
  	.pg_test = nfs_generic_pg_test,
  	.pg_doio = nfs_generic_pg_writepages,
  };
e2fecb215   Trond Myklebust   NFS: Remove pNFS ...
999
  void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio,
c63c7b051   Trond Myklebust   NFS: Fix a race w...
1000
  				  struct inode *inode, int ioflags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1001
  {
1751c3638   Trond Myklebust   NFS: Cleanup of t...
1002
1003
1004
  	nfs_pageio_init(pgio, inode, &nfs_pageio_write_ops,
  				NFS_SERVER(inode)->wsize, ioflags);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1005

dce81290e   Trond Myklebust   NFS: Move the pnf...
1006
1007
1008
1009
1010
  void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio)
  {
  	pgio->pg_ops = &nfs_pageio_write_ops;
  	pgio->pg_bsize = NFS_SERVER(pgio->pg_inode)->wsize;
  }
1f9453578   Trond Myklebust   NFS: Clean up - s...
1011
  EXPORT_SYMBOL_GPL(nfs_pageio_reset_write_mds);
dce81290e   Trond Myklebust   NFS: Move the pnf...
1012

1751c3638   Trond Myklebust   NFS: Cleanup of t...
1013
1014
1015
1016
1017
  static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
  				  struct inode *inode, int ioflags)
  {
  	if (!pnfs_pageio_init_write(pgio, inode, ioflags))
  		nfs_pageio_init_write_mds(pgio, inode, ioflags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1018
1019
1020
1021
1022
  }
  
  /*
   * Handle a write reply that flushed part of a page.
   */
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
1023
  static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1024
  {
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
1025
  	struct nfs_write_data	*data = calldata;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1026

48186c7d5   Chuck Lever   NFS: Fix trace de...
1027
1028
  	dprintk("NFS: %5u write(%s/%lld %d@%lld)",
  		task->tk_pid,
3d4ff43d8   Al Viro   nfs_open_context ...
1029
  		data->req->wb_context->dentry->d_inode->i_sb->s_id,
48186c7d5   Chuck Lever   NFS: Fix trace de...
1030
  		(long long)
3d4ff43d8   Al Viro   nfs_open_context ...
1031
  		  NFS_FILEID(data->req->wb_context->dentry->d_inode),
48186c7d5   Chuck Lever   NFS: Fix trace de...
1032
  		data->req->wb_bytes, (long long)req_offset(data->req));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033

c9d8f89d9   Trond Myklebust   NFS: Ensure that ...
1034
1035
  	nfs_writeback_done(task, data);
  }
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
1036

c9d8f89d9   Trond Myklebust   NFS: Ensure that ...
1037
1038
1039
1040
1041
1042
1043
1044
  static void nfs_writeback_release_partial(void *calldata)
  {
  	struct nfs_write_data	*data = calldata;
  	struct nfs_page		*req = data->req;
  	struct page		*page = req->wb_page;
  	int status = data->task.tk_status;
  
  	if (status < 0) {
a301b7777   Trond Myklebust   NFS: Don't use Cl...
1045
  		nfs_set_pageerror(page);
c9d8f89d9   Trond Myklebust   NFS: Ensure that ...
1046
1047
1048
  		nfs_context_set_write_error(req->wb_context, status);
  		dprintk(", error = %d
  ", status);
8e821cad1   Trond Myklebust   NFS: clean up the...
1049
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1050
  	}
8e821cad1   Trond Myklebust   NFS: clean up the...
1051
  	if (nfs_write_need_commit(data)) {
587142f85   Trond Myklebust   NFS: Replace NFS_...
1052
  		struct inode *inode = page->mapping->host;
8e821cad1   Trond Myklebust   NFS: clean up the...
1053

587142f85   Trond Myklebust   NFS: Replace NFS_...
1054
  		spin_lock(&inode->i_lock);
8e821cad1   Trond Myklebust   NFS: clean up the...
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
  		if (test_bit(PG_NEED_RESCHED, &req->wb_flags)) {
  			/* Do nothing we need to resend the writes */
  		} else if (!test_and_set_bit(PG_NEED_COMMIT, &req->wb_flags)) {
  			memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf));
  			dprintk(" defer commit
  ");
  		} else if (memcmp(&req->wb_verf, &data->verf, sizeof(req->wb_verf))) {
  			set_bit(PG_NEED_RESCHED, &req->wb_flags);
  			clear_bit(PG_NEED_COMMIT, &req->wb_flags);
  			dprintk(" server reboot detected
  ");
  		}
587142f85   Trond Myklebust   NFS: Replace NFS_...
1067
  		spin_unlock(&inode->i_lock);
8e821cad1   Trond Myklebust   NFS: clean up the...
1068
1069
1070
1071
1072
  	} else
  		dprintk(" OK
  ");
  
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1073
  	if (atomic_dec_and_test(&req->wb_complete))
a861a1e1c   Fred Isaman   NFSv4.1: add gene...
1074
  		nfs_writepage_release(req, data);
c9d8f89d9   Trond Myklebust   NFS: Ensure that ...
1075
  	nfs_writedata_release(calldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1076
  }
def6ed7ef   Andy Adamson   nfs41 write seque...
1077
1078
1079
1080
  #if defined(CONFIG_NFS_V4_1)
  void nfs_write_prepare(struct rpc_task *task, void *calldata)
  {
  	struct nfs_write_data *data = calldata;
def6ed7ef   Andy Adamson   nfs41 write seque...
1081

035168ab3   Trond Myklebust   NFSv4.1: Make nfs...
1082
1083
  	if (nfs4_setup_sequence(NFS_SERVER(data->inode),
  				&data->args.seq_args,
def6ed7ef   Andy Adamson   nfs41 write seque...
1084
1085
1086
1087
1088
  				&data->res.seq_res, 1, task))
  		return;
  	rpc_call_start(task);
  }
  #endif /* CONFIG_NFS_V4_1 */
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
1089
  static const struct rpc_call_ops nfs_write_partial_ops = {
def6ed7ef   Andy Adamson   nfs41 write seque...
1090
1091
1092
  #if defined(CONFIG_NFS_V4_1)
  	.rpc_call_prepare = nfs_write_prepare,
  #endif /* CONFIG_NFS_V4_1 */
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
1093
  	.rpc_call_done = nfs_writeback_done_partial,
c9d8f89d9   Trond Myklebust   NFS: Ensure that ...
1094
  	.rpc_release = nfs_writeback_release_partial,
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
1095
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1096
1097
1098
1099
1100
1101
1102
  /*
   * Handle a write reply that flushes a whole page.
   *
   * FIXME: There is an inherent race with invalidate_inode_pages and
   *	  writebacks since the page->count is kept > 1 for as long
   *	  as the page has a write request pending.
   */
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
1103
  static void nfs_writeback_done_full(struct rpc_task *task, void *calldata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1104
  {
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
1105
  	struct nfs_write_data	*data = calldata;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1106

c9d8f89d9   Trond Myklebust   NFS: Ensure that ...
1107
1108
1109
1110
1111
1112
  	nfs_writeback_done(task, data);
  }
  
  static void nfs_writeback_release_full(void *calldata)
  {
  	struct nfs_write_data	*data = calldata;
e2fecb215   Trond Myklebust   NFS: Remove pNFS ...
1113
  	int status = data->task.tk_status;
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
1114

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1115
1116
  	/* Update attributes as result of writeback. */
  	while (!list_empty(&data->pages)) {
c9d8f89d9   Trond Myklebust   NFS: Ensure that ...
1117
1118
  		struct nfs_page *req = nfs_list_entry(data->pages.next);
  		struct page *page = req->wb_page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119
  		nfs_list_remove_request(req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1120

48186c7d5   Chuck Lever   NFS: Fix trace de...
1121
1122
  		dprintk("NFS: %5u write (%s/%lld %d@%lld)",
  			data->task.tk_pid,
3d4ff43d8   Al Viro   nfs_open_context ...
1123
1124
  			req->wb_context->dentry->d_inode->i_sb->s_id,
  			(long long)NFS_FILEID(req->wb_context->dentry->d_inode),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1125
1126
  			req->wb_bytes,
  			(long long)req_offset(req));
c9d8f89d9   Trond Myklebust   NFS: Ensure that ...
1127
  		if (status < 0) {
a301b7777   Trond Myklebust   NFS: Don't use Cl...
1128
  			nfs_set_pageerror(page);
c9d8f89d9   Trond Myklebust   NFS: Ensure that ...
1129
1130
1131
  			nfs_context_set_write_error(req->wb_context, status);
  			dprintk(", error = %d
  ", status);
8e821cad1   Trond Myklebust   NFS: clean up the...
1132
  			goto remove_request;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1133
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1134

8e821cad1   Trond Myklebust   NFS: clean up the...
1135
1136
  		if (nfs_write_need_commit(data)) {
  			memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf));
a861a1e1c   Fred Isaman   NFSv4.1: add gene...
1137
  			nfs_mark_request_commit(req, data->lseg);
8e821cad1   Trond Myklebust   NFS: clean up the...
1138
1139
  			dprintk(" marked for commit
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
1141
  			goto next;
  		}
8e821cad1   Trond Myklebust   NFS: clean up the...
1142
1143
1144
  		dprintk(" OK
  ");
  remove_request:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1145
  		nfs_inode_remove_request(req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1146
  	next:
9fd367f0f   Trond Myklebust   NFS cleanup: Rena...
1147
  		nfs_clear_page_tag_locked(req);
a6305ddb0   Trond Myklebust   NFS: Fix a race w...
1148
  		nfs_end_page_writeback(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1149
  	}
c9d8f89d9   Trond Myklebust   NFS: Ensure that ...
1150
  	nfs_writedata_release(calldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1151
  }
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
1152
  static const struct rpc_call_ops nfs_write_full_ops = {
def6ed7ef   Andy Adamson   nfs41 write seque...
1153
1154
1155
  #if defined(CONFIG_NFS_V4_1)
  	.rpc_call_prepare = nfs_write_prepare,
  #endif /* CONFIG_NFS_V4_1 */
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
1156
  	.rpc_call_done = nfs_writeback_done_full,
c9d8f89d9   Trond Myklebust   NFS: Ensure that ...
1157
  	.rpc_release = nfs_writeback_release_full,
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
1158
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1159
1160
1161
  /*
   * This function is called when the WRITE call is complete.
   */
136028967   Fred Isaman   NFS: change nfs_w...
1162
  void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1163
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1164
1165
  	struct nfs_writeargs	*argp = &data->args;
  	struct nfs_writeres	*resp = &data->res;
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
1166
  	int status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1167

a3f565b1e   Chuck Lever   NFS: fix print fo...
1168
1169
  	dprintk("NFS: %5u nfs_writeback_done (status %d)
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
  		task->tk_pid, task->tk_status);
f551e44ff   Chuck Lever   NFS: add comments...
1171
1172
1173
1174
1175
1176
1177
  	/*
  	 * ->write_done will attempt to use post-op attributes to detect
  	 * conflicting writes by other clients.  A strict interpretation
  	 * of close-to-open would allow us to continue caching even if
  	 * another writer had changed the file, but some applications
  	 * depend on tighter cache coherency when writing.
  	 */
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
1178
1179
  	status = NFS_PROTO(data->inode)->write_done(task, data);
  	if (status != 0)
136028967   Fred Isaman   NFS: change nfs_w...
1180
  		return;
91d5b4702   Chuck Lever   NFS: add I/O perf...
1181
  	nfs_add_stats(data->inode, NFSIOS_SERVERWRITTENBYTES, resp->count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
  #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
  	if (resp->verf->committed < argp->stable && task->tk_status >= 0) {
  		/* We tried a write call, but the server did not
  		 * commit data to stable storage even though we
  		 * requested it.
  		 * Note: There is a known bug in Tru64 < 5.0 in which
  		 *	 the server reports NFS_DATA_SYNC, but performs
  		 *	 NFS_FILE_SYNC. We therefore implement this checking
  		 *	 as a dprintk() in order to avoid filling syslog.
  		 */
  		static unsigned long    complain;
a69aef149   Fred Isaman   NFSv4.1: pnfs fil...
1193
  		/* Note this will print the MDS for a DS write */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1194
  		if (time_before(complain, jiffies)) {
48186c7d5   Chuck Lever   NFS: Fix trace de...
1195
  			dprintk("NFS:       faulty NFS server %s:"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1196
1197
  				" (committed = %d) != (stable = %d)
  ",
2b72c9ccd   Rakib Mullick   nfs: Remove unuse...
1198
  				NFS_SERVER(data->inode)->nfs_client->cl_hostname,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1199
1200
1201
1202
1203
1204
1205
1206
  				resp->verf->committed, argp->stable);
  			complain = jiffies + 300 * HZ;
  		}
  	}
  #endif
  	/* Is this a short write? */
  	if (task->tk_status >= 0 && resp->count < argp->count) {
  		static unsigned long    complain;
91d5b4702   Chuck Lever   NFS: add I/O perf...
1207
  		nfs_inc_stats(data->inode, NFSIOS_SHORTWRITE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1208
1209
1210
1211
1212
  		/* Has the server at least made some progress? */
  		if (resp->count != 0) {
  			/* Was this an NFSv2 write or an NFSv3 stable write? */
  			if (resp->verf->committed != NFS_UNSTABLE) {
  				/* Resend from where the server left off */
a69aef149   Fred Isaman   NFSv4.1: pnfs fil...
1213
  				data->mds_offset += resp->count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1214
1215
1216
1217
1218
1219
1220
1221
1222
  				argp->offset += resp->count;
  				argp->pgbase += resp->count;
  				argp->count -= resp->count;
  			} else {
  				/* Resend as a stable write in order to avoid
  				 * headaches in the case of a server crash.
  				 */
  				argp->stable = NFS_FILE_SYNC;
  			}
d00c5d438   Trond Myklebust   NFS: Get rid of n...
1223
  			rpc_restart_call_prepare(task);
136028967   Fred Isaman   NFS: change nfs_w...
1224
  			return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
  		}
  		if (time_before(complain, jiffies)) {
  			printk(KERN_WARNING
  			       "NFS: Server wrote zero bytes, expected %u.
  ",
  					argp->count);
  			complain = jiffies + 300 * HZ;
  		}
  		/* Can't do anything about it except throw an error. */
  		task->tk_status = -EIO;
  	}
136028967   Fred Isaman   NFS: change nfs_w...
1236
  	return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1237
1238
1239
1240
  }
  
  
  #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
71d0a6112   Trond Myklebust   NFS: Fix an unsta...
1241
1242
  static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait)
  {
b8413f98f   Trond Myklebust   NFS: Fix a hang/i...
1243
  	int ret;
71d0a6112   Trond Myklebust   NFS: Fix an unsta...
1244
1245
  	if (!test_and_set_bit(NFS_INO_COMMIT, &nfsi->flags))
  		return 1;
b8413f98f   Trond Myklebust   NFS: Fix a hang/i...
1246
1247
1248
1249
1250
1251
1252
  	if (!may_wait)
  		return 0;
  	ret = out_of_line_wait_on_bit_lock(&nfsi->flags,
  				NFS_INO_COMMIT,
  				nfs_wait_bit_killable,
  				TASK_KILLABLE);
  	return (ret < 0) ? ret : 1;
71d0a6112   Trond Myklebust   NFS: Fix an unsta...
1253
  }
e0c2b3801   Fred Isaman   NFSv4.1: filelayo...
1254
  void nfs_commit_clear_lock(struct nfs_inode *nfsi)
71d0a6112   Trond Myklebust   NFS: Fix an unsta...
1255
1256
1257
1258
1259
  {
  	clear_bit(NFS_INO_COMMIT, &nfsi->flags);
  	smp_mb__after_clear_bit();
  	wake_up_bit(&nfsi->flags, NFS_INO_COMMIT);
  }
e0c2b3801   Fred Isaman   NFSv4.1: filelayo...
1260
  EXPORT_SYMBOL_GPL(nfs_commit_clear_lock);
71d0a6112   Trond Myklebust   NFS: Fix an unsta...
1261

e0c2b3801   Fred Isaman   NFSv4.1: filelayo...
1262
  void nfs_commitdata_release(void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1263
  {
383ba7193   Trond Myklebust   NFS: Fix a deadlo...
1264
  	struct nfs_write_data *wdata = data;
988b6dceb   Fred Isaman   NFSv4.1: remove G...
1265
  	put_lseg(wdata->lseg);
383ba7193   Trond Myklebust   NFS: Fix a deadlo...
1266
  	put_nfs_open_context(wdata->args.context);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1267
1268
  	nfs_commit_free(wdata);
  }
e0c2b3801   Fred Isaman   NFSv4.1: filelayo...
1269
  EXPORT_SYMBOL_GPL(nfs_commitdata_release);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1270

e0c2b3801   Fred Isaman   NFSv4.1: filelayo...
1271
  int nfs_initiate_commit(struct nfs_write_data *data, struct rpc_clnt *clnt,
9ace33cdc   Fred Isaman   NFSv4.1: rearrang...
1272
1273
  			const struct rpc_call_ops *call_ops,
  			int how)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274
  {
077376919   Trond Myklebust   NFS/SUNRPC: Conve...
1275
  	struct rpc_task *task;
9ace33cdc   Fred Isaman   NFSv4.1: rearrang...
1276
  	int priority = flush_task_priority(how);
bdc7f021f   Trond Myklebust   NFS: Clean up the...
1277
1278
1279
  	struct rpc_message msg = {
  		.rpc_argp = &data->args,
  		.rpc_resp = &data->res,
9ace33cdc   Fred Isaman   NFSv4.1: rearrang...
1280
  		.rpc_cred = data->cred,
bdc7f021f   Trond Myklebust   NFS: Clean up the...
1281
  	};
84115e1cd   Trond Myklebust   SUNRPC: Cleanup o...
1282
  	struct rpc_task_setup task_setup_data = {
077376919   Trond Myklebust   NFS/SUNRPC: Conve...
1283
  		.task = &data->task,
9ace33cdc   Fred Isaman   NFSv4.1: rearrang...
1284
  		.rpc_client = clnt,
bdc7f021f   Trond Myklebust   NFS: Clean up the...
1285
  		.rpc_message = &msg,
9ace33cdc   Fred Isaman   NFSv4.1: rearrang...
1286
  		.callback_ops = call_ops,
84115e1cd   Trond Myklebust   SUNRPC: Cleanup o...
1287
  		.callback_data = data,
101070ca2   Trond Myklebust   NFS: Ensure that ...
1288
  		.workqueue = nfsiod_workqueue,
2c61be0a9   Trond Myklebust   NFS: Ensure that ...
1289
  		.flags = RPC_TASK_ASYNC,
3ff7576dd   Trond Myklebust   SUNRPC: Clean up ...
1290
  		.priority = priority,
84115e1cd   Trond Myklebust   SUNRPC: Cleanup o...
1291
  	};
9ace33cdc   Fred Isaman   NFSv4.1: rearrang...
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
  	/* Set up the initial task struct.  */
  	NFS_PROTO(data->inode)->commit_setup(data, &msg);
  
  	dprintk("NFS: %5u initiated commit call
  ", data->task.tk_pid);
  
  	task = rpc_run_task(&task_setup_data);
  	if (IS_ERR(task))
  		return PTR_ERR(task);
  	if (how & FLUSH_SYNC)
  		rpc_wait_for_completion_task(task);
  	rpc_put_task(task);
  	return 0;
  }
e0c2b3801   Fred Isaman   NFSv4.1: filelayo...
1306
  EXPORT_SYMBOL_GPL(nfs_initiate_commit);
9ace33cdc   Fred Isaman   NFSv4.1: rearrang...
1307
1308
1309
1310
  
  /*
   * Set up the argument/result storage required for the RPC call.
   */
e0c2b3801   Fred Isaman   NFSv4.1: filelayo...
1311
  void nfs_init_commit(struct nfs_write_data *data,
988b6dceb   Fred Isaman   NFSv4.1: remove G...
1312
1313
  			    struct list_head *head,
  			    struct pnfs_layout_segment *lseg)
9ace33cdc   Fred Isaman   NFSv4.1: rearrang...
1314
1315
  {
  	struct nfs_page *first = nfs_list_entry(head->next);
3d4ff43d8   Al Viro   nfs_open_context ...
1316
  	struct inode *inode = first->wb_context->dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1317
1318
1319
1320
1321
  
  	/* Set up the RPC argument and reply structs
  	 * NB: take care not to mess about with data->commit et al. */
  
  	list_splice_init(head, &data->pages);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1322

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323
  	data->inode	  = inode;
9ace33cdc   Fred Isaman   NFSv4.1: rearrang...
1324
  	data->cred	  = first->wb_context->cred;
988b6dceb   Fred Isaman   NFSv4.1: remove G...
1325
  	data->lseg	  = lseg; /* reference transferred */
9ace33cdc   Fred Isaman   NFSv4.1: rearrang...
1326
  	data->mds_ops     = &nfs_commit_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1327
1328
  
  	data->args.fh     = NFS_FH(data->inode);
3da28eb1c   Trond Myklebust   [PATCH] NFS: Repl...
1329
1330
1331
  	/* Note: we always request a commit of the entire inode */
  	data->args.offset = 0;
  	data->args.count  = 0;
383ba7193   Trond Myklebust   NFS: Fix a deadlo...
1332
  	data->args.context = get_nfs_open_context(first->wb_context);
3da28eb1c   Trond Myklebust   [PATCH] NFS: Repl...
1333
  	data->res.count   = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1334
1335
  	data->res.fattr   = &data->fattr;
  	data->res.verf    = &data->verf;
0e574af1b   Trond Myklebust   NFS: Cleanup init...
1336
  	nfs_fattr_init(&data->fattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1337
  }
e0c2b3801   Fred Isaman   NFSv4.1: filelayo...
1338
  EXPORT_SYMBOL_GPL(nfs_init_commit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339

e0c2b3801   Fred Isaman   NFSv4.1: filelayo...
1340
  void nfs_retry_commit(struct list_head *page_list,
a861a1e1c   Fred Isaman   NFSv4.1: add gene...
1341
  		      struct pnfs_layout_segment *lseg)
64bfeb49b   Fred Isaman   NFSv4.1: pull err...
1342
1343
1344
1345
1346
1347
  {
  	struct nfs_page *req;
  
  	while (!list_empty(page_list)) {
  		req = nfs_list_entry(page_list->next);
  		nfs_list_remove_request(req);
a861a1e1c   Fred Isaman   NFSv4.1: add gene...
1348
  		nfs_mark_request_commit(req, lseg);
64bfeb49b   Fred Isaman   NFSv4.1: pull err...
1349
1350
1351
1352
1353
1354
  		dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
  		dec_bdi_stat(req->wb_page->mapping->backing_dev_info,
  			     BDI_RECLAIMABLE);
  		nfs_clear_page_tag_locked(req);
  	}
  }
e0c2b3801   Fred Isaman   NFSv4.1: filelayo...
1355
  EXPORT_SYMBOL_GPL(nfs_retry_commit);
64bfeb49b   Fred Isaman   NFSv4.1: pull err...
1356

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1357
1358
1359
1360
  /*
   * Commit dirty pages
   */
  static int
40859d7ee   Chuck Lever   NFS: support larg...
1361
  nfs_commit_list(struct inode *inode, struct list_head *head, int how)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1362
1363
  {
  	struct nfs_write_data	*data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1364

c9d8f89d9   Trond Myklebust   NFS: Ensure that ...
1365
  	data = nfs_commitdata_alloc();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1366
1367
1368
1369
1370
  
  	if (!data)
  		goto out_bad;
  
  	/* Set up the argument struct */
988b6dceb   Fred Isaman   NFSv4.1: remove G...
1371
  	nfs_init_commit(data, head, NULL);
9ace33cdc   Fred Isaman   NFSv4.1: rearrang...
1372
  	return nfs_initiate_commit(data, NFS_CLIENT(inode), data->mds_ops, how);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1373
   out_bad:
a861a1e1c   Fred Isaman   NFSv4.1: add gene...
1374
  	nfs_retry_commit(head, NULL);
71d0a6112   Trond Myklebust   NFS: Fix an unsta...
1375
  	nfs_commit_clear_lock(NFS_I(inode));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1376
1377
1378
1379
1380
1381
  	return -ENOMEM;
  }
  
  /*
   * COMMIT call returned
   */
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
1382
  static void nfs_commit_done(struct rpc_task *task, void *calldata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1383
  {
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
1384
  	struct nfs_write_data	*data = calldata;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1385

a3f565b1e   Chuck Lever   NFS: fix print fo...
1386
1387
          dprintk("NFS: %5u nfs_commit_done (status %d)
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1388
                                  task->tk_pid, task->tk_status);
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
1389
  	/* Call the NFS version-specific code */
c0d0e96b8   Trond Myklebust   NFS: Get rid of p...
1390
  	NFS_PROTO(data->inode)->commit_done(task, data);
c9d8f89d9   Trond Myklebust   NFS: Ensure that ...
1391
  }
e0c2b3801   Fred Isaman   NFSv4.1: filelayo...
1392
  void nfs_commit_release_pages(struct nfs_write_data *data)
c9d8f89d9   Trond Myklebust   NFS: Ensure that ...
1393
  {
5917ce844   Fred Isaman   NFSv4.1: pull out...
1394
  	struct nfs_page	*req;
c9d8f89d9   Trond Myklebust   NFS: Ensure that ...
1395
  	int status = data->task.tk_status;
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
1396

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1397
1398
1399
  	while (!list_empty(&data->pages)) {
  		req = nfs_list_entry(data->pages.next);
  		nfs_list_remove_request(req);
e468bae97   Trond Myklebust   NFS: Allow redirt...
1400
  		nfs_clear_request_commit(req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1401

48186c7d5   Chuck Lever   NFS: Fix trace de...
1402
  		dprintk("NFS:       commit (%s/%lld %d@%lld)",
3d4ff43d8   Al Viro   nfs_open_context ...
1403
1404
  			req->wb_context->dentry->d_sb->s_id,
  			(long long)NFS_FILEID(req->wb_context->dentry->d_inode),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1405
1406
  			req->wb_bytes,
  			(long long)req_offset(req));
c9d8f89d9   Trond Myklebust   NFS: Ensure that ...
1407
1408
  		if (status < 0) {
  			nfs_context_set_write_error(req->wb_context, status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1409
  			nfs_inode_remove_request(req);
c9d8f89d9   Trond Myklebust   NFS: Ensure that ...
1410
1411
  			dprintk(", error = %d
  ", status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
  			goto next;
  		}
  
  		/* Okay, COMMIT succeeded, apparently. Check the verifier
  		 * returned by the server against all stored verfs. */
  		if (!memcmp(req->wb_verf.verifier, data->verf.verifier, sizeof(data->verf.verifier))) {
  			/* We have a match */
  			nfs_inode_remove_request(req);
  			dprintk(" OK
  ");
  			goto next;
  		}
  		/* We have a mismatch. Write the page again */
  		dprintk(" mismatch
  ");
6d884e8fc   Fred   nfs: nfs_redirty_...
1427
  		nfs_mark_request_dirty(req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1428
  	next:
9fd367f0f   Trond Myklebust   NFS cleanup: Rena...
1429
  		nfs_clear_page_tag_locked(req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1430
  	}
5917ce844   Fred Isaman   NFSv4.1: pull out...
1431
  }
e0c2b3801   Fred Isaman   NFSv4.1: filelayo...
1432
  EXPORT_SYMBOL_GPL(nfs_commit_release_pages);
5917ce844   Fred Isaman   NFSv4.1: pull out...
1433
1434
1435
1436
1437
1438
  
  static void nfs_commit_release(void *calldata)
  {
  	struct nfs_write_data *data = calldata;
  
  	nfs_commit_release_pages(data);
71d0a6112   Trond Myklebust   NFS: Fix an unsta...
1439
  	nfs_commit_clear_lock(NFS_I(data->inode));
c9d8f89d9   Trond Myklebust   NFS: Ensure that ...
1440
  	nfs_commitdata_release(calldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1441
  }
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
1442
1443
  
  static const struct rpc_call_ops nfs_commit_ops = {
21d9a851a   Andy Adamson   nfs41 commit sequ...
1444
1445
1446
  #if defined(CONFIG_NFS_V4_1)
  	.rpc_call_prepare = nfs_write_prepare,
  #endif /* CONFIG_NFS_V4_1 */
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
1447
1448
1449
  	.rpc_call_done = nfs_commit_done,
  	.rpc_release = nfs_commit_release,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1450

b608b283a   Trond Myklebust   NFS: kswapd must ...
1451
  int nfs_commit_inode(struct inode *inode, int how)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1452
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1453
  	LIST_HEAD(head);
71d0a6112   Trond Myklebust   NFS: Fix an unsta...
1454
  	int may_wait = how & FLUSH_SYNC;
b8413f98f   Trond Myklebust   NFS: Fix a hang/i...
1455
  	int res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1456

b8413f98f   Trond Myklebust   NFS: Fix a hang/i...
1457
1458
  	res = nfs_commit_set_lock(NFS_I(inode), may_wait);
  	if (res <= 0)
c5efa5fc9   Trond Myklebust   NFS: Ensure that ...
1459
  		goto out_mark_dirty;
3da28eb1c   Trond Myklebust   [PATCH] NFS: Repl...
1460
  	res = nfs_scan_commit(inode, &head, 0, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1461
  	if (res) {
a861a1e1c   Fred Isaman   NFSv4.1: add gene...
1462
1463
1464
1465
1466
  		int error;
  
  		error = pnfs_commit_list(inode, &head, how);
  		if (error == PNFS_NOT_ATTEMPTED)
  			error = nfs_commit_list(inode, &head, how);
3da28eb1c   Trond Myklebust   [PATCH] NFS: Repl...
1467
1468
  		if (error < 0)
  			return error;
b8413f98f   Trond Myklebust   NFS: Fix a hang/i...
1469
  		if (!may_wait)
c5efa5fc9   Trond Myklebust   NFS: Ensure that ...
1470
  			goto out_mark_dirty;
b8413f98f   Trond Myklebust   NFS: Fix a hang/i...
1471
1472
1473
1474
1475
1476
  		error = wait_on_bit(&NFS_I(inode)->flags,
  				NFS_INO_COMMIT,
  				nfs_wait_bit_killable,
  				TASK_KILLABLE);
  		if (error < 0)
  			return error;
71d0a6112   Trond Myklebust   NFS: Fix an unsta...
1477
1478
  	} else
  		nfs_commit_clear_lock(NFS_I(inode));
c5efa5fc9   Trond Myklebust   NFS: Ensure that ...
1479
1480
1481
1482
1483
1484
1485
1486
  	return res;
  	/* Note: If we exit without ensuring that the commit is complete,
  	 * we must mark the inode as dirty. Otherwise, future calls to
  	 * sync_inode() with the WB_SYNC_ALL flag set will fail to ensure
  	 * that the data is on the disk.
  	 */
  out_mark_dirty:
  	__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1487
1488
  	return res;
  }
8fc795f70   Trond Myklebust   NFS: Cleanup - mo...
1489
1490
1491
  
  static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_control *wbc)
  {
420e3646b   Trond Myklebust   NFS: Reduce the n...
1492
1493
1494
  	struct nfs_inode *nfsi = NFS_I(inode);
  	int flags = FLUSH_SYNC;
  	int ret = 0;
8fc795f70   Trond Myklebust   NFS: Cleanup - mo...
1495

3236c3e1a   Jeff Layton   nfs: don't redirt...
1496
1497
1498
  	/* no commits means nothing needs to be done */
  	if (!nfsi->ncommit)
  		return ret;
a00dd6c03   Jeff Layton   NFS: don't use FL...
1499
1500
1501
1502
1503
1504
  	if (wbc->sync_mode == WB_SYNC_NONE) {
  		/* Don't commit yet if this is a non-blocking flush and there
  		 * are a lot of outstanding writes for this mapping.
  		 */
  		if (nfsi->ncommit <= (nfsi->npages >> 1))
  			goto out_mark_dirty;
420e3646b   Trond Myklebust   NFS: Reduce the n...
1505

a00dd6c03   Jeff Layton   NFS: don't use FL...
1506
  		/* don't wait for the COMMIT response */
420e3646b   Trond Myklebust   NFS: Reduce the n...
1507
  		flags = 0;
a00dd6c03   Jeff Layton   NFS: don't use FL...
1508
  	}
420e3646b   Trond Myklebust   NFS: Reduce the n...
1509
1510
1511
1512
1513
1514
1515
1516
  	ret = nfs_commit_inode(inode, flags);
  	if (ret >= 0) {
  		if (wbc->sync_mode == WB_SYNC_NONE) {
  			if (ret < wbc->nr_to_write)
  				wbc->nr_to_write -= ret;
  			else
  				wbc->nr_to_write = 0;
  		}
8fc795f70   Trond Myklebust   NFS: Cleanup - mo...
1517
  		return 0;
420e3646b   Trond Myklebust   NFS: Reduce the n...
1518
1519
  	}
  out_mark_dirty:
8fc795f70   Trond Myklebust   NFS: Cleanup - mo...
1520
1521
1522
  	__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
  	return ret;
  }
c63c7b051   Trond Myklebust   NFS: Fix a race w...
1523
  #else
8fc795f70   Trond Myklebust   NFS: Cleanup - mo...
1524
1525
1526
1527
  static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_control *wbc)
  {
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1528
  #endif
8fc795f70   Trond Myklebust   NFS: Cleanup - mo...
1529
1530
  int nfs_write_inode(struct inode *inode, struct writeback_control *wbc)
  {
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1531
1532
1533
1534
  	int ret;
  
  	ret = nfs_commit_unstable_pages(inode, wbc);
  	if (ret >= 0 && test_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags)) {
ef3115378   Andy Adamson   NFSv4.1 convert l...
1535
1536
  		int status;
  		bool sync = true;
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1537

846d5a091   Wu Fengguang   writeback: remove...
1538
  		if (wbc->sync_mode == WB_SYNC_NONE)
ef3115378   Andy Adamson   NFSv4.1 convert l...
1539
  			sync = false;
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1540
1541
1542
1543
1544
1545
  
  		status = pnfs_layoutcommit_inode(inode, sync);
  		if (status < 0)
  			return status;
  	}
  	return ret;
8fc795f70   Trond Myklebust   NFS: Cleanup - mo...
1546
  }
acdc53b21   Trond Myklebust   NFS: Replace __nf...
1547
1548
1549
1550
  /*
   * flush the inode to disk.
   */
  int nfs_wb_all(struct inode *inode)
34901f70d   Trond Myklebust   NFS: Writeback op...
1551
1552
  {
  	struct writeback_control wbc = {
72cb77f4a   Trond Myklebust   NFS: Throttle pag...
1553
  		.sync_mode = WB_SYNC_ALL,
34901f70d   Trond Myklebust   NFS: Writeback op...
1554
  		.nr_to_write = LONG_MAX,
d7fb12077   Trond Myklebust   NFS: Don't use ra...
1555
1556
  		.range_start = 0,
  		.range_end = LLONG_MAX,
34901f70d   Trond Myklebust   NFS: Writeback op...
1557
  	};
34901f70d   Trond Myklebust   NFS: Writeback op...
1558

acdc53b21   Trond Myklebust   NFS: Replace __nf...
1559
  	return sync_inode(inode, &wbc);
1c75950b9   Trond Myklebust   NFS: cleanup of n...
1560
  }
1b3b4a1a2   Trond Myklebust   NFS: Fix a write ...
1561
1562
1563
  int nfs_wb_page_cancel(struct inode *inode, struct page *page)
  {
  	struct nfs_page *req;
1b3b4a1a2   Trond Myklebust   NFS: Fix a write ...
1564
1565
1566
1567
  	int ret = 0;
  
  	BUG_ON(!PageLocked(page));
  	for (;;) {
ba8b06e67   Trond Myklebust   NFS: Ensure that ...
1568
  		wait_on_page_writeback(page);
1b3b4a1a2   Trond Myklebust   NFS: Fix a write ...
1569
1570
  		req = nfs_page_find_request(page);
  		if (req == NULL)
1b3b4a1a2   Trond Myklebust   NFS: Fix a write ...
1571
  			break;
1b3b4a1a2   Trond Myklebust   NFS: Fix a write ...
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
  		if (nfs_lock_request_dontget(req)) {
  			nfs_inode_remove_request(req);
  			/*
  			 * In case nfs_inode_remove_request has marked the
  			 * page as being dirty
  			 */
  			cancel_dirty_page(page, PAGE_CACHE_SIZE);
  			nfs_unlock_request(req);
  			break;
  		}
  		ret = nfs_wait_on_request(req);
c9edda714   Trond Myklebust   NFS: Fix a refere...
1583
  		nfs_release_request(req);
1b3b4a1a2   Trond Myklebust   NFS: Fix a write ...
1584
  		if (ret < 0)
c988950eb   Trond Myklebust   NFS: Simplify nfs...
1585
  			break;
1b3b4a1a2   Trond Myklebust   NFS: Fix a write ...
1586
  	}
1b3b4a1a2   Trond Myklebust   NFS: Fix a write ...
1587
1588
  	return ret;
  }
7f2f12d96   Trond Myklebust   NFS: Simplify nfs...
1589
1590
1591
1592
  /*
   * Write back all requests on one page - we do this before reading it.
   */
  int nfs_wb_page(struct inode *inode, struct page *page)
1c75950b9   Trond Myklebust   NFS: cleanup of n...
1593
1594
1595
  {
  	loff_t range_start = page_offset(page);
  	loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1);
4d770ccf4   Trond Myklebust   NFS: Ensure that ...
1596
  	struct writeback_control wbc = {
4d770ccf4   Trond Myklebust   NFS: Ensure that ...
1597
  		.sync_mode = WB_SYNC_ALL,
7f2f12d96   Trond Myklebust   NFS: Simplify nfs...
1598
  		.nr_to_write = 0,
4d770ccf4   Trond Myklebust   NFS: Ensure that ...
1599
1600
1601
1602
  		.range_start = range_start,
  		.range_end = range_end,
  	};
  	int ret;
1c75950b9   Trond Myklebust   NFS: cleanup of n...
1603

0522f6ade   Trond Myklebust   NFS: Fix another ...
1604
  	for (;;) {
ba8b06e67   Trond Myklebust   NFS: Ensure that ...
1605
  		wait_on_page_writeback(page);
73e3302f6   Trond Myklebust   NFS: Fix nfs_wb_p...
1606
1607
1608
1609
  		if (clear_page_dirty_for_io(page)) {
  			ret = nfs_writepage_locked(page, &wbc);
  			if (ret < 0)
  				goto out_error;
0522f6ade   Trond Myklebust   NFS: Fix another ...
1610
  			continue;
7f2f12d96   Trond Myklebust   NFS: Simplify nfs...
1611
  		}
0522f6ade   Trond Myklebust   NFS: Fix another ...
1612
1613
1614
  		if (!PagePrivate(page))
  			break;
  		ret = nfs_commit_inode(inode, FLUSH_SYNC);
ba8b06e67   Trond Myklebust   NFS: Ensure that ...
1615
  		if (ret < 0)
73e3302f6   Trond Myklebust   NFS: Fix nfs_wb_p...
1616
  			goto out_error;
7f2f12d96   Trond Myklebust   NFS: Simplify nfs...
1617
  	}
73e3302f6   Trond Myklebust   NFS: Fix nfs_wb_p...
1618
1619
  	return 0;
  out_error:
4d770ccf4   Trond Myklebust   NFS: Ensure that ...
1620
  	return ret;
1c75950b9   Trond Myklebust   NFS: cleanup of n...
1621
  }
074cc1dee   Trond Myklebust   NFS: Add a ->migr...
1622
1623
  #ifdef CONFIG_MIGRATION
  int nfs_migrate_page(struct address_space *mapping, struct page *newpage,
a6bc32b89   Mel Gorman   mm: compaction: i...
1624
  		struct page *page, enum migrate_mode mode)
074cc1dee   Trond Myklebust   NFS: Add a ->migr...
1625
  {
2da956523   Jeff Layton   nfs: don't try to...
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
  	/*
  	 * If PagePrivate is set, then the page is currently associated with
  	 * an in-progress read or write request. Don't try to migrate it.
  	 *
  	 * FIXME: we could do this in principle, but we'll need a way to ensure
  	 *        that we can safely release the inode reference while holding
  	 *        the page lock.
  	 */
  	if (PagePrivate(page))
  		return -EBUSY;
074cc1dee   Trond Myklebust   NFS: Add a ->migr...
1636

7549ad5f9   Trond Myklebust   NFS: Remove a red...
1637
  	nfs_fscache_release_page(page, GFP_KERNEL);
074cc1dee   Trond Myklebust   NFS: Add a ->migr...
1638

a6bc32b89   Mel Gorman   mm: compaction: i...
1639
  	return migrate_page(mapping, newpage, page, mode);
074cc1dee   Trond Myklebust   NFS: Add a ->migr...
1640
1641
  }
  #endif
f7b422b17   David Howells   NFS: Split fs/nfs...
1642
  int __init nfs_init_writepagecache(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1643
1644
1645
1646
  {
  	nfs_wdata_cachep = kmem_cache_create("nfs_write_data",
  					     sizeof(struct nfs_write_data),
  					     0, SLAB_HWCACHE_ALIGN,
20c2df83d   Paul Mundt   mm: Remove slab d...
1647
  					     NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1648
1649
  	if (nfs_wdata_cachep == NULL)
  		return -ENOMEM;
93d2341c7   Matthew Dobson   [PATCH] mempool: ...
1650
1651
  	nfs_wdata_mempool = mempool_create_slab_pool(MIN_POOL_WRITE,
  						     nfs_wdata_cachep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1652
1653
  	if (nfs_wdata_mempool == NULL)
  		return -ENOMEM;
93d2341c7   Matthew Dobson   [PATCH] mempool: ...
1654
1655
  	nfs_commit_mempool = mempool_create_slab_pool(MIN_POOL_COMMIT,
  						      nfs_wdata_cachep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1656
1657
  	if (nfs_commit_mempool == NULL)
  		return -ENOMEM;
89a09141d   Peter Zijlstra   [PATCH] nfs: fix ...
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
  	/*
  	 * NFS congestion size, scale with available memory.
  	 *
  	 *  64MB:    8192k
  	 * 128MB:   11585k
  	 * 256MB:   16384k
  	 * 512MB:   23170k
  	 *   1GB:   32768k
  	 *   2GB:   46340k
  	 *   4GB:   65536k
  	 *   8GB:   92681k
  	 *  16GB:  131072k
  	 *
  	 * This allows larger machines to have larger/more transfers.
  	 * Limit the default to 256M
  	 */
  	nfs_congestion_kb = (16*int_sqrt(totalram_pages)) << (PAGE_SHIFT-10);
  	if (nfs_congestion_kb > 256*1024)
  		nfs_congestion_kb = 256*1024;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1677
1678
  	return 0;
  }
266bee886   David Brownell   [PATCH] fix stati...
1679
  void nfs_destroy_writepagecache(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1680
1681
1682
  {
  	mempool_destroy(nfs_commit_mempool);
  	mempool_destroy(nfs_wdata_mempool);
1a1d92c10   Alexey Dobriyan   [PATCH] Really ig...
1683
  	kmem_cache_destroy(nfs_wdata_cachep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1684
  }