Blame view

fs/nfs/pnfs.c 40.7 KB
85e174ba6   Ricardo Labiaga   NFS: set layout d...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  /*
   *  pNFS functions to call and manage layout drivers.
   *
   *  Copyright (c) 2002 [year of first publication]
   *  The Regents of the University of Michigan
   *  All Rights Reserved
   *
   *  Dean Hildebrand <dhildebz@umich.edu>
   *
   *  Permission is granted to use, copy, create derivative works, and
   *  redistribute this software and such derivative works for any purpose,
   *  so long as the name of the University of Michigan is not used in
   *  any advertising or publicity pertaining to the use or distribution
   *  of this software without specific, written prior authorization. If
   *  the above copyright notice or any other identification of the
   *  University of Michigan is included in any copy of any portion of
   *  this software, then the disclaimer below must also be included.
   *
   *  This software is provided as is, without representation or warranty
   *  of any kind either express or implied, including without limitation
   *  the implied warranties of merchantability, fitness for a particular
   *  purpose, or noninfringement.  The Regents of the University of
   *  Michigan shall not be liable for any damages, including special,
   *  indirect, incidental, or consequential damages, with respect to any
   *  claim arising out of or in connection with the use of the software,
   *  even if it has been or is hereafter advised of the possibility of
   *  such damages.
   */
  
  #include <linux/nfs_fs.h>
493292ddc   Trond Myklebust   NFS: Move the pnf...
31
  #include <linux/nfs_page.h>
143cb494c   Paul Gortmaker   fs: add module.h ...
32
  #include <linux/module.h>
974cec8ca   Andy Adamson   NFS: client needs...
33
  #include "internal.h"
85e174ba6   Ricardo Labiaga   NFS: set layout d...
34
  #include "pnfs.h"
64419a9b2   Andy Adamson   NFSv4.1: generic ...
35
  #include "iostat.h"
85e174ba6   Ricardo Labiaga   NFS: set layout d...
36
37
  
  #define NFSDBG_FACILITY		NFSDBG_PNFS
