aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2011-10-19 15:29:49 -0400
committerJeff Layton <jlayton@redhat.com>2011-10-19 15:29:49 -0400
commit44d22d846fdc7c3e688fc1ff5ae6d06d08bb5656 (patch)
treea7c55381c4eee74c2be9a4dc0728f0a927367d04 /fs
parente9097ab48978c89b9c0926e2ae5d49bf6ea91b18 (diff)
cifs: add a callback function to receive the rest of the frame
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/cifsglob.h23
-rw-r--r--fs/cifs/cifsproto.h5
-rw-r--r--fs/cifs/cifssmb.c5
-rw-r--r--fs/cifs/connect.c6
-rw-r--r--fs/cifs/transport.c5
5 files changed, 34 insertions, 10 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index a73dd1d5e7ef..d153d0b89d39 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -656,8 +656,24 @@ static inline void cifs_stats_bytes_read(struct cifs_tcon *tcon,
656struct mid_q_entry; 656struct mid_q_entry;
657 657
658/* 658/*
659 * This is the prototype for the mid callback function. When creating one, 659 * This is the prototype for the mid receive function. This function is for
660 * take special care to avoid deadlocks. Things to bear in mind: 660 * receiving the rest of the SMB frame, starting with the WordCount (which is
661 * just after the MID in struct smb_hdr). Note:
662 *
663 * - This will be called by cifsd, with no locks held.
664 * - The mid will still be on the pending_mid_q.
665 * - mid->resp_buf will point to the current buffer.
666 *
667 * Returns zero on a successful receive, or an error. The receive state in
668 * the TCP_Server_Info will also be updated.
669 */
670typedef int (mid_receive_t)(struct TCP_Server_Info *server,
671 struct mid_q_entry *mid);
672
673/*
674 * This is the prototype for the mid callback function. This is called once the
675 * mid has been received off of the socket. When creating one, take special
676 * care to avoid deadlocks. Things to bear in mind:
661 * 677 *
662 * - it will be called by cifsd, with no locks held 678 * - it will be called by cifsd, with no locks held
663 * - the mid will be removed from any lists 679 * - the mid will be removed from any lists
@@ -675,9 +691,10 @@ struct mid_q_entry {
675 unsigned long when_sent; /* time when smb send finished */ 691 unsigned long when_sent; /* time when smb send finished */
676 unsigned long when_received; /* when demux complete (taken off wire) */ 692 unsigned long when_received; /* when demux complete (taken off wire) */
677#endif 693#endif
694 mid_receive_t *receive; /* call receive callback */
678 mid_callback_t *callback; /* call completion callback */ 695 mid_callback_t *callback; /* call completion callback */
679 void *callback_data; /* general purpose pointer for callback */ 696 void *callback_data; /* general purpose pointer for callback */
680 struct smb_hdr *resp_buf; /* response buffer */ 697 struct smb_hdr *resp_buf; /* pointer to received SMB header */
681 int midState; /* wish this were enum but can not pass to wait_event */ 698 int midState; /* wish this were enum but can not pass to wait_event */
682 __u8 command; /* smb command code */ 699 __u8 command; /* smb command code */
683 bool largeBuf:1; /* if valid response, is pointer to large buf */ 700 bool largeBuf:1; /* if valid response, is pointer to large buf */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index a1fa9cec05d6..8a7adb31ffed 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -69,8 +69,9 @@ extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
69 struct TCP_Server_Info *server); 69 struct TCP_Server_Info *server);
70extern void DeleteMidQEntry(struct mid_q_entry *midEntry); 70extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
71extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, 71extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
72 unsigned int nvec, mid_callback_t *callback, 72 unsigned int nvec, mid_receive_t *receive,
73 void *cbdata, bool ignore_pend); 73 mid_callback_t *callback, void *cbdata,
74 bool ignore_pend);
74extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *, 75extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
75 struct smb_hdr * /* input */ , 76 struct smb_hdr * /* input */ ,
76 struct smb_hdr * /* out */ , 77 struct smb_hdr * /* out */ ,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index c824c106b2b7..0613df4d8e74 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -737,7 +737,8 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
737 iov.iov_base = smb; 737 iov.iov_base = smb;
738 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4; 738 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
739 739
740 rc = cifs_call_async(server, &iov, 1, cifs_echo_callback, server, true); 740 rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
741 server, true);
741 if (rc) 742 if (rc)
742 cFYI(1, "Echo request failed: %d", rc); 743 cFYI(1, "Echo request failed: %d", rc);
743 744
@@ -1834,7 +1835,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
1834 1835
1835 kref_get(&wdata->refcount); 1836 kref_get(&wdata->refcount);
1836 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1, 1837 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
1837 cifs_writev_callback, wdata, false); 1838 NULL, cifs_writev_callback, wdata, false);
1838 1839
1839 if (rc == 0) 1840 if (rc == 0)
1840 cifs_stats_inc(&tcon->num_writes); 1841 cifs_stats_inc(&tcon->num_writes);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index f05dedda37c6..eeee2f5d13ce 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -824,7 +824,11 @@ cifs_demultiplex_thread(void *p)
824 824
825 mid_entry = find_mid(server, smb_buffer); 825 mid_entry = find_mid(server, smb_buffer);
826 826
827 length = standard_receive3(server, mid_entry); 827 if (!mid_entry || !mid_entry->receive)
828 length = standard_receive3(server, mid_entry);
829 else
830 length = mid_entry->receive(server, mid_entry);
831
828 if (length < 0) 832 if (length < 0)
829 continue; 833 continue;
830 834
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 33a3fbf3a3a5..e7398d0cd054 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -339,8 +339,8 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
339 */ 339 */
340int 340int
341cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, 341cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
342 unsigned int nvec, mid_callback_t *callback, void *cbdata, 342 unsigned int nvec, mid_receive_t *receive,
343 bool ignore_pend) 343 mid_callback_t *callback, void *cbdata, bool ignore_pend)
344{ 344{
345 int rc; 345 int rc;
346 struct mid_q_entry *mid; 346 struct mid_q_entry *mid;
@@ -374,6 +374,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
374 goto out_err; 374 goto out_err;
375 } 375 }
376 376
377 mid->receive = receive;
377 mid->callback = callback; 378 mid->callback = callback;
378 mid->callback_data = cbdata; 379 mid->callback_data = cbdata;
379 mid->midState = MID_REQUEST_SUBMITTED; 380 mid->midState = MID_REQUEST_SUBMITTED;