aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/callback_proc.c71
1 files changed, 67 insertions, 4 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 6b342e82ebb3..b7da1f54da68 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -105,6 +105,57 @@ out:
105#if defined(CONFIG_NFS_V4_1) 105#if defined(CONFIG_NFS_V4_1)
106 106
107/* 107/*
108 * Validate the sequenceID sent by the server.
109 * Return success if the sequenceID is one more than what we last saw on
110 * this slot, accounting for wraparound. Increments the slot's sequence.
111 *
112 * We don't yet implement a duplicate request cache, so at this time
113 * we will log replays, and process them as if we had not seen them before,
114 * but we don't bump the sequence in the slot. Not too worried about it,
115 * since we only currently implement idempotent callbacks anyway.
116 *
117 * We have a single slot backchannel at this time, so we don't bother
118 * checking the used_slots bit array on the table. The lower layer guarantees
119 * a single outstanding callback request at a time.
120 */
121static int
122validate_seqid(struct nfs4_slot_table *tbl, u32 slotid, u32 seqid)
123{
124 struct nfs4_slot *slot;
125
126 dprintk("%s enter. slotid %d seqid %d\n",
127 __func__, slotid, seqid);
128
129 if (slotid > NFS41_BC_MAX_CALLBACKS)
130 return htonl(NFS4ERR_BADSLOT);
131
132 slot = tbl->slots + slotid;
133 dprintk("%s slot table seqid: %d\n", __func__, slot->seq_nr);
134
135 /* Normal */
136 if (likely(seqid == slot->seq_nr + 1)) {
137 slot->seq_nr++;
138 return htonl(NFS4_OK);
139 }
140
141 /* Replay */
142 if (seqid == slot->seq_nr) {
143 dprintk("%s seqid %d is a replay - no DRC available\n",
144 __func__, seqid);
145 return htonl(NFS4_OK);
146 }
147
148 /* Wraparound */
149 if (seqid == 1 && (slot->seq_nr + 1) == 0) {
150 slot->seq_nr = 1;
151 return htonl(NFS4_OK);
152 }
153
154 /* Misordered request */
155 return htonl(NFS4ERR_SEQ_MISORDERED);
156}
157
158/*
108 * Returns a pointer to a held 'struct nfs_client' that matches the server's 159 * Returns a pointer to a held 'struct nfs_client' that matches the server's
109 * address, major version number, and session ID. It is the caller's 160 * address, major version number, and session ID. It is the caller's
110 * responsibility to release the returned reference. 161 * responsibility to release the returned reference.
@@ -140,18 +191,27 @@ out:
140 return NULL; 191 return NULL;
141} 192}
142 193
143/* FIXME: validate args->cbs_{sequence,slot}id */
144/* FIXME: referring calls should be processed */ 194/* FIXME: referring calls should be processed */
145unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, 195unsigned nfs4_callback_sequence(struct cb_sequenceargs *args,
146 struct cb_sequenceres *res) 196 struct cb_sequenceres *res)
147{ 197{
148 int i; 198 struct nfs_client *clp;
149 unsigned status = 0; 199 int i, status;
150 200
151 for (i = 0; i < args->csa_nrclists; i++) 201 for (i = 0; i < args->csa_nrclists; i++)
152 kfree(args->csa_rclists[i].rcl_refcalls); 202 kfree(args->csa_rclists[i].rcl_refcalls);
153 kfree(args->csa_rclists); 203 kfree(args->csa_rclists);
154 204
205 status = htonl(NFS4ERR_BADSESSION);
206 clp = find_client_with_session(args->csa_addr, 4, &args->csa_sessionid);
207 if (clp == NULL)
208 goto out;
209
210 status = validate_seqid(&clp->cl_session->bc_slot_table,
211 args->csa_slotid, args->csa_sequenceid);
212 if (status)
213 goto out_putclient;
214
155 memcpy(&res->csr_sessionid, &args->csa_sessionid, 215 memcpy(&res->csr_sessionid, &args->csa_sessionid,
156 sizeof(res->csr_sessionid)); 216 sizeof(res->csr_sessionid));
157 res->csr_sequenceid = args->csa_sequenceid; 217 res->csr_sequenceid = args->csa_sequenceid;
@@ -159,9 +219,12 @@ unsigned nfs4_callback_sequence(struct cb_sequenceargs *args,
159 res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; 219 res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
160 res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; 220 res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
161 221
222out_putclient:
223 nfs_put_client(clp);
224out:
162 dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); 225 dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
163 res->csr_status = status; 226 res->csr_status = status;
164 return status; 227 return res->csr_status;
165} 228}
166 229
167#endif /* CONFIG_NFS_V4_1 */ 230#endif /* CONFIG_NFS_V4_1 */