02c35fca7   Fred Isaman   NFSv4.1: pnfs: fu...
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  /* Locking:
   *
   * pnfs_spinlock:
   *      protects pnfs_modules_tbl.
   */
  static DEFINE_SPINLOCK(pnfs_spinlock);
  
  /*
   * pnfs_modules_tbl holds all pnfs modules
   */
  static LIST_HEAD(pnfs_modules_tbl);
  
  /* Return the registered pnfs layout driver module matching given id */
  static struct pnfs_layoutdriver_type *
  find_pnfs_driver_locked(u32 id)
  {
  	struct pnfs_layoutdriver_type *local;
  
  	list_for_each_entry(local, &pnfs_modules_tbl, pnfs_tblid)
  		if (local->id == id)
  			goto out;
  	local = NULL;
  out:
  	dprintk("%s: Searching for id %u, found %p
  ", __func__, id, local);
  	return local;
  }
85e174ba6   Ricardo Labiaga   NFS: set layout d...
65
66
67
  static struct pnfs_layoutdriver_type *
  find_pnfs_driver(u32 id)
  {
02c35fca7   Fred Isaman   NFSv4.1: pnfs: fu...
68
69
70
71
72
73
  	struct pnfs_layoutdriver_type *local;
  
  	spin_lock(&pnfs_spinlock);
  	local = find_pnfs_driver_locked(id);
  	spin_unlock(&pnfs_spinlock);
  	return local;
85e174ba6   Ricardo Labiaga   NFS: set layout d...
74
75
76
77
78
  }
  
  void
  unset_pnfs_layoutdriver(struct nfs_server *nfss)
  {
738fd0f36   Benny Halevy   pnfs: add set-cle...
79
80
81
  	if (nfss->pnfs_curr_ld) {
  		if (nfss->pnfs_curr_ld->clear_layoutdriver)
  			nfss->pnfs_curr_ld->clear_layoutdriver(nfss);
02c35fca7   Fred Isaman   NFSv4.1: pnfs: fu...
82
  		module_put(nfss->pnfs_curr_ld->owner);
738fd0f36   Benny Halevy   pnfs: add set-cle...
83
  	}
85e174ba6   Ricardo Labiaga   NFS: set layout d...
84
85
86
87
88
89
90
91
92
93
  	nfss->pnfs_curr_ld = NULL;
  }
  
  /*
   * Try to set the server's pnfs module to the pnfs layout type specified by id.
   * Currently only one pNFS layout driver per filesystem is supported.
   *
   * @id layout type. Zero (illegal layout type) indicates pNFS not in use.
   */
  void
738fd0f36   Benny Halevy   pnfs: add set-cle...
94
95
  set_pnfs_layoutdriver(struct nfs_server *server, const struct nfs_fh *mntfh,
  		      u32 id)
85e174ba6   Ricardo Labiaga   NFS: set layout d...
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
  {
  	struct pnfs_layoutdriver_type *ld_type = NULL;
  
  	if (id == 0)
  		goto out_no_driver;
  	if (!(server->nfs_client->cl_exchange_flags &
  		 (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS))) {
  		printk(KERN_ERR "%s: id %u cl_exchange_flags 0x%x
  ", __func__,
  		       id, server->nfs_client->cl_exchange_flags);
  		goto out_no_driver;
  	}
  	ld_type = find_pnfs_driver(id);
  	if (!ld_type) {
  		request_module("%s-%u", LAYOUT_NFSV4_1_MODULE_PREFIX, id);
  		ld_type = find_pnfs_driver(id);
  		if (!ld_type) {
  			dprintk("%s: No pNFS module found for %u.
  ",
  				__func__, id);
  			goto out_no_driver;
  		}
  	}
02c35fca7   Fred Isaman   NFSv4.1: pnfs: fu...
119
120
121
122
123
  	if (!try_module_get(ld_type->owner)) {
  		dprintk("%s: Could not grab reference on module
  ", __func__);
  		goto out_no_driver;
  	}
85e174ba6   Ricardo Labiaga   NFS: set layout d...
124
  	server->pnfs_curr_ld = ld_type;
738fd0f36   Benny Halevy   pnfs: add set-cle...
125
126
127
128
129
130
131
132
  	if (ld_type->set_layoutdriver
  	    && ld_type->set_layoutdriver(server, mntfh)) {
  		printk(KERN_ERR "%s: Error initializing pNFS layout driver %u.
  ",
  				__func__, id);
  		module_put(ld_type->owner);
  		goto out_no_driver;
  	}
ea8eecdd1   Christoph Hellwig   NFSv4.1 move devi...
133

85e174ba6   Ricardo Labiaga   NFS: set layout d...
134
135
136
137
138
139
140
141
142
  	dprintk("%s: pNFS module for %u set
  ", __func__, id);
  	return;
  
  out_no_driver:
  	dprintk("%s: Using NFSv4 I/O
  ", __func__);
  	server->pnfs_curr_ld = NULL;
  }
02c35fca7   Fred Isaman   NFSv4.1: pnfs: fu...
143
144
145
146
147
148
149
150
151
152
153
154
  
  int
  pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *ld_type)
  {
  	int status = -EINVAL;
  	struct pnfs_layoutdriver_type *tmp;
  
  	if (ld_type->id == 0) {
  		printk(KERN_ERR "%s id 0 is reserved
  ", __func__);
  		return status;
  	}
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
155
156
157
158
159
160
  	if (!ld_type->alloc_lseg || !ld_type->free_lseg) {
  		printk(KERN_ERR "%s Layout driver must provide "
  		       "alloc_lseg and free_lseg.
  ", __func__);
  		return status;
  	}
02c35fca7   Fred Isaman   NFSv4.1: pnfs: fu...
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
  
  	spin_lock(&pnfs_spinlock);
  	tmp = find_pnfs_driver_locked(ld_type->id);
  	if (!tmp) {
  		list_add(&ld_type->pnfs_tblid, &pnfs_modules_tbl);
  		status = 0;
  		dprintk("%s Registering id:%u name:%s
  ", __func__, ld_type->id,
  			ld_type->name);
  	} else {
  		printk(KERN_ERR "%s Module with id %d already loaded!
  ",
  			__func__, ld_type->id);
  	}
  	spin_unlock(&pnfs_spinlock);
  
  	return status;
  }
  EXPORT_SYMBOL_GPL(pnfs_register_layoutdriver);
  
  void
  pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *ld_type)
  {
  	dprintk("%s Deregistering id:%u
  ", __func__, ld_type->id);
  	spin_lock(&pnfs_spinlock);
  	list_del(&ld_type->pnfs_tblid);
  	spin_unlock(&pnfs_spinlock);
  }
  EXPORT_SYMBOL_GPL(pnfs_unregister_layoutdriver);
e5e940170   Benny Halevy   NFS: create and d...
191

b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
192
193
194
  /*
   * pNFS client layout cache
   */
cc6e5340b   Fred Isaman   pnfs: change lo r...
195
  /* Need to hold i_lock if caller does not already hold reference */
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
196
  void
cc6e5340b   Fred Isaman   pnfs: change lo r...
197
  get_layout_hdr(struct pnfs_layout_hdr *lo)
e5e940170   Benny Halevy   NFS: create and d...
198
  {
cc6e5340b   Fred Isaman   pnfs: change lo r...
199
  	atomic_inc(&lo->plh_refcount);
e5e940170   Benny Halevy   NFS: create and d...
200
  }
636fb9c89   Benny Halevy   pnfs: alloc and f...
201
202
203
204
205
206
207
208
209
210
211
212
  static struct pnfs_layout_hdr *
  pnfs_alloc_layout_hdr(struct inode *ino, gfp_t gfp_flags)
  {
  	struct pnfs_layoutdriver_type *ld = NFS_SERVER(ino)->pnfs_curr_ld;
  	return ld->alloc_layout_hdr ? ld->alloc_layout_hdr(ino, gfp_flags) :
  		kzalloc(sizeof(struct pnfs_layout_hdr), gfp_flags);
  }
  
  static void
  pnfs_free_layout_hdr(struct pnfs_layout_hdr *lo)
  {
  	struct pnfs_layoutdriver_type *ld = NFS_SERVER(lo->plh_inode)->pnfs_curr_ld;
9fa407587   Peng Tao   pnfs: save layout...
213
  	put_rpccred(lo->plh_lc_cred);
636fb9c89   Benny Halevy   pnfs: alloc and f...
214
215
  	return ld->alloc_layout_hdr ? ld->free_layout_hdr(lo) : kfree(lo);
  }
e5e940170   Benny Halevy   NFS: create and d...
216
  static void
cc6e5340b   Fred Isaman   pnfs: change lo r...
217
  destroy_layout_hdr(struct pnfs_layout_hdr *lo)
e5e940170   Benny Halevy   NFS: create and d...
218
  {
cc6e5340b   Fred Isaman   pnfs: change lo r...
219
220
221
222
  	dprintk("%s: freeing layout cache %p
  ", __func__, lo);
  	BUG_ON(!list_empty(&lo->plh_layouts));
  	NFS_I(lo->plh_inode)->layout = NULL;
636fb9c89   Benny Halevy   pnfs: alloc and f...
223
  	pnfs_free_layout_hdr(lo);
cc6e5340b   Fred Isaman   pnfs: change lo r...
224
  }
e5e940170   Benny Halevy   NFS: create and d...
225

cc6e5340b   Fred Isaman   pnfs: change lo r...
226
227
228
229
230
  static void
  put_layout_hdr_locked(struct pnfs_layout_hdr *lo)
  {
  	if (atomic_dec_and_test(&lo->plh_refcount))
  		destroy_layout_hdr(lo);
e5e940170   Benny Halevy   NFS: create and d...
231
  }
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
232
  void
cc6e5340b   Fred Isaman   pnfs: change lo r...
233
  put_layout_hdr(struct pnfs_layout_hdr *lo)
974cec8ca   Andy Adamson   NFS: client needs...
234
  {
cc6e5340b   Fred Isaman   pnfs: change lo r...
235
236
237
238
239
240
  	struct inode *inode = lo->plh_inode;
  
  	if (atomic_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) {
  		destroy_layout_hdr(lo);
  		spin_unlock(&inode->i_lock);
  	}
974cec8ca   Andy Adamson   NFS: client needs...
241
242
243
244
245
  }
  
  static void
  init_lseg(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg)
  {
566052c53   Fred Isaman   pnfs: add prefix ...
246
  	INIT_LIST_HEAD(&lseg->pls_list);
a9bae5666   Peng Tao   pnfs: let layoutc...
247
  	INIT_LIST_HEAD(&lseg->pls_lc_list);
4541d16c0   Fred Isaman   pnfs: change how ...
248
249
250
  	atomic_set(&lseg->pls_refcount, 1);
  	smp_mb();
  	set_bit(NFS_LSEG_VALID, &lseg->pls_flags);
566052c53   Fred Isaman   pnfs: add prefix ...
251
  	lseg->pls_layout = lo;
974cec8ca   Andy Adamson   NFS: client needs...
252
  }
4541d16c0   Fred Isaman   pnfs: change how ...
253
  static void free_lseg(struct pnfs_layout_segment *lseg)
974cec8ca   Andy Adamson   NFS: client needs...
254
  {
b7edfaa19   Fred Isaman   pnfs: add prefix ...
255
  	struct inode *ino = lseg->pls_layout->plh_inode;
974cec8ca   Andy Adamson   NFS: client needs...
256

b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
257
  	NFS_SERVER(ino)->pnfs_curr_ld->free_lseg(lseg);
52fabd731   Fred Isaman   pnfs: fix incorre...
258
  	/* Matched by get_layout_hdr in pnfs_insert_layout */
cc6e5340b   Fred Isaman   pnfs: change lo r...
259
  	put_layout_hdr(NFS_I(ino)->layout);
974cec8ca   Andy Adamson   NFS: client needs...
260
  }
d684d2ae1   Fred Isaman   NFSv4.1: lseg ref...
261
262
263
264
  static void
  put_lseg_common(struct pnfs_layout_segment *lseg)
  {
  	struct inode *inode = lseg->pls_layout->plh_inode;
d20581aa4   Benny Halevy   pnfs: support for...
265
  	WARN_ON(test_bit(NFS_LSEG_VALID, &lseg->pls_flags));
d684d2ae1   Fred Isaman   NFSv4.1: lseg ref...
266
267
268
269
270
271
272
273
  	list_del_init(&lseg->pls_list);
  	if (list_empty(&lseg->pls_layout->plh_segs)) {
  		set_bit(NFS_LAYOUT_DESTROYED, &lseg->pls_layout->plh_flags);
  		/* Matched by initial refcount set in alloc_init_layout_hdr */
  		put_layout_hdr_locked(lseg->pls_layout);
  	}
  	rpc_wake_up(&NFS_SERVER(inode)->roc_rpcwaitq);
  }
bae724ef9   Fred Isaman   NFSv4.1: shift pn...
274
  void
d684d2ae1   Fred Isaman   NFSv4.1: lseg ref...
275
  put_lseg(struct pnfs_layout_segment *lseg)
974cec8ca   Andy Adamson   NFS: client needs...
276
  {
d684d2ae1   Fred Isaman   NFSv4.1: lseg ref...
277
278
279
280
  	struct inode *inode;
  
  	if (!lseg)
  		return;
4541d16c0   Fred Isaman   pnfs: change how ...
281
282
283
284
  	dprintk("%s: lseg %p ref %d valid %d
  ", __func__, lseg,
  		atomic_read(&lseg->pls_refcount),
  		test_bit(NFS_LSEG_VALID, &lseg->pls_flags));
d684d2ae1   Fred Isaman   NFSv4.1: lseg ref...
285
286
287
  	inode = lseg->pls_layout->plh_inode;
  	if (atomic_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) {
  		LIST_HEAD(free_me);
4541d16c0   Fred Isaman   pnfs: change how ...
288

d684d2ae1   Fred Isaman   NFSv4.1: lseg ref...
289
290
291
292
  		put_lseg_common(lseg);
  		list_add(&lseg->pls_list, &free_me);
  		spin_unlock(&inode->i_lock);
  		pnfs_free_lseg_list(&free_me);
4541d16c0   Fred Isaman   pnfs: change how ...
293
  	}
4541d16c0   Fred Isaman   pnfs: change how ...
294
  }
e0c2b3801   Fred Isaman   NFSv4.1: filelayo...
295
  EXPORT_SYMBOL_GPL(put_lseg);
974cec8ca   Andy Adamson   NFS: client needs...
296

fb3296eb4   Benny Halevy   pnfs: Use byte-ra...
297
298
299
300
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
343
344
345
346
347
348
349
350
351
352
353
354
  static inline u64
  end_offset(u64 start, u64 len)
  {
  	u64 end;
  
  	end = start + len;
  	return end >= start ? end : NFS4_MAX_UINT64;
  }
  
  /* last octet in a range */
  static inline u64
  last_byte_offset(u64 start, u64 len)
  {
  	u64 end;
  
  	BUG_ON(!len);
  	end = start + len;
  	return end > start ? end - 1 : NFS4_MAX_UINT64;
  }
  
  /*
   * is l2 fully contained in l1?
   *   start1                             end1
   *   [----------------------------------)
   *           start2           end2
   *           [----------------)
   */
  static inline int
  lo_seg_contained(struct pnfs_layout_range *l1,
  		 struct pnfs_layout_range *l2)
  {
  	u64 start1 = l1->offset;
  	u64 end1 = end_offset(start1, l1->length);
  	u64 start2 = l2->offset;
  	u64 end2 = end_offset(start2, l2->length);
  
  	return (start1 <= start2) && (end1 >= end2);
  }
  
  /*
   * is l1 and l2 intersecting?
   *   start1                             end1
   *   [----------------------------------)
   *                              start2           end2
   *                              [----------------)
   */
  static inline int
  lo_seg_intersecting(struct pnfs_layout_range *l1,
  		    struct pnfs_layout_range *l2)
  {
  	u64 start1 = l1->offset;
  	u64 end1 = end_offset(start1, l1->length);
  	u64 start2 = l2->offset;
  	u64 end2 = end_offset(start2, l2->length);
  
  	return (end1 == NFS4_MAX_UINT64 || end1 > start2) &&
  	       (end2 == NFS4_MAX_UINT64 || end2 > start1);
  }
4541d16c0   Fred Isaman   pnfs: change how ...
355
  static bool
778b5502f   Benny Halevy   pnfs: Use byte-ra...
356
357
  should_free_lseg(struct pnfs_layout_range *lseg_range,
  		 struct pnfs_layout_range *recall_range)
4541d16c0   Fred Isaman   pnfs: change how ...
358
  {
778b5502f   Benny Halevy   pnfs: Use byte-ra...
359
360
361
  	return (recall_range->iomode == IOMODE_ANY ||
  		lseg_range->iomode == recall_range->iomode) &&
  	       lo_seg_intersecting(lseg_range, recall_range);
974cec8ca   Andy Adamson   NFS: client needs...
362
  }
4541d16c0   Fred Isaman   pnfs: change how ...
363
364
365
366
367
368
369
370
371
372
373
  /* Returns 1 if lseg is removed from list, 0 otherwise */
  static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
  			     struct list_head *tmp_list)
  {
  	int rv = 0;
  
  	if (test_and_clear_bit(NFS_LSEG_VALID, &lseg->pls_flags)) {
  		/* Remove the reference keeping the lseg in the
  		 * list.  It will now be removed when all
  		 * outstanding io is finished.
  		 */
d684d2ae1   Fred Isaman   NFSv4.1: lseg ref...
374
375
376
377
378
379
380
381
  		dprintk("%s: lseg %p ref %d
  ", __func__, lseg,
  			atomic_read(&lseg->pls_refcount));
  		if (atomic_dec_and_test(&lseg->pls_refcount)) {
  			put_lseg_common(lseg);
  			list_add(&lseg->pls_list, tmp_list);
  			rv = 1;
  		}
4541d16c0   Fred Isaman   pnfs: change how ...
382
383
384
385
386
387
388
  	}
  	return rv;
  }
  
  /* Returns count of number of matching invalid lsegs remaining in list
   * after call.
   */
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
389
  int
4541d16c0   Fred Isaman   pnfs: change how ...
390
391
  mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
  			    struct list_head *tmp_list,
778b5502f   Benny Halevy   pnfs: Use byte-ra...
392
  			    struct pnfs_layout_range *recall_range)
974cec8ca   Andy Adamson   NFS: client needs...
393
394
  {
  	struct pnfs_layout_segment *lseg, *next;
4541d16c0   Fred Isaman   pnfs: change how ...
395
  	int invalid = 0, removed = 0;
974cec8ca   Andy Adamson   NFS: client needs...
396
397
398
  
  	dprintk("%s:Begin lo %p
  ", __func__, lo);
385117224   Fred Isaman   pnfs: avoid incor...
399
400
401
402
403
  	if (list_empty(&lo->plh_segs)) {
  		if (!test_and_set_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags))
  			put_layout_hdr_locked(lo);
  		return 0;
  	}
4541d16c0   Fred Isaman   pnfs: change how ...
404
  	list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list)
778b5502f   Benny Halevy   pnfs: Use byte-ra...
405
406
  		if (!recall_range ||
  		    should_free_lseg(&lseg->pls_range, recall_range)) {
4541d16c0   Fred Isaman   pnfs: change how ...
407
408
409
410
411
412
413
414
415
416
417
  			dprintk("%s: freeing lseg %p iomode %d "
  				"offset %llu length %llu
  ", __func__,
  				lseg, lseg->pls_range.iomode, lseg->pls_range.offset,
  				lseg->pls_range.length);
  			invalid++;
  			removed += mark_lseg_invalid(lseg, tmp_list);
  		}
  	dprintk("%s:Return %i
  ", __func__, invalid - removed);
  	return invalid - removed;
974cec8ca   Andy Adamson   NFS: client needs...
418
  }
f49f9baac   Fred Isaman   pnfs: fix pnfs lo...
419
  /* note free_me must contain lsegs from a single layout_hdr */
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
420
  void
4541d16c0   Fred Isaman   pnfs: change how ...
421
  pnfs_free_lseg_list(struct list_head *free_me)
974cec8ca   Andy Adamson   NFS: client needs...
422
  {
4541d16c0   Fred Isaman   pnfs: change how ...
423
  	struct pnfs_layout_segment *lseg, *tmp;
f49f9baac   Fred Isaman   pnfs: fix pnfs lo...
424
425
426
427
428
429
430
  	struct pnfs_layout_hdr *lo;
  
  	if (list_empty(free_me))
  		return;
  
  	lo = list_first_entry(free_me, struct pnfs_layout_segment,
  			      pls_list)->pls_layout;
974cec8ca   Andy Adamson   NFS: client needs...
431

f49f9baac   Fred Isaman   pnfs: fix pnfs lo...
432
433
434
435
436
437
438
439
  	if (test_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags)) {
  		struct nfs_client *clp;
  
  		clp = NFS_SERVER(lo->plh_inode)->nfs_client;
  		spin_lock(&clp->cl_lock);
  		list_del_init(&lo->plh_layouts);
  		spin_unlock(&clp->cl_lock);
  	}
4541d16c0   Fred Isaman   pnfs: change how ...
440
  	list_for_each_entry_safe(lseg, tmp, free_me, pls_list) {
566052c53   Fred Isaman   pnfs: add prefix ...
441
  		list_del(&lseg->pls_list);
4541d16c0   Fred Isaman   pnfs: change how ...
442
  		free_lseg(lseg);
974cec8ca   Andy Adamson   NFS: client needs...
443
444
  	}
  }
e5e940170   Benny Halevy   NFS: create and d...
445
446
447
448
  void
  pnfs_destroy_layout(struct nfs_inode *nfsi)
  {
  	struct pnfs_layout_hdr *lo;
974cec8ca   Andy Adamson   NFS: client needs...
449
  	LIST_HEAD(tmp_list);
e5e940170   Benny Halevy   NFS: create and d...
450
451
452
453
  
  	spin_lock(&nfsi->vfs_inode.i_lock);
  	lo = nfsi->layout;
  	if (lo) {
385117224   Fred Isaman   pnfs: avoid incor...
454
  		lo->plh_block_lgets++; /* permanently block new LAYOUTGETs */
778b5502f   Benny Halevy   pnfs: Use byte-ra...
455
  		mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
e5e940170   Benny Halevy   NFS: create and d...
456
457
  	}
  	spin_unlock(&nfsi->vfs_inode.i_lock);
974cec8ca   Andy Adamson   NFS: client needs...
458
459
460
461
462
463
464
465
466
467
  	pnfs_free_lseg_list(&tmp_list);
  }
  
  /*
   * Called by the state manger to remove all layouts established under an
   * expired lease.
   */
  void
  pnfs_destroy_all_layouts(struct nfs_client *clp)
  {
6382a4413   Weston Andros Adamson   NFS: move pnfs la...
468
  	struct nfs_server *server;
974cec8ca   Andy Adamson   NFS: client needs...
469
470
  	struct pnfs_layout_hdr *lo;
  	LIST_HEAD(tmp_list);
c47abcf8f   Andy Adamson   NFSv4.1: do not u...
471
472
  	nfs4_deviceid_mark_client_invalid(clp);
  	nfs4_deviceid_purge_client(clp);
974cec8ca   Andy Adamson   NFS: client needs...
473
  	spin_lock(&clp->cl_lock);
6382a4413   Weston Andros Adamson   NFS: move pnfs la...
474
475
476
477
478
479
  	rcu_read_lock();
  	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
  		if (!list_empty(&server->layouts))
  			list_splice_init(&server->layouts, &tmp_list);
  	}
  	rcu_read_unlock();
974cec8ca   Andy Adamson   NFS: client needs...
480
481
482
483
  	spin_unlock(&clp->cl_lock);
  
  	while (!list_empty(&tmp_list)) {
  		lo = list_entry(tmp_list.next, struct pnfs_layout_hdr,
b7edfaa19   Fred Isaman   pnfs: add prefix ...
484
  				plh_layouts);
974cec8ca   Andy Adamson   NFS: client needs...
485
486
  		dprintk("%s freeing layout for inode %lu
  ", __func__,
b7edfaa19   Fred Isaman   pnfs: add prefix ...
487
  			lo->plh_inode->i_ino);
2887fe455   Andy Adamson   NFSv4.1: remove p...
488
  		list_del_init(&lo->plh_layouts);
b7edfaa19   Fred Isaman   pnfs: add prefix ...
489
  		pnfs_destroy_layout(NFS_I(lo->plh_inode));
974cec8ca   Andy Adamson   NFS: client needs...
490
  	}
e5e940170   Benny Halevy   NFS: create and d...
491
  }
fd6002e9b   Fred Isaman   pnfs: change layo...
492
  /* update lo->plh_stateid with new if is more recent */
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
493
494
495
  void
  pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new,
  			bool update_barrier)
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
496
  {
fd6002e9b   Fred Isaman   pnfs: change layo...
497
  	u32 oldseq, newseq;
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
498

fd6002e9b   Fred Isaman   pnfs: change layo...
499
500
  	oldseq = be32_to_cpu(lo->plh_stateid.stateid.seqid);
  	newseq = be32_to_cpu(new->stateid.seqid);
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
501
  	if ((int)(newseq - oldseq) > 0) {
fd6002e9b   Fred Isaman   pnfs: change layo...
502
  		memcpy(&lo->plh_stateid, &new->stateid, sizeof(new->stateid));
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
  		if (update_barrier) {
  			u32 new_barrier = be32_to_cpu(new->stateid.seqid);
  
  			if ((int)(new_barrier - lo->plh_barrier))
  				lo->plh_barrier = new_barrier;
  		} else {
  			/* Because of wraparound, we want to keep the barrier
  			 * "close" to the current seqids.  It needs to be
  			 * within 2**31 to count as "behind", so if it
  			 * gets too near that limit, give us a litle leeway
  			 * and bring it to within 2**30.
  			 * NOTE - and yes, this is all unsigned arithmetic.
  			 */
  			if (unlikely((newseq - lo->plh_barrier) > (3 << 29)))
  				lo->plh_barrier = newseq - (1 << 30);
  		}
  	}
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
520
  }
cf7d63f1f   Fred Isaman   pnfs: serialize L...
521
522
  /* lget is set to 1 if called from inside send_layoutget call chain */
  static bool
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
523
524
525
526
527
528
  pnfs_layoutgets_blocked(struct pnfs_layout_hdr *lo, nfs4_stateid *stateid,
  			int lget)
  {
  	if ((stateid) &&
  	    (int)(lo->plh_barrier - be32_to_cpu(stateid->stateid.seqid)) >= 0)
  		return true;
f7e8917a6   Fred Isaman   pnfs: layout roc ...
529
  	return lo->plh_block_lgets ||
385117224   Fred Isaman   pnfs: avoid incor...
530
  		test_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags) ||
f7e8917a6   Fred Isaman   pnfs: layout roc ...
531
  		test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
532
  		(list_empty(&lo->plh_segs) &&
cf7d63f1f   Fred Isaman   pnfs: serialize L...
533
534
  		 (atomic_read(&lo->plh_outstanding) > lget));
  }
