Blame view

fs/nfs/pagelist.c 37.3 KB
457c89965   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
  /*
   * linux/fs/nfs/pagelist.c
   *
   * A set of helper functions for managing NFS read and write requests.
   * The main purpose of these routines is to provide support for the
   * coalescing of several requests into a single RPC call.
   *
   * Copyright 2000, 2001 (c) Trond Myklebust <trond.myklebust@fys.uio.no>
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
  #include <linux/slab.h>
  #include <linux/file.h>
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
14
  #include <linux/sched.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include <linux/sunrpc/clnt.h>
1313e6034   Trond Myklebust   NFS: Remove unnec...
16
  #include <linux/nfs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
  #include <linux/nfs3.h>
  #include <linux/nfs4.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
  #include <linux/nfs_fs.h>
33344e0f7   Trond Myklebust   pNFS: Add trackin...
20
  #include <linux/nfs_page.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  #include <linux/nfs_mount.h>
afeacc8c1   Paul Gortmaker   fs: add export.h ...
22
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23

8d5658c94   Trond Myklebust   NFS: Fix a buffer...
24
  #include "internal.h"
bae724ef9   Fred Isaman   NFSv4.1: shift pn...
25
  #include "pnfs.h"
cd2ed9bdc   Chuck Lever   NFS: Add a tracep...
26
  #include "nfstrace.h"
8d5658c94   Trond Myklebust   NFS: Fix a buffer...
27

0eecb2145   Anna Schumaker   NFS: Create a com...
28
  #define NFSDBG_FACILITY		NFSDBG_PAGECACHE
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
29
  static struct kmem_cache *nfs_page_cachep;
ef2c488c0   Anna Schumaker   NFS: Create a gen...
30
  static const struct rpc_call_ops nfs_pgio_common_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31

63e2fffa5   Trond Myklebust   pNFS/flexfiles: F...
32
33
34
35
36
37
38
  static struct nfs_pgio_mirror *
  nfs_pgio_get_mirror(struct nfs_pageio_descriptor *desc, u32 idx)
  {
  	if (desc->pg_ops->pg_get_mirror)
  		return desc->pg_ops->pg_get_mirror(desc, idx);
  	return &desc->pg_mirrors[0];
  }
48d635f14   Peng Tao   nfs: add nfs_pgio...
39
40
41
  struct nfs_pgio_mirror *
  nfs_pgio_current_mirror(struct nfs_pageio_descriptor *desc)
  {
63e2fffa5   Trond Myklebust   pNFS/flexfiles: F...
42
  	return nfs_pgio_get_mirror(desc, desc->pg_mirror_idx);
48d635f14   Peng Tao   nfs: add nfs_pgio...
43
44
  }
  EXPORT_SYMBOL_GPL(nfs_pgio_current_mirror);
63e2fffa5   Trond Myklebust   pNFS/flexfiles: F...
45
46
47
48
49
50
51
  static u32
  nfs_pgio_set_current_mirror(struct nfs_pageio_descriptor *desc, u32 idx)
  {
  	if (desc->pg_ops->pg_set_mirror)
  		return desc->pg_ops->pg_set_mirror(desc, idx);
  	return desc->pg_mirror_idx;
  }
4db6e0b74   Fred Isaman   NFS: merge _full ...
52
53
54
55
  void nfs_pgheader_init(struct nfs_pageio_descriptor *desc,
  		       struct nfs_pgio_header *hdr,
  		       void (*release)(struct nfs_pgio_header *hdr))
  {
48d635f14   Peng Tao   nfs: add nfs_pgio...
56
  	struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc);
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
57
58
59
  
  
  	hdr->req = nfs_list_entry(mirror->pg_list.next);
4db6e0b74   Fred Isaman   NFS: merge _full ...
60
  	hdr->inode = desc->pg_inode;
9fcd5960e   Trond Myklebust   NFS: Add a helper...
61
  	hdr->cred = nfs_req_openctx(hdr->req)->cred;
4db6e0b74   Fred Isaman   NFS: merge _full ...
62
  	hdr->io_start = req_offset(hdr->req);
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
63
  	hdr->good_bytes = mirror->pg_count;
919e3bd9a   Trond Myklebust   NFS: Ensure we co...
64
  	hdr->io_completion = desc->pg_io_completion;
584aa810b   Fred Isaman   NFS: rewrite dire...
65
  	hdr->dreq = desc->pg_dreq;
4db6e0b74   Fred Isaman   NFS: merge _full ...
66
  	hdr->release = release;
061ae2edb   Fred Isaman   NFS: create compl...
67
  	hdr->completion_ops = desc->pg_completion_ops;
584aa810b   Fred Isaman   NFS: rewrite dire...
68
69
  	if (hdr->completion_ops->init_hdr)
  		hdr->completion_ops->init_hdr(hdr);
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
70
71
  
  	hdr->pgio_mirror_idx = desc->pg_mirror_idx;
4db6e0b74   Fred Isaman   NFS: merge _full ...
72
  }
89d77c8fa   Bryan Schumaker   NFS: Convert v4 i...
73
  EXPORT_SYMBOL_GPL(nfs_pgheader_init);
4db6e0b74   Fred Isaman   NFS: merge _full ...
74
75
76
  
  void nfs_set_pgio_error(struct nfs_pgio_header *hdr, int error, loff_t pos)
  {
1c6c4b740   Trond Myklebust   NFS: Remove priva...
77
  	unsigned int new = pos - hdr->io_start;
cd2ed9bdc   Chuck Lever   NFS: Add a tracep...
78
  	trace_nfs_pgio_error(hdr, error, pos);
1c6c4b740   Trond Myklebust   NFS: Remove priva...
79
80
  	if (hdr->good_bytes > new) {
  		hdr->good_bytes = new;
4db6e0b74   Fred Isaman   NFS: merge _full ...
81
  		clear_bit(NFS_IOHDR_EOF, &hdr->flags);
1c6c4b740   Trond Myklebust   NFS: Remove priva...
82
83
  		if (!test_and_set_bit(NFS_IOHDR_ERROR, &hdr->flags))
  			hdr->error = error;
4db6e0b74   Fred Isaman   NFS: merge _full ...
84
  	}
4db6e0b74   Fred Isaman   NFS: merge _full ...
85
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
  static inline struct nfs_page *
  nfs_page_alloc(void)
  {
2b17d725f   Trond Myklebust   NFS: Clean up wri...
89
  	struct nfs_page	*p = kmem_cache_zalloc(nfs_page_cachep, GFP_KERNEL);
72895b1ac   Jesper Juhl   nfs: Take advanta...
90
  	if (p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
  		INIT_LIST_HEAD(&p->wb_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
96
97
98
99
  	return p;
  }
  
  static inline void
  nfs_page_free(struct nfs_page *p)
  {
  	kmem_cache_free(nfs_page_cachep, p);
  }
577b42327   Trond Myklebust   NFS: Add function...
100
101
  /**
   * nfs_iocounter_wait - wait for i/o to complete
210c7c175   Benjamin Coddington   NFS: Use wait_on_...
102
   * @l_ctx: nfs_lock_context with io_counter to use
577b42327   Trond Myklebust   NFS: Add function...
103
104
105
106
107
   *
   * returns -ERESTARTSYS if interrupted by a fatal signal.
   * Otherwise returns 0 once the io_count hits 0.
   */
  int
210c7c175   Benjamin Coddington   NFS: Use wait_on_...
108
  nfs_iocounter_wait(struct nfs_lock_context *l_ctx)
577b42327   Trond Myklebust   NFS: Add function...
109
  {
723c921e7   Peter Zijlstra   sched/wait, fs/nf...
110
111
  	return wait_var_event_killable(&l_ctx->io_count,
  				       !atomic_read(&l_ctx->io_count));
577b42327   Trond Myklebust   NFS: Add function...
112
  }
7d6ddf88c   Benjamin Coddington   NFS: Add an iocou...
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  /**
   * nfs_async_iocounter_wait - wait on a rpc_waitqueue for I/O
   * to complete
   * @task: the rpc_task that should wait
   * @l_ctx: nfs_lock_context with io_counter to check
   *
   * Returns true if there is outstanding I/O to wait on and the
   * task has been put to sleep.
   */
  bool
  nfs_async_iocounter_wait(struct rpc_task *task, struct nfs_lock_context *l_ctx)
  {
  	struct inode *inode = d_inode(l_ctx->open_context->dentry);
  	bool ret = false;
  
  	if (atomic_read(&l_ctx->io_count) > 0) {
  		rpc_sleep_on(&NFS_SERVER(inode)->uoc_rpcwaitq, task, NULL);
  		ret = true;
  	}
  
  	if (atomic_read(&l_ctx->io_count) == 0) {
  		rpc_wake_up_queued_task(&NFS_SERVER(inode)->uoc_rpcwaitq, task);
  		ret = false;
  	}
  
  	return ret;
  }
  EXPORT_SYMBOL_GPL(nfs_async_iocounter_wait);
2bfc6e566   Weston Andros Adamson   nfs: add support ...
141
  /*
e00ed89d7   Trond Myklebust   NFS: Refactor nfs...
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
   * nfs_page_lock_head_request - page lock the head of the page group
   * @req: any member of the page group
   */
  struct nfs_page *
  nfs_page_group_lock_head(struct nfs_page *req)
  {
  	struct nfs_page *head = req->wb_head;
  
  	while (!nfs_lock_request(head)) {
  		int ret = nfs_wait_on_request(head);
  		if (ret < 0)
  			return ERR_PTR(ret);
  	}
  	if (head != req)
  		kref_get(&head->wb_kref);
  	return head;
  }
  
  /*
a62f8e3bd   Trond Myklebust   NFS: Clean up nfs...
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
   * nfs_unroll_locks -  unlock all newly locked reqs and wait on @req
   * @head: head request of page group, must be holding head lock
   * @req: request that couldn't lock and needs to wait on the req bit lock
   *
   * This is a helper function for nfs_lock_and_join_requests
   * returns 0 on success, < 0 on error.
   */
  static void
  nfs_unroll_locks(struct nfs_page *head, struct nfs_page *req)
  {
  	struct nfs_page *tmp;
  
  	/* relinquish all the locks successfully grabbed this run */
  	for (tmp = head->wb_this_page ; tmp != req; tmp = tmp->wb_this_page) {
  		if (!kref_read(&tmp->wb_kref))
  			continue;
  		nfs_unlock_and_release_request(tmp);
  	}
  }
  
  /*
   * nfs_page_group_lock_subreq -  try to lock a subrequest
   * @head: head request of page group
   * @subreq: request to lock
   *
   * This is a helper function for nfs_lock_and_join_requests which
   * must be called with the head request and page group both locked.
   * On error, it returns with the page group unlocked.
   */
  static int
  nfs_page_group_lock_subreq(struct nfs_page *head, struct nfs_page *subreq)
  {
  	int ret;
  
  	if (!kref_get_unless_zero(&subreq->wb_kref))
  		return 0;
  	while (!nfs_lock_request(subreq)) {
  		nfs_page_group_unlock(head);
  		ret = nfs_wait_on_request(subreq);
  		if (!ret)
  			ret = nfs_page_group_lock(head);
  		if (ret < 0) {
  			nfs_unroll_locks(head, subreq);
  			nfs_release_request(subreq);
  			return ret;
  		}
  	}
  	return 0;
  }
  
  /*
   * nfs_page_group_lock_subrequests -  try to lock the subrequests
   * @head: head request of page group
   *
   * This is a helper function for nfs_lock_and_join_requests which
e00ed89d7   Trond Myklebust   NFS: Refactor nfs...
216
   * must be called with the head request locked.
a62f8e3bd   Trond Myklebust   NFS: Clean up nfs...
217
218
219
220
221
   */
  int nfs_page_group_lock_subrequests(struct nfs_page *head)
  {
  	struct nfs_page *subreq;
  	int ret;
e00ed89d7   Trond Myklebust   NFS: Refactor nfs...
222
223
224
  	ret = nfs_page_group_lock(head);
  	if (ret < 0)
  		return ret;
a62f8e3bd   Trond Myklebust   NFS: Clean up nfs...
225
226
227
228
229
230
231
  	/* lock each request in the page group */
  	for (subreq = head->wb_this_page; subreq != head;
  			subreq = subreq->wb_this_page) {
  		ret = nfs_page_group_lock_subreq(head, subreq);
  		if (ret < 0)
  			return ret;
  	}
e00ed89d7   Trond Myklebust   NFS: Refactor nfs...
232
  	nfs_page_group_unlock(head);
a62f8e3bd   Trond Myklebust   NFS: Clean up nfs...
233
234
235
236
  	return 0;
  }
  
  /*
08ca8b21f   Trond Myklebust   NFS: Fix races nf...
237
238
   * nfs_page_set_headlock - set the request PG_HEADLOCK
   * @req: request that is to be locked
2bfc6e566   Weston Andros Adamson   nfs: add support ...
239
   *
08ca8b21f   Trond Myklebust   NFS: Fix races nf...
240
   * this lock must be held when modifying req->wb_head
e7029206f   Weston Andros Adamson   nfs: check wait_o...
241
   *
1344b7ea1   Trond Myklebust   NFS: Remove unuse...
242
   * return 0 on success, < 0 on error
2bfc6e566   Weston Andros Adamson   nfs: add support ...
243
   */
