xref: /openbmc/linux/fs/nfs/callback_proc.c (revision a09d2831)
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, so at this time
147  * we will log replays, and process them as if we had not seen them before,
148  * but we don't bump the sequence in the slot.  Not too worried about it,
149  * since we only currently implement idempotent callbacks anyway.
150  *
151  * We have a single slot backchannel at this time, so we don't bother
152  * checking the used_slots bit array on the table.  The lower layer guarantees
153  * a single outstanding callback request at a time.
154  */
155 static int
156 validate_seqid(struct nfs4_slot_table *tbl, u32 slotid, u32 seqid)
157 {
158 	struct nfs4_slot *slot;
159 
160 	dprintk("%s enter. slotid %d seqid %d\n",
161 		__func__, slotid, seqid);
162 
163 	if (slotid > NFS41_BC_MAX_CALLBACKS)
164 		return htonl(NFS4ERR_BADSLOT);
165 
166 	slot = tbl->slots + slotid;
167 	dprintk("%s slot table seqid: %d\n", __func__, slot->seq_nr);
168 
169 	/* Normal */
170 	if (likely(seqid == slot->seq_nr + 1)) {
171 		slot->seq_nr++;
172 		return htonl(NFS4_OK);
173 	}
174 
175 	/* Replay */
176 	if (seqid == slot->seq_nr) {
177 		dprintk("%s seqid %d is a replay - no DRC available\n",
178 			__func__, seqid);
179 		return htonl(NFS4_OK);
180 	}
181 
182 	/* Wraparound */
183 	if (seqid == 1 && (slot->seq_nr + 1) == 0) {
184 		slot->seq_nr = 1;
185 		return htonl(NFS4_OK);
186 	}
187 
188 	/* Misordered request */
189 	return htonl(NFS4ERR_SEQ_MISORDERED);
190 }
191 
192 /*
193  * Returns a pointer to a held 'struct nfs_client' that matches the server's
194  * address, major version number, and session ID.  It is the caller's
195  * responsibility to release the returned reference.
196  *
197  * Returns NULL if there are no connections with sessions, or if no session
198  * matches the one of interest.
199  */
200  static struct nfs_client *find_client_with_session(
201 	const struct sockaddr *addr, u32 nfsversion,
202 	struct nfs4_sessionid *sessionid)
203 {
204 	struct nfs_client *clp;
205 
206 	clp = nfs_find_client(addr, 4);
207 	if (clp == NULL)
208 		return NULL;
209 
210 	do {
211 		struct nfs_client *prev = clp;
212 
213 		if (clp->cl_session != NULL) {
214 			if (memcmp(clp->cl_session->sess_id.data,
215 					sessionid->data,
216 					NFS4_MAX_SESSIONID_LEN) == 0) {
217 				/* Returns a held reference to clp */
218 				return clp;
219 			}
220 		}
221 		clp = nfs_find_client_next(prev);
222 		nfs_put_client(prev);
223 	} while (clp != NULL);
224 
225 	return NULL;
226 }
227 
228 /* FIXME: referring calls should be processed */
229 unsigned nfs4_callback_sequence(struct cb_sequenceargs *args,
230 				struct cb_sequenceres *res)
231 {
232 	struct nfs_client *clp;
233 	int i, status;
234 
235 	for (i = 0; i < args->csa_nrclists; i++)
236 		kfree(args->csa_rclists[i].rcl_refcalls);
237 	kfree(args->csa_rclists);
238 
239 	status = htonl(NFS4ERR_BADSESSION);
240 	clp = find_client_with_session(args->csa_addr, 4, &args->csa_sessionid);
241 	if (clp == NULL)
242 		goto out;
243 
244 	status = validate_seqid(&clp->cl_session->bc_slot_table,
245 				args->csa_slotid, args->csa_sequenceid);
246 	if (status)
247 		goto out_putclient;
248 
249 	memcpy(&res->csr_sessionid, &args->csa_sessionid,
250 	       sizeof(res->csr_sessionid));
251 	res->csr_sequenceid = args->csa_sequenceid;
252 	res->csr_slotid = args->csa_slotid;
253 	res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
254 	res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
255 
256 out_putclient:
257 	nfs_put_client(clp);
258 out:
259 	dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
260 	res->csr_status = status;
261 	return res->csr_status;
262 }
263 
264 unsigned nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy)
265 {
266 	struct nfs_client *clp;
267 	int status;
268 	fmode_t flags = 0;
269 
270 	status = htonl(NFS4ERR_OP_NOT_IN_SESSION);
271 	clp = nfs_find_client(args->craa_addr, 4);
272 	if (clp == NULL)
273 		goto out;
274 
275 	dprintk("NFS: RECALL_ANY callback request from %s\n",
276 		rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));
277 
278 	if (test_bit(RCA4_TYPE_MASK_RDATA_DLG, (const unsigned long *)
279 		     &args->craa_type_mask))
280 		flags = FMODE_READ;
281 	if (test_bit(RCA4_TYPE_MASK_WDATA_DLG, (const unsigned long *)
282 		     &args->craa_type_mask))
283 		flags |= FMODE_WRITE;
284 
285 	if (flags)
286 		nfs_expire_all_delegation_types(clp, flags);
287 	status = htonl(NFS4_OK);
288 out:
289 	dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
290 	return status;
291 }
292 #endif /* CONFIG_NFS_V4_1 */
293