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