e7029206f   Weston Andros Adamson   nfs: check wait_o...
244
  int
08ca8b21f   Trond Myklebust   NFS: Fix races nf...
245
  nfs_page_set_headlock(struct nfs_page *req)
2bfc6e566   Weston Andros Adamson   nfs: add support ...
246
  {
08ca8b21f   Trond Myklebust   NFS: Fix races nf...
247
  	if (!test_and_set_bit(PG_HEADLOCK, &req->wb_flags))
bc8a309e8   Weston Andros Adamson   nfs: fix nonblock...
248
  		return 0;
e7029206f   Weston Andros Adamson   nfs: check wait_o...
249

08ca8b21f   Trond Myklebust   NFS: Fix races nf...
250
  	set_bit(PG_CONTENDED1, &req->wb_flags);
1344b7ea1   Trond Myklebust   NFS: Remove unuse...
251
  	smp_mb__after_atomic();
08ca8b21f   Trond Myklebust   NFS: Fix races nf...
252
  	return wait_on_bit_lock(&req->wb_flags, PG_HEADLOCK,
bc8a309e8   Weston Andros Adamson   nfs: fix nonblock...
253
  				TASK_UNINTERRUPTIBLE);
2bfc6e566   Weston Andros Adamson   nfs: add support ...
254
255
256
  }
  
  /*
08ca8b21f   Trond Myklebust   NFS: Fix races nf...
257
258
   * nfs_page_clear_headlock - clear the request PG_HEADLOCK
   * @req: request that is to be locked
2bfc6e566   Weston Andros Adamson   nfs: add support ...
259
260
   */
  void
08ca8b21f   Trond Myklebust   NFS: Fix races nf...
261
  nfs_page_clear_headlock(struct nfs_page *req)
2bfc6e566   Weston Andros Adamson   nfs: add support ...
262
  {
d1e1cda86   Linus Torvalds   Merge tag 'nfs-fo...
263
  	smp_mb__before_atomic();
08ca8b21f   Trond Myklebust   NFS: Fix races nf...
264
  	clear_bit(PG_HEADLOCK, &req->wb_flags);
d1e1cda86   Linus Torvalds   Merge tag 'nfs-fo...
265
  	smp_mb__after_atomic();
08ca8b21f   Trond Myklebust   NFS: Fix races nf...
266
  	if (!test_bit(PG_CONTENDED1, &req->wb_flags))
b4f937cff   Trond Myklebust   NFS: Don't run wa...
267
  		return;
08ca8b21f   Trond Myklebust   NFS: Fix races nf...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
  	wake_up_bit(&req->wb_flags, PG_HEADLOCK);
  }
  
  /*
   * nfs_page_group_lock - lock the head of the page group
   * @req: request in group that is to be locked
   *
   * this lock must be held when traversing or modifying the page
   * group list
   *
   * return 0 on success, < 0 on error
   */
  int
  nfs_page_group_lock(struct nfs_page *req)
  {
  	int ret;
  
  	ret = nfs_page_set_headlock(req);
  	if (ret || req->wb_head == req)
  		return ret;
  	return nfs_page_set_headlock(req->wb_head);
  }
  
  /*
   * nfs_page_group_unlock - unlock the head of the page group
   * @req: request in group that is to be unlocked
   */
  void
  nfs_page_group_unlock(struct nfs_page *req)
  {
  	if (req != req->wb_head)
  		nfs_page_clear_headlock(req->wb_head);
  	nfs_page_clear_headlock(req);
2bfc6e566   Weston Andros Adamson   nfs: add support ...
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
  }
  
  /*
   * nfs_page_group_sync_on_bit_locked
   *
   * must be called with page group lock held
   */
  static bool
  nfs_page_group_sync_on_bit_locked(struct nfs_page *req, unsigned int bit)
  {
  	struct nfs_page *head = req->wb_head;
  	struct nfs_page *tmp;
  
  	WARN_ON_ONCE(!test_bit(PG_HEADLOCK, &head->wb_flags));
  	WARN_ON_ONCE(test_and_set_bit(bit, &req->wb_flags));
  
  	tmp = req->wb_this_page;
  	while (tmp != req) {
  		if (!test_bit(bit, &tmp->wb_flags))
  			return false;
  		tmp = tmp->wb_this_page;
  	}
  
  	/* true! reset all bits */
  	tmp = req;
  	do {
  		clear_bit(bit, &tmp->wb_flags);
  		tmp = tmp->wb_this_page;
  	} while (tmp != req);
  
  	return true;
  }
  
  /*
   * nfs_page_group_sync_on_bit - set bit on current request, but only
   *   return true if the bit is set for all requests in page group
   * @req - request in page group
   * @bit - PG_* bit that is used to sync page group
   */
  bool nfs_page_group_sync_on_bit(struct nfs_page *req, unsigned int bit)
  {
  	bool ret;
1344b7ea1   Trond Myklebust   NFS: Remove unuse...
343
  	nfs_page_group_lock(req);
2bfc6e566   Weston Andros Adamson   nfs: add support ...
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
  	ret = nfs_page_group_sync_on_bit_locked(req, bit);
  	nfs_page_group_unlock(req);
  
  	return ret;
  }
  
  /*
   * nfs_page_group_init - Initialize the page group linkage for @req
   * @req - a new nfs request
   * @prev - the previous request in page group, or NULL if @req is the first
   *         or only request in the group (the head).
   */
  static inline void
  nfs_page_group_init(struct nfs_page *req, struct nfs_page *prev)
  {
cb1410c71   Weston Andros Adamson   NFS: fix subtle c...
359
  	struct inode *inode;
2bfc6e566   Weston Andros Adamson   nfs: add support ...
360
361
362
  	WARN_ON_ONCE(prev == req);
  
  	if (!prev) {
85710a837   Weston Andros Adamson   nfs: nfs_page sho...
363
  		/* a head request */
2bfc6e566   Weston Andros Adamson   nfs: add support ...
364
365
366
  		req->wb_head = req;
  		req->wb_this_page = req;
  	} else {
85710a837   Weston Andros Adamson   nfs: nfs_page sho...
367
  		/* a subrequest */
2bfc6e566   Weston Andros Adamson   nfs: add support ...
368
369
370
371
372
  		WARN_ON_ONCE(prev->wb_this_page != prev->wb_head);
  		WARN_ON_ONCE(!test_bit(PG_HEADLOCK, &prev->wb_head->wb_flags));
  		req->wb_head = prev->wb_head;
  		req->wb_this_page = prev->wb_this_page;
  		prev->wb_this_page = req;
85710a837   Weston Andros Adamson   nfs: nfs_page sho...
373
374
375
  		/* All subrequests take a ref on the head request until
  		 * nfs_page_group_destroy is called */
  		kref_get(&req->wb_head->wb_kref);
cb1410c71   Weston Andros Adamson   NFS: fix subtle c...
376
377
378
  		/* grab extra ref and bump the request count if head request
  		 * has extra ref from the write/commit path to handle handoff
  		 * between write and commit lists. */
17089a29a   Weston Andros Adamson   nfs: mark nfs_pag...
379
  		if (test_bit(PG_INODE_REF, &prev->wb_head->wb_flags)) {
cb1410c71   Weston Andros Adamson   NFS: fix subtle c...
380
  			inode = page_file_mapping(req->wb_page)->host;
17089a29a   Weston Andros Adamson   nfs: mark nfs_pag...
381
  			set_bit(PG_INODE_REF, &req->wb_flags);
2bfc6e566   Weston Andros Adamson   nfs: add support ...
382
  			kref_get(&req->wb_kref);
a6b6d5b85   Trond Myklebust   NFS: Use an atomi...
383
  			atomic_long_inc(&NFS_I(inode)->nrequests);
17089a29a   Weston Andros Adamson   nfs: mark nfs_pag...
384
  		}
2bfc6e566   Weston Andros Adamson   nfs: add support ...
385
386
387
388
389
390
391
392
393
394
395
396
397
398
  	}
  }
  
  /*
   * nfs_page_group_destroy - sync the destruction of page groups
   * @req - request that no longer needs the page group
   *
   * releases the page group reference from each member once all
   * members have called this function.
   */
  static void
  nfs_page_group_destroy(struct kref *kref)
  {
  	struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref);
08fead2ae   Trond Myklebust   NFS: Ensure we al...
399
  	struct nfs_page *head = req->wb_head;
2bfc6e566   Weston Andros Adamson   nfs: add support ...
400
401
402
  	struct nfs_page *tmp, *next;
  
  	if (!nfs_page_group_sync_on_bit(req, PG_TEARDOWN))
08fead2ae   Trond Myklebust   NFS: Ensure we al...
403
  		goto out;
2bfc6e566   Weston Andros Adamson   nfs: add support ...
404
405
406
407
408
409
410
411
412
413
  
  	tmp = req;
  	do {
  		next = tmp->wb_this_page;
  		/* unlink and free */
  		tmp->wb_this_page = tmp;
  		tmp->wb_head = tmp;
  		nfs_free_request(tmp);
  		tmp = next;
  	} while (tmp != req);
08fead2ae   Trond Myklebust   NFS: Ensure we al...
414
415
416
417
  out:
  	/* subrequests must release the ref on the head request */
  	if (head != req)
  		nfs_release_request(head);
2bfc6e566   Weston Andros Adamson   nfs: add support ...
418
  }
