xref: /linux/fs/nfs/callback_proc.c (revision a115bc070b1fc57ab23f3972401425927b5b465c)
1 /*
2  * linux/fs/nfs/callback_proc.c
3  *
4  * Copyright (C) 2004 Trond Myklebust
5  *
6  * NFSv4 callback procedures
7  */
8 #include <linux/nfs4.h>
9 #include <linux/nfs_fs.h>
10 #include "nfs4_fs.h"
11 #include "callback.h"
12 #include "delegation.h"
13 #include "internal.h"
14 
15 #ifdef NFS_DEBUG
16 #define NFSDBG_FACILITY NFSDBG_CALLBACK
17 #endif
18 
19 __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res)
20 {
21 	struct nfs_client *clp;
22 	struct nfs_delegation *delegation;
23 	struct nfs_inode *nfsi;
24 	struct inode *inode;
25 
26 	res->bitmap[0] = res->bitmap[1] = 0;
27 	res->status = htonl(NFS4ERR_BADHANDLE);
28 	clp = nfs_find_client(args->addr, 4);
29 	if (clp == NULL)
30 		goto out;
31 
32 	dprintk("NFS: GETATTR callback request from %s\n",
33 		rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));
34 
35 	inode = nfs_delegation_find_inode(clp, &args->fh);
36 	if (inode == NULL)
37 		goto out_putclient;
38 	nfsi = NFS_I(inode);
39 	down_read(&nfsi->rwsem);
40 	delegation = nfsi->delegation;
41 	if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0)
42 		goto out_iput;
43 	res->size = i_size_read(inode);
44 	res->change_attr = delegation->change_attr;
45 	if (nfsi->npages != 0)
46 		res->change_attr++;
47 	res->ctime = inode->i_ctime;
48 	res->mtime = inode->i_mtime;
49 	res->bitmap[0] = (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE) &
50 		args->bitmap[0];
51 	res->bitmap[1] = (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY) &
52 		args->bitmap[1];
53 	res->status = 0;
54 out_iput:
55 	up_read(&nfsi->rwsem);
56 	iput(inode);
57 out_putclient:
58 	nfs_put_client(clp);
59 out:
60 	dprintk("%s: exit with status = %d\n", __func__, ntohl(res->status));
61 	return res->status;
62 }
63 
64 static int (*nfs_validate_delegation_stateid(struct nfs_client *clp))(struct nfs_delegation *, const nfs4_stateid *)
65 {
66 #if defined(CONFIG_NFS_V4_1)
67 	if (clp->cl_minorversion > 0)
68 		return nfs41_validate_delegation_stateid;
69 #endif
70 	return nfs4_validate_delegation_stateid;
71 }
72 
73 
74 __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
75 {
76 	struct nfs_client *clp;
77 	struct inode *inode;
78 	__be32 res;
79 
80 	res = htonl(NFS4ERR_BADHANDLE);
81 	clp = nfs_find_client(args->addr, 4);
82 	if (clp == NULL)
83 		goto out;
84 
85 	dprintk("NFS: RECALL callback request from %s\n",
86 		rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));
87 
88 	do {
89 		struct nfs_client *prev = clp;
90 
91 		inode = nfs_delegation_find_inode(clp, &args->fh);
92 		if (inode != NULL) {
93 			/* Set up a helper thread to actually return the delegation */
94 			switch (nfs_async_inode_return_delegation(inode, &args->stateid,
95 								  nfs_validate_delegation_stateid(clp))) {
96 				case 0:
97 					res = 0;
98 					break;
99 				case -ENOENT:
100 					if (res != 0)
101 						res = htonl(NFS4ERR_BAD_STATEID);
102 					break;
103 				default:
104 					res = htonl(NFS4ERR_RESOURCE);
105 			}
106 			iput(inode);
107 		}
108 		clp = nfs_find_client_next(prev);
109 		nfs_put_client(prev);
110 	} while (clp != NULL);
111 out:
112 	dprintk("%s: exit with status = %d\n", __func__, ntohl(res));
113 	return res;
114 }
115 
116 int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
117 {
118 	if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data,
119 					 sizeof(delegation->stateid.data)) != 0)
120 		return 0;
121 	return 1;
122 }
123 
124 #if defined(CONFIG_NFS_V4_1)
125 
126 int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
127 {
128 	if (delegation == NULL)
129 		return 0;
130 
131 	/* seqid is 4-bytes long */
132 	if (((u32 *) &stateid->data)[0] != 0)
133 		return 0;
134 	if (memcmp(&delegation->stateid.data[4], &stateid->data[4],
135 		   sizeof(stateid->data)-4))
136 		return 0;
137 
138 	return 1;
139 }
140 
141 /*
142  * Validate the sequenceID sent by the server.
143  * Return success if the sequenceID is one more than what we last saw on
144  * this slot, accounting for wraparound.  Increments the slot's sequence.
145  *
146  * We don't yet implement a duplicate request cache, instead we set the
147  * back channel ca_maxresponsesize_cached to zero. This is OK for now
148  * since we only currently implement idempotent callbacks anyway.
149  *
150  * We have a single slot backchannel at this time, so we don't bother
151  * checking the used_slots bit array on the table.  The lower layer guarantees
152  * a single outstanding callback request at a time.
153  */
154 static __be32
155 validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args)
156 {
157 	struct nfs4_slot *slot;
158 
159 	dprintk("%s enter. slotid %d seqid %d\n",
160 		__func__, args->csa_slotid, args->csa_sequenceid);
161 
162 	if (args->csa_slotid > NFS41_BC_MAX_CALLBACKS)
163 		return htonl(NFS4ERR_BADSLOT);
164 
165 	slot = tbl->slots + args->csa_slotid;
166 	dprintk("%s slot table seqid: %d\n", __func__, slot->seq_nr);
167 
168 	/* Normal */
169 	if (likely(args->csa_sequenceid == slot->seq_nr + 1)) {
170 		slot->seq_nr++;
171 		return htonl(NFS4_OK);
172 	}
173 
174 	/* Replay */
175 	if (args->csa_sequenceid == slot->seq_nr) {
176 		dprintk("%s seqid %d is a replay\n",
177 			__func__, args->csa_sequenceid);
178 		/* Signal process_op to set this error on next op */
179 		if (args->csa_cachethis == 0)
180 			return htonl(NFS4ERR_RETRY_UNCACHED_REP);
181 
182 		/* The ca_maxresponsesize_cached is 0 with no DRC */
183 		else if (args->csa_cachethis == 1)
184 			return htonl(NFS4ERR_REP_TOO_BIG_TO_CACHE);
185 	}
186 
187 	/* Wraparound */
188 	if (args->csa_sequenceid == 1 && (slot->seq_nr + 1) == 0) {
189 		slot->seq_nr = 1;
190 		return htonl(NFS4_OK);
191 	}
192 
193 	/* Misordered request */
194 	return htonl(NFS4ERR_SEQ_MISORDERED);
195 }
196 
197 /*
198  * Returns a pointer to a held 'struct nfs_client' that matches the server's
199  * address, major version number, and session ID.  It is the caller's
200  * responsibility to release the returned reference.
201  *
202  * Returns NULL if there are no connections with sessions, or if no session
203  * matches the one of interest.
204  */
205  static struct nfs_client *find_client_with_session(
206 	const struct sockaddr *addr, u32 nfsversion,
207 	struct nfs4_sessionid *sessionid)
208 {
209 	struct nfs_client *clp;
210 
211 	clp = nfs_find_client(addr, 4);
212 	if (clp == NULL)
213 		return NULL;
214 
215 	do {
216 		struct nfs_client *prev = clp;
217 
218 		if (clp->cl_session != NULL) {
219 			if (memcmp(clp->cl_session->sess_id.data,
220 					sessionid->data,
221 					NFS4_MAX_SESSIONID_LEN) == 0) {
222 				/* Returns a held reference to clp */
223 				return clp;
224 			}
225 		}
226 		clp = nfs_find_client_next(prev);
227 		nfs_put_client(prev);
228 	} while (clp != NULL);
229 
230 	return NULL;
231 }
232 
233 /*
234  * For each referring call triple, check the session's slot table for
235  * a match.  If the slot is in use and the sequence numbers match, the
236  * client is still waiting for a response to the original request.
237  */
238 static bool referring_call_exists(struct nfs_client *clp,
239 				  uint32_t nrclists,
240 				  struct referring_call_list *rclists)
241 {
242 	bool status = 0;
243 	int i, j;
244 	struct nfs4_session *session;
245 	struct nfs4_slot_table *tbl;
246 	struct referring_call_list *rclist;
247 	struct referring_call *ref;
248 
249 	/*
250 	 * XXX When client trunking is implemented, this becomes
251 	 * a session lookup from within the loop
252 	 */
253 	session = clp->cl_session;
254 	tbl = &session->fc_slot_table;
255 
256 	for (i = 0; i < nrclists; i++) {
257 		rclist = &rclists[i];
258 		if (memcmp(session->sess_id.data,
259 			   rclist->rcl_sessionid.data,
260 			   NFS4_MAX_SESSIONID_LEN) != 0)
261 			continue;
262 
263 		for (j = 0; j < rclist->rcl_nrefcalls; j++) {
264 			ref = &rclist->rcl_refcalls[j];
265 
266 			dprintk("%s: sessionid %x:%x:%x:%x sequenceid %u "
267 				"slotid %u\n", __func__,
268 				((u32 *)&rclist->rcl_sessionid.data)[0],
269 				((u32 *)&rclist->rcl_sessionid.data)[1],
270 				((u32 *)&rclist->rcl_sessionid.data)[2],
271 				((u32 *)&rclist->rcl_sessionid.data)[3],
272 				ref->rc_sequenceid, ref->rc_slotid);
273 
274 			spin_lock(&tbl->slot_tbl_lock);
275 			status = (test_bit(ref->rc_slotid, tbl->used_slots) &&
276 				  tbl->slots[ref->rc_slotid].seq_nr ==
277 					ref->rc_sequenceid);
278 			spin_unlock(&tbl->slot_tbl_lock);
279 			if (status)
280 				goto out;
281 		}
282 	}
283 
284 out:
285 	return status;
286 }
287 
288 __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
289 				struct cb_sequenceres *res)
290 {
291 	struct nfs_client *clp;
292 	int i;
293 	__be32 status;
294 
295 	status = htonl(NFS4ERR_BADSESSION);
296 	clp = find_client_with_session(args->csa_addr, 4, &args->csa_sessionid);
297 	if (clp == NULL)
298 		goto out;
299 
300 	status = validate_seqid(&clp->cl_session->bc_slot_table, args);
301 	if (status)
302 		goto out_putclient;
303 
304 	/*
305 	 * Check for pending referring calls.  If a match is found, a
306 	 * related callback was received before the response to the original
307 	 * call.
308 	 */
309 	if (referring_call_exists(clp, args->csa_nrclists, args->csa_rclists)) {
310 		status = htonl(NFS4ERR_DELAY);
311 		goto out_putclient;
312 	}
313 
314 	memcpy(&res->csr_sessionid, &args->csa_sessionid,
315 	       sizeof(res->csr_sessionid));
316 	res->csr_sequenceid = args->csa_sequenceid;
317 	res->csr_slotid = args->csa_slotid;
318 	res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
319 	res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
320 
321 out_putclient:
322 	nfs_put_client(clp);
323 out:
324 	for (i = 0; i < args->csa_nrclists; i++)
325 		kfree(args->csa_rclists[i].rcl_refcalls);
326 	kfree(args->csa_rclists);
327 
328 	if (status == htonl(NFS4ERR_RETRY_UNCACHED_REP))
329 		res->csr_status = 0;
330 	else
331 		res->csr_status = status;
332 	dprintk("%s: exit with status = %d res->csr_status %d\n", __func__,
333 		ntohl(status), ntohl(res->csr_status));
334 	return status;
335 }
336 
337 __be32 nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy)
338 {
339 	struct nfs_client *clp;
340 	__be32 status;
341 	fmode_t flags = 0;
342 
343 	status = htonl(NFS4ERR_OP_NOT_IN_SESSION);
344 	clp = nfs_find_client(args->craa_addr, 4);
345 	if (clp == NULL)
346 		goto out;
347 
348 	dprintk("NFS: RECALL_ANY callback request from %s\n",
349 		rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));
350 
351 	if (test_bit(RCA4_TYPE_MASK_RDATA_DLG, (const unsigned long *)
352 		     &args->craa_type_mask))
353 		flags = FMODE_READ;
354 	if (test_bit(RCA4_TYPE_MASK_WDATA_DLG, (const unsigned long *)
355 		     &args->craa_type_mask))
356 		flags |= FMODE_WRITE;
357 
358 	if (flags)
359 		nfs_expire_all_delegation_types(clp, flags);
360 	status = htonl(NFS4_OK);
361 out:
362 	dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
363 	return status;
364 }
365 
366 /* Reduce the fore channel's max_slots to the target value */
367 __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy)
368 {
369 	struct nfs_client *clp;
370 	struct nfs4_slot_table *fc_tbl;
371 	__be32 status;
372 
373 	status = htonl(NFS4ERR_OP_NOT_IN_SESSION);
374 	clp = nfs_find_client(args->crsa_addr, 4);
375 	if (clp == NULL)
376 		goto out;
377 
378 	dprintk("NFS: CB_RECALL_SLOT request from %s target max slots %d\n",
379 		rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR),
380 		args->crsa_target_max_slots);
381 
382 	fc_tbl = &clp->cl_session->fc_slot_table;
383 
384 	status = htonl(NFS4ERR_BAD_HIGH_SLOT);
385 	if (args->crsa_target_max_slots > fc_tbl->max_slots ||
386 	    args->crsa_target_max_slots < 1)
387 		goto out_putclient;
388 
389 	status = htonl(NFS4_OK);
390 	if (args->crsa_target_max_slots == fc_tbl->max_slots)
391 		goto out_putclient;
392 
393 	fc_tbl->target_max_slots = args->crsa_target_max_slots;
394 	nfs41_handle_recall_slot(clp);
395 out_putclient:
396 	nfs_put_client(clp);	/* balance nfs_find_client */
397 out:
398 	dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
399 	return status;
400 }
401 #endif /* CONFIG_NFS_V4_1 */
402