Blame view

fs/nfs/callback_proc.c 15.2 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
  /*
   * linux/fs/nfs/callback_proc.c
   *
   * Copyright (C) 2004 Trond Myklebust
   *
   * NFSv4 callback procedures
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
  #include <linux/nfs4.h>
  #include <linux/nfs_fs.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
10
  #include <linux/slab.h>
4ce79717c   Trond Myklebust   [PATCH] NFS: Head...
11
  #include "nfs4_fs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
  #include "callback.h"
  #include "delegation.h"
24c8dbbb5   David Howells   NFS: Generalise t...
14
  #include "internal.h"
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
15
  #include "pnfs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16

1d98fe671   Chuck Lever   NFS: Move dprintk...
17
  #ifdef NFS_DEBUG
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
  #define NFSDBG_FACILITY NFSDBG_CALLBACK
1d98fe671   Chuck Lever   NFS: Move dprintk...
19
  #endif
c36fca52f   Andy Adamson   NFS refactor nfs_...
20
21
22
23
  
  __be32 nfs4_callback_getattr(struct cb_getattrargs *args,
  			     struct cb_getattrres *res,
  			     struct cb_process_state *cps)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
  	struct nfs_delegation *delegation;
  	struct nfs_inode *nfsi;
  	struct inode *inode;
1d98fe671   Chuck Lever   NFS: Move dprintk...
28

c36fca52f   Andy Adamson   NFS refactor nfs_...
29
30
31
  	res->status = htonl(NFS4ERR_OP_NOT_IN_SESSION);
  	if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
  	res->bitmap[0] = res->bitmap[1] = 0;
  	res->status = htonl(NFS4ERR_BADHANDLE);
1d98fe671   Chuck Lever   NFS: Move dprintk...
34
35
36
  
  	dprintk("NFS: GETATTR callback request from %s
  ",
c36fca52f   Andy Adamson   NFS refactor nfs_...
37
  		rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
1d98fe671   Chuck Lever   NFS: Move dprintk...
38

c36fca52f   Andy Adamson   NFS refactor nfs_...
39
  	inode = nfs_delegation_find_inode(cps->clp, &args->fh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
  	if (inode == NULL)
c36fca52f   Andy Adamson   NFS refactor nfs_...
41
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
  	nfsi = NFS_I(inode);
761fe93cd   Trond Myklebust   NFS: Fix the lock...
43
44
  	rcu_read_lock();
  	delegation = rcu_dereference(nfsi->delegation);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
  	if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0)
  		goto out_iput;
  	res->size = i_size_read(inode);
beb2a5ec3   Trond Myklebust   NFSv4: Ensure cha...
48
49
50
  	res->change_attr = delegation->change_attr;
  	if (nfsi->npages != 0)
  		res->change_attr++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
53
54
55
56
57
58
  	res->ctime = inode->i_ctime;
  	res->mtime = inode->i_mtime;
  	res->bitmap[0] = (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE) &
  		args->bitmap[0];
  	res->bitmap[1] = (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY) &
  		args->bitmap[1];
  	res->status = 0;
  out_iput:
761fe93cd   Trond Myklebust   NFS: Fix the lock...
59
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
  	iput(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
  out:
3110ff804   Harvey Harrison   nfs: replace rema...
62
63
  	dprintk("%s: exit with status = %d
  ", __func__, ntohl(res->status));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
  	return res->status;
  }
c36fca52f   Andy Adamson   NFS refactor nfs_...
66
67
  __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
  			    struct cb_process_state *cps)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  	struct inode *inode;
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
70
  	__be32 res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
  	
c36fca52f   Andy Adamson   NFS refactor nfs_...
72
73
  	res = htonl(NFS4ERR_OP_NOT_IN_SESSION);
  	if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
  		goto out;
1d98fe671   Chuck Lever   NFS: Move dprintk...
75
76
77
  
  	dprintk("NFS: RECALL callback request from %s
  ",
c36fca52f   Andy Adamson   NFS refactor nfs_...
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  		rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
  
  	res = htonl(NFS4ERR_BADHANDLE);
  	inode = nfs_delegation_find_inode(cps->clp, &args->fh);
  	if (inode == NULL)
  		goto out;
  	/* Set up a helper thread to actually return the delegation */
  	switch (nfs_async_inode_return_delegation(inode, &args->stateid)) {
  	case 0:
  		res = 0;
  		break;
  	case -ENOENT:
  		if (res != 0)
  			res = htonl(NFS4ERR_BAD_STATEID);
  		break;
  	default:
  		res = htonl(NFS4ERR_RESOURCE);
  	}
  	iput(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  out:
3110ff804   Harvey Harrison   nfs: replace rema...
98
99
  	dprintk("%s: exit with status = %d
  ", __func__, ntohl(res));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
  	return res;
  }
d49433e1e   Benny Halevy   nfs41: cb_sequenc...
102

2597641de   Alexandros Batsakis   nfs41: v2 fix cb_...
103
104
105
106
107
108
109
  int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
  {
  	if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data,
  					 sizeof(delegation->stateid.data)) != 0)
  		return 0;
  	return 1;
  }
