aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/smb2ops.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/smb2ops.c')
-rw-r--r--fs/cifs/smb2ops.c115
1 files changed, 98 insertions, 17 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 6f96e2292856..085e91436da7 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -67,10 +67,13 @@ change_conf(struct TCP_Server_Info *server)
67} 67}
68 68
69static void 69static void
70smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add, 70smb2_add_credits(struct TCP_Server_Info *server,
71 const int optype) 71 const struct cifs_credits *credits, const int optype)
72{ 72{
73 int *val, rc = -1; 73 int *val, rc = -1;
74 unsigned int add = credits->value;
75 unsigned int instance = credits->instance;
76 bool reconnect_detected = false;
74 77
75 spin_lock(&server->req_lock); 78 spin_lock(&server->req_lock);
76 val = server->ops->get_credits_field(server, optype); 79 val = server->ops->get_credits_field(server, optype);
@@ -79,8 +82,11 @@ smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
79 if (((optype & CIFS_OP_MASK) == CIFS_NEG_OP) && (*val != 0)) 82 if (((optype & CIFS_OP_MASK) == CIFS_NEG_OP) && (*val != 0))
80 trace_smb3_reconnect_with_invalid_credits(server->CurrentMid, 83 trace_smb3_reconnect_with_invalid_credits(server->CurrentMid,
81 server->hostname, *val); 84 server->hostname, *val);
85 if ((instance == 0) || (instance == server->reconnect_instance))
86 *val += add;
87 else
88 reconnect_detected = true;
82 89
83 *val += add;
84 if (*val > 65000) { 90 if (*val > 65000) {
85 *val = 65000; /* Don't get near 64K credits, avoid srv bugs */ 91 *val = 65000; /* Don't get near 64K credits, avoid srv bugs */
86 printk_once(KERN_WARNING "server overflowed SMB3 credits\n"); 92 printk_once(KERN_WARNING "server overflowed SMB3 credits\n");
@@ -102,7 +108,12 @@ smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
102 spin_unlock(&server->req_lock); 108 spin_unlock(&server->req_lock);
103 wake_up(&server->request_q); 109 wake_up(&server->request_q);
104 110
105 if (server->tcpStatus == CifsNeedReconnect) 111 if (reconnect_detected)
112 cifs_dbg(FYI, "trying to put %d credits from the old server instance %d\n",
113 add, instance);
114
115 if (server->tcpStatus == CifsNeedReconnect
116 || server->tcpStatus == CifsExiting)
106 return; 117 return;
107 118
108 switch (rc) { 119 switch (rc) {
@@ -163,7 +174,7 @@ smb2_get_credits(struct mid_q_entry *mid)
163 174
164static int 175static int
165smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, 176smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
166 unsigned int *num, unsigned int *credits) 177 unsigned int *num, struct cifs_credits *credits)
167{ 178{
168 int rc = 0; 179 int rc = 0;
169 unsigned int scredits; 180 unsigned int scredits;
@@ -189,7 +200,8 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
189 /* can deadlock with reopen */ 200 /* can deadlock with reopen */
190 if (scredits <= 8) { 201 if (scredits <= 8) {
191 *num = SMB2_MAX_BUFFER_SIZE; 202 *num = SMB2_MAX_BUFFER_SIZE;
192 *credits = 0; 203 credits->value = 0;
204 credits->instance = 0;
193 break; 205 break;
194 } 206 }
195 207
@@ -198,8 +210,10 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
198 *num = min_t(unsigned int, size, 210 *num = min_t(unsigned int, size,
199 scredits * SMB2_MAX_BUFFER_SIZE); 211 scredits * SMB2_MAX_BUFFER_SIZE);
200 212
201 *credits = DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE); 213 credits->value =
202 server->credits -= *credits; 214 DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE);
215 credits->instance = server->reconnect_instance;
216 server->credits -= credits->value;
203 server->in_flight++; 217 server->in_flight++;
204 break; 218 break;
205 } 219 }
@@ -208,6 +222,38 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
208 return rc; 222 return rc;
209} 223}
210 224
225static int
226smb2_adjust_credits(struct TCP_Server_Info *server,
227 struct cifs_credits *credits,
228 const unsigned int payload_size)
229{
230 int new_val = DIV_ROUND_UP(payload_size, SMB2_MAX_BUFFER_SIZE);
231
232 if (!credits->value || credits->value == new_val)
233 return 0;
234
235 if (credits->value < new_val) {
236 WARN_ONCE(1, "request has less credits (%d) than required (%d)",
237 credits->value, new_val);
238 return -ENOTSUPP;
239 }
240
241 spin_lock(&server->req_lock);
242
243 if (server->reconnect_instance != credits->instance) {
244 spin_unlock(&server->req_lock);
245 cifs_dbg(VFS, "trying to return %d credits to old session\n",
246 credits->value - new_val);
247 return -EAGAIN;
248 }
249
250 server->credits += credits->value - new_val;
251 spin_unlock(&server->req_lock);
252 wake_up(&server->request_q);
253 credits->value = new_val;
254 return 0;
255}
256
211static __u64 257static __u64
212smb2_get_next_mid(struct TCP_Server_Info *server) 258smb2_get_next_mid(struct TCP_Server_Info *server)
213{ 259{
@@ -219,6 +265,15 @@ smb2_get_next_mid(struct TCP_Server_Info *server)
219 return mid; 265 return mid;
220} 266}
221 267
268static void
269smb2_revert_current_mid(struct TCP_Server_Info *server, const unsigned int val)
270{
271 spin_lock(&GlobalMid_Lock);
272 if (server->CurrentMid >= val)
273 server->CurrentMid -= val;
274 spin_unlock(&GlobalMid_Lock);
275}
276
222static struct mid_q_entry * 277static struct mid_q_entry *
223smb2_find_mid(struct TCP_Server_Info *server, char *buf) 278smb2_find_mid(struct TCP_Server_Info *server, char *buf)
224{ 279{
@@ -940,6 +995,16 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
940 resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; 995 resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
941 memset(rsp_iov, 0, sizeof(rsp_iov)); 996 memset(rsp_iov, 0, sizeof(rsp_iov));
942 997
998 if (ses->server->ops->query_all_EAs) {
999 if (!ea_value) {
1000 rc = ses->server->ops->query_all_EAs(xid, tcon, path,
1001 ea_name, NULL, 0,
1002 cifs_sb);
1003 if (rc == -ENODATA)
1004 goto sea_exit;
1005 }
1006 }
1007
943 /* Open */ 1008 /* Open */
944 memset(&open_iov, 0, sizeof(open_iov)); 1009 memset(&open_iov, 0, sizeof(open_iov));
945 rqst[0].rq_iov = open_iov; 1010 rqst[0].rq_iov = open_iov;
@@ -1753,14 +1818,14 @@ smb2_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
1753* the number of credits and return true. Otherwise - return false. 1818* the number of credits and return true. Otherwise - return false.
1754*/ 1819*/
1755static bool 1820static bool
1756smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length) 1821smb2_is_status_pending(char *buf, struct TCP_Server_Info *server)
1757{ 1822{
1758 struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf; 1823 struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
1759 1824
1760 if (shdr->Status != STATUS_PENDING) 1825 if (shdr->Status != STATUS_PENDING)
1761 return false; 1826 return false;
1762 1827
1763 if (!length) { 1828 if (shdr->CreditRequest) {
1764 spin_lock(&server->req_lock); 1829 spin_lock(&server->req_lock);
1765 server->credits += le16_to_cpu(shdr->CreditRequest); 1830 server->credits += le16_to_cpu(shdr->CreditRequest);
1766 spin_unlock(&server->req_lock); 1831 spin_unlock(&server->req_lock);
@@ -2595,6 +2660,15 @@ smb2_downgrade_oplock(struct TCP_Server_Info *server,
2595} 2660}
2596 2661
2597static void 2662static void
2663smb21_downgrade_oplock(struct TCP_Server_Info *server,
2664 struct cifsInodeInfo *cinode, bool set_level2)
2665{
2666 server->ops->set_oplock_level(cinode,
2667 set_level2 ? SMB2_LEASE_READ_CACHING_HE :
2668 0, 0, NULL);
2669}
2670
2671static void
2598smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock, 2672smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
2599 unsigned int epoch, bool *purge_cache) 2673 unsigned int epoch, bool *purge_cache)
2600{ 2674{
@@ -3210,15 +3284,15 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
3210 } 3284 }
3211 3285
3212 if (server->ops->is_status_pending && 3286 if (server->ops->is_status_pending &&
3213 server->ops->is_status_pending(buf, server, 0)) 3287 server->ops->is_status_pending(buf, server))
3214 return -1; 3288 return -1;
3215 3289
3216 /* set up first two iov to get credits */ 3290 /* set up first two iov to get credits */
3217 rdata->iov[0].iov_base = buf; 3291 rdata->iov[0].iov_base = buf;
3218 rdata->iov[0].iov_len = 4; 3292 rdata->iov[0].iov_len = 0;
3219 rdata->iov[1].iov_base = buf + 4; 3293 rdata->iov[1].iov_base = buf;
3220 rdata->iov[1].iov_len = 3294 rdata->iov[1].iov_len =
3221 min_t(unsigned int, buf_len, server->vals->read_rsp_size) - 4; 3295 min_t(unsigned int, buf_len, server->vals->read_rsp_size);
3222 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n", 3296 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
3223 rdata->iov[0].iov_base, rdata->iov[0].iov_len); 3297 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
3224 cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n", 3298 cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
@@ -3541,6 +3615,7 @@ struct smb_version_operations smb20_operations = {
3541 .get_credits = smb2_get_credits, 3615 .get_credits = smb2_get_credits,
3542 .wait_mtu_credits = cifs_wait_mtu_credits, 3616 .wait_mtu_credits = cifs_wait_mtu_credits,
3543 .get_next_mid = smb2_get_next_mid, 3617 .get_next_mid = smb2_get_next_mid,
3618 .revert_current_mid = smb2_revert_current_mid,
3544 .read_data_offset = smb2_read_data_offset, 3619 .read_data_offset = smb2_read_data_offset,
3545 .read_data_length = smb2_read_data_length, 3620 .read_data_length = smb2_read_data_length,
3546 .map_error = map_smb2_to_linux_error, 3621 .map_error = map_smb2_to_linux_error,
@@ -3635,7 +3710,9 @@ struct smb_version_operations smb21_operations = {
3635 .get_credits_field = smb2_get_credits_field, 3710 .get_credits_field = smb2_get_credits_field,
3636 .get_credits = smb2_get_credits, 3711 .get_credits = smb2_get_credits,
3637 .wait_mtu_credits = smb2_wait_mtu_credits, 3712 .wait_mtu_credits = smb2_wait_mtu_credits,
3713 .adjust_credits = smb2_adjust_credits,
3638 .get_next_mid = smb2_get_next_mid, 3714 .get_next_mid = smb2_get_next_mid,
3715 .revert_current_mid = smb2_revert_current_mid,
3639 .read_data_offset = smb2_read_data_offset, 3716 .read_data_offset = smb2_read_data_offset,
3640 .read_data_length = smb2_read_data_length, 3717 .read_data_length = smb2_read_data_length,
3641 .map_error = map_smb2_to_linux_error, 3718 .map_error = map_smb2_to_linux_error,
@@ -3646,7 +3723,7 @@ struct smb_version_operations smb21_operations = {
3646 .print_stats = smb2_print_stats, 3723 .print_stats = smb2_print_stats,
3647 .is_oplock_break = smb2_is_valid_oplock_break, 3724 .is_oplock_break = smb2_is_valid_oplock_break,
3648 .handle_cancelled_mid = smb2_handle_cancelled_mid, 3725 .handle_cancelled_mid = smb2_handle_cancelled_mid,
3649 .downgrade_oplock = smb2_downgrade_oplock, 3726 .downgrade_oplock = smb21_downgrade_oplock,
3650 .need_neg = smb2_need_neg, 3727 .need_neg = smb2_need_neg,
3651 .negotiate = smb2_negotiate, 3728 .negotiate = smb2_negotiate,
3652 .negotiate_wsize = smb2_negotiate_wsize, 3729 .negotiate_wsize = smb2_negotiate_wsize,
@@ -3731,7 +3808,9 @@ struct smb_version_operations smb30_operations = {
3731 .get_credits_field = smb2_get_credits_field, 3808 .get_credits_field = smb2_get_credits_field,
3732 .get_credits = smb2_get_credits, 3809 .get_credits = smb2_get_credits,
3733 .wait_mtu_credits = smb2_wait_mtu_credits, 3810 .wait_mtu_credits = smb2_wait_mtu_credits,
3811 .adjust_credits = smb2_adjust_credits,
3734 .get_next_mid = smb2_get_next_mid, 3812 .get_next_mid = smb2_get_next_mid,
3813 .revert_current_mid = smb2_revert_current_mid,
3735 .read_data_offset = smb2_read_data_offset, 3814 .read_data_offset = smb2_read_data_offset,
3736 .read_data_length = smb2_read_data_length, 3815 .read_data_length = smb2_read_data_length,
3737 .map_error = map_smb2_to_linux_error, 3816 .map_error = map_smb2_to_linux_error,
@@ -3743,7 +3822,7 @@ struct smb_version_operations smb30_operations = {
3743 .dump_share_caps = smb2_dump_share_caps, 3822 .dump_share_caps = smb2_dump_share_caps,
3744 .is_oplock_break = smb2_is_valid_oplock_break, 3823 .is_oplock_break = smb2_is_valid_oplock_break,
3745 .handle_cancelled_mid = smb2_handle_cancelled_mid, 3824 .handle_cancelled_mid = smb2_handle_cancelled_mid,
3746 .downgrade_oplock = smb2_downgrade_oplock, 3825 .downgrade_oplock = smb21_downgrade_oplock,
3747 .need_neg = smb2_need_neg, 3826 .need_neg = smb2_need_neg,
3748 .negotiate = smb2_negotiate, 3827 .negotiate = smb2_negotiate,
3749 .negotiate_wsize = smb3_negotiate_wsize, 3828 .negotiate_wsize = smb3_negotiate_wsize,
@@ -3836,7 +3915,9 @@ struct smb_version_operations smb311_operations = {
3836 .get_credits_field = smb2_get_credits_field, 3915 .get_credits_field = smb2_get_credits_field,
3837 .get_credits = smb2_get_credits, 3916 .get_credits = smb2_get_credits,
3838 .wait_mtu_credits = smb2_wait_mtu_credits, 3917 .wait_mtu_credits = smb2_wait_mtu_credits,
3918 .adjust_credits = smb2_adjust_credits,
3839 .get_next_mid = smb2_get_next_mid, 3919 .get_next_mid = smb2_get_next_mid,
3920 .revert_current_mid = smb2_revert_current_mid,
3840 .read_data_offset = smb2_read_data_offset, 3921 .read_data_offset = smb2_read_data_offset,
3841 .read_data_length = smb2_read_data_length, 3922 .read_data_length = smb2_read_data_length,
3842 .map_error = map_smb2_to_linux_error, 3923 .map_error = map_smb2_to_linux_error,
@@ -3848,7 +3929,7 @@ struct smb_version_operations smb311_operations = {
3848 .dump_share_caps = smb2_dump_share_caps, 3929 .dump_share_caps = smb2_dump_share_caps,
3849 .is_oplock_break = smb2_is_valid_oplock_break, 3930 .is_oplock_break = smb2_is_valid_oplock_break,
3850 .handle_cancelled_mid = smb2_handle_cancelled_mid, 3931 .handle_cancelled_mid = smb2_handle_cancelled_mid,
3851 .downgrade_oplock = smb2_downgrade_oplock, 3932 .downgrade_oplock = smb21_downgrade_oplock,
3852 .need_neg = smb2_need_neg, 3933 .need_neg = smb2_need_neg,
3853 .negotiate = smb2_negotiate, 3934 .negotiate = smb2_negotiate,
3854 .negotiate_wsize = smb3_negotiate_wsize, 3935 .negotiate_wsize = smb3_negotiate_wsize,