c917cfaf9   Trond Myklebust   NFS: Fix up NFS I...
419
420
  static struct nfs_page *
  __nfs_create_request(struct nfs_lock_context *l_ctx, struct page *page,
28b1d3f5a   Trond Myklebust   NFS: Remove unuse...
421
422
  		   unsigned int pgbase, unsigned int offset,
  		   unsigned int count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
  	struct nfs_page		*req;
c917cfaf9   Trond Myklebust   NFS: Fix up NFS I...
425
  	struct nfs_open_context *ctx = l_ctx->open_context;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426

c58c84418   Trond Myklebust   NFS: Don't accept...
427
428
  	if (test_bit(NFS_CONTEXT_BAD, &ctx->flags))
  		return ERR_PTR(-EBADF);
18eb88428   Trond Myklebust   NFS: Clean up nfs...
429
430
431
432
  	/* try to allocate the request struct */
  	req = nfs_page_alloc();
  	if (req == NULL)
  		return ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433

b3c54de6f   Trond Myklebust   NFS: Convert nfs_...
434
  	req->wb_lock_context = l_ctx;
c917cfaf9   Trond Myklebust   NFS: Fix up NFS I...
435
  	refcount_inc(&l_ctx->count);
210c7c175   Benjamin Coddington   NFS: Use wait_on_...
436
  	atomic_inc(&l_ctx->io_count);
015f0212d   Jeff Layton   nfs: handle lock ...
437

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
439
440
441
  	/* Initialize the request struct. Initially, we assume a
  	 * long write-back delay. This will be adjusted in
  	 * update_nfs_request below if the region is not locked. */
  	req->wb_page    = page;
67911c8f1   Anna Schumaker   NFS: Add nfs_comm...
442
  	if (page) {
8cd797887   Huang Ying   mm: remove page_f...
443
  		req->wb_index = page_index(page);
67911c8f1   Anna Schumaker   NFS: Add nfs_comm...
444
445
  		get_page(page);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
  	req->wb_offset  = offset;
c917cfaf9   Trond Myklebust   NFS: Fix up NFS I...
447
  	req->wb_pgbase	= pgbase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
  	req->wb_bytes   = count;
c03b40246   Trond Myklebust   NFS: Convert stru...
449
  	kref_init(&req->wb_kref);
33344e0f7   Trond Myklebust   pNFS: Add trackin...
450
  	req->wb_nio = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
452
453
454
  	return req;
  }
  
  /**
c917cfaf9   Trond Myklebust   NFS: Fix up NFS I...
455
456
457
   * nfs_create_request - Create an NFS read/write request.
   * @ctx: open context to use
   * @page: page to write
c917cfaf9   Trond Myklebust   NFS: Fix up NFS I...
458
459
460
461
462
463
464
465
466
   * @offset: starting offset within the page for the write
   * @count: number of bytes to read/write
   *
   * The page must be locked by the caller. This makes sure we never
   * create two different requests for the same page.
   * User should ensure it is safe to sleep in this function.
   */
  struct nfs_page *
  nfs_create_request(struct nfs_open_context *ctx, struct page *page,
28b1d3f5a   Trond Myklebust   NFS: Remove unuse...
467
  		   unsigned int offset, unsigned int count)
c917cfaf9   Trond Myklebust   NFS: Fix up NFS I...
468
469
470
471
472
473
  {
  	struct nfs_lock_context *l_ctx = nfs_get_lock_context(ctx);
  	struct nfs_page *ret;
  
  	if (IS_ERR(l_ctx))
  		return ERR_CAST(l_ctx);
28b1d3f5a   Trond Myklebust   NFS: Remove unuse...
474
475
476
  	ret = __nfs_create_request(l_ctx, page, offset, offset, count);
  	if (!IS_ERR(ret))
  		nfs_page_group_init(ret, NULL);
c917cfaf9   Trond Myklebust   NFS: Fix up NFS I...
477
478
479
480
481
  	nfs_put_lock_context(l_ctx);
  	return ret;
  }
  
  static struct nfs_page *
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
482
483
484
  nfs_create_subreq(struct nfs_page *req,
  		  unsigned int pgbase,
  		  unsigned int offset,
c917cfaf9   Trond Myklebust   NFS: Fix up NFS I...
485
486
  		  unsigned int count)
  {
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
487
  	struct nfs_page *last;
c917cfaf9   Trond Myklebust   NFS: Fix up NFS I...
488
  	struct nfs_page *ret;
28b1d3f5a   Trond Myklebust   NFS: Remove unuse...
489
  	ret = __nfs_create_request(req->wb_lock_context, req->wb_page,
c917cfaf9   Trond Myklebust   NFS: Fix up NFS I...
490
491
  			pgbase, offset, count);
  	if (!IS_ERR(ret)) {
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
492
493
494
495
496
  		/* find the last request */
  		for (last = req->wb_head;
  		     last->wb_this_page != req->wb_head;
  		     last = last->wb_this_page)
  			;
c917cfaf9   Trond Myklebust   NFS: Fix up NFS I...
497
498
  		nfs_lock_request(ret);
  		ret->wb_index = req->wb_index;
28b1d3f5a   Trond Myklebust   NFS: Remove unuse...
499
  		nfs_page_group_init(ret, last);
33344e0f7   Trond Myklebust   pNFS: Add trackin...
500
  		ret->wb_nio = req->wb_nio;
c917cfaf9   Trond Myklebust   NFS: Fix up NFS I...
501
502
503
504
505
  	}
  	return ret;
  }
  
  /**
1d1afcbc2   Trond Myklebust   NFS: Clean up - R...
506
   * nfs_unlock_request - Unlock request and wake up sleepers.
302fad7bd   Trond Myklebust   NFS: Fix up docum...
507
   * @req: pointer to request
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
   */
1d1afcbc2   Trond Myklebust   NFS: Clean up - R...
509
  void nfs_unlock_request(struct nfs_page *req)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
511
512
513
514
515
  {
  	if (!NFS_WBACK_BUSY(req)) {
  		printk(KERN_ERR "NFS: Invalid unlock attempted
  ");
  		BUG();
  	}
4e857c58e   Peter Zijlstra   arch: Mass conver...
516
  	smp_mb__before_atomic();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
  	clear_bit(PG_BUSY, &req->wb_flags);
4e857c58e   Peter Zijlstra   arch: Mass conver...
518
  	smp_mb__after_atomic();
b4f937cff   Trond Myklebust   NFS: Don't run wa...
519
520
  	if (!test_bit(PG_CONTENDED2, &req->wb_flags))
  		return;
464a98bd7   Trond Myklebust   [PATCH] NFS: clea...
521
  	wake_up_bit(&req->wb_flags, PG_BUSY);
3aff4ebb9   Trond Myklebust   NFS: Prevent a de...
522
523
524
  }
  
  /**
1d1afcbc2   Trond Myklebust   NFS: Clean up - R...
525
   * nfs_unlock_and_release_request - Unlock request and release the nfs_page
302fad7bd   Trond Myklebust   NFS: Fix up docum...
526
   * @req: pointer to request
3aff4ebb9   Trond Myklebust   NFS: Prevent a de...
527
   */
1d1afcbc2   Trond Myklebust   NFS: Clean up - R...
528
  void nfs_unlock_and_release_request(struct nfs_page *req)
3aff4ebb9   Trond Myklebust   NFS: Prevent a de...
529
  {
1d1afcbc2   Trond Myklebust   NFS: Clean up - R...
530
  	nfs_unlock_request(req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
532
  	nfs_release_request(req);
  }
4d65c520f   Trond Myklebust   NFS: Fix a hang i...
533
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
535
536
   * nfs_clear_request - Free up all resources allocated to the request
   * @req:
   *
bb6fbc454   Trond Myklebust   NFS: Avoid a dead...
537
538
   * Release page and open context resources associated with a read/write
   * request after it has completed.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
   */
4d65c520f   Trond Myklebust   NFS: Fix a hang i...
540
  static void nfs_clear_request(struct nfs_page *req)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
  {
cd52ed355   Trond Myklebust   NFS: Avoid races ...
542
  	struct page *page = req->wb_page;
f11ac8db5   Trond Myklebust   NFSv4: Ensure tha...
543
  	struct nfs_lock_context *l_ctx = req->wb_lock_context;
c79d183eb   Trond Myklebust   NFS: Remove redun...
544
  	struct nfs_open_context *ctx;
bb6fbc454   Trond Myklebust   NFS: Avoid a dead...
545

cd52ed355   Trond Myklebust   NFS: Avoid races ...
546
  	if (page != NULL) {
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
547
  		put_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
549
  		req->wb_page = NULL;
  	}
f11ac8db5   Trond Myklebust   NFSv4: Ensure tha...
550
  	if (l_ctx != NULL) {
7d6ddf88c   Benjamin Coddington   NFS: Add an iocou...
551
  		if (atomic_dec_and_test(&l_ctx->io_count)) {
723c921e7   Peter Zijlstra   sched/wait, fs/nf...
552
  			wake_up_var(&l_ctx->io_count);
c79d183eb   Trond Myklebust   NFS: Remove redun...
553
  			ctx = l_ctx->open_context;
7d6ddf88c   Benjamin Coddington   NFS: Add an iocou...
554
555
556
  			if (test_bit(NFS_CONTEXT_UNLOCK, &ctx->flags))
  				rpc_wake_up(&NFS_SERVER(d_inode(ctx->dentry))->uoc_rpcwaitq);
  		}
f11ac8db5   Trond Myklebust   NFSv4: Ensure tha...
557
558
559
  		nfs_put_lock_context(l_ctx);
  		req->wb_lock_context = NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
562
563
564
565
566
  /**
   * nfs_release_request - Release the count on an NFS read/write request
   * @req: request to release
   *
   * Note: Should never be called with the spinlock held!
   */
d45813835   Weston Andros Adamson   nfs: handle multi...
567
  void nfs_free_request(struct nfs_page *req)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
  {
2bfc6e566   Weston Andros Adamson   nfs: add support ...
569
570
571
572
  	WARN_ON_ONCE(req->wb_this_page != req);
  
  	/* extra debug: make sure no sync bits are still set */
  	WARN_ON_ONCE(test_bit(PG_TEARDOWN, &req->wb_flags));
67d0338ed   Weston Andros Adamson   nfs: page group s...
573
574
  	WARN_ON_ONCE(test_bit(PG_UNLOCKPAGE, &req->wb_flags));
  	WARN_ON_ONCE(test_bit(PG_UPTODATE, &req->wb_flags));
20633f042   Weston Andros Adamson   nfs: page group s...
575
576
  	WARN_ON_ONCE(test_bit(PG_WB_END, &req->wb_flags));
  	WARN_ON_ONCE(test_bit(PG_REMOVE, &req->wb_flags));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577

bb6fbc454   Trond Myklebust   NFS: Avoid a dead...
578
  	/* Release struct file and open context */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
  	nfs_clear_request(req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
581
  	nfs_page_free(req);
  }
c03b40246   Trond Myklebust   NFS: Convert stru...
582
583
  void nfs_release_request(struct nfs_page *req)
  {
2bfc6e566   Weston Andros Adamson   nfs: add support ...
584
  	kref_put(&req->wb_kref, nfs_page_group_destroy);
9f557cd80   Trond Myklebust   NFS: Fix an Oops ...
585
  }
2ce209c42   Trond Myklebust   NFS: Wait for req...
586
  EXPORT_SYMBOL_GPL(nfs_release_request);
9f557cd80   Trond Myklebust   NFS: Fix an Oops ...
587

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
589
590
591
  /**
   * nfs_wait_on_request - Wait for a request to complete.
   * @req: request to wait upon.
   *
150030b78   Matthew Wilcox   NFS: Switch from ...
592
   * Interruptible by fatal signals only.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
594
595
596
597
   * The user is responsible for holding a count on the request.
   */
  int
  nfs_wait_on_request(struct nfs_page *req)
  {
b4f937cff   Trond Myklebust   NFS: Don't run wa...
598
599
600
601
  	if (!test_bit(PG_BUSY, &req->wb_flags))
  		return 0;
  	set_bit(PG_CONTENDED2, &req->wb_flags);
  	smp_mb__after_atomic();
743162013   NeilBrown   sched: Remove pro...
602
603
  	return wait_on_bit_io(&req->wb_flags, PG_BUSY,
  			      TASK_UNINTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
  }
2ce209c42   Trond Myklebust   NFS: Wait for req...
605
  EXPORT_SYMBOL_GPL(nfs_wait_on_request);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606

b4fdac1a5   Weston Andros Adamson   nfs: modify pg_te...
607
608
609
610
611
612
  /*
   * nfs_generic_pg_test - determine if requests can be coalesced
   * @desc: pointer to descriptor
   * @prev: previous request in desc, or NULL
   * @req: this request
   *
ac0aa5e84   Pavel Tikhomirov   nfs: fix comment ...
613
   * Returns zero if @req cannot be coalesced into @desc, otherwise it returns
b4fdac1a5   Weston Andros Adamson   nfs: modify pg_te...
614
615
616
617
   * the size of the request.
   */
  size_t nfs_generic_pg_test(struct nfs_pageio_descriptor *desc,
  			   struct nfs_page *prev, struct nfs_page *req)
5b36c7dc4   Boaz Harrosh   NFSv4.1: define n...
618
  {
48d635f14   Peng Tao   nfs: add nfs_pgio...
619
  	struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc);
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
620
621
622
  
  
  	if (mirror->pg_count > mirror->pg_bsize) {
f0cb9ab8d   Weston Andros Adamson   nfs: use > 1 requ...
623
624
  		/* should never happen */
  		WARN_ON_ONCE(1);
5b36c7dc4   Boaz Harrosh   NFSv4.1: define n...
625
  		return 0;
f0cb9ab8d   Weston Andros Adamson   nfs: use > 1 requ...
626
  	}
5b36c7dc4   Boaz Harrosh   NFSv4.1: define n...
627

2e11f8296   Christoph Hellwig   nfs: cap request ...
628
629
630
631
  	/*
  	 * Limit the request size so that we can still allocate a page array
  	 * for it without upsetting the slab allocator.
  	 */
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
632
  	if (((mirror->pg_count + req->wb_bytes) >> PAGE_SHIFT) *
048883e0b   Peng Tao   nfs: fix pg_test ...
633
  			sizeof(struct page *) > PAGE_SIZE)
2e11f8296   Christoph Hellwig   nfs: cap request ...
634
  		return 0;
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
635
  	return min(mirror->pg_bsize - mirror->pg_count, (size_t)req->wb_bytes);
5b36c7dc4   Boaz Harrosh   NFSv4.1: define n...
636
  }
19345cb29   Benny Halevy   NFSv4.1: file lay...
637
  EXPORT_SYMBOL_GPL(nfs_generic_pg_test);
5b36c7dc4   Boaz Harrosh   NFSv4.1: define n...
638

1e7f3a485   Weston Andros Adamson   nfs: move nfs_pgi...
639
  struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *ops)
4a0de55c5   Anna Schumaker   NFS: Create a com...
640
  {
1e7f3a485   Weston Andros Adamson   nfs: move nfs_pgi...
641
  	struct nfs_pgio_header *hdr = ops->rw_alloc_header();
4a0de55c5   Anna Schumaker   NFS: Create a com...
642

1e7f3a485   Weston Andros Adamson   nfs: move nfs_pgi...
643
  	if (hdr) {
4a0de55c5   Anna Schumaker   NFS: Create a com...
644
  		INIT_LIST_HEAD(&hdr->pages);
4a0de55c5   Anna Schumaker   NFS: Create a com...
645
646
  		hdr->rw_ops = ops;
  	}
1e7f3a485   Weston Andros Adamson   nfs: move nfs_pgi...
647
  	return hdr;
4a0de55c5   Anna Schumaker   NFS: Create a com...
648
  }
1e7f3a485   Weston Andros Adamson   nfs: move nfs_pgi...
649
  EXPORT_SYMBOL_GPL(nfs_pgio_header_alloc);
4a0de55c5   Anna Schumaker   NFS: Create a com...
650

4a0de55c5   Anna Schumaker   NFS: Create a com...
651
  /**
4714fb51f   Weston Andros Adamson   nfs: remove pgio_...
652
653
654
655
656
657
   * nfs_pgio_data_destroy - make @hdr suitable for reuse
   *
   * Frees memory and releases refs from nfs_generic_pgio, so that it may
   * be called again.
   *
   * @hdr: A header that has had nfs_generic_pgio called
00bfa30ab   Anna Schumaker   NFS: Create a com...
658
   */
196639ebb   Trond Myklebust   NFS: Fix 2 use af...
659
  static void nfs_pgio_data_destroy(struct nfs_pgio_header *hdr)
00bfa30ab   Anna Schumaker   NFS: Create a com...
660
  {
3caa0c6ed   Trond Myklebust   NFS: Fix an unini...
661
662
  	if (hdr->args.context)
  		put_nfs_open_context(hdr->args.context);
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
663
664
  	if (hdr->page_array.pagevec != hdr->page_array.page_array)
  		kfree(hdr->page_array.pagevec);
00bfa30ab   Anna Schumaker   NFS: Create a com...
665
  }
196639ebb   Trond Myklebust   NFS: Fix 2 use af...
666
667
668
669
670
671
672
673
674
675
676
  
  /*
   * nfs_pgio_header_free - Free a read or write header
   * @hdr: The header to free
   */
  void nfs_pgio_header_free(struct nfs_pgio_header *hdr)
  {
  	nfs_pgio_data_destroy(hdr);
  	hdr->rw_ops->rw_free_header(hdr);
  }
  EXPORT_SYMBOL_GPL(nfs_pgio_header_free);
00bfa30ab   Anna Schumaker   NFS: Create a com...
677

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
  /**
ce59515c1   Anna Schumaker   NFS: Create a com...
679
   * nfs_pgio_rpcsetup - Set up arguments for a pageio call
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
680
   * @hdr: The pageio hdr
ce59515c1   Anna Schumaker   NFS: Create a com...
681
   * @count: Number of bytes to read
ce59515c1   Anna Schumaker   NFS: Create a com...
682
683
684
   * @how: How to commit data (writes only)
   * @cinfo: Commit information for the call (writes only)
   */
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
685
  static void nfs_pgio_rpcsetup(struct nfs_pgio_header *hdr,
e545735a3   Benjamin Coddington   NFS: remove unuse...
686
  			      unsigned int count,
ce59515c1   Anna Schumaker   NFS: Create a com...
687
688
  			      int how, struct nfs_commit_info *cinfo)
  {
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
689
  	struct nfs_page *req = hdr->req;
ce59515c1   Anna Schumaker   NFS: Create a com...
690
691
  
  	/* Set up the RPC argument and reply structs
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
692
  	 * NB: take care not to mess about with hdr->commit et al. */
ce59515c1   Anna Schumaker   NFS: Create a com...
693

d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
694
  	hdr->args.fh     = NFS_FH(hdr->inode);
e545735a3   Benjamin Coddington   NFS: remove unuse...
695
  	hdr->args.offset = req_offset(req);
ce59515c1   Anna Schumaker   NFS: Create a com...
696
  	/* pnfs_set_layoutcommit needs this */
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
697
  	hdr->mds_offset = hdr->args.offset;
e545735a3   Benjamin Coddington   NFS: remove unuse...
698
  	hdr->args.pgbase = req->wb_pgbase;
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
699
700
  	hdr->args.pages  = hdr->page_array.pagevec;
  	hdr->args.count  = count;
9fcd5960e   Trond Myklebust   NFS: Add a helper...
701
  	hdr->args.context = get_nfs_open_context(nfs_req_openctx(req));
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
702
703
  	hdr->args.lock_context = req->wb_lock_context;
  	hdr->args.stable  = NFS_UNSTABLE;
ce59515c1   Anna Schumaker   NFS: Create a com...
704
705
706
707
708
709
  	switch (how & (FLUSH_STABLE | FLUSH_COND_STABLE)) {
  	case 0:
  		break;
  	case FLUSH_COND_STABLE:
  		if (nfs_reqs_to_commit(cinfo))
  			break;
df561f668   Gustavo A. R. Silva   treewide: Use fal...
710
  		fallthrough;
ce59515c1   Anna Schumaker   NFS: Create a com...
711
  	default:
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
712
  		hdr->args.stable = NFS_FILE_SYNC;
ce59515c1   Anna Schumaker   NFS: Create a com...
713
  	}
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
714
  	hdr->res.fattr   = &hdr->fattr;
17d8c5d14   Trond Myklebust   NFS: Fix initiali...
715
  	hdr->res.count   = 0;
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
716
  	hdr->res.eof     = 0;
c65e6254c   Weston Andros Adamson   nfs: remove unuse...
717
  	hdr->res.verf    = &hdr->verf;
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
718
  	nfs_fattr_init(&hdr->fattr);
ce59515c1   Anna Schumaker   NFS: Create a com...
719
720
721
  }
  
  /**
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
722
   * nfs_pgio_prepare - Prepare pageio hdr to go over the wire
a4cdda591   Anna Schumaker   NFS: Create a com...
723
   * @task: The current task
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
724
   * @calldata: pageio header to prepare
a4cdda591   Anna Schumaker   NFS: Create a com...
725
   */
6f92fa458   Anna Schumaker   NFS: Create a com...
726
  static void nfs_pgio_prepare(struct rpc_task *task, void *calldata)
a4cdda591   Anna Schumaker   NFS: Create a com...
727
  {
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
728
  	struct nfs_pgio_header *hdr = calldata;
a4cdda591   Anna Schumaker   NFS: Create a com...
729
  	int err;
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
730
  	err = NFS_PROTO(hdr->inode)->pgio_rpc_prepare(task, hdr);
a4cdda591   Anna Schumaker   NFS: Create a com...
731
732
733
  	if (err)
  		rpc_exit(task, err);
  }
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
734
  int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr,
a52458b48   NeilBrown   NFS/NFSD/SUNRPC: ...
735
  		      const struct cred *cred, const struct nfs_rpc_ops *rpc_ops,
1ed26f330   Anna Schumaker   NFS: Create a com...
736
737
738
739
  		      const struct rpc_call_ops *call_ops, int how, int flags)
  {
  	struct rpc_task *task;
  	struct rpc_message msg = {
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
740
741
  		.rpc_argp = &hdr->args,
  		.rpc_resp = &hdr->res,
46a5ab475   Peng Tao   nfs: allow to spe...
742
  		.rpc_cred = cred,
1ed26f330   Anna Schumaker   NFS: Create a com...
743
744
745
  	};
  	struct rpc_task_setup task_setup_data = {
  		.rpc_client = clnt,
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
746
  		.task = &hdr->task,
1ed26f330   Anna Schumaker   NFS: Create a com...
747
748
  		.rpc_message = &msg,
  		.callback_ops = call_ops,
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
749
  		.callback_data = hdr,
1ed26f330   Anna Schumaker   NFS: Create a com...
750
  		.workqueue = nfsiod_workqueue,
4fa7ef69e   Trond Myklebust   NFS/pnfs: Don't u...
751
  		.flags = RPC_TASK_ASYNC | flags,
1ed26f330   Anna Schumaker   NFS: Create a com...
752
  	};
1ed26f330   Anna Schumaker   NFS: Create a com...
753

abde71f4d   Tom Haynes   pnfs: Add nfs_rpc...
754
  	hdr->rw_ops->rw_initiate(hdr, &msg, rpc_ops, &task_setup_data, how);
1ed26f330   Anna Schumaker   NFS: Create a com...
755

b4839ebe2   Kinglong Mee   nfs: Remove inval...
756
  	dprintk("NFS: initiated pgio call "
1ed26f330   Anna Schumaker   NFS: Create a com...
757
758
  		"(req %s/%llu, %u bytes @ offset %llu)
  ",
343ae531f   Anna Schumaker   nfs: Fix unused v...
759
760
  		hdr->inode->i_sb->s_id,
  		(unsigned long long)NFS_FILEID(hdr->inode),
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
761
762
  		hdr->args.count,
  		(unsigned long long)hdr->args.offset);
1ed26f330   Anna Schumaker   NFS: Create a com...
763
764
  
  	task = rpc_run_task(&task_setup_data);
1de3af988   Trond Myklebust   NFS: Remove unuse...
765
766
  	if (IS_ERR(task))
  		return PTR_ERR(task);
1ed26f330   Anna Schumaker   NFS: Create a com...
767
  	rpc_put_task(task);
1de3af988   Trond Myklebust   NFS: Remove unuse...
768
  	return 0;
1ed26f330   Anna Schumaker   NFS: Create a com...
769
770
  }
  EXPORT_SYMBOL_GPL(nfs_initiate_pgio);
a4cdda591   Anna Schumaker   NFS: Create a com...
771
  /**
844c9e691   Anna Schumaker   NFS: Create a com...
772
   * nfs_pgio_error - Clean up from a pageio error
844c9e691   Anna Schumaker   NFS: Create a com...
773
774
   * @hdr: pageio header
   */
2bff22885   Peng Tao   nfs: centralize p...
775
  static void nfs_pgio_error(struct nfs_pgio_header *hdr)
844c9e691   Anna Schumaker   NFS: Create a com...
776
  {
844c9e691   Anna Schumaker   NFS: Create a com...
777
  	set_bit(NFS_IOHDR_REDO, &hdr->flags);
4714fb51f   Weston Andros Adamson   nfs: remove pgio_...
778
  	hdr->completion_ops->completion(hdr);
844c9e691   Anna Schumaker   NFS: Create a com...
779
780
781
  }
  
  /**
a4cdda591   Anna Schumaker   NFS: Create a com...
782
   * nfs_pgio_release - Release pageio data
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
783
   * @calldata: The pageio header to release
a4cdda591   Anna Schumaker   NFS: Create a com...
784
   */
6f92fa458   Anna Schumaker   NFS: Create a com...
785
  static void nfs_pgio_release(void *calldata)
a4cdda591   Anna Schumaker   NFS: Create a com...
786
  {
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
787
  	struct nfs_pgio_header *hdr = calldata;
4714fb51f   Weston Andros Adamson   nfs: remove pgio_...
788
  	hdr->completion_ops->completion(hdr);
a4cdda591   Anna Schumaker   NFS: Create a com...
789
  }
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
790
791
792
793
794
795
796
797
798
799
  static void nfs_pageio_mirror_init(struct nfs_pgio_mirror *mirror,
  				   unsigned int bsize)
  {
  	INIT_LIST_HEAD(&mirror->pg_list);
  	mirror->pg_bytes_written = 0;
  	mirror->pg_count = 0;
  	mirror->pg_bsize = bsize;
  	mirror->pg_base = 0;
  	mirror->pg_recoalesce = 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
  /**
d8a5ad75c   Trond Myklebust   NFS: Cleanup the ...
801
802
   * nfs_pageio_init - initialise a page io descriptor
   * @desc: pointer to descriptor
bcb71bba7   Trond Myklebust   NFS: Another clea...
803
   * @inode: pointer to inode
dfad7000f   Yijing Wang   nfs: Fix comment ...
804
805
806
   * @pg_ops: pointer to pageio operations
   * @compl_ops: pointer to pageio completion operations
   * @rw_ops: pointer to nfs read/write operations
bcb71bba7   Trond Myklebust   NFS: Another clea...
807
808
   * @bsize: io block size
   * @io_flags: extra parameters for the io function
d8a5ad75c   Trond Myklebust   NFS: Cleanup the ...
809
   */
bcb71bba7   Trond Myklebust   NFS: Another clea...
810
811
  void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
  		     struct inode *inode,
1751c3638   Trond Myklebust   NFS: Cleanup of t...
812
  		     const struct nfs_pageio_ops *pg_ops,
061ae2edb   Fred Isaman   NFS: create compl...
813
  		     const struct nfs_pgio_completion_ops *compl_ops,
4a0de55c5   Anna Schumaker   NFS: Create a com...
814
  		     const struct nfs_rw_ops *rw_ops,
84dde76c4   Trond Myklebust   NFS: Fix a compil...
815
  		     size_t bsize,
3bde7afda   Trond Myklebust   NFS: Remove unuse...
816
  		     int io_flags)
d8a5ad75c   Trond Myklebust   NFS: Cleanup the ...
817
  {
b31268ac7   Trond Myklebust   FS: Use stable wr...
818
  	desc->pg_moreio = 0;
bcb71bba7   Trond Myklebust   NFS: Another clea...
819
  	desc->pg_inode = inode;
1751c3638   Trond Myklebust   NFS: Cleanup of t...
820
  	desc->pg_ops = pg_ops;
061ae2edb   Fred Isaman   NFS: create compl...
821
  	desc->pg_completion_ops = compl_ops;
4a0de55c5   Anna Schumaker   NFS: Create a com...
822
  	desc->pg_rw_ops = rw_ops;
bcb71bba7   Trond Myklebust   NFS: Another clea...
823
824
  	desc->pg_ioflags = io_flags;
  	desc->pg_error = 0;
94ad1c80e   Fred Isaman   NFSv4.1: coelesce...
825
  	desc->pg_lseg = NULL;
919e3bd9a   Trond Myklebust   NFS: Ensure we co...
826
  	desc->pg_io_completion = NULL;
584aa810b   Fred Isaman   NFS: rewrite dire...
827
  	desc->pg_dreq = NULL;
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
828
829
830
831
  	desc->pg_bsize = bsize;
  
  	desc->pg_mirror_count = 1;
  	desc->pg_mirror_idx = 0;
14abcb0bf   Trond Myklebust   NFSv4: Fix up mir...
832
833
834
  	desc->pg_mirrors_dynamic = NULL;
  	desc->pg_mirrors = desc->pg_mirrors_static;
  	nfs_pageio_mirror_init(&desc->pg_mirrors[0], bsize);
33344e0f7   Trond Myklebust   pNFS: Add trackin...
835
  	desc->pg_maxretrans = 0;
d8a5ad75c   Trond Myklebust   NFS: Cleanup the ...
836
  }
0eecb2145   Anna Schumaker   NFS: Create a com...
837
838
839
  /**
   * nfs_pgio_result - Basic pageio error handling
   * @task: The task that ran
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
840
   * @calldata: Pageio header to check
0eecb2145   Anna Schumaker   NFS: Create a com...
841
   */
6f92fa458   Anna Schumaker   NFS: Create a com...
842
  static void nfs_pgio_result(struct rpc_task *task, void *calldata)
0eecb2145   Anna Schumaker   NFS: Create a com...
843
  {
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
844
845
  	struct nfs_pgio_header *hdr = calldata;
  	struct inode *inode = hdr->inode;
0eecb2145   Anna Schumaker   NFS: Create a com...
846
847
848
849
  
  	dprintk("NFS: %s: %5u, (status %d)
  ", __func__,
  		task->tk_pid, task->tk_status);
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
850
  	if (hdr->rw_ops->rw_done(task, hdr, inode) != 0)
0eecb2145   Anna Schumaker   NFS: Create a com...
851
852
  		return;
  	if (task->tk_status < 0)
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
853
  		nfs_set_pgio_error(hdr, task->tk_status, hdr->args.offset);
0eecb2145   Anna Schumaker   NFS: Create a com...
854
  	else
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
855
  		hdr->rw_ops->rw_result(task, hdr);
0eecb2145   Anna Schumaker   NFS: Create a com...
856
  }
ef2c488c0   Anna Schumaker   NFS: Create a gen...
857
  /*
ef2c488c0   Anna Schumaker   NFS: Create a gen...
858
859
860
861
862
863
864
   * Create an RPC task for the given read or 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.
   */
f0cb9ab8d   Weston Andros Adamson   nfs: use > 1 requ...
865
866
  int nfs_generic_pgio(struct nfs_pageio_descriptor *desc,
  		     struct nfs_pgio_header *hdr)
ef2c488c0   Anna Schumaker   NFS: Create a gen...
867
  {
48d635f14   Peng Tao   nfs: add nfs_pgio...
868
  	struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc);
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
869

ef2c488c0   Anna Schumaker   NFS: Create a gen...
870
  	struct nfs_page		*req;
bba5c1887   Weston Andros Adamson   nfs: disallow dup...
871
872
  	struct page		**pages,
  				*last_page;
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
873
  	struct list_head *head = &mirror->pg_list;
ef2c488c0   Anna Schumaker   NFS: Create a gen...
874
  	struct nfs_commit_info cinfo;
8ef9b0b9e   Benjamin Coddington   NFS: move nfs_pga...
875
  	struct nfs_page_array *pg_array = &hdr->page_array;
bba5c1887   Weston Andros Adamson   nfs: disallow dup...
876
  	unsigned int pagecount, pageused;
ae97aa524   Benjamin Coddington   NFS: Use GFP_NOIO...
877
  	gfp_t gfp_flags = GFP_KERNEL;
ef2c488c0   Anna Schumaker   NFS: Create a gen...
878

a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
879
  	pagecount = nfs_page_array_len(mirror->pg_base, mirror->pg_count);
2eb3aea7d   Benjamin Coddington   NFS: Fix initiali...
880
  	pg_array->npages = pagecount;
8ef9b0b9e   Benjamin Coddington   NFS: move nfs_pga...
881
882
883
884
  
  	if (pagecount <= ARRAY_SIZE(pg_array->page_array))
  		pg_array->pagevec = pg_array->page_array;
  	else {
8ef9b0b9e   Benjamin Coddington   NFS: move nfs_pga...
885
886
887
888
889
890
891
  		pg_array->pagevec = kcalloc(pagecount, sizeof(struct page *), gfp_flags);
  		if (!pg_array->pagevec) {
  			pg_array->npages = 0;
  			nfs_pgio_error(hdr);
  			desc->pg_error = -ENOMEM;
  			return desc->pg_error;
  		}
2bff22885   Peng Tao   nfs: centralize p...
892
  	}
ef2c488c0   Anna Schumaker   NFS: Create a gen...
893
894
  
  	nfs_init_cinfo(&cinfo, desc->pg_inode, desc->pg_dreq);
d45f60c67   Weston Andros Adamson   nfs: merge nfs_pg...
895
  	pages = hdr->page_array.pagevec;
bba5c1887   Weston Andros Adamson   nfs: disallow dup...
896
897
  	last_page = NULL;
  	pageused = 0;
ef2c488c0   Anna Schumaker   NFS: Create a gen...
898
899
  	while (!list_empty(head)) {
  		req = nfs_list_entry(head->next);
078b5fd92   Trond Myklebust   NFS: Clean up lis...
900
  		nfs_list_move_request(req, &hdr->pages);
bba5c1887   Weston Andros Adamson   nfs: disallow dup...
901

bba5c1887   Weston Andros Adamson   nfs: disallow dup...
902
  		if (!last_page || last_page != req->wb_page) {
bba5c1887   Weston Andros Adamson   nfs: disallow dup...
903
  			pageused++;
b8fb9c30f   Trond Myklebust   NFS: Fix a bogus ...
904
905
906
  			if (pageused > pagecount)
  				break;
  			*pages++ = last_page = req->wb_page;
bba5c1887   Weston Andros Adamson   nfs: disallow dup...
907
  		}
ef2c488c0   Anna Schumaker   NFS: Create a gen...
908
  	}
2bff22885   Peng Tao   nfs: centralize p...
909
910
911
912
913
  	if (WARN_ON_ONCE(pageused != pagecount)) {
  		nfs_pgio_error(hdr);
  		desc->pg_error = -EINVAL;
  		return desc->pg_error;
  	}
ef2c488c0   Anna Schumaker   NFS: Create a gen...
914
915
916
917
918
919
  
  	if ((desc->pg_ioflags & FLUSH_COND_STABLE) &&
  	    (desc->pg_moreio || nfs_reqs_to_commit(&cinfo)))
  		desc->pg_ioflags &= ~FLUSH_COND_STABLE;
  
  	/* Set up the argument struct */
e545735a3   Benjamin Coddington   NFS: remove unuse...
920
  	nfs_pgio_rpcsetup(hdr, mirror->pg_count, desc->pg_ioflags, &cinfo);
ef2c488c0   Anna Schumaker   NFS: Create a gen...
921
922
923
  	desc->pg_rpc_callops = &nfs_pgio_common_ops;
  	return 0;
  }
f0cb9ab8d   Weston Andros Adamson   nfs: use > 1 requ...
924
  EXPORT_SYMBOL_GPL(nfs_generic_pgio);
ef2c488c0   Anna Schumaker   NFS: Create a gen...
925

41d8d5b7a   Anna Schumaker   NFS: Create a com...
926
  static int nfs_generic_pg_pgios(struct nfs_pageio_descriptor *desc)
cf485fcd6   Anna Schumaker   NFS: Create a com...
927
  {
cf485fcd6   Anna Schumaker   NFS: Create a com...
928
929
  	struct nfs_pgio_header *hdr;
  	int ret;
1e7f3a485   Weston Andros Adamson   nfs: move nfs_pgi...
930
931
  	hdr = nfs_pgio_header_alloc(desc->pg_rw_ops);
  	if (!hdr) {
2bff22885   Peng Tao   nfs: centralize p...
932
933
  		desc->pg_error = -ENOMEM;
  		return desc->pg_error;
cf485fcd6   Anna Schumaker   NFS: Create a com...
934
  	}
1e7f3a485   Weston Andros Adamson   nfs: move nfs_pgi...
935
  	nfs_pgheader_init(desc, hdr, nfs_pgio_header_free);
cf485fcd6   Anna Schumaker   NFS: Create a com...
936
937
  	ret = nfs_generic_pgio(desc, hdr);
  	if (ret == 0)
7f714720f   Weston Andros Adamson   nfs: remove data ...
938
  		ret = nfs_initiate_pgio(NFS_CLIENT(hdr->inode),
46a5ab475   Peng Tao   nfs: allow to spe...
939
940
941
  					hdr,
  					hdr->cred,
  					NFS_PROTO(hdr->inode),
abde71f4d   Tom Haynes   pnfs: Add nfs_rpc...
942
  					desc->pg_rpc_callops,
4fa7ef69e   Trond Myklebust   NFS/pnfs: Don't u...
943
944
  					desc->pg_ioflags,
  					RPC_TASK_CRED_NOREF);
cf485fcd6   Anna Schumaker   NFS: Create a com...
945
946
  	return ret;
  }
14abcb0bf   Trond Myklebust   NFSv4: Fix up mir...
947
948
949
950
951
952
953
954
955
956
957
  static struct nfs_pgio_mirror *
  nfs_pageio_alloc_mirrors(struct nfs_pageio_descriptor *desc,
  		unsigned int mirror_count)
  {
  	struct nfs_pgio_mirror *ret;
  	unsigned int i;
  
  	kfree(desc->pg_mirrors_dynamic);
  	desc->pg_mirrors_dynamic = NULL;
  	if (mirror_count == 1)
  		return desc->pg_mirrors_static;
2b17d725f   Trond Myklebust   NFS: Clean up wri...
958
  	ret = kmalloc_array(mirror_count, sizeof(*ret), GFP_KERNEL);
14abcb0bf   Trond Myklebust   NFSv4: Fix up mir...
959
960
961
962
963
964
965
  	if (ret != NULL) {
  		for (i = 0; i < mirror_count; i++)
  			nfs_pageio_mirror_init(&ret[i], desc->pg_bsize);
  		desc->pg_mirrors_dynamic = ret;
  	}
  	return ret;
  }
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
966
967
968
969
  /*
   * nfs_pageio_setup_mirroring - determine if mirroring is to be used
   *				by calling the pg_get_mirror_count op
   */
14abcb0bf   Trond Myklebust   NFSv4: Fix up mir...
970
  static void nfs_pageio_setup_mirroring(struct nfs_pageio_descriptor *pgio,
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
971
972
  				       struct nfs_page *req)
  {
14abcb0bf   Trond Myklebust   NFSv4: Fix up mir...
973
  	unsigned int mirror_count = 1;
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
974

14abcb0bf   Trond Myklebust   NFSv4: Fix up mir...
975
976
977
978
  	if (pgio->pg_ops->pg_get_mirror_count)
  		mirror_count = pgio->pg_ops->pg_get_mirror_count(pgio, req);
  	if (mirror_count == pgio->pg_mirror_count || pgio->pg_error < 0)
  		return;
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
979

14abcb0bf   Trond Myklebust   NFSv4: Fix up mir...
980
981
982
983
  	if (!mirror_count || mirror_count > NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX) {
  		pgio->pg_error = -EINVAL;
  		return;
  	}
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
984

14abcb0bf   Trond Myklebust   NFSv4: Fix up mir...
985
986
987
988
989
990
  	pgio->pg_mirrors = nfs_pageio_alloc_mirrors(pgio, mirror_count);
  	if (pgio->pg_mirrors == NULL) {
  		pgio->pg_error = -ENOMEM;
  		pgio->pg_mirrors = pgio->pg_mirrors_static;
  		mirror_count = 1;
  	}
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
991
  	pgio->pg_mirror_count = mirror_count;
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
992
  }
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
993
994
995
996
997
998
999
1000
  static void nfs_pageio_cleanup_mirroring(struct nfs_pageio_descriptor *pgio)
  {
  	pgio->pg_mirror_count = 1;
  	pgio->pg_mirror_idx = 0;
  	pgio->pg_mirrors = pgio->pg_mirrors_static;
  	kfree(pgio->pg_mirrors_dynamic);
  	pgio->pg_mirrors_dynamic = NULL;
  }
4109bb749   Trond Myklebust   NFS: Don't check ...
1001
1002
1003
  static bool nfs_match_lock_context(const struct nfs_lock_context *l1,
  		const struct nfs_lock_context *l2)
  {
d51fdb87a   NeilBrown   NFS: discard nfs_...
1004
  	return l1->lockowner == l2->lockowner;
4109bb749   Trond Myklebust   NFS: Don't check ...
1005
  }
d8a5ad75c   Trond Myklebust   NFS: Cleanup the ...
1006
  /**
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1007
   * nfs_coalesce_size - test two requests for compatibility
d8a5ad75c   Trond Myklebust   NFS: Cleanup the ...
1008
1009
   * @prev: pointer to nfs_page
   * @req: pointer to nfs_page
302fad7bd   Trond Myklebust   NFS: Fix up docum...
1010
   * @pgio: pointer to nfs_pagio_descriptor
d8a5ad75c   Trond Myklebust   NFS: Cleanup the ...
1011
1012
1013
1014
1015
   *
   * The nfs_page structures 'prev' and 'req' are compared to ensure that the
   * page data area they describe is contiguous, and that their RPC
   * credentials, NFSv4 open state, and lockowners are the same.
   *
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1016
   * Returns size of the request that can be coalesced
d8a5ad75c   Trond Myklebust   NFS: Cleanup the ...
1017
   */
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1018
  static unsigned int nfs_coalesce_size(struct nfs_page *prev,
18ad0a9f2   Benny Halevy   NFSv4.1: change p...
1019
1020
  				      struct nfs_page *req,
  				      struct nfs_pageio_descriptor *pgio)
d8a5ad75c   Trond Myklebust   NFS: Cleanup the ...
1021
  {
5263e31e4   Jeff Layton   locks: move flock...
1022
  	struct file_lock_context *flctx;
b4fdac1a5   Weston Andros Adamson   nfs: modify pg_te...
1023

ab75e4171   Weston Andros Adamson   nfs: call nfs_can...
1024
  	if (prev) {
9fcd5960e   Trond Myklebust   NFS: Add a helper...
1025
  		if (!nfs_match_open_context(nfs_req_openctx(req), nfs_req_openctx(prev)))
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1026
  			return 0;
9fcd5960e   Trond Myklebust   NFS: Add a helper...
1027
  		flctx = d_inode(nfs_req_openctx(req)->dentry)->i_flctx;
bd61e0a9c   Jeff Layton   locks: convert po...
1028
1029
1030
  		if (flctx != NULL &&
  		    !(list_empty_careful(&flctx->flc_posix) &&
  		      list_empty_careful(&flctx->flc_flock)) &&
5263e31e4   Jeff Layton   locks: move flock...
1031
1032
  		    !nfs_match_lock_context(req->wb_lock_context,
  					    prev->wb_lock_context))
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1033
  			return 0;
ab75e4171   Weston Andros Adamson   nfs: call nfs_can...
1034
  		if (req_offset(req) != req_offset(prev) + prev->wb_bytes)
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1035
  			return 0;
78270e8fb   Weston Andros Adamson   nfs: can_coalesce...
1036
1037
  		if (req->wb_page == prev->wb_page) {
  			if (req->wb_pgbase != prev->wb_pgbase + prev->wb_bytes)
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1038
  				return 0;
78270e8fb   Weston Andros Adamson   nfs: can_coalesce...
1039
1040
  		} else {
  			if (req->wb_pgbase != 0 ||
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
1041
  			    prev->wb_pgbase + prev->wb_bytes != PAGE_SIZE)
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1042
  				return 0;
78270e8fb   Weston Andros Adamson   nfs: can_coalesce...
1043
  		}
ab75e4171   Weston Andros Adamson   nfs: call nfs_can...
1044
  	}
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1045
  	return pgio->pg_ops->pg_test(pgio, prev, req);
d8a5ad75c   Trond Myklebust   NFS: Cleanup the ...
1046
1047
1048
  }
  
  /**
bcb71bba7   Trond Myklebust   NFS: Another clea...
1049
   * nfs_pageio_do_add_request - Attempt to coalesce a request into a page list.
d8a5ad75c   Trond Myklebust   NFS: Cleanup the ...
1050
1051
1052
   * @desc: destination io descriptor
   * @req: request
   *
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1053
1054
   * If the request 'req' was successfully coalesced into the existing list
   * of pages 'desc', it returns the size of req.
d8a5ad75c   Trond Myklebust   NFS: Cleanup the ...
1055
   */
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1056
1057
1058
  static unsigned int
  nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc,
  		struct nfs_page *req)
d8a5ad75c   Trond Myklebust   NFS: Cleanup the ...
1059
  {
48d635f14   Peng Tao   nfs: add nfs_pgio...
1060
  	struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc);
ab75e4171   Weston Andros Adamson   nfs: call nfs_can...
1061
  	struct nfs_page *prev = NULL;
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1062
  	unsigned int size;
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1063
1064
1065
  
  	if (mirror->pg_count != 0) {
  		prev = nfs_list_entry(mirror->pg_list.prev);
5b36c7dc4   Boaz Harrosh   NFSv4.1: define n...
1066
  	} else {
d8007d4dd   Trond Myklebust   NFSv4.1: Add an i...
1067
1068
  		if (desc->pg_ops->pg_init)
  			desc->pg_ops->pg_init(desc, req);
d600ad1f2   Peng Tao   NFS41: pop some l...
1069
1070
  		if (desc->pg_error < 0)
  			return 0;
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1071
  		mirror->pg_base = req->wb_pgbase;
5b36c7dc4   Boaz Harrosh   NFSv4.1: define n...
1072
  	}
33344e0f7   Trond Myklebust   pNFS: Add trackin...
1073
1074
1075
1076
1077
1078
1079
1080
  
  	if (desc->pg_maxretrans && req->wb_nio > desc->pg_maxretrans) {
  		if (NFS_SERVER(desc->pg_inode)->flags & NFS_MOUNT_SOFTERR)
  			desc->pg_error = -ETIMEDOUT;
  		else
  			desc->pg_error = -EIO;
  		return 0;
  	}
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1081
1082
1083
  	size = nfs_coalesce_size(prev, req, desc);
  	if (size < req->wb_bytes)
  		return size;
078b5fd92   Trond Myklebust   NFS: Clean up lis...
1084
  	nfs_list_move_request(req, &mirror->pg_list);
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1085
  	mirror->pg_count += req->wb_bytes;
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1086
  	return req->wb_bytes;
d8a5ad75c   Trond Myklebust   NFS: Cleanup the ...
1087
  }
bcb71bba7   Trond Myklebust   NFS: Another clea...
1088
1089
1090
1091
1092
  /*
   * Helper for nfs_pageio_add_request and nfs_pageio_complete
   */
  static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc)
  {
48d635f14   Peng Tao   nfs: add nfs_pgio...
1093
  	struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc);
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1094
1095
1096
  
  
  	if (!list_empty(&mirror->pg_list)) {
1751c3638   Trond Myklebust   NFS: Cleanup of t...
1097
  		int error = desc->pg_ops->pg_doio(desc);
bcb71bba7   Trond Myklebust   NFS: Another clea...
1098
1099
1100
  		if (error < 0)
  			desc->pg_error = error;
  		else
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1101
  			mirror->pg_bytes_written += mirror->pg_count;
bcb71bba7   Trond Myklebust   NFS: Another clea...
1102
  	}
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1103
1104
1105
  	if (list_empty(&mirror->pg_list)) {
  		mirror->pg_count = 0;
  		mirror->pg_base = 0;
bcb71bba7   Trond Myklebust   NFS: Another clea...
1106
1107
  	}
  }