fd6002e9b   Fred Isaman   pnfs: change layo...
535
536
537
  int
  pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo,
  			      struct nfs4_state *open_state)
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
538
  {
fd6002e9b   Fred Isaman   pnfs: change layo...
539
  	int status = 0;
974cec8ca   Andy Adamson   NFS: client needs...
540

b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
541
542
  	dprintk("--> %s
  ", __func__);
fd6002e9b   Fred Isaman   pnfs: change layo...
543
  	spin_lock(&lo->plh_inode->i_lock);
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
544
  	if (pnfs_layoutgets_blocked(lo, NULL, 1)) {
cf7d63f1f   Fred Isaman   pnfs: serialize L...
545
546
  		status = -EAGAIN;
  	} else if (list_empty(&lo->plh_segs)) {
fd6002e9b   Fred Isaman   pnfs: change layo...
547
548
549
550
551
552
553
554
555
556
  		int seq;
  
  		do {
  			seq = read_seqbegin(&open_state->seqlock);
  			memcpy(dst->data, open_state->stateid.data,
  			       sizeof(open_state->stateid.data));
  		} while (read_seqretry(&open_state->seqlock, seq));
  	} else
  		memcpy(dst->data, lo->plh_stateid.data, sizeof(lo->plh_stateid.data));
  	spin_unlock(&lo->plh_inode->i_lock);
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
557
558
  	dprintk("<-- %s
  ", __func__);
fd6002e9b   Fred Isaman   pnfs: change layo...
559
  	return status;
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
560
561
562
563
564
565
566
567
  }
  
  /*
  * Get layout from server.
  *    for now, assume that whole file layouts are requested.
  *    arg->offset: 0
  *    arg->length: all ones
  */
e5e940170   Benny Halevy   NFS: create and d...
568
569
570
  static struct pnfs_layout_segment *
  send_layoutget(struct pnfs_layout_hdr *lo,
  	   struct nfs_open_context *ctx,
fb3296eb4   Benny Halevy   pnfs: Use byte-ra...
571
  	   struct pnfs_layout_range *range,
a75b9df9d   Trond Myklebust   NFSv4.1: Ensure t...
572
  	   gfp_t gfp_flags)
e5e940170   Benny Halevy   NFS: create and d...
573
  {
b7edfaa19   Fred Isaman   pnfs: add prefix ...
574
  	struct inode *ino = lo->plh_inode;
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
575
576
577
  	struct nfs_server *server = NFS_SERVER(ino);
  	struct nfs4_layoutget *lgp;
  	struct pnfs_layout_segment *lseg = NULL;
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
578
579
580
  	struct page **pages = NULL;
  	int i;
  	u32 max_resp_sz, max_pages;
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
581
582
583
  
  	dprintk("--> %s
  ", __func__);
e5e940170   Benny Halevy   NFS: create and d...
584

b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
585
  	BUG_ON(ctx == NULL);
a75b9df9d   Trond Myklebust   NFSv4.1: Ensure t...
586
  	lgp = kzalloc(sizeof(*lgp), gfp_flags);
cf7d63f1f   Fred Isaman   pnfs: serialize L...
587
  	if (lgp == NULL)
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
588
  		return NULL;
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
589
590
591
592
  
  	/* allocate pages for xdr post processing */
  	max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
  	max_pages = max_resp_sz >> PAGE_SHIFT;
a75b9df9d   Trond Myklebust   NFSv4.1: Ensure t...
593
  	pages = kzalloc(max_pages * sizeof(struct page *), gfp_flags);
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
594
595
596
597
  	if (!pages)
  		goto out_err_free;
  
  	for (i = 0; i < max_pages; i++) {
a75b9df9d   Trond Myklebust   NFSv4.1: Ensure t...
598
  		pages[i] = alloc_page(gfp_flags);
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
599
600
601
  		if (!pages[i])
  			goto out_err_free;
  	}
fb3296eb4   Benny Halevy   pnfs: Use byte-ra...
602
603
604
  	lgp->args.minlength = PAGE_CACHE_SIZE;
  	if (lgp->args.minlength > range->length)
  		lgp->args.minlength = range->length;
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
605
  	lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE;
fb3296eb4   Benny Halevy   pnfs: Use byte-ra...
606
  	lgp->args.range = *range;
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
607
608
609
  	lgp->args.type = server->pnfs_curr_ld->id;
  	lgp->args.inode = ino;
  	lgp->args.ctx = get_nfs_open_context(ctx);
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
610
611
  	lgp->args.layout.pages = pages;
  	lgp->args.layout.pglen = max_pages * PAGE_SIZE;
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
612
  	lgp->lsegpp = &lseg;
a75b9df9d   Trond Myklebust   NFSv4.1: Ensure t...
613
  	lgp->gfp_flags = gfp_flags;
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
614
615
616
617
618
  
  	/* Synchronously retrieve layout information from server and
  	 * store in lseg.
  	 */
  	nfs4_proc_layoutget(lgp);
974cec8ca   Andy Adamson   NFS: client needs...
619
  	if (!lseg) {
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
620
  		/* remember that LAYOUTGET failed and suspend trying */
fb3296eb4   Benny Halevy   pnfs: Use byte-ra...
621
  		set_bit(lo_fail_bit(range->iomode), &lo->plh_flags);
974cec8ca   Andy Adamson   NFS: client needs...
622
  	}
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
623
624
625
626
627
  
  	/* free xdr pages */
  	for (i = 0; i < max_pages; i++)
  		__free_page(pages[i]);
  	kfree(pages);
974cec8ca   Andy Adamson   NFS: client needs...
628
  	return lseg;
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
629
630
631
632
633
634
635
636
637
638
639
640
641
  
  out_err_free:
  	/* free any allocated xdr pages, lgp as it's not used */
  	if (pages) {
  		for (i = 0; i < max_pages; i++) {
  			if (!pages[i])
  				break;
  			__free_page(pages[i]);
  		}
  		kfree(pages);
  	}
  	kfree(lgp);
  	return NULL;
974cec8ca   Andy Adamson   NFS: client needs...
642
  }
cbe826036   Benny Halevy   pnfs: layoutreturn
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
  /* Initiates a LAYOUTRETURN(FILE) */
  int
  _pnfs_return_layout(struct inode *ino)
  {
  	struct pnfs_layout_hdr *lo = NULL;
  	struct nfs_inode *nfsi = NFS_I(ino);
  	LIST_HEAD(tmp_list);
  	struct nfs4_layoutreturn *lrp;
  	nfs4_stateid stateid;
  	int status = 0;
  
  	dprintk("--> %s
  ", __func__);
  
  	spin_lock(&ino->i_lock);
  	lo = nfsi->layout;
a2e1d4f2e   Fred Isaman   nfs4.1: fix sever...
659
  	if (!lo) {
cbe826036   Benny Halevy   pnfs: layoutreturn
660
  		spin_unlock(&ino->i_lock);
a2e1d4f2e   Fred Isaman   nfs4.1: fix sever...
661
662
663
  		dprintk("%s: no layout to return
  ", __func__);
  		return status;
cbe826036   Benny Halevy   pnfs: layoutreturn
664
665
666
667
  	}
  	stateid = nfsi->layout->plh_stateid;
  	/* Reference matched in nfs4_layoutreturn_release */
  	get_layout_hdr(lo);
ea0ded748   Fred Isaman   nfs4.1: prevent r...
668
669
  	mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
  	lo->plh_block_lgets++;
cbe826036   Benny Halevy   pnfs: layoutreturn
670
671
672
673
674
675
676
677
  	spin_unlock(&ino->i_lock);
  	pnfs_free_lseg_list(&tmp_list);
  
  	WARN_ON(test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags));
  
  	lrp = kzalloc(sizeof(*lrp), GFP_KERNEL);
  	if (unlikely(lrp == NULL)) {
  		status = -ENOMEM;
9e2dfdb30   Fred Isaman   nfs4.1: mark layo...
678
679
  		set_bit(NFS_LAYOUT_RW_FAILED, &lo->plh_flags);
  		set_bit(NFS_LAYOUT_RO_FAILED, &lo->plh_flags);
1ed3a8539   Benny Halevy   NFSv4.1: need to ...
680
  		put_layout_hdr(lo);
cbe826036   Benny Halevy   pnfs: layoutreturn
681
682
683
684
685
686
  		goto out;
  	}
  
  	lrp->args.stateid = stateid;
  	lrp->args.layout_type = NFS_SERVER(ino)->pnfs_curr_ld->id;
  	lrp->args.inode = ino;
a56aaa02b   Trond Myklebust   NFSv4.1: Clean up...
687
  	lrp->args.layout = lo;
cbe826036   Benny Halevy   pnfs: layoutreturn
688
689
690
691
692
693
694
695
  	lrp->clp = NFS_SERVER(ino)->nfs_client;
  
  	status = nfs4_proc_layoutreturn(lrp);
  out:
  	dprintk("<-- %s status: %d
  ", __func__, status);
  	return status;
  }
f7e8917a6   Fred Isaman   pnfs: layout roc ...
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
  bool pnfs_roc(struct inode *ino)
  {
  	struct pnfs_layout_hdr *lo;
  	struct pnfs_layout_segment *lseg, *tmp;
  	LIST_HEAD(tmp_list);
  	bool found = false;
  
  	spin_lock(&ino->i_lock);
  	lo = NFS_I(ino)->layout;
  	if (!lo || !test_and_clear_bit(NFS_LAYOUT_ROC, &lo->plh_flags) ||
  	    test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags))
  		goto out_nolayout;
  	list_for_each_entry_safe(lseg, tmp, &lo->plh_segs, pls_list)
  		if (test_bit(NFS_LSEG_ROC, &lseg->pls_flags)) {
  			mark_lseg_invalid(lseg, &tmp_list);
  			found = true;
  		}
  	if (!found)
  		goto out_nolayout;
  	lo->plh_block_lgets++;
  	get_layout_hdr(lo); /* matched in pnfs_roc_release */
  	spin_unlock(&ino->i_lock);
  	pnfs_free_lseg_list(&tmp_list);
  	return true;
  
  out_nolayout:
  	spin_unlock(&ino->i_lock);
  	return false;
  }
  
  void pnfs_roc_release(struct inode *ino)
  {
  	struct pnfs_layout_hdr *lo;
  
  	spin_lock(&ino->i_lock);
  	lo = NFS_I(ino)->layout;
  	lo->plh_block_lgets--;
  	put_layout_hdr_locked(lo);
  	spin_unlock(&ino->i_lock);
  }
  
  void pnfs_roc_set_barrier(struct inode *ino, u32 barrier)
  {
  	struct pnfs_layout_hdr *lo;
  
  	spin_lock(&ino->i_lock);
  	lo = NFS_I(ino)->layout;
  	if ((int)(barrier - lo->plh_barrier) > 0)
  		lo->plh_barrier = barrier;
  	spin_unlock(&ino->i_lock);
  }
  
  bool pnfs_roc_drain(struct inode *ino, u32 *barrier)
  {
  	struct nfs_inode *nfsi = NFS_I(ino);
  	struct pnfs_layout_segment *lseg;
  	bool found = false;
  
  	spin_lock(&ino->i_lock);
  	list_for_each_entry(lseg, &nfsi->layout->plh_segs, pls_list)
  		if (test_bit(NFS_LSEG_ROC, &lseg->pls_flags)) {
  			found = true;
  			break;
  		}
  	if (!found) {
  		struct pnfs_layout_hdr *lo = nfsi->layout;
  		u32 current_seqid = be32_to_cpu(lo->plh_stateid.stateid.seqid);
  
  		/* Since close does not return a layout stateid for use as
  		 * a barrier, we choose the worst-case barrier.
  		 */
  		*barrier = current_seqid + atomic_read(&lo->plh_outstanding);
  	}
  	spin_unlock(&ino->i_lock);
  	return found;
  }
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
772
773
774
775
776
777
  /*
   * Compare two layout segments for sorting into layout cache.
   * We want to preferentially return RW over RO layouts, so ensure those
   * are seen first.
   */
  static s64
fb3296eb4   Benny Halevy   pnfs: Use byte-ra...
778
779
  cmp_layout(struct pnfs_layout_range *l1,
  	   struct pnfs_layout_range *l2)
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
780
  {
fb3296eb4   Benny Halevy   pnfs: Use byte-ra...
781
782
783
784
785
786
787
788
789
790
791
  	s64 d;
  
  	/* high offset > low offset */
  	d = l1->offset - l2->offset;
  	if (d)
  		return d;
  
  	/* short length > long length */
  	d = l2->length - l1->length;
  	if (d)
  		return d;
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
792
  	/* read > read/write */
fb3296eb4   Benny Halevy   pnfs: Use byte-ra...
793
  	return (int)(l1->iomode == IOMODE_READ) - (int)(l2->iomode == IOMODE_READ);
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
794
  }
974cec8ca   Andy Adamson   NFS: client needs...
795
796
797
798
  static void
  pnfs_insert_layout(struct pnfs_layout_hdr *lo,
  		   struct pnfs_layout_segment *lseg)
  {
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
799
  	struct pnfs_layout_segment *lp;
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
800

974cec8ca   Andy Adamson   NFS: client needs...
801
802
  	dprintk("%s:Begin
  ", __func__);
b7edfaa19   Fred Isaman   pnfs: add prefix ...
803
  	assert_spin_locked(&lo->plh_inode->i_lock);
b7edfaa19   Fred Isaman   pnfs: add prefix ...
804
  	list_for_each_entry(lp, &lo->plh_segs, pls_list) {
fb3296eb4   Benny Halevy   pnfs: Use byte-ra...
805
  		if (cmp_layout(&lseg->pls_range, &lp->pls_range) > 0)
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
806
  			continue;
566052c53   Fred Isaman   pnfs: add prefix ...
807
  		list_add_tail(&lseg->pls_list, &lp->pls_list);
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
808
809
810
811
  		dprintk("%s: inserted lseg %p "
  			"iomode %d offset %llu length %llu before "
  			"lp %p iomode %d offset %llu length %llu
  ",
566052c53   Fred Isaman   pnfs: add prefix ...
812
813
814
815
  			__func__, lseg, lseg->pls_range.iomode,
  			lseg->pls_range.offset, lseg->pls_range.length,
  			lp, lp->pls_range.iomode, lp->pls_range.offset,
  			lp->pls_range.length);
fb3296eb4   Benny Halevy   pnfs: Use byte-ra...
816
  		goto out;
974cec8ca   Andy Adamson   NFS: client needs...
817
  	}
fb3296eb4   Benny Halevy   pnfs: Use byte-ra...
818
819
820
821
822
823
824
  	list_add_tail(&lseg->pls_list, &lo->plh_segs);
  	dprintk("%s: inserted lseg %p "
  		"iomode %d offset %llu length %llu at tail
  ",
  		__func__, lseg, lseg->pls_range.iomode,
  		lseg->pls_range.offset, lseg->pls_range.length);
  out:
cc6e5340b   Fred Isaman   pnfs: change lo r...
825
  	get_layout_hdr(lo);
974cec8ca   Andy Adamson   NFS: client needs...
826
827
828
  
  	dprintk("%s:Return
  ", __func__);
e5e940170   Benny Halevy   NFS: create and d...
829
830
831
  }
  
  static struct pnfs_layout_hdr *
9fa407587   Peng Tao   pnfs: save layout...
832
833
834
  alloc_init_layout_hdr(struct inode *ino,
  		      struct nfs_open_context *ctx,
  		      gfp_t gfp_flags)
e5e940170   Benny Halevy   NFS: create and d...
835
836
  {
  	struct pnfs_layout_hdr *lo;
636fb9c89   Benny Halevy   pnfs: alloc and f...
837
  	lo = pnfs_alloc_layout_hdr(ino, gfp_flags);
e5e940170   Benny Halevy   NFS: create and d...
838
839
  	if (!lo)
  		return NULL;
cc6e5340b   Fred Isaman   pnfs: change lo r...
840
  	atomic_set(&lo->plh_refcount, 1);
b7edfaa19   Fred Isaman   pnfs: add prefix ...
841
842
  	INIT_LIST_HEAD(&lo->plh_layouts);
  	INIT_LIST_HEAD(&lo->plh_segs);
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
843
  	INIT_LIST_HEAD(&lo->plh_bulk_recall);
b7edfaa19   Fred Isaman   pnfs: add prefix ...
844
  	lo->plh_inode = ino;
9fa407587   Peng Tao   pnfs: save layout...
845
  	lo->plh_lc_cred = get_rpccred(ctx->state->owner->so_cred);
e5e940170   Benny Halevy   NFS: create and d...
846
847
848
849
  	return lo;
  }
  
  static struct pnfs_layout_hdr *
9fa407587   Peng Tao   pnfs: save layout...
850
851
852
  pnfs_find_alloc_layout(struct inode *ino,
  		       struct nfs_open_context *ctx,
  		       gfp_t gfp_flags)
e5e940170   Benny Halevy   NFS: create and d...
853
854
855
856
857
858
859
860
  {
  	struct nfs_inode *nfsi = NFS_I(ino);
  	struct pnfs_layout_hdr *new = NULL;
  
  	dprintk("%s Begin ino=%p layout=%p
  ", __func__, ino, nfsi->layout);
  
  	assert_spin_locked(&ino->i_lock);
4541d16c0   Fred Isaman   pnfs: change how ...
861
862
863
864
865
866
  	if (nfsi->layout) {
  		if (test_bit(NFS_LAYOUT_DESTROYED, &nfsi->layout->plh_flags))
  			return NULL;
  		else
  			return nfsi->layout;
  	}
e5e940170   Benny Halevy   NFS: create and d...
867
  	spin_unlock(&ino->i_lock);
9fa407587   Peng Tao   pnfs: save layout...
868
  	new = alloc_init_layout_hdr(ino, ctx, gfp_flags);
e5e940170   Benny Halevy   NFS: create and d...
869
870
871
872
873
  	spin_lock(&ino->i_lock);
  
  	if (likely(nfsi->layout == NULL))	/* Won the race? */
  		nfsi->layout = new;
  	else
636fb9c89   Benny Halevy   pnfs: alloc and f...
874
  		pnfs_free_layout_hdr(new);
e5e940170   Benny Halevy   NFS: create and d...
875
876
  	return nfsi->layout;
  }
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
877
878
879
880
881
882
883
884
885
886
887
888
  /*
   * iomode matching rules:
   * iomode	lseg	match
   * -----	-----	-----
   * ANY		READ	true
   * ANY		RW	true
   * RW		READ	false
   * RW		RW	true
   * READ		READ	true
   * READ		RW	true
   */
  static int
fb3296eb4   Benny Halevy   pnfs: Use byte-ra...
889
890
  is_matching_lseg(struct pnfs_layout_range *ls_range,
  		 struct pnfs_layout_range *range)
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
891
  {
fb3296eb4   Benny Halevy   pnfs: Use byte-ra...
892
893
894
895
896
897
898
899
900
901
902
  	struct pnfs_layout_range range1;
  
  	if ((range->iomode == IOMODE_RW &&
  	     ls_range->iomode != IOMODE_RW) ||
  	    !lo_seg_intersecting(ls_range, range))
  		return 0;
  
  	/* range1 covers only the first byte in the range */
  	range1 = *range;
  	range1.length = 1;
  	return lo_seg_contained(ls_range, &range1);
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
903
904
905
906
907
  }
  
  /*
   * lookup range in layout
   */
e5e940170   Benny Halevy   NFS: create and d...
908
  static struct pnfs_layout_segment *
fb3296eb4   Benny Halevy   pnfs: Use byte-ra...
909
910
  pnfs_find_lseg(struct pnfs_layout_hdr *lo,
  		struct pnfs_layout_range *range)
e5e940170   Benny Halevy   NFS: create and d...
911
  {
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
912
913
914
915
  	struct pnfs_layout_segment *lseg, *ret = NULL;
  
  	dprintk("%s:Begin
  ", __func__);
b7edfaa19   Fred Isaman   pnfs: add prefix ...
916
917
  	assert_spin_locked(&lo->plh_inode->i_lock);
  	list_for_each_entry(lseg, &lo->plh_segs, pls_list) {
4541d16c0   Fred Isaman   pnfs: change how ...
918
  		if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags) &&
fb3296eb4   Benny Halevy   pnfs: Use byte-ra...
919
  		    is_matching_lseg(&lseg->pls_range, range)) {
d684d2ae1   Fred Isaman   NFSv4.1: lseg ref...
920
  			ret = get_lseg(lseg);
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
921
922
  			break;
  		}
d771e3a43   Benny Halevy   NFSv4.1: fix brea...
923
  		if (lseg->pls_range.offset > range->offset)
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
924
925
926
927
928
  			break;
  	}
  
  	dprintk("%s:Return lseg %p ref %d
  ",
4541d16c0   Fred Isaman   pnfs: change how ...
929
  		__func__, ret, ret ? atomic_read(&ret->pls_refcount) : 0);
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
930
  	return ret;
e5e940170   Benny Halevy   NFS: create and d...
931
932
933
934
935
936
  }
  
  /*
   * Layout segment is retreived from the server if not cached.
   * The appropriate layout segment is referenced and returned to the caller.
   */
7c24d9489   Andy Adamson   NFSv4.1: File lay...
937
  struct pnfs_layout_segment *
e5e940170   Benny Halevy   NFS: create and d...
938
939
  pnfs_update_layout(struct inode *ino,
  		   struct nfs_open_context *ctx,
fb3296eb4   Benny Halevy   pnfs: Use byte-ra...
940
941
  		   loff_t pos,
  		   u64 count,
a75b9df9d   Trond Myklebust   NFSv4.1: Ensure t...
942
943
  		   enum pnfs_iomode iomode,
  		   gfp_t gfp_flags)
e5e940170   Benny Halevy   NFS: create and d...
944
  {
fb3296eb4   Benny Halevy   pnfs: Use byte-ra...
945
946
947
948
949
  	struct pnfs_layout_range arg = {
  		.iomode = iomode,
  		.offset = pos,
  		.length = count,
  	};
707ed5fdb   Benny Halevy   pnfs: align layou...
950
  	unsigned pg_offset;
e5e940170   Benny Halevy   NFS: create and d...
951
  	struct nfs_inode *nfsi = NFS_I(ino);
6382a4413   Weston Andros Adamson   NFS: move pnfs la...
952
953
  	struct nfs_server *server = NFS_SERVER(ino);
  	struct nfs_client *clp = server->nfs_client;
e5e940170   Benny Halevy   NFS: create and d...
954
955
  	struct pnfs_layout_hdr *lo;
  	struct pnfs_layout_segment *lseg = NULL;
f49f9baac   Fred Isaman   pnfs: fix pnfs lo...
956
  	bool first = false;
e5e940170   Benny Halevy   NFS: create and d...
957
958
959
960
  
  	if (!pnfs_enabled_sb(NFS_SERVER(ino)))
  		return NULL;
  	spin_lock(&ino->i_lock);
9fa407587   Peng Tao   pnfs: save layout...
961
  	lo = pnfs_find_alloc_layout(ino, ctx, gfp_flags);
e5e940170   Benny Halevy   NFS: create and d...
962
963
964
965
966
  	if (lo == NULL) {
  		dprintk("%s ERROR: can't get pnfs_layout_hdr
  ", __func__);
  		goto out_unlock;
  	}
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
967
968
969
970
971
  	/* Do we even need to bother with this? */
  	if (test_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state) ||
  	    test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
  		dprintk("%s matches recall, use MDS
  ", __func__);
e5e940170   Benny Halevy   NFS: create and d...
972
973
974
975
  		goto out_unlock;
  	}
  
  	/* if LAYOUTGET already failed once we don't try again */
566052c53   Fred Isaman   pnfs: add prefix ...
976
  	if (test_bit(lo_fail_bit(iomode), &nfsi->layout->plh_flags))
e5e940170   Benny Halevy   NFS: create and d...
977
  		goto out_unlock;
568e8c494   Andy Adamson   NFSv4.1: turn off...
978
  	/* Check to see if the layout for the given range already exists */
fb3296eb4   Benny Halevy   pnfs: Use byte-ra...
979
  	lseg = pnfs_find_lseg(lo, &arg);
568e8c494   Andy Adamson   NFSv4.1: turn off...
980
981
  	if (lseg)
  		goto out_unlock;
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
982
  	if (pnfs_layoutgets_blocked(lo, NULL, 0))
cf7d63f1f   Fred Isaman   pnfs: serialize L...
983
984
  		goto out_unlock;
  	atomic_inc(&lo->plh_outstanding);
cc6e5340b   Fred Isaman   pnfs: change lo r...
985
  	get_layout_hdr(lo);
f49f9baac   Fred Isaman   pnfs: fix pnfs lo...
986
987
988
989
  	if (list_empty(&lo->plh_segs))
  		first = true;
  	spin_unlock(&ino->i_lock);
  	if (first) {
2130ff663   Fred Isaman   pnfs: add layout ...
990
991
992
993
994
  		/* The lo must be on the clp list if there is any
  		 * chance of a CB_LAYOUTRECALL(FILE) coming in.
  		 */
  		spin_lock(&clp->cl_lock);
  		BUG_ON(!list_empty(&lo->plh_layouts));
6382a4413   Weston Andros Adamson   NFS: move pnfs la...
995
  		list_add_tail(&lo->plh_layouts, &server->layouts);
2130ff663   Fred Isaman   pnfs: add layout ...
996
997
  		spin_unlock(&clp->cl_lock);
  	}
e5e940170   Benny Halevy   NFS: create and d...
998

707ed5fdb   Benny Halevy   pnfs: align layou...
999
1000
1001
1002
1003
  	pg_offset = arg.offset & ~PAGE_CACHE_MASK;
  	if (pg_offset) {
  		arg.offset -= pg_offset;
  		arg.length += pg_offset;
  	}
7c24d9489   Andy Adamson   NFSv4.1: File lay...
1004
1005
  	if (arg.length != NFS4_MAX_UINT64)
  		arg.length = PAGE_CACHE_ALIGN(arg.length);
707ed5fdb   Benny Halevy   pnfs: align layou...
1006

fb3296eb4   Benny Halevy   pnfs: Use byte-ra...
1007
  	lseg = send_layoutget(lo, ctx, &arg, gfp_flags);
f49f9baac   Fred Isaman   pnfs: fix pnfs lo...
1008
1009
1010
1011
  	if (!lseg && first) {
  		spin_lock(&clp->cl_lock);
  		list_del_init(&lo->plh_layouts);
  		spin_unlock(&clp->cl_lock);
2130ff663   Fred Isaman   pnfs: add layout ...
1012
  	}
cf7d63f1f   Fred Isaman   pnfs: serialize L...
1013
  	atomic_dec(&lo->plh_outstanding);
cc6e5340b   Fred Isaman   pnfs: change lo r...
1014
  	put_layout_hdr(lo);
e5e940170   Benny Halevy   NFS: create and d...
1015
1016
1017
  out:
  	dprintk("%s end, state 0x%lx lseg %p
  ", __func__,
bf9c1387c   Andy Adamson   NFSv4.1: put_layo...
1018
  		nfsi->layout ? nfsi->layout->plh_flags : -1, lseg);
e5e940170   Benny Halevy   NFS: create and d...
1019
1020
1021
1022
1023
  	return lseg;
  out_unlock:
  	spin_unlock(&ino->i_lock);
  	goto out;
  }
7c24d9489   Andy Adamson   NFSv4.1: File lay...
1024
  EXPORT_SYMBOL_GPL(pnfs_update_layout);
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
1025
1026
1027
1028
1029
1030
1031
  
  int
  pnfs_layout_process(struct nfs4_layoutget *lgp)
  {
  	struct pnfs_layout_hdr *lo = NFS_I(lgp->args.inode)->layout;
  	struct nfs4_layoutget_res *res = &lgp->res;
  	struct pnfs_layout_segment *lseg;
b7edfaa19   Fred Isaman   pnfs: add prefix ...
1032
  	struct inode *ino = lo->plh_inode;
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
1033
  	struct nfs_client *clp = NFS_SERVER(ino)->nfs_client;
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
1034
1035
1036
  	int status = 0;
  
  	/* Inject layout blob into I/O device driver */
a75b9df9d   Trond Myklebust   NFSv4.1: Ensure t...
1037
  	lseg = NFS_SERVER(ino)->pnfs_curr_ld->alloc_lseg(lo, res, lgp->gfp_flags);
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
  	if (!lseg || IS_ERR(lseg)) {
  		if (!lseg)
  			status = -ENOMEM;
  		else
  			status = PTR_ERR(lseg);
  		dprintk("%s: Could not allocate layout: error %d
  ",
  		       __func__, status);
  		goto out;
  	}
  
  	spin_lock(&ino->i_lock);
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
  	if (test_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state) ||
  	    test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
  		dprintk("%s forget reply due to recall
  ", __func__);
  		goto out_forget_reply;
  	}
  
  	if (pnfs_layoutgets_blocked(lo, &res->stateid, 1)) {
  		dprintk("%s forget reply due to state
  ", __func__);
  		goto out_forget_reply;
  	}
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
1062
  	init_lseg(lo, lseg);
566052c53   Fred Isaman   pnfs: add prefix ...
1063
  	lseg->pls_range = res->range;
d684d2ae1   Fred Isaman   NFSv4.1: lseg ref...
1064
  	*lgp->lsegpp = get_lseg(lseg);
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
1065
  	pnfs_insert_layout(lo, lseg);
f7e8917a6   Fred Isaman   pnfs: layout roc ...
1066
1067
1068
1069
  	if (res->return_on_close) {
  		set_bit(NFS_LSEG_ROC, &lseg->pls_flags);
  		set_bit(NFS_LAYOUT_ROC, &lo->plh_flags);
  	}
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
1070
  	/* Done processing layoutget. Set the layout stateid */
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
1071
  	pnfs_set_layout_stateid(lo, &res->stateid, false);
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
1072
1073
1074
  	spin_unlock(&ino->i_lock);
  out:
  	return status;
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
1075
1076
1077
1078
1079
1080
  
  out_forget_reply:
  	spin_unlock(&ino->i_lock);
  	lseg->pls_layout = lo;
  	NFS_SERVER(ino)->pnfs_curr_ld->free_lseg(lseg);
  	goto out;
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
1081
  }
d8007d4dd   Trond Myklebust   NFSv4.1: Add an i...
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
  void
  pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
  {
  	BUG_ON(pgio->pg_lseg != NULL);
  
  	pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
  					   req->wb_context,
  					   req_offset(req),
  					   req->wb_bytes,
  					   IOMODE_READ,
  					   GFP_KERNEL);
e885de1a5   Trond Myklebust   NFSv4.1: Fall bac...
1093
1094
  	/* If no lseg, fall back to read through mds */
  	if (pgio->pg_lseg == NULL)
1f9453578   Trond Myklebust   NFS: Clean up - s...
1095
  		nfs_pageio_reset_read_mds(pgio);
e885de1a5   Trond Myklebust   NFSv4.1: Fall bac...
1096

d8007d4dd   Trond Myklebust   NFSv4.1: Add an i...
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
  }
  EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_read);
  
  void
  pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
  {
  	BUG_ON(pgio->pg_lseg != NULL);
  
  	pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
  					   req->wb_context,
  					   req_offset(req),
  					   req->wb_bytes,
  					   IOMODE_RW,
  					   GFP_NOFS);
e885de1a5   Trond Myklebust   NFSv4.1: Fall bac...
1111
1112
  	/* If no lseg, fall back to write through mds */
  	if (pgio->pg_lseg == NULL)
1f9453578   Trond Myklebust   NFS: Clean up - s...
1113
  		nfs_pageio_reset_write_mds(pgio);
d8007d4dd   Trond Myklebust   NFSv4.1: Add an i...
1114
1115
  }
  EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_write);
18ad0a9f2   Benny Halevy   NFSv4.1: change p...
1116
  bool
1751c3638   Trond Myklebust   NFS: Cleanup of t...
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
  pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode)
  {
  	struct nfs_server *server = NFS_SERVER(inode);
  	struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld;
  
  	if (ld == NULL)
  		return false;
  	nfs_pageio_init(pgio, inode, ld->pg_read_ops, server->rsize, 0);
  	return true;
  }
  
  bool
  pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode, int ioflags)
  {
  	struct nfs_server *server = NFS_SERVER(inode);
  	struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld;
  
  	if (ld == NULL)
  		return false;
  	nfs_pageio_init(pgio, inode, ld->pg_write_ops, server->wsize, ioflags);
  	return true;
  }
  
  bool
dfed206b8   Benny Halevy   NFSv4.1: unify pn...
1141
1142
  pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
  		     struct nfs_page *req)
94ad1c80e   Fred Isaman   NFSv4.1: coelesce...
1143
  {
d8007d4dd   Trond Myklebust   NFSv4.1: Add an i...
1144
1145
  	if (pgio->pg_lseg == NULL)
  		return nfs_generic_pg_test(pgio, prev, req);
94ad1c80e   Fred Isaman   NFSv4.1: coelesce...
1146

19982ba85   Trond Myklebust   NFSv4.1: Fix an o...
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
  	/*
  	 * Test if a nfs_page is fully contained in the pnfs_layout_range.
  	 * Note that this test makes several assumptions:
  	 * - that the previous nfs_page in the struct nfs_pageio_descriptor
  	 *   is known to lie within the range.
  	 *   - that the nfs_page being tested is known to be contiguous with the
  	 *   previous nfs_page.
  	 *   - Layout ranges are page aligned, so we only have to test the
  	 *   start offset of the request.
  	 *
  	 * Please also note that 'end_offset' is actually the offset of the
  	 * first byte that lies outside the pnfs_layout_range. FIXME?
  	 *
  	 */
  	return req_offset(req) < end_offset(pgio->pg_lseg->pls_range.offset,
  					 pgio->pg_lseg->pls_range.length);
94ad1c80e   Fred Isaman   NFSv4.1: coelesce...
1163
  }
89a58e32d   Benny Halevy   NFSv4.1: use pnfs...
1164
  EXPORT_SYMBOL_GPL(pnfs_generic_pg_test);
94ad1c80e   Fred Isaman   NFSv4.1: coelesce...
1165

e2fecb215   Trond Myklebust   NFS: Remove pNFS ...
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
  static int pnfs_write_done_resend_to_mds(struct inode *inode, struct list_head *head)
  {
  	struct nfs_pageio_descriptor pgio;
  	LIST_HEAD(failed);
  
  	/* Resend all requests through the MDS */
  	nfs_pageio_init_write_mds(&pgio, inode, FLUSH_STABLE);
  	while (!list_empty(head)) {
  		struct nfs_page *req = nfs_list_entry(head->next);
  
  		nfs_list_remove_request(req);
  		if (!nfs_pageio_add_request(&pgio, req))
  			nfs_list_add_request(req, &failed);
  	}
  	nfs_pageio_complete(&pgio);
  
  	if (!list_empty(&failed)) {
  		/* For some reason our attempt to resend pages. Mark the
  		 * overall send request as having failed, and let
  		 * nfs_writeback_release_full deal with the error.
  		 */
  		list_move(&failed, head);
  		return -EIO;
  	}
  	return 0;
  }
d20581aa4   Benny Halevy   pnfs: support for...
1192
1193
1194
  /*
   * Called by non rpc-based layout drivers
   */
8ce160c5e   Peng Tao   pnfs: recoalesce ...
1195
  void pnfs_ld_write_done(struct nfs_write_data *data)
44b83799a   Fred Isaman   NFSv4.1: trigger ...
1196
  {
8ce160c5e   Peng Tao   pnfs: recoalesce ...
1197
  	if (likely(!data->pnfs_error)) {
d20581aa4   Benny Halevy   pnfs: support for...
1198
1199
  		pnfs_set_layoutcommit(data);
  		data->mds_ops->rpc_call_done(&data->task, data);
8ce160c5e   Peng Tao   pnfs: recoalesce ...
1200
  	} else {
8ce160c5e   Peng Tao   pnfs: recoalesce ...
1201
1202
  		dprintk("pnfs write error = %d
  ", data->pnfs_error);
fe0fe8358   Boaz Harrosh   pnfs-obj: Must re...
1203
1204
1205
1206
1207
1208
1209
1210
1211
  		if (NFS_SERVER(data->inode)->pnfs_curr_ld->flags &
  						PNFS_LAYOUTRET_ON_ERROR) {
  			/* Don't lo_commit on error, Server will needs to
  			 * preform a file recovery.
  			 */
  			clear_bit(NFS_INO_LAYOUTCOMMIT,
  				  &NFS_I(data->inode)->flags);
  			pnfs_return_layout(data->inode);
  		}
e2fecb215   Trond Myklebust   NFS: Remove pNFS ...
1212
  		data->task.tk_status = pnfs_write_done_resend_to_mds(data->inode, &data->pages);
d20581aa4   Benny Halevy   pnfs: support for...
1213
  	}
8ce160c5e   Peng Tao   pnfs: recoalesce ...
1214
  	data->mds_ops->rpc_release(data);
44b83799a   Fred Isaman   NFSv4.1: trigger ...
1215
  }
d20581aa4   Benny Halevy   pnfs: support for...
1216
  EXPORT_SYMBOL_GPL(pnfs_ld_write_done);
44b83799a   Fred Isaman   NFSv4.1: trigger ...
1217

dce81290e   Trond Myklebust   NFS: Move the pnf...
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
  static void
  pnfs_write_through_mds(struct nfs_pageio_descriptor *desc,
  		struct nfs_write_data *data)
  {
  	list_splice_tail_init(&data->pages, &desc->pg_list);
  	if (data->req && list_empty(&data->req->wb_list))
  		nfs_list_add_request(data->req, &desc->pg_list);
  	nfs_pageio_reset_write_mds(desc);
  	desc->pg_recoalesce = 1;
  	nfs_writedata_release(data);
  }
  
  static enum pnfs_try_status
0382b7440   Andy Adamson   NFSv4.1: implemen...
1231
  pnfs_try_to_write_data(struct nfs_write_data *wdata,
dce81290e   Trond Myklebust   NFS: Move the pnf...
1232
1233
1234
  			const struct rpc_call_ops *call_ops,
  			struct pnfs_layout_segment *lseg,
  			int how)
0382b7440   Andy Adamson   NFSv4.1: implemen...
1235
1236
1237
1238
1239
1240
  {
  	struct inode *inode = wdata->inode;
  	enum pnfs_try_status trypnfs;
  	struct nfs_server *nfss = NFS_SERVER(inode);
  
  	wdata->mds_ops = call_ops;
dce81290e   Trond Myklebust   NFS: Move the pnf...
1241
  	wdata->lseg = get_lseg(lseg);
0382b7440   Andy Adamson   NFSv4.1: implemen...
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
  
  	dprintk("%s: Writing ino:%lu %u@%llu (how %d)
  ", __func__,
  		inode->i_ino, wdata->args.count, wdata->args.offset, how);
  
  	trypnfs = nfss->pnfs_curr_ld->write_pagelist(wdata, how);
  	if (trypnfs == PNFS_NOT_ATTEMPTED) {
  		put_lseg(wdata->lseg);
  		wdata->lseg = NULL;
  	} else
  		nfs_inc_stats(inode, NFSIOS_PNFS_WRITE);
  
  	dprintk("%s End (trypnfs:%d)
  ", __func__, trypnfs);
  	return trypnfs;
  }
dce81290e   Trond Myklebust   NFS: Move the pnf...
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
  static void
  pnfs_do_multiple_writes(struct nfs_pageio_descriptor *desc, struct list_head *head, int how)
  {
  	struct nfs_write_data *data;
  	const struct rpc_call_ops *call_ops = desc->pg_rpc_callops;
  	struct pnfs_layout_segment *lseg = desc->pg_lseg;
  
  	desc->pg_lseg = NULL;
  	while (!list_empty(head)) {
  		enum pnfs_try_status trypnfs;
  
  		data = list_entry(head->next, struct nfs_write_data, list);
  		list_del_init(&data->list);
  
  		trypnfs = pnfs_try_to_write_data(data, call_ops, lseg, how);
  		if (trypnfs == PNFS_NOT_ATTEMPTED)
  			pnfs_write_through_mds(desc, data);
  	}
  	put_lseg(lseg);
  }
  
  int
  pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc)
  {
  	LIST_HEAD(head);
  	int ret;
  
  	ret = nfs_generic_flush(desc, &head);
  	if (ret != 0) {
  		put_lseg(desc->pg_lseg);
  		desc->pg_lseg = NULL;
  		return ret;
  	}
  	pnfs_do_multiple_writes(desc, &head, desc->pg_ioflags);
  	return 0;
  }
  EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages);
62e4a7698   Trond Myklebust   NFS: Revert pnfs ...
1295
1296
1297
1298
1299
1300
1301
1302
  static void pnfs_ld_handle_read_error(struct nfs_read_data *data)
  {
  	struct nfs_pageio_descriptor pgio;
  
  	put_lseg(data->lseg);
  	data->lseg = NULL;
  	dprintk("pnfs write error = %d
  ", data->pnfs_error);
fe0fe8358   Boaz Harrosh   pnfs-obj: Must re...
1303
1304
1305
  	if (NFS_SERVER(data->inode)->pnfs_curr_ld->flags &
  						PNFS_LAYOUTRET_ON_ERROR)
  		pnfs_return_layout(data->inode);
62e4a7698   Trond Myklebust   NFS: Revert pnfs ...
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
  
  	nfs_pageio_init_read_mds(&pgio, data->inode);
  
  	while (!list_empty(&data->pages)) {
  		struct nfs_page *req = nfs_list_entry(data->pages.next);
  
  		nfs_list_remove_request(req);
  		nfs_pageio_add_request(&pgio, req);
  	}
  	nfs_pageio_complete(&pgio);
  }
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
1317
  /*
d20581aa4   Benny Halevy   pnfs: support for...
1318
1319
   * Called by non rpc-based layout drivers
   */
9b7eecdcf   Peng Tao   pnfs: recoalesce ...
1320
  void pnfs_ld_read_done(struct nfs_read_data *data)
d20581aa4   Benny Halevy   pnfs: support for...
1321
  {
9b7eecdcf   Peng Tao   pnfs: recoalesce ...
1322
  	if (likely(!data->pnfs_error)) {
d20581aa4   Benny Halevy   pnfs: support for...
1323
1324
  		__nfs4_read_done_cb(data);
  		data->mds_ops->rpc_call_done(&data->task, data);
62e4a7698   Trond Myklebust   NFS: Revert pnfs ...
1325
1326
  	} else
  		pnfs_ld_handle_read_error(data);
9b7eecdcf   Peng Tao   pnfs: recoalesce ...
1327
  	data->mds_ops->rpc_release(data);
d20581aa4   Benny Halevy   pnfs: support for...
1328
1329
  }
  EXPORT_SYMBOL_GPL(pnfs_ld_read_done);
493292ddc   Trond Myklebust   NFS: Move the pnf...
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
  static void
  pnfs_read_through_mds(struct nfs_pageio_descriptor *desc,
  		struct nfs_read_data *data)
  {
  	list_splice_tail_init(&data->pages, &desc->pg_list);
  	if (data->req && list_empty(&data->req->wb_list))
  		nfs_list_add_request(data->req, &desc->pg_list);
  	nfs_pageio_reset_read_mds(desc);
  	desc->pg_recoalesce = 1;
  	nfs_readdata_release(data);
  }
d20581aa4   Benny Halevy   pnfs: support for...
1341
  /*
64419a9b2   Andy Adamson   NFSv4.1: generic ...
1342
1343
   * Call the appropriate parallel I/O subsystem read function.
   */
493292ddc   Trond Myklebust   NFS: Move the pnf...
1344
  static enum pnfs_try_status
64419a9b2   Andy Adamson   NFSv4.1: generic ...
1345
  pnfs_try_to_read_data(struct nfs_read_data *rdata,
493292ddc   Trond Myklebust   NFS: Move the pnf...
1346
1347
  		       const struct rpc_call_ops *call_ops,
  		       struct pnfs_layout_segment *lseg)
64419a9b2   Andy Adamson   NFSv4.1: generic ...
1348
1349
1350
1351
1352
1353
  {
  	struct inode *inode = rdata->inode;
  	struct nfs_server *nfss = NFS_SERVER(inode);
  	enum pnfs_try_status trypnfs;
  
  	rdata->mds_ops = call_ops;
493292ddc   Trond Myklebust   NFS: Move the pnf...
1354
  	rdata->lseg = get_lseg(lseg);
64419a9b2   Andy Adamson   NFSv4.1: generic ...
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
  
  	dprintk("%s: Reading ino:%lu %u@%llu
  ",
  		__func__, inode->i_ino, rdata->args.count, rdata->args.offset);
  
  	trypnfs = nfss->pnfs_curr_ld->read_pagelist(rdata);
  	if (trypnfs == PNFS_NOT_ATTEMPTED) {
  		put_lseg(rdata->lseg);
  		rdata->lseg = NULL;
  	} else {
  		nfs_inc_stats(inode, NFSIOS_PNFS_READ);
  	}
  	dprintk("%s End (trypnfs:%d)
  ", __func__, trypnfs);
  	return trypnfs;
  }
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1371

493292ddc   Trond Myklebust   NFS: Move the pnf...
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
  static void
  pnfs_do_multiple_reads(struct nfs_pageio_descriptor *desc, struct list_head *head)
  {
  	struct nfs_read_data *data;
  	const struct rpc_call_ops *call_ops = desc->pg_rpc_callops;
  	struct pnfs_layout_segment *lseg = desc->pg_lseg;
  
  	desc->pg_lseg = NULL;
  	while (!list_empty(head)) {
  		enum pnfs_try_status trypnfs;
  
  		data = list_entry(head->next, struct nfs_read_data, list);
  		list_del_init(&data->list);
  
  		trypnfs = pnfs_try_to_read_data(data, call_ops, lseg);
  		if (trypnfs == PNFS_NOT_ATTEMPTED)
  			pnfs_read_through_mds(desc, data);
  	}
  	put_lseg(lseg);
  }
  
  int
  pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
  {
  	LIST_HEAD(head);
  	int ret;
  
  	ret = nfs_generic_pagein(desc, &head);
  	if (ret != 0) {
  		put_lseg(desc->pg_lseg);
  		desc->pg_lseg = NULL;
  		return ret;
  	}
  	pnfs_do_multiple_reads(desc, &head);
  	return 0;
  }
  EXPORT_SYMBOL_GPL(pnfs_generic_pg_readpages);
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1409
  /*
a9bae5666   Peng Tao   pnfs: let layoutc...
1410
   * There can be multiple RW segments.
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1411
   */
a9bae5666   Peng Tao   pnfs: let layoutc...
1412
  static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp)
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1413
  {
a9bae5666   Peng Tao   pnfs: let layoutc...
1414
  	struct pnfs_layout_segment *lseg;
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1415

a9bae5666   Peng Tao   pnfs: let layoutc...
1416
1417
1418
1419
1420
  	list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) {
  		if (lseg->pls_range.iomode == IOMODE_RW &&
  		    test_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags))
  			list_add(&lseg->pls_lc_list, listp);
  	}
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1421
  }
