cifs: add a callback function to receive the rest of the frame
authorJeff Layton <jlayton@redhat.com>
Wed, 19 Oct 2011 19:29:49 +0000 (15:29 -0400)
committerJeff Layton <jlayton@redhat.com>
Wed, 19 Oct 2011 19:29:49 +0000 (15:29 -0400)
In order to handle larger SMBs for readpages and other calls, we want
to be able to read into a preallocated set of buffers. Rather than
changing all of the existing code to preallocate buffers however, we
instead add a receive callback function to the MID.

cifsd will call this function once the mid_q_entry has been identified
in order to receive the rest of the SMB. If the mid can't be identified
or the receive pointer is unset, then the standard 3rd phase receive
function will be called.

Reviewed-and-Tested-by: Pavel Shilovsky <piastry@etersoft.ru>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/transport.c

index a73dd1d5e7ef0dd0e49e55c6733e119ba09b529f..d153d0b89d398165f2383d991a2b2b884dbbdc04 100644 (file)
@@ -656,8 +656,24 @@ static inline void cifs_stats_bytes_read(struct cifs_tcon *tcon,
 struct mid_q_entry;
 
 /*
- * This is the prototype for the mid callback function. When creating one,
- * take special care to avoid deadlocks. Things to bear in mind:
+ * This is the prototype for the mid receive function. This function is for
+ * receiving the rest of the SMB frame, starting with the WordCount (which is
+ * just after the MID in struct smb_hdr). Note:
+ *
+ * - This will be called by cifsd, with no locks held.
+ * - The mid will still be on the pending_mid_q.
+ * - mid->resp_buf will point to the current buffer.
+ *
+ * Returns zero on a successful receive, or an error. The receive state in
+ * the TCP_Server_Info will also be updated.
+ */
+typedef int (mid_receive_t)(struct TCP_Server_Info *server,
+                           struct mid_q_entry *mid);
+
+/*
+ * This is the prototype for the mid callback function. This is called once the
+ * mid has been received off of the socket. When creating one, take special
+ * care to avoid deadlocks. Things to bear in mind:
  *
  * - it will be called by cifsd, with no locks held
  * - the mid will be removed from any lists
@@ -675,9 +691,10 @@ struct mid_q_entry {
        unsigned long when_sent; /* time when smb send finished */
        unsigned long when_received; /* when demux complete (taken off wire) */
 #endif
+       mid_receive_t *receive; /* call receive callback */
        mid_callback_t *callback; /* call completion callback */
        void *callback_data;      /* general purpose pointer for callback */
-       struct smb_hdr *resp_buf;       /* response buffer */
+       struct smb_hdr *resp_buf;       /* pointer to received SMB header */
        int midState;   /* wish this were enum but can not pass to wait_event */
        __u8 command;   /* smb command code */
        bool largeBuf:1;        /* if valid response, is pointer to large buf */
index a1fa9cec05d6e7bb56e26f69f372072eed42ca81..8a7adb31ffedfcc0eae303f892ef6629eb26ea78 100644 (file)
@@ -69,8 +69,9 @@ extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
                                        struct TCP_Server_Info *server);
 extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
 extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
-                          unsigned int nvec, mid_callback_t *callback,
-                          void *cbdata, bool ignore_pend);
+                          unsigned int nvec, mid_receive_t *receive,
+                          mid_callback_t *callback, void *cbdata,
+                          bool ignore_pend);
 extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
                        struct smb_hdr * /* input */ ,
                        struct smb_hdr * /* out */ ,
index c824c106b2b787f3d53e189045693fa49a706fc5..0613df4d8e744b91f037a7a455d0450fe7fd49ee 100644 (file)
@@ -737,7 +737,8 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
        iov.iov_base = smb;
        iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
 
-       rc = cifs_call_async(server, &iov, 1, cifs_echo_callback, server, true);
+       rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
+                            server, true);
        if (rc)
                cFYI(1, "Echo request failed: %d", rc);
 
@@ -1834,7 +1835,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
 
        kref_get(&wdata->refcount);
        rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
-                            cifs_writev_callback, wdata, false);
+                            NULL, cifs_writev_callback, wdata, false);
 
        if (rc == 0)
                cifs_stats_inc(&tcon->num_writes);
index f05dedda37c6ef651d695d9b1c81db8112911fbe..eeee2f5d13ce1570560ebf8c388ab3ee1a125d1f 100644 (file)
@@ -824,7 +824,11 @@ cifs_demultiplex_thread(void *p)
 
                mid_entry = find_mid(server, smb_buffer);
 
-               length = standard_receive3(server, mid_entry);
+               if (!mid_entry || !mid_entry->receive)
+                       length = standard_receive3(server, mid_entry);
+               else
+                       length = mid_entry->receive(server, mid_entry);
+
                if (length < 0)
                        continue;
 
index 33a3fbf3a3a54e72c536c0b9c72aa0b83286530c..e7398d0cd054e634d4e9f87e592b091b4206b25e 100644 (file)
@@ -339,8 +339,8 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
  */
 int
 cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
-               unsigned int nvec, mid_callback_t *callback, void *cbdata,
-               bool ignore_pend)
+               unsigned int nvec, mid_receive_t *receive,
+               mid_callback_t *callback, void *cbdata, bool ignore_pend)
 {
        int rc;
        struct mid_q_entry *mid;
@@ -374,6 +374,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
                goto out_err;
        }
 
+       mid->receive = receive;
        mid->callback = callback;
        mid->callback_data = cbdata;
        mid->midState = MID_REQUEST_SUBMITTED;