From 433b8dd7672be1140ffbb17eacba776298bf4733 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 26 Mar 2019 13:53:21 -0500 Subject: SMB3: Track total time spent on roundtrips for each SMB3 command Also track minimum and maximum time by command in /proc/fs/cifs/Stats Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'fs/cifs/cifs_debug.c') diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 13c1288b04a7..19ed9abe00de 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -462,8 +462,13 @@ static ssize_t cifs_stats_proc_write(struct file *file, server = list_entry(tmp1, struct TCP_Server_Info, tcp_ses_list); #ifdef CONFIG_CIFS_STATS2 - for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) + for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) { + atomic_set(&server->num_cmds[i], 0); atomic_set(&server->smb2slowcmd[i], 0); + server->time_per_cmd[i] = 0; + server->slowest_cmd[i] = 0; + server->fastest_cmd[0] = 0; + } #endif /* CONFIG_CIFS_STATS2 */ list_for_each(tmp2, &server->smb_ses_list) { ses = list_entry(tmp2, struct cifs_ses, @@ -531,9 +536,19 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v) server = list_entry(tmp1, struct TCP_Server_Info, tcp_ses_list); #ifdef CONFIG_CIFS_STATS2 + seq_puts(m, "\nTotal time spent processing by command. Time "); + seq_printf(m, "units are jiffies (%d per second)\n", HZ); + seq_puts(m, " SMB3 CMD\tNumber\tTotal Time\tFastest\tSlowest\n"); + seq_puts(m, " --------\t------\t----------\t-------\t-------\n"); + for (j = 0; j < NUMBER_OF_SMB2_COMMANDS; j++) + seq_printf(m, " %d\t\t%d\t%llu\t\t%u\t%u\n", j, + atomic_read(&server->num_cmds[j]), + server->time_per_cmd[j], + server->fastest_cmd[j], + server->slowest_cmd[j]); for (j = 0; j < NUMBER_OF_SMB2_COMMANDS; j++) if (atomic_read(&server->smb2slowcmd[j])) - seq_printf(m, "%d slow responses from %s for command %d\n", + seq_printf(m, " %d slow responses from %s for command %d\n", atomic_read(&server->smb2slowcmd[j]), server->hostname, j); #endif /* STATS2 */ -- cgit v1.2.3 From e8b3bfe9bc651acd0338b331fcee3aaafb27caeb Mon Sep 17 00:00:00 2001 From: Long Li Date: Fri, 5 Apr 2019 21:36:31 +0000 Subject: cifs: smbd: Don't destroy transport on RDMA disconnect Now upper layer is handling the transport shutdown and reconnect, remove the code that handling transport shutdown on RDMA disconnect. Signed-off-by: Long Li Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 8 ++-- fs/cifs/smbdirect.c | 120 +++------------------------------------------------ fs/cifs/smbdirect.h | 9 ---- 3 files changed, 10 insertions(+), 127 deletions(-) (limited to 'fs/cifs/cifs_debug.c') diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 19ed9abe00de..5ff0b3d4c484 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -312,12 +312,10 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) atomic_read(&server->smbd_conn->send_credits), atomic_read(&server->smbd_conn->receive_credits), server->smbd_conn->receive_credit_target); - seq_printf(m, "\nPending send_pending: %x send_payload_pending:" - " %x smbd_send_pending: %x smbd_recv_pending: %x", + seq_printf(m, "\nPending send_pending: %x " + "send_payload_pending: %x", atomic_read(&server->smbd_conn->send_pending), - atomic_read(&server->smbd_conn->send_payload_pending), - server->smbd_conn->smbd_send_pending, - server->smbd_conn->smbd_recv_pending); + atomic_read(&server->smbd_conn->send_payload_pending)); seq_printf(m, "\nReceive buffers count_receive_queue: %x " "count_empty_packet_queue: %x", server->smbd_conn->count_receive_queue, diff --git a/fs/cifs/smbdirect.c b/fs/cifs/smbdirect.c index 06449cf19934..72594277f800 100644 --- a/fs/cifs/smbdirect.c +++ b/fs/cifs/smbdirect.c @@ -164,95 +164,6 @@ do { \ #define log_rdma_mr(level, fmt, args...) \ log_rdma(level, LOG_RDMA_MR, fmt, ##args) -/* - * Destroy the transport and related RDMA and memory resources - * Need to go through all the pending counters and make sure on one is using - * the transport while it is destroyed - */ -static void smbd_destroy_rdma_work(struct work_struct *work) -{ - struct smbd_response *response; - struct smbd_connection *info = - container_of(work, struct smbd_connection, destroy_work); - unsigned long flags; - - log_rdma_event(INFO, "destroying qp\n"); - ib_drain_qp(info->id->qp); - rdma_destroy_qp(info->id); - - /* Unblock all I/O waiting on the send queue */ - wake_up_interruptible_all(&info->wait_send_queue); - - log_rdma_event(INFO, "cancelling idle timer\n"); - cancel_delayed_work_sync(&info->idle_timer_work); - log_rdma_event(INFO, "cancelling send immediate work\n"); - cancel_delayed_work_sync(&info->send_immediate_work); - - log_rdma_event(INFO, "wait for all send to finish\n"); - wait_event(info->wait_smbd_send_pending, - info->smbd_send_pending == 0); - - log_rdma_event(INFO, "wait for all recv to finish\n"); - wake_up_interruptible(&info->wait_reassembly_queue); - wait_event(info->wait_smbd_recv_pending, - info->smbd_recv_pending == 0); - - log_rdma_event(INFO, "wait for all send posted to IB to finish\n"); - wait_event(info->wait_send_pending, - atomic_read(&info->send_pending) == 0); - wait_event(info->wait_send_payload_pending, - atomic_read(&info->send_payload_pending) == 0); - - log_rdma_event(INFO, "freeing mr list\n"); - wake_up_interruptible_all(&info->wait_mr); - wait_event(info->wait_for_mr_cleanup, - atomic_read(&info->mr_used_count) == 0); - destroy_mr_list(info); - - /* It's not posssible for upper layer to get to reassembly */ - log_rdma_event(INFO, "drain the reassembly queue\n"); - do { - spin_lock_irqsave(&info->reassembly_queue_lock, flags); - response = _get_first_reassembly(info); - if (response) { - list_del(&response->list); - spin_unlock_irqrestore( - &info->reassembly_queue_lock, flags); - put_receive_buffer(info, response); - } else - spin_unlock_irqrestore(&info->reassembly_queue_lock, flags); - } while (response); - - info->reassembly_data_length = 0; - - log_rdma_event(INFO, "free receive buffers\n"); - wait_event(info->wait_receive_queues, - info->count_receive_queue + info->count_empty_packet_queue - == info->receive_credit_max); - destroy_receive_buffers(info); - - ib_free_cq(info->send_cq); - ib_free_cq(info->recv_cq); - ib_dealloc_pd(info->pd); - rdma_destroy_id(info->id); - - /* free mempools */ - mempool_destroy(info->request_mempool); - kmem_cache_destroy(info->request_cache); - - mempool_destroy(info->response_mempool); - kmem_cache_destroy(info->response_cache); - - info->transport_status = SMBD_DESTROYED; - wake_up_all(&info->wait_destroy); -} - -static int smbd_process_disconnected(struct smbd_connection *info) -{ - schedule_work(&info->destroy_work); - return 0; -} - static void smbd_disconnect_rdma_work(struct work_struct *work) { struct smbd_connection *info = @@ -319,8 +230,7 @@ static int smbd_conn_upcall( } info->transport_status = SMBD_DISCONNECTED; - smbd_process_disconnected(info); - wake_up(&info->disconn_wait); + wake_up_interruptible(&info->disconn_wait); wake_up_interruptible(&info->wait_reassembly_queue); wake_up_interruptible_all(&info->wait_send_queue); break; @@ -1501,7 +1411,7 @@ void smbd_destroy(struct TCP_Server_Info *server) if (info->transport_status != SMBD_DISCONNECTED) { rdma_disconnect(server->smbd_conn->id); log_rdma_event(INFO, "wait for transport being disconnected\n"); - wait_event( + wait_event_interruptible( info->disconn_wait, info->transport_status == SMBD_DISCONNECTED); } @@ -1849,12 +1759,6 @@ static struct smbd_connection *_smbd_get_connection( queue_delayed_work(info->workqueue, &info->idle_timer_work, info->keep_alive_interval*HZ); - init_waitqueue_head(&info->wait_smbd_send_pending); - info->smbd_send_pending = 0; - - init_waitqueue_head(&info->wait_smbd_recv_pending); - info->smbd_recv_pending = 0; - init_waitqueue_head(&info->wait_send_pending); atomic_set(&info->send_pending, 0); @@ -1862,7 +1766,6 @@ static struct smbd_connection *_smbd_get_connection( atomic_set(&info->send_payload_pending, 0); INIT_WORK(&info->disconnect_work, smbd_disconnect_rdma_work); - INIT_WORK(&info->destroy_work, smbd_destroy_rdma_work); INIT_WORK(&info->recv_done_work, smbd_recv_done_work); INIT_WORK(&info->post_send_credits_work, smbd_post_send_credits); info->new_credits_offered = 0; @@ -1956,11 +1859,6 @@ static int smbd_recv_buf(struct smbd_connection *info, char *buf, int rc; again: - if (info->transport_status != SMBD_CONNECTED) { - log_read(ERR, "disconnected\n"); - return -ENODEV; - } - /* * No need to hold the reassembly queue lock all the time as we are * the only one reading from the front of the queue. The transport @@ -2076,6 +1974,11 @@ read_rfc1002_done: if (rc) return -ENODEV; + if (info->transport_status != SMBD_CONNECTED) { + log_read(ERR, "disconnected\n"); + return 0; + } + goto again; } @@ -2126,8 +2029,6 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg) unsigned int to_read, page_offset; int rc; - info->smbd_recv_pending++; - if (iov_iter_rw(&msg->msg_iter) == WRITE) { /* It's a bug in upper layer to get there */ cifs_dbg(VFS, "CIFS: invalid msg iter dir %u\n", @@ -2158,9 +2059,6 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg) } out: - info->smbd_recv_pending--; - wake_up(&info->wait_smbd_recv_pending); - /* SMBDirect will read it all or nothing */ if (rc > 0) msg->msg_iter.count = 0; @@ -2186,7 +2084,6 @@ int smbd_send(struct TCP_Server_Info *server, struct smb_rqst *rqst) struct kvec *iov; int rc; - info->smbd_send_pending++; if (info->transport_status != SMBD_CONNECTED) { rc = -ENODEV; goto done; @@ -2342,9 +2239,6 @@ done: wait_event(info->wait_send_payload_pending, atomic_read(&info->send_payload_pending) == 0); - info->smbd_send_pending--; - wake_up(&info->wait_smbd_send_pending); - return rc; } diff --git a/fs/cifs/smbdirect.h b/fs/cifs/smbdirect.h index 73cc923b953c..a3c7b3d0561e 100644 --- a/fs/cifs/smbdirect.h +++ b/fs/cifs/smbdirect.h @@ -70,13 +70,11 @@ struct smbd_connection { int ri_rc; struct completion ri_done; wait_queue_head_t conn_wait; - wait_queue_head_t wait_destroy; wait_queue_head_t disconn_wait; struct completion negotiate_completion; bool negotiate_done; - struct work_struct destroy_work; struct work_struct disconnect_work; struct work_struct recv_done_work; struct work_struct post_send_credits_work; @@ -124,13 +122,6 @@ struct smbd_connection { wait_queue_head_t wait_for_mr_cleanup; /* Activity accoutning */ - /* Pending reqeusts issued from upper layer */ - int smbd_send_pending; - wait_queue_head_t wait_smbd_send_pending; - - int smbd_recv_pending; - wait_queue_head_t wait_smbd_recv_pending; - atomic_t send_pending; wait_queue_head_t wait_send_pending; atomic_t send_payload_pending; -- cgit v1.2.3 From 26ea888f6282b0f5c1977d8ddb2fff1ea0238bd7 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 26 Apr 2019 20:36:08 -0700 Subject: Negotiate and save preferred compression algorithms New negotiate context (3) allows the server and client to negotiate which compression algorithms to use. Add support for this and save it off in the server structure. Also now displayed in /proc/fs/cifs/DebugData (see below example to Windows 10) where compression algoirthm "LZ77" was negotiated: Servers: Number of credits: 326 Dialect 0x311 COMPRESS_LZ77 signed 1) Name: 192.168.92.17 Uses: 1 Capability: 0x300067 Session Status: 1 TCP status: 1 Instance: 1 See MS-XCA and MS-SMB2 2.2.3.1 for more details. Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg --- fs/cifs/cifs_debug.c | 6 ++++++ fs/cifs/cifsglob.h | 1 + fs/cifs/smb2pdu.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- fs/cifs/smb2pdu.h | 15 +++++++++------ 4 files changed, 61 insertions(+), 7 deletions(-) (limited to 'fs/cifs/cifs_debug.c') diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 5ff0b3d4c484..6a69f11aacf7 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -332,6 +332,12 @@ skip_rdma: #endif seq_printf(m, "\nNumber of credits: %d Dialect 0x%x", server->credits, server->dialect); + if (server->compress_algorithm == SMB3_COMPRESS_LZNT1) + seq_printf(m, " COMPRESS_LZNT1"); + else if (server->compress_algorithm == SMB3_COMPRESS_LZ77) + seq_printf(m, " COMPRESS_LZ77"); + else if (server->compress_algorithm == SMB3_COMPRESS_LZ77_HUFF) + seq_printf(m, " COMPRESS_LZ77_HUFF"); if (server->sign) seq_printf(m, " signed"); if (server->posix_ext_supported) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index c22ab330238c..561f1395eddd 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -734,6 +734,7 @@ struct TCP_Server_Info { #endif /* STATS2 */ unsigned int max_read; unsigned int max_write; + __le16 compress_algorithm; __le16 cipher_type; /* save initital negprot hash */ __u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE]; diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 035a568b3dbd..29f011d8d8e2 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -472,6 +472,19 @@ build_preauth_ctxt(struct smb2_preauth_neg_context *pneg_ctxt) pneg_ctxt->HashAlgorithms = SMB2_PREAUTH_INTEGRITY_SHA512; } +static void +build_compression_ctxt(struct smb2_compression_capabilities_context *pneg_ctxt) +{ + pneg_ctxt->ContextType = SMB2_COMPRESSION_CAPABILITIES; + pneg_ctxt->DataLength = + cpu_to_le16(sizeof(struct smb2_compression_capabilities_context) + - sizeof(struct smb2_neg_context)); + pneg_ctxt->CompressionAlgorithmCount = cpu_to_le16(3); + pneg_ctxt->CompressionAlgorithms[0] = SMB3_COMPRESS_LZ77; + pneg_ctxt->CompressionAlgorithms[1] = SMB3_COMPRESS_LZ77_HUFF; + pneg_ctxt->CompressionAlgorithms[2] = SMB3_COMPRESS_LZNT1; +} + static void build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt) { @@ -538,10 +551,17 @@ assemble_neg_contexts(struct smb2_negotiate_req *req, *total_len += ctxt_len; pneg_ctxt += ctxt_len; + build_compression_ctxt((struct smb2_compression_capabilities_context *) + pneg_ctxt); + ctxt_len = DIV_ROUND_UP( + sizeof(struct smb2_compression_capabilities_context), 8) * 8; + *total_len += ctxt_len; + pneg_ctxt += ctxt_len; + build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt); *total_len += sizeof(struct smb2_posix_neg_context); - req->NegotiateContextCount = cpu_to_le16(3); + req->NegotiateContextCount = cpu_to_le16(4); } static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt) @@ -559,6 +579,27 @@ static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt) printk_once(KERN_WARNING "unknown SMB3 hash algorithm\n"); } +static void decode_compress_ctx(struct TCP_Server_Info *server, + struct smb2_compression_capabilities_context *ctxt) +{ + unsigned int len = le16_to_cpu(ctxt->DataLength); + + /* sizeof compress context is a one element compression capbility struct */ + if (len < 10) { + printk_once(KERN_WARNING "server sent bad compression cntxt\n"); + return; + } + if (le16_to_cpu(ctxt->CompressionAlgorithmCount) != 1) { + printk_once(KERN_WARNING "illegal SMB3 compress algorithm count\n"); + return; + } + if (le16_to_cpu(ctxt->CompressionAlgorithms[0]) > 3) { + printk_once(KERN_WARNING "unknown compression algorithm\n"); + return; + } + server->compress_algorithm = ctxt->CompressionAlgorithms[0]; +} + static int decode_encrypt_ctx(struct TCP_Server_Info *server, struct smb2_encryption_neg_context *ctxt) { @@ -623,6 +664,9 @@ static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp, else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES) rc = decode_encrypt_ctx(server, (struct smb2_encryption_neg_context *)pctx); + else if (pctx->ContextType == SMB2_COMPRESSION_CAPABILITIES) + decode_compress_ctx(server, + (struct smb2_compression_capabilities_context *)pctx); else if (pctx->ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE) server->posix_ext_supported = true; else diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index 93dd3b431585..c7d5813bebd8 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -297,16 +297,19 @@ struct smb2_encryption_neg_context { } __packed; /* See MS-SMB2 2.2.3.1.3 */ -#define SMB3_COMPRESS_NONE 0x0000 -#define SMB3_COMPRESS_LZNT1 0x0001 -#define SMB3_COMPRESS_LZ77 0x0002 -#define SMB3_COMPRESS_LZ77_HUFF 0x0003 +#define SMB3_COMPRESS_NONE cpu_to_le16(0x0000) +#define SMB3_COMPRESS_LZNT1 cpu_to_le16(0x0001) +#define SMB3_COMPRESS_LZ77 cpu_to_le16(0x0002) +#define SMB3_COMPRESS_LZ77_HUFF cpu_to_le16(0x0003) struct smb2_compression_capabilities_context { + __le16 ContextType; /* 3 */ + __le16 DataLength; + __u32 Reserved; __le16 CompressionAlgorithmCount; __u16 Padding; - __u32 Reserved; - __u16 CompressionAlgorithms[1]; + __u32 Reserved1; + __le16 CompressionAlgorithms[3]; } __packed; /* -- cgit v1.2.3