d49433e1e   Benny Halevy   nfs41: cb_sequenc...
110
  #if defined(CONFIG_NFS_V4_1)
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
111
112
113
  static u32 initiate_file_draining(struct nfs_client *clp,
  				  struct cb_layoutrecallargs *args)
  {
6382a4413   Weston Andros Adamson   NFS: move pnfs la...
114
  	struct nfs_server *server;
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
115
116
117
118
119
120
121
  	struct pnfs_layout_hdr *lo;
  	struct inode *ino;
  	bool found = false;
  	u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
  	LIST_HEAD(free_me_list);
  
  	spin_lock(&clp->cl_lock);
6382a4413   Weston Andros Adamson   NFS: move pnfs la...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
  	rcu_read_lock();
  	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
  		list_for_each_entry(lo, &server->layouts, plh_layouts) {
  			if (nfs_compare_fh(&args->cbl_fh,
  					   &NFS_I(lo->plh_inode)->fh))
  				continue;
  			ino = igrab(lo->plh_inode);
  			if (!ino)
  				continue;
  			found = true;
  			/* Without this, layout can be freed as soon
  			 * as we release cl_lock.
  			 */
  			get_layout_hdr(lo);
  			break;
  		}
  		if (found)
  			break;
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
140
  	}
6382a4413   Weston Andros Adamson   NFS: move pnfs la...
141
  	rcu_read_unlock();
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
142
  	spin_unlock(&clp->cl_lock);
6382a4413   Weston Andros Adamson   NFS: move pnfs la...
143

43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
144
145
146
147
148
149
  	if (!found)
  		return NFS4ERR_NOMATCHING_LAYOUT;
  
  	spin_lock(&ino->i_lock);
  	if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
  	    mark_matching_lsegs_invalid(lo, &free_me_list,
778b5502f   Benny Halevy   pnfs: Use byte-ra...
150
  					&args->cbl_range))
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  		rv = NFS4ERR_DELAY;
  	else
  		rv = NFS4ERR_NOMATCHING_LAYOUT;
  	pnfs_set_layout_stateid(lo, &args->cbl_stateid, true);
  	spin_unlock(&ino->i_lock);
  	pnfs_free_lseg_list(&free_me_list);
  	put_layout_hdr(lo);
  	iput(ino);
  	return rv;
  }
  
  static u32 initiate_bulk_draining(struct nfs_client *clp,
  				  struct cb_layoutrecallargs *args)
  {
6382a4413   Weston Andros Adamson   NFS: move pnfs la...
165
  	struct nfs_server *server;
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
166
167
168
169
170
171
172
173
174
175
176
177
178
  	struct pnfs_layout_hdr *lo;
  	struct inode *ino;
  	u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
  	struct pnfs_layout_hdr *tmp;
  	LIST_HEAD(recall_list);
  	LIST_HEAD(free_me_list);
  	struct pnfs_layout_range range = {
  		.iomode = IOMODE_ANY,
  		.offset = 0,
  		.length = NFS4_MAX_UINT64,
  	};
  
  	spin_lock(&clp->cl_lock);
6382a4413   Weston Andros Adamson   NFS: move pnfs la...
179
180
  	rcu_read_lock();
  	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
181
  		if ((args->cbl_recall_type == RETURN_FSID) &&
6382a4413   Weston Andros Adamson   NFS: move pnfs la...
182
183
  		    memcmp(&server->fsid, &args->cbl_fsid,
  			   sizeof(struct nfs_fsid)))
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
184
  			continue;
6382a4413   Weston Andros Adamson   NFS: move pnfs la...
185
186
187
188
189
190
191
192
  
  		list_for_each_entry(lo, &server->layouts, plh_layouts) {
  			if (!igrab(lo->plh_inode))
  				continue;
  			get_layout_hdr(lo);
  			BUG_ON(!list_empty(&lo->plh_bulk_recall));
  			list_add(&lo->plh_bulk_recall, &recall_list);
  		}
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
193
  	}
