aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRonnie Sahlberg <lsahlber@redhat.com>2018-08-08 01:07:45 -0400
committerSteve French <stfrench@microsoft.com>2018-08-09 22:19:45 -0400
commitb24df3e30cbf48255db866720fb71f14bf9d2f39 (patch)
tree9ca3cb0b9f8be1814f87b24dfe85b7714bbea3ad
parent1eb9fb52040fc6e5656c277b562229f09467c9f8 (diff)
cifs: update receive_encrypted_standard to handle compounded responses
Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> Signed-off-by: Steve French <stfrench@microsoft.com> Reviewed-by: Paulo Alcantara <palcantara@suse.com> Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
-rw-r--r--fs/cifs/cifsglob.h5
-rw-r--r--fs/cifs/connect.c82
-rw-r--r--fs/cifs/smb2ops.c61
-rw-r--r--fs/cifs/transport.c2
4 files changed, 107 insertions, 43 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 41803d374da0..0c9ab62c3df4 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -76,6 +76,9 @@
76#define SMB_ECHO_INTERVAL_MAX 600 76#define SMB_ECHO_INTERVAL_MAX 600
77#define SMB_ECHO_INTERVAL_DEFAULT 60 77#define SMB_ECHO_INTERVAL_DEFAULT 60
78 78
79/* maximum number of PDUs in one compound */
80#define MAX_COMPOUND 5
81
79/* 82/*
80 * Default number of credits to keep available for SMB3. 83 * Default number of credits to keep available for SMB3.
81 * This value is chosen somewhat arbitrarily. The Windows client 84 * This value is chosen somewhat arbitrarily. The Windows client
@@ -458,7 +461,7 @@ struct smb_version_operations {
458 struct smb_rqst *, struct smb_rqst *); 461 struct smb_rqst *, struct smb_rqst *);
459 int (*is_transform_hdr)(void *buf); 462 int (*is_transform_hdr)(void *buf);
460 int (*receive_transform)(struct TCP_Server_Info *, 463 int (*receive_transform)(struct TCP_Server_Info *,
461 struct mid_q_entry **); 464 struct mid_q_entry **, char **, int *);
462 enum securityEnum (*select_sectype)(struct TCP_Server_Info *, 465 enum securityEnum (*select_sectype)(struct TCP_Server_Info *,
463 enum securityEnum); 466 enum securityEnum);
464 int (*next_header)(char *); 467 int (*next_header)(char *);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index d9bd10d295a9..c832a8a1970a 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -850,13 +850,14 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
850static int 850static int
851cifs_demultiplex_thread(void *p) 851cifs_demultiplex_thread(void *p)
852{ 852{
853 int length; 853 int i, num_mids, length;
854 struct TCP_Server_Info *server = p; 854 struct TCP_Server_Info *server = p;
855 unsigned int pdu_length; 855 unsigned int pdu_length;
856 unsigned int next_offset; 856 unsigned int next_offset;
857 char *buf = NULL; 857 char *buf = NULL;
858 struct task_struct *task_to_wake = NULL; 858 struct task_struct *task_to_wake = NULL;
859 struct mid_q_entry *mid_entry; 859 struct mid_q_entry *mids[MAX_COMPOUND];
860 char *bufs[MAX_COMPOUND];
860 861
861 current->flags |= PF_MEMALLOC; 862 current->flags |= PF_MEMALLOC;
862 cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current)); 863 cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current));
@@ -923,58 +924,75 @@ next_pdu:
923 server->pdu_size = next_offset; 924 server->pdu_size = next_offset;
924 } 925 }
925 926
926 mid_entry = NULL; 927 memset(mids, 0, sizeof(mids));
928 memset(bufs, 0, sizeof(bufs));
929 num_mids = 0;
930
927 if (server->ops->is_transform_hdr && 931 if (server->ops->is_transform_hdr &&
928 server->ops->receive_transform && 932 server->ops->receive_transform &&
929 server->ops->is_transform_hdr(buf)) { 933 server->ops->is_transform_hdr(buf)) {
930 length = server->ops->receive_transform(server, 934 length = server->ops->receive_transform(server,
931 &mid_entry); 935 mids,
936 bufs,
937 &num_mids);
932 } else { 938 } else {
933 mid_entry = server->ops->find_mid(server, buf); 939 mids[0] = server->ops->find_mid(server, buf);
940 bufs[0] = buf;
941 if (mids[0])
942 num_mids = 1;
934 943
935 if (!mid_entry || !mid_entry->receive) 944 if (!mids[0] || !mids[0]->receive)
936 length = standard_receive3(server, mid_entry); 945 length = standard_receive3(server, mids[0]);
937 else 946 else
938 length = mid_entry->receive(server, mid_entry); 947 length = mids[0]->receive(server, mids[0]);
939 } 948 }
940 949
941 if (length < 0) { 950 if (length < 0) {
942 if (mid_entry) 951 for (i = 0; i < num_mids; i++)
943 cifs_mid_q_entry_release(mid_entry); 952 if (mids[i])
953 cifs_mid_q_entry_release(mids[i]);
944 continue; 954 continue;
945 } 955 }
946 956
947 if (server->large_buf) 957 if (server->large_buf)
948 buf = server->bigbuf; 958 buf = server->bigbuf;
949 959
960
950 server->lstrp = jiffies; 961 server->lstrp = jiffies;
951 if (mid_entry != NULL) {
952 mid_entry->resp_buf_size = server->pdu_size;
953 if ((mid_entry->mid_flags & MID_WAIT_CANCELLED) &&
954 mid_entry->mid_state == MID_RESPONSE_RECEIVED &&
955 server->ops->handle_cancelled_mid)
956 server->ops->handle_cancelled_mid(
957 mid_entry->resp_buf,
958 server);
959 962
960 if (!mid_entry->multiRsp || mid_entry->multiEnd) 963 for (i = 0; i < num_mids; i++) {
961 mid_entry->callback(mid_entry); 964 if (mids[i] != NULL) {
965 mids[i]->resp_buf_size = server->pdu_size;
966 if ((mids[i]->mid_flags & MID_WAIT_CANCELLED) &&
967 mids[i]->mid_state == MID_RESPONSE_RECEIVED &&
968 server->ops->handle_cancelled_mid)
969 server->ops->handle_cancelled_mid(
970 mids[i]->resp_buf,
971 server);
962 972
963 cifs_mid_q_entry_release(mid_entry); 973 if (!mids[i]->multiRsp || mids[i]->multiEnd)
964 } else if (server->ops->is_oplock_break && 974 mids[i]->callback(mids[i]);
965 server->ops->is_oplock_break(buf, server)) { 975
966 cifs_dbg(FYI, "Received oplock break\n"); 976 cifs_mid_q_entry_release(mids[i]);
967 } else { 977 } else if (server->ops->is_oplock_break &&
968 cifs_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n", 978 server->ops->is_oplock_break(bufs[i],
969 atomic_read(&midCount)); 979 server)) {
970 cifs_dump_mem("Received Data is: ", buf, 980 cifs_dbg(FYI, "Received oplock break\n");
971 HEADER_SIZE(server)); 981 } else {
982 cifs_dbg(VFS, "No task to wake, unknown frame "
983 "received! NumMids %d\n",
984 atomic_read(&midCount));
985 cifs_dump_mem("Received Data is: ", bufs[i],
986 HEADER_SIZE(server));
972#ifdef CONFIG_CIFS_DEBUG2 987#ifdef CONFIG_CIFS_DEBUG2
973 if (server->ops->dump_detail) 988 if (server->ops->dump_detail)
974 server->ops->dump_detail(buf, server); 989 server->ops->dump_detail(bufs[i],
975 cifs_dump_mids(server); 990 server);
991 cifs_dump_mids(server);
976#endif /* CIFS_DEBUG2 */ 992#endif /* CIFS_DEBUG2 */
993 }
977 } 994 }
995
978 if (pdu_length > server->pdu_size) { 996 if (pdu_length > server->pdu_size) {
979 if (!allocate_buffers(server)) 997 if (!allocate_buffers(server))
980 continue; 998 continue;
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index ebc13ebebddf..d23715062c8e 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -2942,13 +2942,20 @@ discard_data:
2942 2942
2943static int 2943static int
2944receive_encrypted_standard(struct TCP_Server_Info *server, 2944receive_encrypted_standard(struct TCP_Server_Info *server,
2945 struct mid_q_entry **mid) 2945 struct mid_q_entry **mids, char **bufs,
2946 int *num_mids)
2946{ 2947{
2947 int length; 2948 int ret, length;
2948 char *buf = server->smallbuf; 2949 char *buf = server->smallbuf;
2950 char *tmpbuf;
2951 struct smb2_sync_hdr *shdr;
2949 unsigned int pdu_length = server->pdu_size; 2952 unsigned int pdu_length = server->pdu_size;
2950 unsigned int buf_size; 2953 unsigned int buf_size;
2951 struct mid_q_entry *mid_entry; 2954 struct mid_q_entry *mid_entry;
2955 int next_is_large;
2956 char *next_buffer = NULL;
2957
2958 *num_mids = 0;
2952 2959
2953 /* switch to large buffer if too big for a small one */ 2960 /* switch to large buffer if too big for a small one */
2954 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE) { 2961 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE) {
@@ -2969,24 +2976,61 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
2969 if (length) 2976 if (length)
2970 return length; 2977 return length;
2971 2978
2979 next_is_large = server->large_buf;
2980 one_more:
2981 shdr = (struct smb2_sync_hdr *)buf;
2982 if (shdr->NextCommand) {
2983 if (next_is_large) {
2984 tmpbuf = server->bigbuf;
2985 next_buffer = (char *)cifs_buf_get();
2986 } else {
2987 tmpbuf = server->smallbuf;
2988 next_buffer = (char *)cifs_small_buf_get();
2989 }
2990 memcpy(next_buffer,
2991 tmpbuf + le32_to_cpu(shdr->NextCommand),
2992 pdu_length - le32_to_cpu(shdr->NextCommand));
2993 }
2994
2972 mid_entry = smb2_find_mid(server, buf); 2995 mid_entry = smb2_find_mid(server, buf);
2973 if (mid_entry == NULL) 2996 if (mid_entry == NULL)
2974 cifs_dbg(FYI, "mid not found\n"); 2997 cifs_dbg(FYI, "mid not found\n");
2975 else { 2998 else {
2976 cifs_dbg(FYI, "mid found\n"); 2999 cifs_dbg(FYI, "mid found\n");
2977 mid_entry->decrypted = true; 3000 mid_entry->decrypted = true;
3001 mid_entry->resp_buf_size = server->pdu_size;
2978 } 3002 }
2979 3003
2980 *mid = mid_entry; 3004 if (*num_mids >= MAX_COMPOUND) {
3005 cifs_dbg(VFS, "too many PDUs in compound\n");
3006 return -1;
3007 }
3008 bufs[*num_mids] = buf;
3009 mids[(*num_mids)++] = mid_entry;
2981 3010
2982 if (mid_entry && mid_entry->handle) 3011 if (mid_entry && mid_entry->handle)
2983 return mid_entry->handle(server, mid_entry); 3012 ret = mid_entry->handle(server, mid_entry);
3013 else
3014 ret = cifs_handle_standard(server, mid_entry);
3015
3016 if (ret == 0 && shdr->NextCommand) {
3017 pdu_length -= le32_to_cpu(shdr->NextCommand);
3018 server->large_buf = next_is_large;
3019 if (next_is_large)
3020 server->bigbuf = next_buffer;
3021 else
3022 server->smallbuf = next_buffer;
3023
3024 buf += le32_to_cpu(shdr->NextCommand);
3025 goto one_more;
3026 }
2984 3027
2985 return cifs_handle_standard(server, mid_entry); 3028 return ret;
2986} 3029}
2987 3030
2988static int 3031static int
2989smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid) 3032smb3_receive_transform(struct TCP_Server_Info *server,
3033 struct mid_q_entry **mids, char **bufs, int *num_mids)
2990{ 3034{
2991 char *buf = server->smallbuf; 3035 char *buf = server->smallbuf;
2992 unsigned int pdu_length = server->pdu_size; 3036 unsigned int pdu_length = server->pdu_size;
@@ -3009,10 +3053,11 @@ smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid)
3009 return -ECONNABORTED; 3053 return -ECONNABORTED;
3010 } 3054 }
3011 3055
3056 /* TODO: add support for compounds containing READ. */
3012 if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) 3057 if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server))
3013 return receive_encrypted_read(server, mid); 3058 return receive_encrypted_read(server, &mids[0]);
3014 3059
3015 return receive_encrypted_standard(server, mid); 3060 return receive_encrypted_standard(server, mids, bufs, num_mids);
3016} 3061}
3017 3062
3018int 3063int
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index c53c0908d4c6..78f96fa3d7d9 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -383,8 +383,6 @@ smbd_done:
383 return rc; 383 return rc;
384} 384}
385 385
386#define MAX_COMPOUND 5
387
388static int 386static int
389smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, 387smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
390 struct smb_rqst *rqst, int flags) 388 struct smb_rqst *rqst, int flags)