f57dcf4c7   Trond Myklebust   NFS: Fix I/O requ...
1108
1109
1110
1111
1112
  static void
  nfs_pageio_cleanup_request(struct nfs_pageio_descriptor *desc,
  		struct nfs_page *req)
  {
  	LIST_HEAD(head);
078b5fd92   Trond Myklebust   NFS: Clean up lis...
1113
  	nfs_list_move_request(req, &head);
df3accb84   Trond Myklebust   NFS: Pass error i...
1114
  	desc->pg_completion_ops->error_cleanup(&head, desc->pg_error);
f57dcf4c7   Trond Myklebust   NFS: Fix I/O requ...
1115
  }
bcb71bba7   Trond Myklebust   NFS: Another clea...
1116
1117
1118
1119
1120
  /**
   * nfs_pageio_add_request - Attempt to coalesce a request into a page list.
   * @desc: destination io descriptor
   * @req: request
   *
2bfc6e566   Weston Andros Adamson   nfs: add support ...
1121
   * This may split a request into subrequests which are all part of the
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1122
1123
   * same page group. If so, it will submit @req as the last one, to ensure
   * the pointer to @req is still valid in case of failure.
2bfc6e566   Weston Andros Adamson   nfs: add support ...
1124
   *
bcb71bba7   Trond Myklebust   NFS: Another clea...
1125
1126
1127
   * Returns true if the request 'req' was successfully coalesced into the
   * existing list of pages 'desc'.
   */
