diff options
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/CHANGES | 5 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 6 | ||||
-rw-r--r-- | fs/cifs/connect.c | 40 | ||||
-rw-r--r-- | fs/cifs/file.c | 3 | ||||
-rw-r--r-- | fs/cifs/transport.c | 6 |
5 files changed, 53 insertions, 7 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index bd3b55e1be17..4d2404305ab6 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -1,7 +1,10 @@ | |||
1 | Version 1.34 | 1 | Version 1.34 |
2 | ------------ | 2 | ------------ |
3 | Fix error mapping of the TOO_MANY_LINKS (hardlinks) case. | 3 | Fix error mapping of the TOO_MANY_LINKS (hardlinks) case. |
4 | Do not oops if user kills cifs oplock kernel thread. | 4 | Do not oops if root user kills cifs oplock kernel thread or |
5 | kills the cifsd thread (NB: killing the cifs kernel threads is not | ||
6 | recommended, unmount and rmmod cifs will kill them when they are | ||
7 | no longer needed). | ||
5 | 8 | ||
6 | Version 1.33 | 9 | Version 1.33 |
7 | ------------ | 10 | ------------ |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index f8edf816b4be..b004fef0a42b 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -90,7 +90,8 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
90 | check for tcp and smb session status done differently | 90 | check for tcp and smb session status done differently |
91 | for those three - in the calling routine */ | 91 | for those three - in the calling routine */ |
92 | if(tcon) { | 92 | if(tcon) { |
93 | if((tcon->ses) && (tcon->ses->server)){ | 93 | if((tcon->ses) && (tcon->ses->status != CifsExiting) && |
94 | (tcon->ses->server)){ | ||
94 | struct nls_table *nls_codepage; | 95 | struct nls_table *nls_codepage; |
95 | /* Give Demultiplex thread up to 10 seconds to | 96 | /* Give Demultiplex thread up to 10 seconds to |
96 | reconnect, should be greater than cifs socket | 97 | reconnect, should be greater than cifs socket |
@@ -185,7 +186,8 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
185 | check for tcp and smb session status done differently | 186 | check for tcp and smb session status done differently |
186 | for those three - in the calling routine */ | 187 | for those three - in the calling routine */ |
187 | if(tcon) { | 188 | if(tcon) { |
188 | if((tcon->ses) && (tcon->ses->server)){ | 189 | if((tcon->ses) && (tcon->ses->status != CifsExiting) && |
190 | (tcon->ses->server)){ | ||
189 | struct nls_table *nls_codepage; | 191 | struct nls_table *nls_codepage; |
190 | /* Give Demultiplex thread up to 10 seconds to | 192 | /* Give Demultiplex thread up to 10 seconds to |
191 | reconnect, should be greater than cifs socket | 193 | reconnect, should be greater than cifs socket |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 437be1efe99e..ac1f970e5369 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -604,7 +604,13 @@ multi_t2_fnd: | |||
604 | spin_lock(&GlobalMid_Lock); | 604 | spin_lock(&GlobalMid_Lock); |
605 | server->tcpStatus = CifsExiting; | 605 | server->tcpStatus = CifsExiting; |
606 | server->tsk = NULL; | 606 | server->tsk = NULL; |
607 | atomic_set(&server->inFlight, 0); | 607 | /* check if we have blocked requests that need to free */ |
608 | /* Note that cifs_max_pending is normally 50, but | ||
609 | can be set at module install time to as little as two */ | ||
610 | if(atomic_read(&server->inFlight) >= cifs_max_pending) | ||
611 | atomic_set(&server->inFlight, cifs_max_pending - 1); | ||
612 | /* We do not want to set the max_pending too low or we | ||
613 | could end up with the counter going negative */ | ||
608 | spin_unlock(&GlobalMid_Lock); | 614 | spin_unlock(&GlobalMid_Lock); |
609 | /* Although there should not be any requests blocked on | 615 | /* Although there should not be any requests blocked on |
610 | this queue it can not hurt to be paranoid and try to wake up requests | 616 | this queue it can not hurt to be paranoid and try to wake up requests |
@@ -640,6 +646,17 @@ multi_t2_fnd: | |||
640 | } | 646 | } |
641 | read_unlock(&GlobalSMBSeslock); | 647 | read_unlock(&GlobalSMBSeslock); |
642 | } else { | 648 | } else { |
649 | /* although we can not zero the server struct pointer yet, | ||
650 | since there are active requests which may depnd on them, | ||
651 | mark the corresponding SMB sessions as exiting too */ | ||
652 | list_for_each(tmp, &GlobalSMBSessionList) { | ||
653 | ses = list_entry(tmp, struct cifsSesInfo, | ||
654 | cifsSessionList); | ||
655 | if (ses->server == server) { | ||
656 | ses->status = CifsExiting; | ||
657 | } | ||
658 | } | ||
659 | |||
643 | spin_lock(&GlobalMid_Lock); | 660 | spin_lock(&GlobalMid_Lock); |
644 | list_for_each(tmp, &server->pending_mid_q) { | 661 | list_for_each(tmp, &server->pending_mid_q) { |
645 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | 662 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); |
@@ -661,17 +678,34 @@ multi_t2_fnd: | |||
661 | if (list_empty(&server->pending_mid_q)) { | 678 | if (list_empty(&server->pending_mid_q)) { |
662 | /* mpx threads have not exited yet give them | 679 | /* mpx threads have not exited yet give them |
663 | at least the smb send timeout time for long ops */ | 680 | at least the smb send timeout time for long ops */ |
681 | /* due to delays on oplock break requests, we need | ||
682 | to wait at least 45 seconds before giving up | ||
683 | on a request getting a response and going ahead | ||
684 | and killing cifsd */ | ||
664 | cFYI(1, ("Wait for exit from demultiplex thread")); | 685 | cFYI(1, ("Wait for exit from demultiplex thread")); |
665 | msleep(46); | 686 | msleep(46000); |
666 | /* if threads still have not exited they are probably never | 687 | /* if threads still have not exited they are probably never |
667 | coming home not much else we can do but free the memory */ | 688 | coming home not much else we can do but free the memory */ |
668 | } | 689 | } |
669 | kfree(server); | ||
670 | 690 | ||
671 | write_lock(&GlobalSMBSeslock); | 691 | write_lock(&GlobalSMBSeslock); |
672 | atomic_dec(&tcpSesAllocCount); | 692 | atomic_dec(&tcpSesAllocCount); |
673 | length = tcpSesAllocCount.counter; | 693 | length = tcpSesAllocCount.counter; |
694 | |||
695 | /* last chance to mark ses pointers invalid | ||
696 | if there are any pointing to this (e.g | ||
697 | if a crazy root user tried to kill cifsd | ||
698 | kernel thread explicitly this might happen) */ | ||
699 | list_for_each(tmp, &GlobalSMBSessionList) { | ||
700 | ses = list_entry(tmp, struct cifsSesInfo, | ||
701 | cifsSessionList); | ||
702 | if (ses->server == server) { | ||
703 | ses->server = NULL; | ||
704 | } | ||
705 | } | ||
674 | write_unlock(&GlobalSMBSeslock); | 706 | write_unlock(&GlobalSMBSeslock); |
707 | |||
708 | kfree(server); | ||
675 | if(length > 0) { | 709 | if(length > 0) { |
676 | mempool_resize(cifs_req_poolp, | 710 | mempool_resize(cifs_req_poolp, |
677 | length + cifs_min_rcv, | 711 | length + cifs_min_rcv, |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 1df26ddf68b1..dde2d251fc3d 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -512,7 +512,8 @@ int cifs_closedir(struct inode *inode, struct file *file) | |||
512 | pTcon = cifs_sb->tcon; | 512 | pTcon = cifs_sb->tcon; |
513 | 513 | ||
514 | cFYI(1, ("Freeing private data in close dir")); | 514 | cFYI(1, ("Freeing private data in close dir")); |
515 | if (pCFileStruct->srch_inf.endOfSearch == FALSE) { | 515 | if ((pCFileStruct->srch_inf.endOfSearch == FALSE) && |
516 | (pCFileStruct->invalidHandle == FALSE)) { | ||
516 | pCFileStruct->invalidHandle = TRUE; | 517 | pCFileStruct->invalidHandle = TRUE; |
517 | rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid); | 518 | rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid); |
518 | cFYI(1, ("Closing uncompleted readdir with rc %d", | 519 | cFYI(1, ("Closing uncompleted readdir with rc %d", |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 79bf686a2a19..0046c219833d 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -270,6 +270,9 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
270 | 270 | ||
271 | 271 | ||
272 | 272 | ||
273 | if(ses->server->tcpStatus == CIFS_EXITING) | ||
274 | return -ENOENT; | ||
275 | |||
273 | /* Ensure that we do not send more than 50 overlapping requests | 276 | /* Ensure that we do not send more than 50 overlapping requests |
274 | to the same server. We may make this configurable later or | 277 | to the same server. We may make this configurable later or |
275 | use ses->maxReq */ | 278 | use ses->maxReq */ |
@@ -401,6 +404,9 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
401 | return -EIO; | 404 | return -EIO; |
402 | } | 405 | } |
403 | 406 | ||
407 | if(ses->server->tcpStatus == CifsExiting) | ||
408 | return -ENOENT; | ||
409 | |||
404 | /* Ensure that we do not send more than 50 overlapping requests | 410 | /* Ensure that we do not send more than 50 overlapping requests |
405 | to the same server. We may make this configurable later or | 411 | to the same server. We may make this configurable later or |
406 | use ses->maxReq */ | 412 | use ses->maxReq */ |