6382a4413   Weston Andros Adamson   NFS: move pnfs la...
194
  	rcu_read_unlock();
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
195
  	spin_unlock(&clp->cl_lock);
6382a4413   Weston Andros Adamson   NFS: move pnfs la...
196

43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
197
198
199
200
201
  	list_for_each_entry_safe(lo, tmp,
  				 &recall_list, plh_bulk_recall) {
  		ino = lo->plh_inode;
  		spin_lock(&ino->i_lock);
  		set_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags);
778b5502f   Benny Halevy   pnfs: Use byte-ra...
202
  		if (mark_matching_lsegs_invalid(lo, &free_me_list, &range))
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
203
204
205
  			rv = NFS4ERR_DELAY;
  		list_del_init(&lo->plh_bulk_recall);
  		spin_unlock(&ino->i_lock);
f49f9baac   Fred Isaman   pnfs: fix pnfs lo...
206
  		pnfs_free_lseg_list(&free_me_list);
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
207
208
209
  		put_layout_hdr(lo);
  		iput(ino);
  	}
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
  	return rv;
  }
  
  static u32 do_callback_layoutrecall(struct nfs_client *clp,
  				    struct cb_layoutrecallargs *args)
  {
  	u32 res = NFS4ERR_DELAY;
  
  	dprintk("%s enter, type=%i
  ", __func__, args->cbl_recall_type);
  	if (test_and_set_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state))
  		goto out;
  	if (args->cbl_recall_type == RETURN_FILE)
  		res = initiate_file_draining(clp, args);
  	else
  		res = initiate_bulk_draining(clp, args);
  	clear_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state);
  out:
  	dprintk("%s returning %i
  ", __func__, res);
  	return res;
  
  }