d9156f9f3   Trond Myklebust   NFS: Allow the nf...
1128
  static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
8b09bee30   Trond Myklebust   NFS: Cleanup for ...
1129
  			   struct nfs_page *req)
bcb71bba7   Trond Myklebust   NFS: Another clea...
1130
  {
48d635f14   Peng Tao   nfs: add nfs_pgio...
1131
  	struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc);
2bfc6e566   Weston Andros Adamson   nfs: add support ...
1132
  	struct nfs_page *subreq;
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1133
  	unsigned int size, subreq_size;
2bfc6e566   Weston Andros Adamson   nfs: add support ...
1134

1344b7ea1   Trond Myklebust   NFS: Remove unuse...
1135
  	nfs_page_group_lock(req);
2bfc6e566   Weston Andros Adamson   nfs: add support ...
1136
1137
  
  	subreq = req;
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
  	subreq_size = subreq->wb_bytes;
  	for(;;) {
  		size = nfs_pageio_do_add_request(desc, subreq);
  		if (size == subreq_size) {
  			/* We successfully submitted a request */
  			if (subreq == req)
  				break;
  			req->wb_pgbase += size;
  			req->wb_bytes -= size;
  			req->wb_offset += size;
  			subreq_size = req->wb_bytes;
  			subreq = req;
  			continue;
  		}
  		if (WARN_ON_ONCE(subreq != req)) {
  			nfs_page_group_unlock(req);
  			nfs_pageio_cleanup_request(desc, subreq);
  			subreq = req;
  			subreq_size = req->wb_bytes;
  			nfs_page_group_lock(req);
  		}
  		if (!size) {
  			/* Can't coalesce any more, so do I/O */
2bfc6e566   Weston Andros Adamson   nfs: add support ...
1161
1162
1163
  			nfs_page_group_unlock(req);
  			desc->pg_moreio = 1;
  			nfs_pageio_doio(desc);
f57dcf4c7   Trond Myklebust   NFS: Fix I/O requ...
1164
  			if (desc->pg_error < 0 || mirror->pg_recoalesce)
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1165
  				return 0;
2bfc6e566   Weston Andros Adamson   nfs: add support ...
1166
  			/* retry add_request for this subreq */
1344b7ea1   Trond Myklebust   NFS: Remove unuse...
1167
  			nfs_page_group_lock(req);
2bfc6e566   Weston Andros Adamson   nfs: add support ...
1168
1169
  			continue;
  		}
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1170
1171
1172
1173
1174
1175
  		subreq = nfs_create_subreq(req, req->wb_pgbase,
  				req->wb_offset, size);
  		if (IS_ERR(subreq))
  			goto err_ptr;
  		subreq_size = size;
  	}