1b0ae0687   Peng Tao   pnfs: make _set_l...
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
  void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg)
  {
  	if (lseg->pls_range.iomode == IOMODE_RW) {
  		dprintk("%s Setting layout IOMODE_RW fail bit
  ", __func__);
  		set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
  	} else {
  		dprintk("%s Setting layout IOMODE_READ fail bit
  ", __func__);
  		set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
  	}
  }
  EXPORT_SYMBOL_GPL(pnfs_set_lo_fail);
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1435
1436
1437
1438
  void
  pnfs_set_layoutcommit(struct nfs_write_data *wdata)
  {
  	struct nfs_inode *nfsi = NFS_I(wdata->inode);
4b8ee2b82   Vitaliy Gusev   nfs41: Correct of...
1439
  	loff_t end_pos = wdata->mds_offset + wdata->res.count;
79a48a1f5   Weston Andros Adamson   Don't mark_inode_...
1440
  	bool mark_as_dirty = false;
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1441
1442
1443
  
  	spin_lock(&nfsi->vfs_inode.i_lock);
  	if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) {
79a48a1f5   Weston Andros Adamson   Don't mark_inode_...
1444
  		mark_as_dirty = true;
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1445
1446
1447
  		dprintk("%s: Set layoutcommit for inode %lu ",
  			__func__, wdata->inode->i_ino);
  	}
a9bae5666   Peng Tao   pnfs: let layoutc...
1448
1449
1450
1451
  	if (!test_and_set_bit(NFS_LSEG_LAYOUTCOMMIT, &wdata->lseg->pls_flags)) {
  		/* references matched in nfs4_layoutcommit_release */
  		get_lseg(wdata->lseg);
  	}
acff58805   Peng Tao   pnfs: save layout...
1452
1453
  	if (end_pos > nfsi->layout->plh_lwb)
  		nfsi->layout->plh_lwb = end_pos;
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1454
  	spin_unlock(&nfsi->vfs_inode.i_lock);
acff58805   Peng Tao   pnfs: save layout...
1455
1456
1457
  	dprintk("%s: lseg %p end_pos %llu
  ",
  		__func__, wdata->lseg, nfsi->layout->plh_lwb);
79a48a1f5   Weston Andros Adamson   Don't mark_inode_...
1458
1459
1460
1461
1462
  
  	/* if pnfs_layoutcommit_inode() runs between inode locks, the next one
  	 * will be a noop because NFS_INO_LAYOUTCOMMIT will not be set */
  	if (mark_as_dirty)
  		mark_inode_dirty_sync(wdata->inode);
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1463
1464
  }
  EXPORT_SYMBOL_GPL(pnfs_set_layoutcommit);
db29c0890   Andy Adamson   pnfs: cleanup_lay...
1465
1466
1467
1468
1469
1470
1471
  void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data)
  {
  	struct nfs_server *nfss = NFS_SERVER(data->args.inode);
  
  	if (nfss->pnfs_curr_ld->cleanup_layoutcommit)
  		nfss->pnfs_curr_ld->cleanup_layoutcommit(data);
  }
