diff options
-rw-r--r-- | fs/nfs/callback_proc.c | 71 |
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 | */ | ||
121 | static int | ||
122 | validate_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 */ |
145 | unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, | 195 | unsigned 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 | ||
222 | out_putclient: | ||
223 | nfs_put_client(clp); | ||
224 | out: | ||
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 */ |