2bfc6e566   Weston Andros Adamson   nfs: add support ...
1176
1177
  
  	nfs_page_group_unlock(req);
bcb71bba7   Trond Myklebust   NFS: Another clea...
1178
  	return 1;
c1109558a   Trond Myklebust   NFS: Fix error ha...
1179
1180
1181
1182
  err_ptr:
  	desc->pg_error = PTR_ERR(subreq);
  	nfs_page_group_unlock(req);
  	return 0;
bcb71bba7   Trond Myklebust   NFS: Another clea...
1183
  }
d9156f9f3   Trond Myklebust   NFS: Allow the nf...
1184
1185
  static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc)
  {
48d635f14   Peng Tao   nfs: add nfs_pgio...
1186
  	struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc);
d9156f9f3   Trond Myklebust   NFS: Allow the nf...
1187
1188
1189
  	LIST_HEAD(head);
  
  	do {
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1190
1191
1192
1193
1194
  		list_splice_init(&mirror->pg_list, &head);
  		mirror->pg_bytes_written -= mirror->pg_count;
  		mirror->pg_count = 0;
  		mirror->pg_base = 0;
  		mirror->pg_recoalesce = 0;
d9156f9f3   Trond Myklebust   NFS: Allow the nf...
1195
1196
1197
1198
  		while (!list_empty(&head)) {
  			struct nfs_page *req;
  
  			req = list_first_entry(&head, struct nfs_page, wb_list);
d9156f9f3   Trond Myklebust   NFS: Allow the nf...
1199
1200
  			if (__nfs_pageio_add_request(desc, req))
  				continue;
03d5eb65b   Trond Myklebust   NFS: Fix a memory...
1201
1202
1203
  			if (desc->pg_error < 0) {
  				list_splice_tail(&head, &mirror->pg_list);
  				mirror->pg_recoalesce = 1;
d9156f9f3   Trond Myklebust   NFS: Allow the nf...
1204
  				return 0;
03d5eb65b   Trond Myklebust   NFS: Fix a memory...
1205
  			}
d9156f9f3   Trond Myklebust   NFS: Allow the nf...
1206
1207
  			break;
  		}
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1208
  	} while (mirror->pg_recoalesce);