f2a625616   Fred Isaman   pnfs: CB_LAYOUTRE...
233
234
235
  __be32 nfs4_callback_layoutrecall(struct cb_layoutrecallargs *args,
  				  void *dummy, struct cb_process_state *cps)
  {
43f1b3da8   Fred Isaman   pnfs: add CB_LAYO...
236
237
238
239
240
241
242
243
244
245
246
247
248
  	u32 res;
  
  	dprintk("%s: -->
  ", __func__);
  
  	if (cps->clp)
  		res = do_callback_layoutrecall(cps->clp, args);
  	else
  		res = NFS4ERR_OP_NOT_IN_SESSION;
  
  	dprintk("%s: exit with status = %d
  ", __func__, res);
  	return cpu_to_be32(res);
f2a625616   Fred Isaman   pnfs: CB_LAYOUTRE...
249
  }
368403708   Alexandros Batsakis   pnfs: update nfs4...
250
251
252
253
254
255
256
257
258
259
  static void pnfs_recall_all_layouts(struct nfs_client *clp)
  {
  	struct cb_layoutrecallargs args;
  
  	/* Pretend we got a CB_LAYOUTRECALL(ALL) */
  	memset(&args, 0, sizeof(args));
  	args.cbl_recall_type = RETURN_ALL;
  	/* FIXME we ignore errors, what should we do? */
  	do_callback_layoutrecall(clp, &args);
  }
1be5683b0   Marc Eshel   pnfs: CB_NOTIFY_D...
260
261
262
263
264
265
266
267
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
  __be32 nfs4_callback_devicenotify(struct cb_devicenotifyargs *args,
  				  void *dummy, struct cb_process_state *cps)
  {
  	int i;
  	__be32 res = 0;
  	struct nfs_client *clp = cps->clp;
  	struct nfs_server *server = NULL;
  
  	dprintk("%s: -->
  ", __func__);
  
  	if (!clp) {
  		res = cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION);
  		goto out;
  	}
  
  	for (i = 0; i < args->ndevs; i++) {
  		struct cb_devicenotifyitem *dev = &args->devs[i];
  
  		if (!server ||
  		    server->pnfs_curr_ld->id != dev->cbd_layout_type) {
  			rcu_read_lock();
  			list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
  				if (server->pnfs_curr_ld &&
  				    server->pnfs_curr_ld->id == dev->cbd_layout_type) {
  					rcu_read_unlock();
  					goto found;
  				}
  			rcu_read_unlock();
  			dprintk("%s: layout type %u not found
  ",
  				__func__, dev->cbd_layout_type);
  			continue;
  		}
  
  	found:
  		if (dev->cbd_notify_type == NOTIFY_DEVICEID4_CHANGE)
  			dprintk("%s: NOTIFY_DEVICEID4_CHANGE not supported, "
  				"deleting instead
  ", __func__);
35c8bb543   Benny Halevy   NFSv4.1: use layo...
300
  		nfs4_delete_deviceid(server->pnfs_curr_ld, clp, &dev->cbd_dev_id);
1be5683b0   Marc Eshel   pnfs: CB_NOTIFY_D...
301
302
303
304
305
306
307
308
309
  	}
  
  out:
  	kfree(args->devs);
  	dprintk("%s: exit with status = %u
  ",
  		__func__, be32_to_cpu(res));
  	return res;
  }
2597641de   Alexandros Batsakis   nfs41: v2 fix cb_...
310
311
312
313
  int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
  {
  	if (delegation == NULL)
  		return 0;
944992527   Alexandros Batsakis   NFS: change state...
314
  	if (stateid->stateid.seqid != 0)
2597641de   Alexandros Batsakis   nfs41: v2 fix cb_...
315
  		return 0;
944992527   Alexandros Batsakis   NFS: change state...
316
317
318
  	if (memcmp(&delegation->stateid.stateid.other,
  		   &stateid->stateid.other,
  		   NFS4_STATEID_OTHER_SIZE))
2597641de   Alexandros Batsakis   nfs41: v2 fix cb_...
319
320
321
322
  		return 0;
  
  	return 1;
  }
963891ac4   Ricardo Labiaga   nfs41: Backchanne...
323
  /*
68f3f9013   Ricardo Labiaga   nfs41: Backchanne...
324
325
326
327
   * Validate the sequenceID sent by the server.
   * Return success if the sequenceID is one more than what we last saw on
   * this slot, accounting for wraparound.  Increments the slot's sequence.
   *
4911096f1   Andy Adamson   nfs41: back chann...
328
329
   * We don't yet implement a duplicate request cache, instead we set the
   * back channel ca_maxresponsesize_cached to zero. This is OK for now
68f3f9013   Ricardo Labiaga   nfs41: Backchanne...
330
331
332
333
334
335
   * since we only currently implement idempotent callbacks anyway.
   *
   * We have a single slot backchannel at this time, so we don't bother
   * checking the used_slots bit array on the table.  The lower layer guarantees
   * a single outstanding callback request at a time.
   */
9733f0d92   Andy Adamson   nfs41: cleanup ca...
336
  static __be32
b2f28bd78   Andy Adamson   nfs41: prepare fo...
337
  validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args)
68f3f9013   Ricardo Labiaga   nfs41: Backchanne...
338
339
340
341
342
  {
  	struct nfs4_slot *slot;
  
  	dprintk("%s enter. slotid %d seqid %d
  ",
b2f28bd78   Andy Adamson   nfs41: prepare fo...
343
  		__func__, args->csa_slotid, args->csa_sequenceid);
68f3f9013   Ricardo Labiaga   nfs41: Backchanne...
344

b2f28bd78   Andy Adamson   nfs41: prepare fo...
345
  	if (args->csa_slotid > NFS41_BC_MAX_CALLBACKS)
68f3f9013   Ricardo Labiaga   nfs41: Backchanne...
346
  		return htonl(NFS4ERR_BADSLOT);
b2f28bd78   Andy Adamson   nfs41: prepare fo...
347
  	slot = tbl->slots + args->csa_slotid;
68f3f9013   Ricardo Labiaga   nfs41: Backchanne...
348
349
350
351
  	dprintk("%s slot table seqid: %d
  ", __func__, slot->seq_nr);
  
  	/* Normal */
b2f28bd78   Andy Adamson   nfs41: prepare fo...
352
  	if (likely(args->csa_sequenceid == slot->seq_nr + 1)) {
68f3f9013   Ricardo Labiaga   nfs41: Backchanne...
353
  		slot->seq_nr++;
55a673990   Trond Myklebust   NFSv4.1: Fix the ...
354
  		goto out_ok;
68f3f9013   Ricardo Labiaga   nfs41: Backchanne...
355
356
357
  	}
  
  	/* Replay */
b2f28bd78   Andy Adamson   nfs41: prepare fo...
358
  	if (args->csa_sequenceid == slot->seq_nr) {
4911096f1   Andy Adamson   nfs41: back chann...
359
360
  		dprintk("%s seqid %d is a replay
  ",
b2f28bd78   Andy Adamson   nfs41: prepare fo...
361
  			__func__, args->csa_sequenceid);
4911096f1   Andy Adamson   nfs41: back chann...
362
363
364
365
366
367
368
  		/* Signal process_op to set this error on next op */
  		if (args->csa_cachethis == 0)
  			return htonl(NFS4ERR_RETRY_UNCACHED_REP);
  
  		/* The ca_maxresponsesize_cached is 0 with no DRC */
  		else if (args->csa_cachethis == 1)
  			return htonl(NFS4ERR_REP_TOO_BIG_TO_CACHE);
68f3f9013   Ricardo Labiaga   nfs41: Backchanne...
369
370
371
  	}
  
  	/* Wraparound */
b2f28bd78   Andy Adamson   nfs41: prepare fo...
372
  	if (args->csa_sequenceid == 1 && (slot->seq_nr + 1) == 0) {
68f3f9013   Ricardo Labiaga   nfs41: Backchanne...
373
  		slot->seq_nr = 1;
55a673990   Trond Myklebust   NFSv4.1: Fix the ...
374
  		goto out_ok;
68f3f9013   Ricardo Labiaga   nfs41: Backchanne...
375
376
377
378
  	}
  
  	/* Misordered request */
  	return htonl(NFS4ERR_SEQ_MISORDERED);
55a673990   Trond Myklebust   NFSv4.1: Fix the ...
379
380
381
  out_ok:
  	tbl->highest_used_slotid = args->csa_slotid;
  	return htonl(NFS4_OK);
68f3f9013   Ricardo Labiaga   nfs41: Backchanne...
382
383
384
  }
  
  /*
a7989c3e4   Mike Sager   nfs41: Check slot...
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
   * For each referring call triple, check the session's slot table for
   * a match.  If the slot is in use and the sequence numbers match, the
   * client is still waiting for a response to the original request.
   */
  static bool referring_call_exists(struct nfs_client *clp,
  				  uint32_t nrclists,
  				  struct referring_call_list *rclists)
  {
  	bool status = 0;
  	int i, j;
  	struct nfs4_session *session;
  	struct nfs4_slot_table *tbl;
  	struct referring_call_list *rclist;
  	struct referring_call *ref;
  
  	/*
  	 * XXX When client trunking is implemented, this becomes
  	 * a session lookup from within the loop
  	 */
  	session = clp->cl_session;
  	tbl = &session->fc_slot_table;
  
  	for (i = 0; i < nrclists; i++) {
  		rclist = &rclists[i];
  		if (memcmp(session->sess_id.data,
  			   rclist->rcl_sessionid.data,
  			   NFS4_MAX_SESSIONID_LEN) != 0)
  			continue;
  
  		for (j = 0; j < rclist->rcl_nrefcalls; j++) {
  			ref = &rclist->rcl_refcalls[j];
  
  			dprintk("%s: sessionid %x:%x:%x:%x sequenceid %u "
  				"slotid %u
  ", __func__,
  				((u32 *)&rclist->rcl_sessionid.data)[0],
  				((u32 *)&rclist->rcl_sessionid.data)[1],
  				((u32 *)&rclist->rcl_sessionid.data)[2],
  				((u32 *)&rclist->rcl_sessionid.data)[3],
  				ref->rc_sequenceid, ref->rc_slotid);
  
  			spin_lock(&tbl->slot_tbl_lock);
  			status = (test_bit(ref->rc_slotid, tbl->used_slots) &&
  				  tbl->slots[ref->rc_slotid].seq_nr ==
  					ref->rc_sequenceid);
  			spin_unlock(&tbl->slot_tbl_lock);
  			if (status)
  				goto out;
  		}
  	}
  
  out:
  	return status;
  }
9733f0d92   Andy Adamson   nfs41: cleanup ca...
439
  __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
c36fca52f   Andy Adamson   NFS refactor nfs_...
440
441
  			      struct cb_sequenceres *res,
  			      struct cb_process_state *cps)
d49433e1e   Benny Halevy   nfs41: cb_sequenc...
442
  {
55a673990   Trond Myklebust   NFSv4.1: Fix the ...
443
  	struct nfs4_slot_table *tbl;
68f3f9013   Ricardo Labiaga   nfs41: Backchanne...
444
  	struct nfs_client *clp;
9733f0d92   Andy Adamson   nfs41: cleanup ca...
445
  	int i;
778be232a   Andy Adamson   NFS do not find c...
446
  	__be32 status = htonl(NFS4ERR_BADSESSION);
d49433e1e   Benny Halevy   nfs41: cb_sequenc...
447

778be232a   Andy Adamson   NFS do not find c...
448
  	clp = nfs4_find_client_sessionid(args->csa_addr, &args->csa_sessionid);
68f3f9013   Ricardo Labiaga   nfs41: Backchanne...
449
450
  	if (clp == NULL)
  		goto out;
55a673990   Trond Myklebust   NFSv4.1: Fix the ...
451
452
453
  	tbl = &clp->cl_session->bc_slot_table;
  
  	spin_lock(&tbl->slot_tbl_lock);
42acd0218   Andy Adamson   NFS add session b...
454
455
  	/* state manager is resetting the session */
  	if (test_bit(NFS4_SESSION_DRAINING, &clp->cl_session->session_state)) {
55a673990   Trond Myklebust   NFSv4.1: Fix the ...
456
457
  		spin_unlock(&tbl->slot_tbl_lock);
  		status = htonl(NFS4ERR_DELAY);
910ac68a2   Trond Myklebust   NFSv4.1: Return N...
458
459
460
461
462
  		/* Return NFS4ERR_BADSESSION if we're draining the session
  		 * in order to reset it.
  		 */
  		if (test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state))
  			status = htonl(NFS4ERR_BADSESSION);
42acd0218   Andy Adamson   NFS add session b...
463
464
  		goto out;
  	}
b2f28bd78   Andy Adamson   nfs41: prepare fo...
465
  	status = validate_seqid(&clp->cl_session->bc_slot_table, args);
55a673990   Trond Myklebust   NFSv4.1: Fix the ...
466
  	spin_unlock(&tbl->slot_tbl_lock);
68f3f9013   Ricardo Labiaga   nfs41: Backchanne...
467
  	if (status)
c36fca52f   Andy Adamson   NFS refactor nfs_...
468
  		goto out;
68f3f9013   Ricardo Labiaga   nfs41: Backchanne...
469

55a673990   Trond Myklebust   NFSv4.1: Fix the ...
470
  	cps->slotid = args->csa_slotid;
72ce2b3c0   Mike Sager   nfs41: Process ca...
471
472
473
474
475
476
477
  	/*
  	 * Check for pending referring calls.  If a match is found, a
  	 * related callback was received before the response to the original
  	 * call.
  	 */
  	if (referring_call_exists(clp, args->csa_nrclists, args->csa_rclists)) {
  		status = htonl(NFS4ERR_DELAY);
c36fca52f   Andy Adamson   NFS refactor nfs_...
478
  		goto out;
72ce2b3c0   Mike Sager   nfs41: Process ca...
479
  	}
d49433e1e   Benny Halevy   nfs41: cb_sequenc...
480
481
482
483
484
485
  	memcpy(&res->csr_sessionid, &args->csa_sessionid,
  	       sizeof(res->csr_sessionid));
  	res->csr_sequenceid = args->csa_sequenceid;
  	res->csr_slotid = args->csa_slotid;
  	res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
  	res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
68f3f9013   Ricardo Labiaga   nfs41: Backchanne...
486
  out:
2c4cdf8f6   Andy Adamson   NFS fix cb_sequen...
487
  	cps->clp = clp; /* put in nfs4_callback_compound */
72ce2b3c0   Mike Sager   nfs41: Process ca...
488
489
490
  	for (i = 0; i < args->csa_nrclists; i++)
  		kfree(args->csa_rclists[i].rcl_refcalls);
  	kfree(args->csa_rclists);
c36fca52f   Andy Adamson   NFS refactor nfs_...
491
492
493
494
  	if (status == htonl(NFS4ERR_RETRY_UNCACHED_REP)) {
  		cps->drc_status = status;
  		status = 0;
  	} else
4911096f1   Andy Adamson   nfs41: back chann...
495
  		res->csr_status = status;
c36fca52f   Andy Adamson   NFS refactor nfs_...
496

4911096f1   Andy Adamson   nfs41: back chann...
497
498
499
500
  	dprintk("%s: exit with status = %d res->csr_status %d
  ", __func__,
  		ntohl(status), ntohl(res->csr_status));
  	return status;
d49433e1e   Benny Halevy   nfs41: cb_sequenc...
501
  }
368403708   Alexandros Batsakis   pnfs: update nfs4...
502
503
504
505
506
  static bool
  validate_bitmap_values(unsigned long mask)
  {
  	return (mask & ~RCA4_TYPE_MASK_ALL) == 0;
  }
c36fca52f   Andy Adamson   NFS refactor nfs_...
507
508
  __be32 nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy,
  			       struct cb_process_state *cps)