de4b15c7e   Andy Adamson   NFSv4.1 pnfs_layo...
1472
1473
1474
1475
1476
1477
1478
1479
  /*
   * For the LAYOUT4_NFSV4_1_FILES layout type, NFS_DATA_SYNC WRITEs and
   * NFS_UNSTABLE WRITEs with a COMMIT to data servers must store enough
   * data to disk to allow the server to recover the data if it crashes.
   * LAYOUTCOMMIT is only needed when the NFL4_UFLG_COMMIT_THRU_MDS flag
   * is off, and a COMMIT is sent to a data server, or
   * if WRITEs to a data server return NFS_DATA_SYNC.
   */
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1480
  int
ef3115378   Andy Adamson   NFSv4.1 convert l...
1481
  pnfs_layoutcommit_inode(struct inode *inode, bool sync)
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1482
1483
1484
  {
  	struct nfs4_layoutcommit_data *data;
  	struct nfs_inode *nfsi = NFS_I(inode);
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1485
1486
1487
1488
1489
  	loff_t end_pos;
  	int status = 0;
  
  	dprintk("--> %s inode %lu
  ", __func__, inode->i_ino);
de4b15c7e   Andy Adamson   NFSv4.1 pnfs_layo...
1490
1491
  	if (!test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags))
  		return 0;
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1492
1493
  	/* Note kzalloc ensures data->res.seq_res.sr_slot == NULL */
  	data = kzalloc(sizeof(*data), GFP_NOFS);
de4b15c7e   Andy Adamson   NFSv4.1 pnfs_layo...
1494
  	if (!data) {
de4b15c7e   Andy Adamson   NFSv4.1 pnfs_layo...
1495
1496
1497
  		status = -ENOMEM;
  		goto out;
  	}
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1498

92407e75c   Peng Tao   nfs4: serialize l...
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
  	if (!test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags))
  		goto out_free;
  
  	if (test_and_set_bit(NFS_INO_LAYOUTCOMMITTING, &nfsi->flags)) {
  		if (!sync) {
  			status = -EAGAIN;
  			goto out_free;
  		}
  		status = wait_on_bit_lock(&nfsi->flags, NFS_INO_LAYOUTCOMMITTING,
  					nfs_wait_bit_killable, TASK_KILLABLE);
  		if (status)
  			goto out_free;
  	}