d9156f9f3   Trond Myklebust   NFS: Allow the nf...
1209
1210
  	return 1;
  }
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1211
  static int nfs_pageio_add_request_mirror(struct nfs_pageio_descriptor *desc,
d9156f9f3   Trond Myklebust   NFS: Allow the nf...
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
  		struct nfs_page *req)
  {
  	int ret;
  
  	do {
  		ret = __nfs_pageio_add_request(desc, req);
  		if (ret)
  			break;
  		if (desc->pg_error < 0)
  			break;
  		ret = nfs_do_recoalesce(desc);
  	} while (ret);
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1224

d9156f9f3   Trond Myklebust   NFS: Allow the nf...
1225
1226
  	return ret;
  }
fdbd1a2e4   Benjamin Coddington   nfs: Fix a missed...
1227
1228
1229
1230
1231
1232
1233
1234
1235
  static void nfs_pageio_error_cleanup(struct nfs_pageio_descriptor *desc)
  {
  	u32 midx;
  	struct nfs_pgio_mirror *mirror;
  
  	if (!desc->pg_error)
  		return;
  
  	for (midx = 0; midx < desc->pg_mirror_count; midx++) {
63e2fffa5   Trond Myklebust   pNFS/flexfiles: F...
1236
  		mirror = nfs_pgio_get_mirror(desc, midx);
df3accb84   Trond Myklebust   NFS: Pass error i...
1237
1238
  		desc->pg_completion_ops->error_cleanup(&mirror->pg_list,
  				desc->pg_error);
fdbd1a2e4   Benjamin Coddington   nfs: Fix a missed...
1239
1240
  	}
  }
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1241
1242
1243
1244
1245
  int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
  			   struct nfs_page *req)
  {
  	u32 midx;
  	unsigned int pgbase, offset, bytes;
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1246
  	struct nfs_page *dupreq;
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1247
1248
1249
1250
1251
1252
  
  	pgbase = req->wb_pgbase;
  	offset = req->wb_offset;
  	bytes = req->wb_bytes;
  
  	nfs_pageio_setup_mirroring(desc, req);
d600ad1f2   Peng Tao   NFS41: pop some l...
1253
  	if (desc->pg_error < 0)
c18b96a1b   Peng Tao   nfs: clean up res...
1254
  		goto out_failed;
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1255

dc9dc2feb   Trond Myklebust   NFS: Fix use-afte...
1256
1257
1258
  	/* Create the mirror instances first, and fire them off */
  	for (midx = 1; midx < desc->pg_mirror_count; midx++) {
  		nfs_page_group_lock(req);
44a65a0c2   Trond Myklebust   NFS: Reverse the ...
1259
  		dupreq = nfs_create_subreq(req,
dc9dc2feb   Trond Myklebust   NFS: Fix use-afte...
1260
1261
1262
1263
1264
1265
1266
  				pgbase, offset, bytes);
  
  		nfs_page_group_unlock(req);
  		if (IS_ERR(dupreq)) {
  			desc->pg_error = PTR_ERR(dupreq);
  			goto out_failed;
  		}
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1267

63e2fffa5   Trond Myklebust   pNFS/flexfiles: F...
1268
  		nfs_pgio_set_current_mirror(desc, midx);
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1269
  		if (!nfs_pageio_add_request_mirror(desc, dupreq))
f57dcf4c7   Trond Myklebust   NFS: Fix I/O requ...
1270
  			goto out_cleanup_subreq;
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1271
  	}
63e2fffa5   Trond Myklebust   pNFS/flexfiles: F...
1272
  	nfs_pgio_set_current_mirror(desc, 0);
dc9dc2feb   Trond Myklebust   NFS: Fix use-afte...
1273
1274
  	if (!nfs_pageio_add_request_mirror(desc, req))
  		goto out_failed;
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1275
  	return 1;
c18b96a1b   Peng Tao   nfs: clean up res...
1276

f57dcf4c7   Trond Myklebust   NFS: Fix I/O requ...
1277
  out_cleanup_subreq:
dc9dc2feb   Trond Myklebust   NFS: Fix use-afte...
1278
  	nfs_pageio_cleanup_request(desc, dupreq);
c18b96a1b   Peng Tao   nfs: clean up res...
1279
  out_failed:
fdbd1a2e4   Benjamin Coddington   nfs: Fix a missed...
1280
  	nfs_pageio_error_cleanup(desc);
c18b96a1b   Peng Tao   nfs: clean up res...
1281
  	return 0;
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1282
1283
1284
1285
1286
1287
  }
  
  /*
   * nfs_pageio_complete_mirror - Complete I/O on the current mirror of an
   *				nfs_pageio_descriptor
   * @desc: pointer to io descriptor
dfad7000f   Yijing Wang   nfs: Fix comment ...
1288
   * @mirror_idx: pointer to mirror index
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1289
1290
1291
1292
   */
  static void nfs_pageio_complete_mirror(struct nfs_pageio_descriptor *desc,
  				       u32 mirror_idx)
  {
63e2fffa5   Trond Myklebust   pNFS/flexfiles: F...
1293
1294
1295
1296
1297
  	struct nfs_pgio_mirror *mirror;
  	u32 restore_idx;
  
  	restore_idx = nfs_pgio_set_current_mirror(desc, mirror_idx);
  	mirror = nfs_pgio_current_mirror(desc);
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1298

a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1299
1300
  	for (;;) {
  		nfs_pageio_doio(desc);
8127d8270   Trond Myklebust   NFS: Don't recoal...
1301
  		if (desc->pg_error < 0 || !mirror->pg_recoalesce)
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1302
1303
1304
1305
  			break;
  		if (!nfs_do_recoalesce(desc))
  			break;
  	}
63e2fffa5   Trond Myklebust   pNFS/flexfiles: F...
1306
  	nfs_pgio_set_current_mirror(desc, restore_idx);
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1307
  }
