]> Pileus Git - ~andy/linux/blobdiff - fs/cifs/transport.c
cifs: add ability to send an echo request
[~andy/linux] / fs / cifs / transport.c
index c41c9c4f0a79418f630afe46a27525b051c32947..a0cef49605168202681199c934c3f458dc1e641f 100644 (file)
 
 extern mempool_t *cifs_mid_poolp;
 
-static struct mid_q_entry *
+static void
+wake_up_task(struct mid_q_entry *mid)
+{
+       wake_up_process(mid->callback_data);
+}
+
+struct mid_q_entry *
 AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
 {
        struct mid_q_entry *temp;
@@ -58,7 +64,13 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
        /*      do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
                /* when mid allocated can be before when sent */
                temp->when_alloc = jiffies;
-               temp->tsk = current;
+
+               /*
+                * The default is for the mid to be synchronous, so the
+                * default callback just wakes up the current task.
+                */
+               temp->callback = wake_up_task;
+               temp->callback_data = current;
        }
 
        atomic_inc(&midCount);
@@ -66,7 +78,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
        return temp;
 }
 
-static void
+void
 DeleteMidQEntry(struct mid_q_entry *midEntry)
 {
 #ifdef CONFIG_CIFS_STATS2
@@ -332,6 +344,62 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
 }
 
 
+/*
+ * Send a SMB request and set the callback function in the mid to handle
+ * the result. Caller is responsible for dealing with timeouts.
+ */
+int
+cifs_call_async(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
+               mid_callback_t *callback, void *cbdata)
+{
+       int rc;
+       struct mid_q_entry *mid;
+
+       rc = wait_for_free_request(server, CIFS_ASYNC_OP);
+       if (rc)
+               return rc;
+
+       mutex_lock(&server->srv_mutex);
+       mid = AllocMidQEntry(in_buf, server);
+       if (mid == NULL) {
+               mutex_unlock(&server->srv_mutex);
+               return -ENOMEM;
+       }
+
+       /* put it on the pending_mid_q */
+       spin_lock(&GlobalMid_Lock);
+       list_add_tail(&mid->qhead, &server->pending_mid_q);
+       spin_unlock(&GlobalMid_Lock);
+
+       rc = cifs_sign_smb(in_buf, server, &mid->sequence_number);
+       if (rc) {
+               mutex_unlock(&server->srv_mutex);
+               goto out_err;
+       }
+
+       mid->callback = callback;
+       mid->callback_data = cbdata;
+       mid->midState = MID_REQUEST_SUBMITTED;
+#ifdef CONFIG_CIFS_STATS2
+       atomic_inc(&server->inSend);
+#endif
+       rc = smb_send(server, in_buf, in_buf->smb_buf_length);
+#ifdef CONFIG_CIFS_STATS2
+       atomic_dec(&server->inSend);
+       mid->when_sent = jiffies;
+#endif
+       mutex_unlock(&server->srv_mutex);
+       if (rc)
+               goto out_err;
+
+       return rc;
+out_err:
+       delete_mid(mid);
+       atomic_dec(&server->inFlight);
+       wake_up(&server->request_q);
+       return rc;
+}
+
 /*
  *
  * Send an SMB Request.  No response info (other than return code)
@@ -363,34 +431,36 @@ sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
 {
        int rc = 0;
 
+       cFYI(1, "%s: cmd=%d mid=%d state=%d", __func__, mid->command,
+               mid->mid, mid->midState);
+
        spin_lock(&GlobalMid_Lock);
+       /* ensure that it's no longer on the pending_mid_q */
+       list_del_init(&mid->qhead);
 
-       if (mid->resp_buf) {
+       switch (mid->midState) {
+       case MID_RESPONSE_RECEIVED:
                spin_unlock(&GlobalMid_Lock);
                return rc;
-       }
-
-       cERROR(1, "No response to cmd %d mid %d", mid->command, mid->mid);
-       if (mid->midState == MID_REQUEST_SUBMITTED) {
-               if (server->tcpStatus == CifsExiting)
+       case MID_REQUEST_SUBMITTED:
+               /* socket is going down, reject all calls */
+               if (server->tcpStatus == CifsExiting) {
+                       cERROR(1, "%s: canceling mid=%d cmd=0x%x state=%d",
+                              __func__, mid->mid, mid->command, mid->midState);
                        rc = -EHOSTDOWN;
-               else {
-                       server->tcpStatus = CifsNeedReconnect;
-                       mid->midState = MID_RETRY_NEEDED;
-               }
-       }
-
-       if (rc != -EHOSTDOWN) {
-               if (mid->midState == MID_RETRY_NEEDED) {
-                       rc = -EAGAIN;
-                       cFYI(1, "marking request for retry");
-               } else {
-                       rc = -EIO;
+                       break;
                }
+       case MID_RETRY_NEEDED:
+               rc = -EAGAIN;
+               break;
+       default:
+               cERROR(1, "%s: invalid mid state mid=%d state=%d", __func__,
+                       mid->mid, mid->midState);
+               rc = -EIO;
        }
        spin_unlock(&GlobalMid_Lock);
 
-       delete_mid(mid);
+       DeleteMidQEntry(mid);
        return rc;
 }