a9bae5666   Peng Tao   pnfs: let layoutc...
1512
  	INIT_LIST_HEAD(&data->lseg_list);
de4b15c7e   Andy Adamson   NFSv4.1 pnfs_layo...
1513
  	spin_lock(&inode->i_lock);
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1514
  	if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) {
92407e75c   Peng Tao   nfs4: serialize l...
1515
  		clear_bit(NFS_INO_LAYOUTCOMMITTING, &nfsi->flags);
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1516
  		spin_unlock(&inode->i_lock);
92407e75c   Peng Tao   nfs4: serialize l...
1517
1518
  		wake_up_bit(&nfsi->flags, NFS_INO_LAYOUTCOMMITTING);
  		goto out_free;
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1519
  	}
a9bae5666   Peng Tao   pnfs: let layoutc...
1520
1521
  
  	pnfs_list_write_lseg(inode, &data->lseg_list);
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1522

acff58805   Peng Tao   pnfs: save layout...
1523
  	end_pos = nfsi->layout->plh_lwb;
acff58805   Peng Tao   pnfs: save layout...
1524
  	nfsi->layout->plh_lwb = 0;
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1525

de4b15c7e   Andy Adamson   NFSv4.1 pnfs_layo...
1526
1527
  	memcpy(&data->args.stateid.data, nfsi->layout->plh_stateid.data,
  		sizeof(nfsi->layout->plh_stateid.data));
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1528
1529
1530
  	spin_unlock(&inode->i_lock);
  
  	data->args.inode = inode;
9fa407587   Peng Tao   pnfs: save layout...
1531
  	data->cred = get_rpccred(nfsi->layout->plh_lc_cred);
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1532
1533
1534
1535
1536
1537
1538
1539
  	nfs_fattr_init(&data->fattr);
  	data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
  	data->res.fattr = &data->fattr;
  	data->args.lastbytewritten = end_pos - 1;
  	data->res.server = NFS_SERVER(inode);
  
  	status = nfs4_proc_layoutcommit(data, sync);
  out:
92407e75c   Peng Tao   nfs4: serialize l...
1540
1541
  	if (status)
  		mark_inode_dirty_sync(inode);
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1542
1543
1544
  	dprintk("<-- %s status %d
  ", __func__, status);
  	return status;
92407e75c   Peng Tao   nfs4: serialize l...
1545
1546
1547
  out_free:
  	kfree(data);
  	goto out;
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
1548
  }