31f096077   Alexandros Batsakis   nfs41: V2 initial...
509
  {
9733f0d92   Andy Adamson   nfs41: cleanup ca...
510
  	__be32 status;
31f096077   Alexandros Batsakis   nfs41: V2 initial...
511
  	fmode_t flags = 0;
368403708   Alexandros Batsakis   pnfs: update nfs4...
512
  	status = cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION);
c36fca52f   Andy Adamson   NFS refactor nfs_...
513
  	if (!cps->clp) /* set in cb_sequence */
31f096077   Alexandros Batsakis   nfs41: V2 initial...
514
515
516
517
  		goto out;
  
  	dprintk("NFS: RECALL_ANY callback request from %s
  ",
c36fca52f   Andy Adamson   NFS refactor nfs_...
518
  		rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
31f096077   Alexandros Batsakis   nfs41: V2 initial...
519

368403708   Alexandros Batsakis   pnfs: update nfs4...
520
521
522
523
524
  	status = cpu_to_be32(NFS4ERR_INVAL);
  	if (!validate_bitmap_values(args->craa_type_mask))
  		goto out;
  
  	status = cpu_to_be32(NFS4_OK);
31f096077   Alexandros Batsakis   nfs41: V2 initial...
525
526
527
528
529
530
  	if (test_bit(RCA4_TYPE_MASK_RDATA_DLG, (const unsigned long *)
  		     &args->craa_type_mask))
  		flags = FMODE_READ;
  	if (test_bit(RCA4_TYPE_MASK_WDATA_DLG, (const unsigned long *)
  		     &args->craa_type_mask))
  		flags |= FMODE_WRITE;
368403708   Alexandros Batsakis   pnfs: update nfs4...
531
532
533
  	if (test_bit(RCA4_TYPE_MASK_FILE_LAYOUT, (const unsigned long *)
  		     &args->craa_type_mask))
  		pnfs_recall_all_layouts(cps->clp);
31f096077   Alexandros Batsakis   nfs41: V2 initial...
534
  	if (flags)
c36fca52f   Andy Adamson   NFS refactor nfs_...
535
  		nfs_expire_all_delegation_types(cps->clp, flags);
31f096077   Alexandros Batsakis   nfs41: V2 initial...
536
537
538
539
540
  out:
  	dprintk("%s: exit with status = %d
  ", __func__, ntohl(status));
  	return status;
  }
b9efa1b27   Andy Adamson   nfs41: implement ...
541
542
  
  /* Reduce the fore channel's max_slots to the target value */
c36fca52f   Andy Adamson   NFS refactor nfs_...
543
544
  __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy,
  				struct cb_process_state *cps)