53113ad35   Weston Andros Adamson   pnfs: clean up *_...
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
  /*
   * nfs_pageio_resend - Transfer requests to new descriptor and resend
   * @hdr - the pgio header to move request from
   * @desc - the pageio descriptor to add requests to
   *
   * Try to move each request (nfs_page) from @hdr to @desc then attempt
   * to send them.
   *
   * Returns 0 on success and < 0 on error.
   */
  int nfs_pageio_resend(struct nfs_pageio_descriptor *desc,
  		      struct nfs_pgio_header *hdr)
  {
f4340e931   Trond Myklebust   NFSv4/pnfs: Fix a...
1321
  	LIST_HEAD(pages);
53113ad35   Weston Andros Adamson   pnfs: clean up *_...
1322

919e3bd9a   Trond Myklebust   NFS: Ensure we co...
1323
  	desc->pg_io_completion = hdr->io_completion;
53113ad35   Weston Andros Adamson   pnfs: clean up *_...
1324
  	desc->pg_dreq = hdr->dreq;
f4340e931   Trond Myklebust   NFSv4/pnfs: Fix a...
1325
1326
1327
  	list_splice_init(&hdr->pages, &pages);
  	while (!list_empty(&pages)) {
  		struct nfs_page *req = nfs_list_entry(pages.next);
53113ad35   Weston Andros Adamson   pnfs: clean up *_...
1328

53113ad35   Weston Andros Adamson   pnfs: clean up *_...
1329
  		if (!nfs_pageio_add_request(desc, req))
f4340e931   Trond Myklebust   NFSv4/pnfs: Fix a...
1330
  			break;
53113ad35   Weston Andros Adamson   pnfs: clean up *_...
1331
1332
  	}
  	nfs_pageio_complete(desc);
f4340e931   Trond Myklebust   NFSv4/pnfs: Fix a...
1333
1334
1335
  	if (!list_empty(&pages)) {
  		int err = desc->pg_error < 0 ? desc->pg_error : -EIO;
  		hdr->completion_ops->error_cleanup(&pages, err);
eb2c50da9   Trond Myklebust   NFS: Ensure O_DIR...
1336
  		nfs_set_pgio_error(hdr, err, hdr->io_start);
f4340e931   Trond Myklebust   NFSv4/pnfs: Fix a...
1337
  		return err;
53113ad35   Weston Andros Adamson   pnfs: clean up *_...
1338
1339
1340
1341
  	}
  	return 0;
  }
  EXPORT_SYMBOL_GPL(nfs_pageio_resend);
d9156f9f3   Trond Myklebust   NFS: Allow the nf...
1342

d8a5ad75c   Trond Myklebust   NFS: Cleanup the ...
1343
  /**
2176bf426   Weston Andros Adamson   nfs: introduce pg...
1344
   * nfs_pageio_complete - Complete I/O then cleanup an nfs_pageio_descriptor
bcb71bba7   Trond Myklebust   NFS: Another clea...
1345
1346
1347
1348
   * @desc: pointer to io descriptor
   */
  void nfs_pageio_complete(struct nfs_pageio_descriptor *desc)
  {
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1349
1350
1351
1352
  	u32 midx;
  
  	for (midx = 0; midx < desc->pg_mirror_count; midx++)
  		nfs_pageio_complete_mirror(desc, midx);
2176bf426   Weston Andros Adamson   nfs: introduce pg...
1353

fdbd1a2e4   Benjamin Coddington   nfs: Fix a missed...
1354
1355
  	if (desc->pg_error < 0)
  		nfs_pageio_error_cleanup(desc);
2176bf426   Weston Andros Adamson   nfs: introduce pg...
1356
1357
  	if (desc->pg_ops->pg_cleanup)
  		desc->pg_ops->pg_cleanup(desc);
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1358
  	nfs_pageio_cleanup_mirroring(desc);
bcb71bba7   Trond Myklebust   NFS: Another clea...
1359
  }
7fe7f8487   Trond Myklebust   NFS: Avoid a dead...
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
  /**
   * nfs_pageio_cond_complete - Conditional I/O completion
   * @desc: pointer to io descriptor
   * @index: page index
   *
   * It is important to ensure that processes don't try to take locks
   * on non-contiguous ranges of pages as that might deadlock. This
   * function should be called before attempting to wait on a locked
   * nfs_page. It will complete the I/O if the page index 'index'
   * is not contiguous with the existing list of pages in 'desc'.
   */
  void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index)
  {
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1373
1374
1375
1376
1377
  	struct nfs_pgio_mirror *mirror;
  	struct nfs_page *prev;
  	u32 midx;
  
  	for (midx = 0; midx < desc->pg_mirror_count; midx++) {
63e2fffa5   Trond Myklebust   pNFS/flexfiles: F...
1378
  		mirror = nfs_pgio_get_mirror(desc, midx);
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1379
1380
  		if (!list_empty(&mirror->pg_list)) {
  			prev = nfs_list_entry(mirror->pg_list.prev);
43b7d964e   Benjamin Coddington   NFS: Fix missing ...
1381
1382
1383
1384
  			if (index != prev->wb_index + 1) {
  				nfs_pageio_complete(desc);
  				break;
  			}
a7d42ddb3   Weston Andros Adamson   nfs: add mirrorin...
1385
  		}
7fe7f8487   Trond Myklebust   NFS: Avoid a dead...
1386
1387
  	}
  }
862f35c94   Trond Myklebust   NFS: Fix memory l...
1388
1389
1390
1391
1392
1393
1394
  /*
   * nfs_pageio_stop_mirroring - stop using mirroring (set mirror count to 1)
   */
  void nfs_pageio_stop_mirroring(struct nfs_pageio_descriptor *pgio)
  {
  	nfs_pageio_complete(pgio);
  }
f7b422b17   David Howells   NFS: Split fs/nfs...
1395
  int __init nfs_init_nfspagecache(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1396
1397
1398
1399
  {
  	nfs_page_cachep = kmem_cache_create("nfs_page",
  					    sizeof(struct nfs_page),
  					    0, SLAB_HWCACHE_ALIGN,
20c2df83d   Paul Mundt   mm: Remove slab d...
1400
  					    NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1401
1402
1403
1404
1405
  	if (nfs_page_cachep == NULL)
  		return -ENOMEM;
  
  	return 0;
  }
266bee886   David Brownell   [PATCH] fix stati...
1406
  void nfs_destroy_nfspagecache(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1407
  {
1a1d92c10   Alexey Dobriyan   [PATCH] Really ig...
1408
  	kmem_cache_destroy(nfs_page_cachep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1409
  }
ef2c488c0   Anna Schumaker   NFS: Create a gen...
1410
  static const struct rpc_call_ops nfs_pgio_common_ops = {
6f92fa458   Anna Schumaker   NFS: Create a com...
1411
1412
1413
1414
  	.rpc_call_prepare = nfs_pgio_prepare,
  	.rpc_call_done = nfs_pgio_result,
  	.rpc_release = nfs_pgio_release,
  };
41d8d5b7a   Anna Schumaker   NFS: Create a com...
1415
1416
1417
1418
1419
  
  const struct nfs_pageio_ops nfs_pgio_rw_ops = {
  	.pg_test = nfs_generic_pg_test,
  	.pg_doio = nfs_generic_pg_pgios,
  };