From ce85852b90a214cf577fc1b4f49d99fd7e98784a Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Sat, 17 Mar 2012 09:46:55 +0300 Subject: [PATCH 01/10] CIFS: Fix a spurious error in cifs_push_posix_locks Signed-off-by: Pavel Shilovsky Reviewed-by: Jeff Layton Reported-by: Ben Hutchings Signed-off-by: Steve French --- fs/cifs/file.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 5e64748a2917..8e02dbd88ae1 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -960,9 +960,9 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) INIT_LIST_HEAD(&locks_to_send); /* - * Allocating count locks is enough because no locks can be added to - * the list while we are holding cinode->lock_mutex that protects - * locking operations of this inode. + * Allocating count locks is enough because no FL_POSIX locks can be + * added to the list while we are holding cinode->lock_mutex that + * protects locking operations of this inode. */ for (; i < count; i++) { lck = kmalloc(sizeof(struct lock_to_push), GFP_KERNEL); @@ -973,18 +973,20 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) list_add_tail(&lck->llist, &locks_to_send); } - i = 0; el = locks_to_send.next; lock_flocks(); cifs_for_each_lock(cfile->dentry->d_inode, before) { - if (el == &locks_to_send) { - /* something is really wrong */ - cERROR(1, "Can't push all brlocks!"); - break; - } flock = *before; if ((flock->fl_flags & FL_POSIX) == 0) continue; + if (el == &locks_to_send) { + /* + * The list ended. We don't have enough allocated + * structures - something is really wrong. + */ + cERROR(1, "Can't push all brlocks!"); + break; + } length = 1 + flock->fl_end - flock->fl_start; if (flock->fl_type == F_RDLCK || flock->fl_type == F_SHLCK) type = CIFS_RDLCK; @@ -996,7 +998,6 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) lck->length = length; lck->type = type; lck->offset = flock->fl_start; - i++; el = el->next; } unlock_flocks(); From 10b9b98e41ba248a899f6175ce96ee91431b6194 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Tue, 20 Mar 2012 12:55:09 +0300 Subject: [PATCH 02/10] CIFS: Respect negotiated MaxMpxCount Some servers sets this value less than 50 that was hardcoded and we lost the connection if when we exceed this limit. Fix this by respecting this value - not sending more than the server allows. Cc: stable@kernel.org Reviewed-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 8 ++++---- fs/cifs/cifsglob.h | 10 +++------- fs/cifs/cifssmb.c | 9 +++++++-- fs/cifs/connect.c | 11 ++++------- fs/cifs/dir.c | 6 ++++-- fs/cifs/file.c | 4 ++-- fs/cifs/transport.c | 4 ++-- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index b1fd382d1952..6ee1cb45ca0d 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -76,7 +76,7 @@ MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 " unsigned int cifs_max_pending = CIFS_MAX_REQ; module_param(cifs_max_pending, int, 0444); MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. " - "Default: 50 Range: 2 to 256"); + "Default: 32767 Range: 2 to 32767."); unsigned short echo_retries = 5; module_param(echo_retries, ushort, 0644); MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and " @@ -1116,9 +1116,9 @@ init_cifs(void) if (cifs_max_pending < 2) { cifs_max_pending = 2; cFYI(1, "cifs_max_pending set to min of 2"); - } else if (cifs_max_pending > 256) { - cifs_max_pending = 256; - cFYI(1, "cifs_max_pending set to max of 256"); + } else if (cifs_max_pending > CIFS_MAX_REQ) { + cifs_max_pending = CIFS_MAX_REQ; + cFYI(1, "cifs_max_pending set to max of %u", CIFS_MAX_REQ); } rc = cifs_fscache_register(); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 76e7d8b6da17..d47d20aac670 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -55,14 +55,9 @@ /* * MAX_REQ is the maximum number of requests that WE will send - * on one socket concurrently. It also matches the most common - * value of max multiplex returned by servers. We may - * eventually want to use the negotiated value (in case - * future servers can handle more) when we are more confident that - * we will not have problems oveloading the socket with pending - * write data. + * on one socket concurrently. */ -#define CIFS_MAX_REQ 50 +#define CIFS_MAX_REQ 32767 #define RFC1001_NAME_LEN 15 #define RFC1001_NAME_LEN_WITH_NULL (RFC1001_NAME_LEN + 1) @@ -263,6 +258,7 @@ struct TCP_Server_Info { bool session_estab; /* mark when very first sess is established */ u16 dialect; /* dialect index that server chose */ enum securityEnum secType; + bool oplocks:1; /* enable oplocks */ unsigned int maxReq; /* Clients should submit no more */ /* than maxReq distinct unanswered SMBs to the server when using */ /* multiplexed reads or writes */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 8b7794c31591..cd66b76e3282 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -458,7 +458,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses) goto neg_err_exit; } server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode); - server->maxReq = le16_to_cpu(rsp->MaxMpxCount); + server->maxReq = min_t(unsigned int, + le16_to_cpu(rsp->MaxMpxCount), + cifs_max_pending); + server->oplocks = server->maxReq > 1 ? enable_oplocks : false; server->maxBuf = le16_to_cpu(rsp->MaxBufSize); server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); /* even though we do not use raw we might as well set this @@ -564,7 +567,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses) /* one byte, so no need to convert this or EncryptionKeyLen from little endian */ - server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); + server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount), + cifs_max_pending); + server->oplocks = server->maxReq > 1 ? enable_oplocks : false; /* probably no need to store and check maxvcs */ server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize); server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 602f77c304c9..03f71fb40a8a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -642,14 +642,10 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server) spin_unlock(&GlobalMid_Lock); wake_up_all(&server->response_q); - /* - * Check if we have blocked requests that need to free. Note that - * cifs_max_pending is normally 50, but can be set at module install - * time to as little as two. - */ + /* Check if we have blocked requests that need to free. */ spin_lock(&GlobalMid_Lock); - if (atomic_read(&server->inFlight) >= cifs_max_pending) - atomic_set(&server->inFlight, cifs_max_pending - 1); + if (atomic_read(&server->inFlight) >= server->maxReq) + atomic_set(&server->inFlight, server->maxReq - 1); /* * We do not want to set the max_pending too low or we could end up * with the counter going negative. @@ -1910,6 +1906,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) tcp_ses->noautotune = volume_info->noautotune; tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay; atomic_set(&tcp_ses->inFlight, 0); + tcp_ses->maxReq = 1; /* enough to send negotiate request */ init_waitqueue_head(&tcp_ses->response_q); init_waitqueue_head(&tcp_ses->request_q); INIT_LIST_HEAD(&tcp_ses->pending_mid_q); diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index bc7e24420ac0..d172c8ed9017 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -171,7 +171,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, } tcon = tlink_tcon(tlink); - if (enable_oplocks) + if (tcon->ses->server->oplocks) oplock = REQ_OPLOCK; if (nd) @@ -492,7 +492,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, { int xid; int rc = 0; /* to get around spurious gcc warning, set to zero here */ - __u32 oplock = enable_oplocks ? REQ_OPLOCK : 0; + __u32 oplock; __u16 fileHandle = 0; bool posix_open = false; struct cifs_sb_info *cifs_sb; @@ -518,6 +518,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, } pTcon = tlink_tcon(tlink); + oplock = pTcon->ses->server->oplocks ? REQ_OPLOCK : 0; + /* * Don't allow the separator character in a path component. * The VFS will not allow "/", but "\" is allowed by posix. diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 8e02dbd88ae1..159fcc56dc2d 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -380,7 +380,7 @@ int cifs_open(struct inode *inode, struct file *file) cFYI(1, "inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags, full_path); - if (enable_oplocks) + if (tcon->ses->server->oplocks) oplock = REQ_OPLOCK; else oplock = 0; @@ -505,7 +505,7 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush) cFYI(1, "inode = 0x%p file flags 0x%x for %s", inode, pCifsFile->f_flags, full_path); - if (enable_oplocks) + if (tcon->ses->server->oplocks) oplock = REQ_OPLOCK; else oplock = 0; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0cc9584f5889..99a27cfa6cd2 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -265,12 +265,12 @@ static int wait_for_free_request(struct TCP_Server_Info *server, spin_lock(&GlobalMid_Lock); while (1) { - if (atomic_read(&server->inFlight) >= cifs_max_pending) { + if (atomic_read(&server->inFlight) >= server->maxReq) { spin_unlock(&GlobalMid_Lock); cifs_num_waiters_inc(server); wait_event(server->request_q, atomic_read(&server->inFlight) - < cifs_max_pending); + < server->maxReq); cifs_num_waiters_dec(server); spin_lock(&GlobalMid_Lock); } else { From 1daaae8fa4afe3df78ca34e724ed7e8187e4eb32 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 21 Mar 2012 06:30:40 -0400 Subject: [PATCH 03/10] cifs: fix issue mounting of DFS ROOT when redirecting from one domain controller to the next This patch fixes an issue when cifs_mount receives a STATUS_BAD_NETWORK_NAME error during cifs_get_tcon but is able to continue after an DFS ROOT referral. In this case, the return code variable is not reset prior to trying to mount from the system referred to. Thus, is_path_accessible is not executed and the final DFS referral is not performed causing a mount error. Use case: In DNS, example.com resolves to the secondary AD server ad2.example.com Our primary domain controller is ad1.example.com and has a DFS redirection set up from \\ad1\share\Users to \\files\share\Users. Mounting \\example.com\share\Users fails. Regression introduced by commit 724d9f1. Cc: stable@vger.kernel.org Reviewed-by: Pavel Shilovsky Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/connect.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 03f71fb40a8a..0ac595c8c262 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3368,7 +3368,7 @@ cifs_ra_pages(struct cifs_sb_info *cifs_sb) int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) { - int rc = 0; + int rc; int xid; struct cifs_ses *pSesInfo; struct cifs_tcon *tcon; @@ -3395,6 +3395,7 @@ try_mount_again: FreeXid(xid); } #endif + rc = 0; tcon = NULL; pSesInfo = NULL; srvTcp = NULL; From fc40f9cf828908e91d9af820e9300a9d42fbbd72 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Fri, 17 Feb 2012 17:09:12 +0300 Subject: [PATCH 04/10] CIFS: Simplify inFlight logic by making it as unsigned integer and surround access with req_lock from server structure. Reviewed-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 3 +-- fs/cifs/cifsglob.h | 21 ++++++++++++++++++++- fs/cifs/cifssmb.c | 6 +++--- fs/cifs/connect.c | 10 +++++----- fs/cifs/transport.c | 45 ++++++++++++++++++++++---------------------- 5 files changed, 52 insertions(+), 33 deletions(-) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 24b3dfc05282..573b899b5a5d 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -171,8 +171,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) seq_printf(m, "TCP status: %d\n\tLocal Users To " "Server: %d SecMode: 0x%x Req On Wire: %d", server->tcpStatus, server->srv_count, - server->sec_mode, - atomic_read(&server->inFlight)); + server->sec_mode, in_flight(server)); #ifdef CONFIG_CIFS_STATS2 seq_printf(m, " In Send: %d In MaxReq Wait: %d", diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index d47d20aac670..fb78bc903887 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -250,7 +250,8 @@ struct TCP_Server_Info { bool noblocksnd; /* use blocking sendmsg */ bool noautotune; /* do not autotune send buf sizes */ bool tcp_nodelay; - atomic_t inFlight; /* number of requests on the wire to server */ + unsigned int in_flight; /* number of requests on the wire to server */ + spinlock_t req_lock; /* protect the value above */ struct mutex srv_mutex; struct task_struct *tsk; char server_GUID[16]; @@ -303,6 +304,24 @@ struct TCP_Server_Info { #endif }; +static inline unsigned int +in_flight(struct TCP_Server_Info *server) +{ + unsigned int num; + spin_lock(&server->req_lock); + num = server->in_flight; + spin_unlock(&server->req_lock); + return num; +} + +static inline void +dec_in_flight(struct TCP_Server_Info *server) +{ + spin_lock(&server->req_lock); + server->in_flight--; + spin_unlock(&server->req_lock); +} + /* * Macros to allow the TCP_Server_Info->net field and related code to drop out * when CONFIG_NET_NS isn't set. diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index cd66b76e3282..d7cbcfa21a0c 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -721,7 +721,7 @@ cifs_echo_callback(struct mid_q_entry *mid) struct TCP_Server_Info *server = mid->callback_data; DeleteMidQEntry(mid); - atomic_dec(&server->inFlight); + dec_in_flight(server); wake_up(&server->request_q); } @@ -1674,7 +1674,7 @@ cifs_readv_callback(struct mid_q_entry *mid) queue_work(system_nrt_wq, &rdata->work); DeleteMidQEntry(mid); - atomic_dec(&server->inFlight); + dec_in_flight(server); wake_up(&server->request_q); } @@ -2115,7 +2115,7 @@ cifs_writev_callback(struct mid_q_entry *mid) queue_work(system_nrt_wq, &wdata->work); DeleteMidQEntry(mid); - atomic_dec(&tcon->ses->server->inFlight); + dec_in_flight(tcon->ses->server); wake_up(&tcon->ses->server->request_q); } diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 0ac595c8c262..ed91abcce8a9 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -643,14 +643,14 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server) wake_up_all(&server->response_q); /* Check if we have blocked requests that need to free. */ - spin_lock(&GlobalMid_Lock); - if (atomic_read(&server->inFlight) >= server->maxReq) - atomic_set(&server->inFlight, server->maxReq - 1); + spin_lock(&server->req_lock); + if (server->in_flight >= server->maxReq) + server->in_flight = server->maxReq - 1; /* * We do not want to set the max_pending too low or we could end up * with the counter going negative. */ - spin_unlock(&GlobalMid_Lock); + spin_unlock(&server->req_lock); /* * Although there should not be any requests blocked on this queue it * can not hurt to be paranoid and try to wake up requests that may @@ -1905,7 +1905,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) tcp_ses->noblocksnd = volume_info->noblocksnd; tcp_ses->noautotune = volume_info->noautotune; tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay; - atomic_set(&tcp_ses->inFlight, 0); + tcp_ses->in_flight = 0; tcp_ses->maxReq = 1; /* enough to send negotiate request */ init_waitqueue_head(&tcp_ses->response_q); init_waitqueue_head(&tcp_ses->request_q); diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 99a27cfa6cd2..e2673aa34381 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -254,28 +254,29 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer, return smb_sendv(server, &iov, 1); } -static int wait_for_free_request(struct TCP_Server_Info *server, - const int long_op) +static int +wait_for_free_request(struct TCP_Server_Info *server, const int long_op) { + spin_lock(&server->req_lock); + if (long_op == CIFS_ASYNC_OP) { /* oplock breaks must not be held up */ - atomic_inc(&server->inFlight); + server->in_flight++; + spin_unlock(&server->req_lock); return 0; } - spin_lock(&GlobalMid_Lock); while (1) { - if (atomic_read(&server->inFlight) >= server->maxReq) { - spin_unlock(&GlobalMid_Lock); + if (server->in_flight >= server->maxReq) { + spin_unlock(&server->req_lock); cifs_num_waiters_inc(server); wait_event(server->request_q, - atomic_read(&server->inFlight) - < server->maxReq); + in_flight(server) < server->maxReq); cifs_num_waiters_dec(server); - spin_lock(&GlobalMid_Lock); + spin_lock(&server->req_lock); } else { if (server->tcpStatus == CifsExiting) { - spin_unlock(&GlobalMid_Lock); + spin_unlock(&server->req_lock); return -ENOENT; } @@ -284,8 +285,8 @@ static int wait_for_free_request(struct TCP_Server_Info *server, /* update # of requests on the wire to server */ if (long_op != CIFS_BLOCKING_OP) - atomic_inc(&server->inFlight); - spin_unlock(&GlobalMid_Lock); + server->in_flight++; + spin_unlock(&server->req_lock); break; } } @@ -359,7 +360,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, mid = AllocMidQEntry(hdr, server); if (mid == NULL) { mutex_unlock(&server->srv_mutex); - atomic_dec(&server->inFlight); + dec_in_flight(server); wake_up(&server->request_q); return -ENOMEM; } @@ -392,7 +393,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, return rc; out_err: delete_mid(mid); - atomic_dec(&server->inFlight); + dec_in_flight(server); wake_up(&server->request_q); return rc; } @@ -564,7 +565,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, mutex_unlock(&ses->server->srv_mutex); cifs_small_buf_release(in_buf); /* Update # of requests on wire to server */ - atomic_dec(&ses->server->inFlight); + dec_in_flight(ses->server); wake_up(&ses->server->request_q); return rc; } @@ -601,7 +602,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, midQ->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); cifs_small_buf_release(in_buf); - atomic_dec(&ses->server->inFlight); + dec_in_flight(ses->server); wake_up(&ses->server->request_q); return rc; } @@ -612,7 +613,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) { - atomic_dec(&ses->server->inFlight); + dec_in_flight(ses->server); wake_up(&ses->server->request_q); return rc; } @@ -637,7 +638,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, midQ->resp_buf = NULL; out: delete_mid(midQ); - atomic_dec(&ses->server->inFlight); + dec_in_flight(ses->server); wake_up(&ses->server->request_q); return rc; @@ -688,7 +689,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, if (rc) { mutex_unlock(&ses->server->srv_mutex); /* Update # of requests on wire to server */ - atomic_dec(&ses->server->inFlight); + dec_in_flight(ses->server); wake_up(&ses->server->request_q); return rc; } @@ -721,7 +722,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, /* no longer considered to be "in-flight" */ midQ->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); - atomic_dec(&ses->server->inFlight); + dec_in_flight(ses->server); wake_up(&ses->server->request_q); return rc; } @@ -730,7 +731,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) { - atomic_dec(&ses->server->inFlight); + dec_in_flight(ses->server); wake_up(&ses->server->request_q); return rc; } @@ -747,7 +748,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, rc = cifs_check_receive(midQ, ses->server, 0); out: delete_mid(midQ); - atomic_dec(&ses->server->inFlight); + dec_in_flight(ses->server); wake_up(&ses->server->request_q); return rc; From 2d86dbc97094ea4cfc2204fdefd7d07685496189 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Mon, 6 Feb 2012 15:59:18 +0400 Subject: [PATCH 05/10] CIFS: Introduce credit-based flow control and send no more than credits value requests at once. For SMB/CIFS it's trivial: increment this value by receiving any message and decrement by sending one. Reviewed-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 11 +++++++---- fs/cifs/cifsproto.h | 3 +++ fs/cifs/cifssmb.c | 13 +++++-------- fs/cifs/connect.c | 14 ++++++-------- fs/cifs/misc.c | 19 +++++++++++++++++++ fs/cifs/transport.c | 44 ++++++++++++++++++++------------------------ 6 files changed, 60 insertions(+), 44 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index fb78bc903887..d55de9684df9 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -250,8 +250,9 @@ struct TCP_Server_Info { bool noblocksnd; /* use blocking sendmsg */ bool noautotune; /* do not autotune send buf sizes */ bool tcp_nodelay; + int credits; /* send no more requests at once */ unsigned int in_flight; /* number of requests on the wire to server */ - spinlock_t req_lock; /* protect the value above */ + spinlock_t req_lock; /* protect the two values above */ struct mutex srv_mutex; struct task_struct *tsk; char server_GUID[16]; @@ -314,12 +315,14 @@ in_flight(struct TCP_Server_Info *server) return num; } -static inline void -dec_in_flight(struct TCP_Server_Info *server) +static inline bool +has_credits(struct TCP_Server_Info *server) { + int num; spin_lock(&server->req_lock); - server->in_flight--; + num = server->credits; spin_unlock(&server->req_lock); + return num > 0; } /* diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 6f4e243e0f62..47a769e535b1 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -88,6 +88,9 @@ extern int SendReceiveBlockingLock(const unsigned int xid, struct smb_hdr *in_buf , struct smb_hdr *out_buf, int *bytes_returned); +extern void cifs_add_credits(struct TCP_Server_Info *server, + const unsigned int add); +extern void cifs_set_credits(struct TCP_Server_Info *server, const int val); extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length); extern bool is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index d7cbcfa21a0c..70aac35c398f 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -461,7 +461,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses) server->maxReq = min_t(unsigned int, le16_to_cpu(rsp->MaxMpxCount), cifs_max_pending); - server->oplocks = server->maxReq > 1 ? enable_oplocks : false; + cifs_set_credits(server, server->maxReq); server->maxBuf = le16_to_cpu(rsp->MaxBufSize); server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); /* even though we do not use raw we might as well set this @@ -569,7 +569,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses) little endian */ server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount), cifs_max_pending); - server->oplocks = server->maxReq > 1 ? enable_oplocks : false; + cifs_set_credits(server, server->maxReq); /* probably no need to store and check maxvcs */ server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize); server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); @@ -721,8 +721,7 @@ cifs_echo_callback(struct mid_q_entry *mid) struct TCP_Server_Info *server = mid->callback_data; DeleteMidQEntry(mid); - dec_in_flight(server); - wake_up(&server->request_q); + cifs_add_credits(server, 1); } int @@ -1674,8 +1673,7 @@ cifs_readv_callback(struct mid_q_entry *mid) queue_work(system_nrt_wq, &rdata->work); DeleteMidQEntry(mid); - dec_in_flight(server); - wake_up(&server->request_q); + cifs_add_credits(server, 1); } /* cifs_async_readv - send an async write, and set up mid to handle result */ @@ -2115,8 +2113,7 @@ cifs_writev_callback(struct mid_q_entry *mid) queue_work(system_nrt_wq, &wdata->work); DeleteMidQEntry(mid); - dec_in_flight(tcon->ses->server); - wake_up(&tcon->ses->server->request_q); + cifs_add_credits(tcon->ses->server, 1); } /* cifs_async_writev - send an async write, and set up mid to handle result */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index ed91abcce8a9..1d489010615b 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -642,14 +642,10 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server) spin_unlock(&GlobalMid_Lock); wake_up_all(&server->response_q); - /* Check if we have blocked requests that need to free. */ + /* check if we have blocked requests that need to free */ spin_lock(&server->req_lock); - if (server->in_flight >= server->maxReq) - server->in_flight = server->maxReq - 1; - /* - * We do not want to set the max_pending too low or we could end up - * with the counter going negative. - */ + if (server->credits <= 0) + server->credits = 1; spin_unlock(&server->req_lock); /* * Although there should not be any requests blocked on this queue it @@ -1906,7 +1902,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) tcp_ses->noautotune = volume_info->noautotune; tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay; tcp_ses->in_flight = 0; - tcp_ses->maxReq = 1; /* enough to send negotiate request */ + tcp_ses->credits = 1; init_waitqueue_head(&tcp_ses->response_q); init_waitqueue_head(&tcp_ses->request_q); INIT_LIST_HEAD(&tcp_ses->pending_mid_q); @@ -3757,9 +3753,11 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses) if (server->maxBuf != 0) return 0; + cifs_set_credits(server, 1); rc = CIFSSMBNegotiate(xid, ses); if (rc == -EAGAIN) { /* retry only once on 1st time connection */ + cifs_set_credits(server, 1); rc = CIFSSMBNegotiate(xid, ses); if (rc == -EAGAIN) rc = -EHOSTDOWN; diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 703ef5c6fdb1..c273c12de98e 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -690,3 +690,22 @@ backup_cred(struct cifs_sb_info *cifs_sb) return false; } + +void +cifs_add_credits(struct TCP_Server_Info *server, const unsigned int add) +{ + spin_lock(&server->req_lock); + server->credits += add; + server->in_flight--; + spin_unlock(&server->req_lock); + wake_up(&server->request_q); +} + +void +cifs_set_credits(struct TCP_Server_Info *server, const int val) +{ + spin_lock(&server->req_lock); + server->credits = val; + server->oplocks = val > 1 ? enable_oplocks : false; + spin_unlock(&server->req_lock); +} diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index e2673aa34381..e5202ddef2fb 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -262,16 +262,16 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op) if (long_op == CIFS_ASYNC_OP) { /* oplock breaks must not be held up */ server->in_flight++; + server->credits--; spin_unlock(&server->req_lock); return 0; } while (1) { - if (server->in_flight >= server->maxReq) { + if (server->credits <= 0) { spin_unlock(&server->req_lock); cifs_num_waiters_inc(server); - wait_event(server->request_q, - in_flight(server) < server->maxReq); + wait_event(server->request_q, has_credits(server)); cifs_num_waiters_dec(server); spin_lock(&server->req_lock); } else { @@ -280,12 +280,16 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op) return -ENOENT; } - /* can not count locking commands against total - as they are allowed to block on server */ + /* + * Can not count locking commands against total + * as they are allowed to block on server. + */ /* update # of requests on the wire to server */ - if (long_op != CIFS_BLOCKING_OP) + if (long_op != CIFS_BLOCKING_OP) { + server->credits--; server->in_flight++; + } spin_unlock(&server->req_lock); break; } @@ -360,7 +364,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, mid = AllocMidQEntry(hdr, server); if (mid == NULL) { mutex_unlock(&server->srv_mutex); - dec_in_flight(server); + cifs_add_credits(server, 1); wake_up(&server->request_q); return -ENOMEM; } @@ -393,7 +397,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, return rc; out_err: delete_mid(mid); - dec_in_flight(server); + cifs_add_credits(server, 1); wake_up(&server->request_q); return rc; } @@ -565,8 +569,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, mutex_unlock(&ses->server->srv_mutex); cifs_small_buf_release(in_buf); /* Update # of requests on wire to server */ - dec_in_flight(ses->server); - wake_up(&ses->server->request_q); + cifs_add_credits(ses->server, 1); return rc; } rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); @@ -602,8 +605,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, midQ->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); cifs_small_buf_release(in_buf); - dec_in_flight(ses->server); - wake_up(&ses->server->request_q); + cifs_add_credits(ses->server, 1); return rc; } spin_unlock(&GlobalMid_Lock); @@ -613,8 +615,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) { - dec_in_flight(ses->server); - wake_up(&ses->server->request_q); + cifs_add_credits(ses->server, 1); return rc; } @@ -638,8 +639,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, midQ->resp_buf = NULL; out: delete_mid(midQ); - dec_in_flight(ses->server); - wake_up(&ses->server->request_q); + cifs_add_credits(ses->server, 1); return rc; } @@ -689,8 +689,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, if (rc) { mutex_unlock(&ses->server->srv_mutex); /* Update # of requests on wire to server */ - dec_in_flight(ses->server); - wake_up(&ses->server->request_q); + cifs_add_credits(ses->server, 1); return rc; } @@ -722,8 +721,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, /* no longer considered to be "in-flight" */ midQ->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); - dec_in_flight(ses->server); - wake_up(&ses->server->request_q); + cifs_add_credits(ses->server, 1); return rc; } spin_unlock(&GlobalMid_Lock); @@ -731,8 +729,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) { - dec_in_flight(ses->server); - wake_up(&ses->server->request_q); + cifs_add_credits(ses->server, 1); return rc; } @@ -748,8 +745,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, rc = cifs_check_receive(midQ, ses->server, 0); out: delete_mid(midQ); - dec_in_flight(ses->server); - wake_up(&ses->server->request_q); + cifs_add_credits(ses->server, 1); return rc; } From 5bc594982f49220d33e927e3c9e028bf87b4745c Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Tue, 21 Feb 2012 19:56:08 +0300 Subject: [PATCH 06/10] CIFS: Make wait_for_free_request killable to let us kill the proccess if it hangs waiting for a credit when the session is down and echo is disabled. Reviewed-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/transport.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index e5202ddef2fb..58b31da17fc5 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -257,6 +257,8 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer, static int wait_for_free_request(struct TCP_Server_Info *server, const int long_op) { + int rc; + spin_lock(&server->req_lock); if (long_op == CIFS_ASYNC_OP) { @@ -271,8 +273,11 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op) if (server->credits <= 0) { spin_unlock(&server->req_lock); cifs_num_waiters_inc(server); - wait_event(server->request_q, has_credits(server)); + rc = wait_event_killable(server->request_q, + has_credits(server)); cifs_num_waiters_dec(server); + if (rc) + return rc; spin_lock(&server->req_lock); } else { if (server->tcpStatus == CifsExiting) { From bc205ed19bdb56576b291830bc3f752aef5e3923 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Thu, 15 Mar 2012 13:22:27 +0300 Subject: [PATCH 07/10] CIFS: Prepare credits code for a slot reservation that is essential for CIFS/SMB/SMB2 oplock breaks and SMB2 echos. Reviewed-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 14 ++++++++++++-- fs/cifs/transport.c | 22 ++++++++++++++-------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index d55de9684df9..2309a67738bf 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -315,12 +315,22 @@ in_flight(struct TCP_Server_Info *server) return num; } +static inline int* +get_credits_field(struct TCP_Server_Info *server) +{ + /* + * This will change to switch statement when we reserve slots for echos + * and oplock breaks. + */ + return &server->credits; +} + static inline bool -has_credits(struct TCP_Server_Info *server) +has_credits(struct TCP_Server_Info *server, int *credits) { int num; spin_lock(&server->req_lock); - num = server->credits; + num = *credits; spin_unlock(&server->req_lock); return num > 0; } diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 58b31da17fc5..310918b6fcb4 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -255,26 +255,26 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer, } static int -wait_for_free_request(struct TCP_Server_Info *server, const int long_op) +wait_for_free_credits(struct TCP_Server_Info *server, const int optype, + int *credits) { int rc; spin_lock(&server->req_lock); - - if (long_op == CIFS_ASYNC_OP) { + if (optype == CIFS_ASYNC_OP) { /* oplock breaks must not be held up */ server->in_flight++; - server->credits--; + *credits -= 1; spin_unlock(&server->req_lock); return 0; } while (1) { - if (server->credits <= 0) { + if (*credits <= 0) { spin_unlock(&server->req_lock); cifs_num_waiters_inc(server); rc = wait_event_killable(server->request_q, - has_credits(server)); + has_credits(server, credits)); cifs_num_waiters_dec(server); if (rc) return rc; @@ -291,8 +291,8 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op) */ /* update # of requests on the wire to server */ - if (long_op != CIFS_BLOCKING_OP) { - server->credits--; + if (optype != CIFS_BLOCKING_OP) { + *credits -= 1; server->in_flight++; } spin_unlock(&server->req_lock); @@ -302,6 +302,12 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op) return 0; } +static int +wait_for_free_request(struct TCP_Server_Info *server, const int optype) +{ + return wait_for_free_credits(server, optype, get_credits_field(server)); +} + static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, struct mid_q_entry **ppmidQ) { From 6dae51a585008535858c29b489dbf90a913d511b Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Tue, 21 Feb 2012 16:50:23 +0300 Subject: [PATCH 08/10] CIFS: Delete echo_retries module parm It's the essential step before respecting MaxMpxCount value during negotiating because we will keep only one extra slot for sending echo requests. If there is no response during two echo intervals - reconnect the tcp session. Reviewed-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/README | 6 +----- fs/cifs/cifsfs.c | 5 ----- fs/cifs/cifsglob.h | 3 --- fs/cifs/connect.c | 18 ++++++++++++++---- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/fs/cifs/README b/fs/cifs/README index 895da1dc1550..b7d782bab797 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -753,10 +753,6 @@ module loading or during the runtime by using the interface i.e. echo "value" > /sys/module/cifs/parameters/ -1. echo_retries - The number of echo attempts before giving up and - reconnecting to the server. The default is 5. The value 0 - means never reconnect. - -2. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default. +1. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default. [Y/y/1]. To disable use any of [N/n/0]. diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 6ee1cb45ca0d..f2661610fcf3 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -77,11 +77,6 @@ unsigned int cifs_max_pending = CIFS_MAX_REQ; module_param(cifs_max_pending, int, 0444); MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. " "Default: 32767 Range: 2 to 32767."); -unsigned short echo_retries = 5; -module_param(echo_retries, ushort, 0644); -MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and " - "reconnecting server. Default: 5. 0 means " - "never reconnect."); module_param(enable_oplocks, bool, 0644); MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks (bool). Default:" "y/Y/1"); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 2309a67738bf..339ebe3ebc0d 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1038,9 +1038,6 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ -/* reconnect after this many failed echo attempts */ -GLOBAL_EXTERN unsigned short echo_retries; - #ifdef CONFIG_CIFS_ACL GLOBAL_EXTERN struct rb_root uidtree; GLOBAL_EXTERN struct rb_root gidtree; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 1d489010615b..5560e1d5e54b 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -373,12 +373,22 @@ allocate_buffers(struct TCP_Server_Info *server) static bool server_unresponsive(struct TCP_Server_Info *server) { - if (echo_retries > 0 && server->tcpStatus == CifsGood && - time_after(jiffies, server->lstrp + - (echo_retries * SMB_ECHO_INTERVAL))) { + /* + * We need to wait 2 echo intervals to make sure we handle such + * situations right: + * 1s client sends a normal SMB request + * 2s client gets a response + * 30s echo workqueue job pops, and decides we got a response recently + * and don't need to send another + * ... + * 65s kernel_recvmsg times out, and we see that we haven't gotten + * a response in >60s. + */ + if (server->tcpStatus == CifsGood && + time_after(jiffies, server->lstrp + 2 * SMB_ECHO_INTERVAL)) { cERROR(1, "Server %s has not responded in %d seconds. " "Reconnecting...", server->hostname, - (echo_retries * SMB_ECHO_INTERVAL / HZ)); + (2 * SMB_ECHO_INTERVAL) / HZ); cifs_reconnect(server); wake_up(&server->response_q); return true; From 815465c4d724e851932843227b4b700d64216cf2 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 21 Mar 2012 06:27:54 -0400 Subject: [PATCH 09/10] cifs: clean up call to cifs_dfs_release_automount_timer() Take the #ifdef junk out of the code, and turn it into a noop macro when CONFIG_CIFS_DFS_UPCALL isn't defined. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 2 -- fs/cifs/cifsproto.h | 6 ++++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index f2661610fcf3..260025fd8c3b 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -1177,9 +1177,7 @@ exit_cifs(void) cFYI(DBG2, "exit_cifs"); cifs_proc_clean(); cifs_fscache_unregister(); -#ifdef CONFIG_CIFS_DFS_UPCALL cifs_dfs_release_automount_timer(); -#endif #ifdef CONFIG_CIFS_ACL cifs_destroy_idmaptrees(); exit_cifs_idmap(); diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 47a769e535b1..503e73d8bdb7 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -171,7 +171,13 @@ extern struct smb_vol *cifs_get_volume_info(char *mount_data, const char *devname); extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *); extern void cifs_umount(struct cifs_sb_info *); + +#if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) extern void cifs_dfs_release_automount_timer(void); +#else /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */ +#define cifs_dfs_release_automount_timer() do { } while (0) +#endif /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */ + void cifs_proc_init(void); void cifs_proc_clean(void); From 3dd933061d3a4f33fb6ba1616e88fa55a8b8cb9c Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 21 Mar 2012 06:27:55 -0400 Subject: [PATCH 10/10] cifs: clean up ordering in exit_cifs ...ensure that we undo things in the reverse order from the way they were done. In truth, the ordering doesn't matter for a lot of these, but it's still better to do it that way to be sure. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 260025fd8c3b..cc098ccac611 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -1175,8 +1175,7 @@ static void __exit exit_cifs(void) { cFYI(DBG2, "exit_cifs"); - cifs_proc_clean(); - cifs_fscache_unregister(); + unregister_filesystem(&cifs_fs_type); cifs_dfs_release_automount_timer(); #ifdef CONFIG_CIFS_ACL cifs_destroy_idmaptrees(); @@ -1185,10 +1184,11 @@ exit_cifs(void) #ifdef CONFIG_CIFS_UPCALL unregister_key_type(&cifs_spnego_key_type); #endif - unregister_filesystem(&cifs_fs_type); - cifs_destroy_inodecache(); - cifs_destroy_mids(); cifs_destroy_request_bufs(); + cifs_destroy_mids(); + cifs_destroy_inodecache(); + cifs_fscache_unregister(); + cifs_proc_clean(); } MODULE_AUTHOR("Steve French ");