b9efa1b27   Andy Adamson   nfs41: implement ...
545
  {
b9efa1b27   Andy Adamson   nfs41: implement ...
546
  	struct nfs4_slot_table *fc_tbl;
9733f0d92   Andy Adamson   nfs41: cleanup ca...
547
  	__be32 status;
b9efa1b27   Andy Adamson   nfs41: implement ...
548
549
  
  	status = htonl(NFS4ERR_OP_NOT_IN_SESSION);
c36fca52f   Andy Adamson   NFS refactor nfs_...
550
  	if (!cps->clp) /* set in cb_sequence */
b9efa1b27   Andy Adamson   nfs41: implement ...
551
552
553
554
  		goto out;
  
  	dprintk("NFS: CB_RECALL_SLOT request from %s target max slots %d
  ",
c36fca52f   Andy Adamson   NFS refactor nfs_...
555
  		rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR),
b9efa1b27   Andy Adamson   nfs41: implement ...
556
  		args->crsa_target_max_slots);
c36fca52f   Andy Adamson   NFS refactor nfs_...
557
  	fc_tbl = &cps->clp->cl_session->fc_slot_table;
b9efa1b27   Andy Adamson   nfs41: implement ...
558
559
  
  	status = htonl(NFS4ERR_BAD_HIGH_SLOT);
