omapfb: HWA742: fix pointer to be const
[safe/jmp/linux-2.6] / fs / nfs / callback_proc.c
index e89a900..b7da1f5 100644 (file)
@@ -57,7 +57,7 @@ out_iput:
 out_putclient:
        nfs_put_client(clp);
 out:
-       dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res->status));
+       dprintk("%s: exit with status = %d\n", __func__, ntohl(res->status));
        return res->status;
 }
 
@@ -75,24 +75,156 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
        dprintk("NFS: RECALL callback request from %s\n",
                rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));
 
-       inode = nfs_delegation_find_inode(clp, &args->fh);
-       if (inode == NULL)
-               goto out_putclient;
-       /* Set up a helper thread to actually return the delegation */
-       switch(nfs_async_inode_return_delegation(inode, &args->stateid)) {
-               case 0:
-                       res = 0;
-                       break;
-               case -ENOENT:
-                       res = htonl(NFS4ERR_BAD_STATEID);
-                       break;
-               default:
-                       res = htonl(NFS4ERR_RESOURCE);
+       do {
+               struct nfs_client *prev = clp;
+
+               inode = nfs_delegation_find_inode(clp, &args->fh);
+               if (inode != NULL) {
+                       /* Set up a helper thread to actually return the delegation */
+                       switch(nfs_async_inode_return_delegation(inode, &args->stateid)) {
+                               case 0:
+                                       res = 0;
+                                       break;
+                               case -ENOENT:
+                                       if (res != 0)
+                                               res = htonl(NFS4ERR_BAD_STATEID);
+                                       break;
+                               default:
+                                       res = htonl(NFS4ERR_RESOURCE);
+                       }
+                       iput(inode);
+               }
+               clp = nfs_find_client_next(prev);
+               nfs_put_client(prev);
+       } while (clp != NULL);
+out:
+       dprintk("%s: exit with status = %d\n", __func__, ntohl(res));
+       return res;
+}
+
+#if defined(CONFIG_NFS_V4_1)
+
+/*
+ * Validate the sequenceID sent by the server.
+ * Return success if the sequenceID is one more than what we last saw on
+ * this slot, accounting for wraparound.  Increments the slot's sequence.
+ *
+ * We don't yet implement a duplicate request cache, so at this time
+ * we will log replays, and process them as if we had not seen them before,
+ * but we don't bump the sequence in the slot.  Not too worried about it,
+ * since we only currently implement idempotent callbacks anyway.
+ *
+ * We have a single slot backchannel at this time, so we don't bother
+ * checking the used_slots bit array on the table.  The lower layer guarantees
+ * a single outstanding callback request at a time.
+ */
+static int
+validate_seqid(struct nfs4_slot_table *tbl, u32 slotid, u32 seqid)
+{
+       struct nfs4_slot *slot;
+
+       dprintk("%s enter. slotid %d seqid %d\n",
+               __func__, slotid, seqid);
+
+       if (slotid > NFS41_BC_MAX_CALLBACKS)
+               return htonl(NFS4ERR_BADSLOT);
+
+       slot = tbl->slots + slotid;
+       dprintk("%s slot table seqid: %d\n", __func__, slot->seq_nr);
+
+       /* Normal */
+       if (likely(seqid == slot->seq_nr + 1)) {
+               slot->seq_nr++;
+               return htonl(NFS4_OK);
        }
-       iput(inode);
+
+       /* Replay */
+       if (seqid == slot->seq_nr) {
+               dprintk("%s seqid %d is a replay - no DRC available\n",
+                       __func__, seqid);
+               return htonl(NFS4_OK);
+       }
+
+       /* Wraparound */
+       if (seqid == 1 && (slot->seq_nr + 1) == 0) {
+               slot->seq_nr = 1;
+               return htonl(NFS4_OK);
+       }
+
+       /* Misordered request */
+       return htonl(NFS4ERR_SEQ_MISORDERED);
+}
+
+/*
+ * Returns a pointer to a held 'struct nfs_client' that matches the server's
+ * address, major version number, and session ID.  It is the caller's
+ * responsibility to release the returned reference.
+ *
+ * Returns NULL if there are no connections with sessions, or if no session
+ * matches the one of interest.
+ */
+ static struct nfs_client *find_client_with_session(
+       const struct sockaddr *addr, u32 nfsversion,
+       struct nfs4_sessionid *sessionid)
+{
+       struct nfs_client *clp;
+
+       clp = nfs_find_client(addr, 4);
+       if (clp == NULL)
+               return NULL;
+
+       do {
+               struct nfs_client *prev = clp;
+
+               if (clp->cl_session != NULL) {
+                       if (memcmp(clp->cl_session->sess_id.data,
+                                       sessionid->data,
+                                       NFS4_MAX_SESSIONID_LEN) == 0) {
+                               /* Returns a held reference to clp */
+                               return clp;
+                       }
+               }
+               clp = nfs_find_client_next(prev);
+               nfs_put_client(prev);
+       } while (clp != NULL);
+
+       return NULL;
+}
+
+/* FIXME: referring calls should be processed */
+unsigned nfs4_callback_sequence(struct cb_sequenceargs *args,
+                               struct cb_sequenceres *res)
+{
+       struct nfs_client *clp;
+       int i, status;
+
+       for (i = 0; i < args->csa_nrclists; i++)
+               kfree(args->csa_rclists[i].rcl_refcalls);
+       kfree(args->csa_rclists);
+
+       status = htonl(NFS4ERR_BADSESSION);
+       clp = find_client_with_session(args->csa_addr, 4, &args->csa_sessionid);
+       if (clp == NULL)
+               goto out;
+
+       status = validate_seqid(&clp->cl_session->bc_slot_table,
+                               args->csa_slotid, args->csa_sequenceid);
+       if (status)
+               goto out_putclient;
+
+       memcpy(&res->csr_sessionid, &args->csa_sessionid,
+              sizeof(res->csr_sessionid));
+       res->csr_sequenceid = args->csa_sequenceid;
+       res->csr_slotid = args->csa_slotid;
+       res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
+       res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
+
 out_putclient:
        nfs_put_client(clp);
 out:
-       dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res));
-       return res;
+       dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
+       res->csr_status = status;
+       return res->csr_status;
 }
+
+#endif /* CONFIG_NFS_V4_1 */