diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2009-06-17 20:59:58 -0400 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2009-06-17 20:59:58 -0400 |
| commit | 301933a0acfdec837fd8b4884093b3f0fff01d8a (patch) | |
| tree | 1f2412a30d710493179b1b3743cf30302872df15 /fs/nfs/callback_proc.c | |
| parent | 3fe0344faf7fdcb158bd5c1a9aec960a8d70c8e8 (diff) | |
| parent | 68f3f90133d56e0c38f04f991e662c2b21592b31 (diff) | |
Merge commit 'linux-pnfs/nfs41-for-2.6.31' into nfsv41-for-2.6.31
Diffstat (limited to 'fs/nfs/callback_proc.c')
| -rw-r--r-- | fs/nfs/callback_proc.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index f7e83e23cf9f..b7da1f54da68 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
| @@ -101,3 +101,130 @@ out: | |||
| 101 | dprintk("%s: exit with status = %d\n", __func__, ntohl(res)); | 101 | dprintk("%s: exit with status = %d\n", __func__, ntohl(res)); |
| 102 | return res; | 102 | return res; |
| 103 | } | 103 | } |
| 104 | |||
| 105 | #if defined(CONFIG_NFS_V4_1) | ||
| 106 | |||
| 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 | /* | ||
| 159 | * Returns a pointer to a held 'struct nfs_client' that matches the server's | ||
| 160 | * address, major version number, and session ID. It is the caller's | ||
| 161 | * responsibility to release the returned reference. | ||
| 162 | * | ||
| 163 | * Returns NULL if there are no connections with sessions, or if no session | ||
| 164 | * matches the one of interest. | ||
| 165 | */ | ||
| 166 | static struct nfs_client *find_client_with_session( | ||
| 167 | const struct sockaddr *addr, u32 nfsversion, | ||
| 168 | struct nfs4_sessionid *sessionid) | ||
| 169 | { | ||
| 170 | struct nfs_client *clp; | ||
| 171 | |||
| 172 | clp = nfs_find_client(addr, 4); | ||
| 173 | if (clp == NULL) | ||
| 174 | return NULL; | ||
| 175 | |||
| 176 | do { | ||
| 177 | struct nfs_client *prev = clp; | ||
| 178 | |||
| 179 | if (clp->cl_session != NULL) { | ||
| 180 | if (memcmp(clp->cl_session->sess_id.data, | ||
| 181 | sessionid->data, | ||
| 182 | NFS4_MAX_SESSIONID_LEN) == 0) { | ||
| 183 | /* Returns a held reference to clp */ | ||
| 184 | return clp; | ||
| 185 | } | ||
| 186 | } | ||
| 187 | clp = nfs_find_client_next(prev); | ||
| 188 | nfs_put_client(prev); | ||
| 189 | } while (clp != NULL); | ||
| 190 | |||
| 191 | return NULL; | ||
| 192 | } | ||
| 193 | |||
| 194 | /* FIXME: referring calls should be processed */ | ||
| 195 | unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, | ||
| 196 | struct cb_sequenceres *res) | ||
| 197 | { | ||
| 198 | struct nfs_client *clp; | ||
| 199 | int i, status; | ||
| 200 | |||
| 201 | for (i = 0; i < args->csa_nrclists; i++) | ||
| 202 | kfree(args->csa_rclists[i].rcl_refcalls); | ||
| 203 | kfree(args->csa_rclists); | ||
| 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 | |||
| 215 | memcpy(&res->csr_sessionid, &args->csa_sessionid, | ||
| 216 | sizeof(res->csr_sessionid)); | ||
| 217 | res->csr_sequenceid = args->csa_sequenceid; | ||
| 218 | res->csr_slotid = args->csa_slotid; | ||
| 219 | res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; | ||
| 220 | res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; | ||
| 221 | |||
| 222 | out_putclient: | ||
| 223 | nfs_put_client(clp); | ||
| 224 | out: | ||
| 225 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
| 226 | res->csr_status = status; | ||
| 227 | return res->csr_status; | ||
| 228 | } | ||
| 229 | |||
| 230 | #endif /* CONFIG_NFS_V4_1 */ | ||