bae0ac0ee   Andy Adamson   nfs41: fix nfs4_c...
560
  	if (args->crsa_target_max_slots > fc_tbl->max_slots ||
b9efa1b27   Andy Adamson   nfs41: implement ...
561
  	    args->crsa_target_max_slots < 1)
c36fca52f   Andy Adamson   NFS refactor nfs_...
562
  		goto out;
bae0ac0ee   Andy Adamson   nfs41: fix nfs4_c...
563
564
565
  
  	status = htonl(NFS4_OK);
  	if (args->crsa_target_max_slots == fc_tbl->max_slots)
c36fca52f   Andy Adamson   NFS refactor nfs_...
566
  		goto out;
b9efa1b27   Andy Adamson   nfs41: implement ...
567
568
  
  	fc_tbl->target_max_slots = args->crsa_target_max_slots;
c36fca52f   Andy Adamson   NFS refactor nfs_...
569
  	nfs41_handle_recall_slot(cps->clp);
b9efa1b27   Andy Adamson   nfs41: implement ...
570
571
572
573
574
  out:
  	dprintk("%s: exit with status = %d
  ", __func__, ntohl(status));
  	return status;
  }
d49433e1e   Benny Halevy   nfs41: cb_sequenc...
575
  #endif /* CONFIG_NFS_V4_1 */