diff options
| -rw-r--r-- | fs/cifs/CHANGES | 6 | ||||
| -rw-r--r-- | fs/cifs/cifsglob.h | 10 | ||||
| -rw-r--r-- | fs/cifs/cifssmb.c | 2 | ||||
| -rw-r--r-- | fs/cifs/file.c | 21 | ||||
| -rw-r--r-- | fs/cifs/misc.c | 3 | ||||
| -rw-r--r-- | fs/cifs/readdir.c | 5 |
6 files changed, 36 insertions, 11 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 8855331b2fba..e078b7aea143 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
| @@ -8,7 +8,11 @@ handling fcntl(F_SETLEASE). Convert cifs to using blocking tcp | |||
| 8 | sends, and also let tcp autotune the socket send and receive buffers. | 8 | sends, and also let tcp autotune the socket send and receive buffers. |
| 9 | This reduces the number of EAGAIN errors returned by TCP/IP in | 9 | This reduces the number of EAGAIN errors returned by TCP/IP in |
| 10 | high stress workloads (and the number of retries on socket writes | 10 | high stress workloads (and the number of retries on socket writes |
| 11 | when sending large SMBWriteX requests). | 11 | when sending large SMBWriteX requests). Fix case in which a portion of |
| 12 | data can in some cases not get written to the file on the server before the | ||
| 13 | file is closed. Fix DFS parsing to properly handle path consumed field, | ||
| 14 | and to handle certain codepage conversions better. Fix mount and | ||
| 15 | umount race that can cause oops in mount or umount or reconnect. | ||
| 12 | 16 | ||
| 13 | Version 1.54 | 17 | Version 1.54 |
| 14 | ------------ | 18 | ------------ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index f1ae1f57c30d..c57c0565547f 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -606,7 +606,15 @@ GLOBAL_EXTERN struct list_head cifs_tcp_ses_list; | |||
| 606 | * changes to the tcon->tidStatus should be done while holding this lock. | 606 | * changes to the tcon->tidStatus should be done while holding this lock. |
| 607 | */ | 607 | */ |
| 608 | GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock; | 608 | GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock; |
| 609 | GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ | 609 | |
| 610 | /* | ||
| 611 | * This lock protects the cifs_file->llist and cifs_file->flist | ||
| 612 | * list operations, and updates to some flags (cifs_file->invalidHandle) | ||
| 613 | * It will be moved to either use the tcon->stat_lock or equivalent later. | ||
| 614 | * If cifs_tcp_ses_lock and the lock below are both needed to be held, then | ||
| 615 | * the cifs_tcp_ses_lock must be grabbed first and released last. | ||
| 616 | */ | ||
| 617 | GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; | ||
| 610 | 618 | ||
| 611 | GLOBAL_EXTERN struct list_head GlobalOplock_Q; | 619 | GLOBAL_EXTERN struct list_head GlobalOplock_Q; |
| 612 | 620 | ||
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index bdda46dd435a..2af8626ced43 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -295,7 +295,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
| 295 | check for tcp and smb session status done differently | 295 | check for tcp and smb session status done differently |
| 296 | for those three - in the calling routine */ | 296 | for those three - in the calling routine */ |
| 297 | if (tcon) { | 297 | if (tcon) { |
| 298 | if (tcon->need_reconnect) { | 298 | if (tcon->tidStatus == CifsExiting) { |
| 299 | /* only tree disconnect, open, and write, | 299 | /* only tree disconnect, open, and write, |
| 300 | (and ulogoff which does not have tcon) | 300 | (and ulogoff which does not have tcon) |
| 301 | are allowed as we start force umount */ | 301 | are allowed as we start force umount */ |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 6449e1aae621..b691b893a848 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -488,12 +488,13 @@ int cifs_close(struct inode *inode, struct file *file) | |||
| 488 | pTcon = cifs_sb->tcon; | 488 | pTcon = cifs_sb->tcon; |
| 489 | if (pSMBFile) { | 489 | if (pSMBFile) { |
| 490 | struct cifsLockInfo *li, *tmp; | 490 | struct cifsLockInfo *li, *tmp; |
| 491 | 491 | write_lock(&GlobalSMBSeslock); | |
| 492 | pSMBFile->closePend = true; | 492 | pSMBFile->closePend = true; |
| 493 | if (pTcon) { | 493 | if (pTcon) { |
| 494 | /* no sense reconnecting to close a file that is | 494 | /* no sense reconnecting to close a file that is |
| 495 | already closed */ | 495 | already closed */ |
| 496 | if (!pTcon->need_reconnect) { | 496 | if (!pTcon->need_reconnect) { |
| 497 | write_unlock(&GlobalSMBSeslock); | ||
| 497 | timeout = 2; | 498 | timeout = 2; |
| 498 | while ((atomic_read(&pSMBFile->wrtPending) != 0) | 499 | while ((atomic_read(&pSMBFile->wrtPending) != 0) |
| 499 | && (timeout <= 2048)) { | 500 | && (timeout <= 2048)) { |
| @@ -510,12 +511,15 @@ int cifs_close(struct inode *inode, struct file *file) | |||
| 510 | timeout *= 4; | 511 | timeout *= 4; |
| 511 | } | 512 | } |
| 512 | if (atomic_read(&pSMBFile->wrtPending)) | 513 | if (atomic_read(&pSMBFile->wrtPending)) |
| 513 | cERROR(1, | 514 | cERROR(1, ("close with pending write")); |
| 514 | ("close with pending writes")); | 515 | if (!pTcon->need_reconnect && |
| 515 | rc = CIFSSMBClose(xid, pTcon, | 516 | !pSMBFile->invalidHandle) |
| 517 | rc = CIFSSMBClose(xid, pTcon, | ||
| 516 | pSMBFile->netfid); | 518 | pSMBFile->netfid); |
| 517 | } | 519 | } else |
| 518 | } | 520 | write_unlock(&GlobalSMBSeslock); |
| 521 | } else | ||
| 522 | write_unlock(&GlobalSMBSeslock); | ||
| 519 | 523 | ||
| 520 | /* Delete any outstanding lock records. | 524 | /* Delete any outstanding lock records. |
| 521 | We'll lose them when the file is closed anyway. */ | 525 | We'll lose them when the file is closed anyway. */ |
| @@ -587,15 +591,18 @@ int cifs_closedir(struct inode *inode, struct file *file) | |||
| 587 | pTcon = cifs_sb->tcon; | 591 | pTcon = cifs_sb->tcon; |
| 588 | 592 | ||
| 589 | cFYI(1, ("Freeing private data in close dir")); | 593 | cFYI(1, ("Freeing private data in close dir")); |
| 594 | write_lock(&GlobalSMBSeslock); | ||
| 590 | if (!pCFileStruct->srch_inf.endOfSearch && | 595 | if (!pCFileStruct->srch_inf.endOfSearch && |
| 591 | !pCFileStruct->invalidHandle) { | 596 | !pCFileStruct->invalidHandle) { |
| 592 | pCFileStruct->invalidHandle = true; | 597 | pCFileStruct->invalidHandle = true; |
| 598 | write_unlock(&GlobalSMBSeslock); | ||
| 593 | rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid); | 599 | rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid); |
| 594 | cFYI(1, ("Closing uncompleted readdir with rc %d", | 600 | cFYI(1, ("Closing uncompleted readdir with rc %d", |
| 595 | rc)); | 601 | rc)); |
| 596 | /* not much we can do if it fails anyway, ignore rc */ | 602 | /* not much we can do if it fails anyway, ignore rc */ |
| 597 | rc = 0; | 603 | rc = 0; |
| 598 | } | 604 | } else |
| 605 | write_unlock(&GlobalSMBSeslock); | ||
| 599 | ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; | 606 | ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; |
| 600 | if (ptmp) { | 607 | if (ptmp) { |
| 601 | cFYI(1, ("closedir free smb buf in srch struct")); | 608 | cFYI(1, ("closedir free smb buf in srch struct")); |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index addd1dcc2d79..9ee3f689c2b0 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
| @@ -555,12 +555,14 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
| 555 | continue; | 555 | continue; |
| 556 | 556 | ||
| 557 | cifs_stats_inc(&tcon->num_oplock_brks); | 557 | cifs_stats_inc(&tcon->num_oplock_brks); |
| 558 | write_lock(&GlobalSMBSeslock); | ||
| 558 | list_for_each(tmp2, &tcon->openFileList) { | 559 | list_for_each(tmp2, &tcon->openFileList) { |
| 559 | netfile = list_entry(tmp2, struct cifsFileInfo, | 560 | netfile = list_entry(tmp2, struct cifsFileInfo, |
| 560 | tlist); | 561 | tlist); |
| 561 | if (pSMB->Fid != netfile->netfid) | 562 | if (pSMB->Fid != netfile->netfid) |
| 562 | continue; | 563 | continue; |
| 563 | 564 | ||
| 565 | write_unlock(&GlobalSMBSeslock); | ||
| 564 | read_unlock(&cifs_tcp_ses_lock); | 566 | read_unlock(&cifs_tcp_ses_lock); |
| 565 | cFYI(1, ("file id match, oplock break")); | 567 | cFYI(1, ("file id match, oplock break")); |
| 566 | pCifsInode = CIFS_I(netfile->pInode); | 568 | pCifsInode = CIFS_I(netfile->pInode); |
| @@ -576,6 +578,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
| 576 | 578 | ||
| 577 | return true; | 579 | return true; |
| 578 | } | 580 | } |
| 581 | write_unlock(&GlobalSMBSeslock); | ||
| 579 | read_unlock(&cifs_tcp_ses_lock); | 582 | read_unlock(&cifs_tcp_ses_lock); |
| 580 | cFYI(1, ("No matching file for oplock break")); | 583 | cFYI(1, ("No matching file for oplock break")); |
| 581 | return true; | 584 | return true; |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 58d57299f2a0..9f51f9bf0292 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
| @@ -741,11 +741,14 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
| 741 | (index_to_find < first_entry_in_buffer)) { | 741 | (index_to_find < first_entry_in_buffer)) { |
| 742 | /* close and restart search */ | 742 | /* close and restart search */ |
| 743 | cFYI(1, ("search backing up - close and restart search")); | 743 | cFYI(1, ("search backing up - close and restart search")); |
| 744 | write_lock(&GlobalSMBSeslock); | ||
| 744 | if (!cifsFile->srch_inf.endOfSearch && | 745 | if (!cifsFile->srch_inf.endOfSearch && |
| 745 | !cifsFile->invalidHandle) { | 746 | !cifsFile->invalidHandle) { |
| 746 | cifsFile->invalidHandle = true; | 747 | cifsFile->invalidHandle = true; |
| 748 | write_unlock(&GlobalSMBSeslock); | ||
| 747 | CIFSFindClose(xid, pTcon, cifsFile->netfid); | 749 | CIFSFindClose(xid, pTcon, cifsFile->netfid); |
| 748 | } | 750 | } else |
| 751 | write_unlock(&GlobalSMBSeslock); | ||
| 749 | if (cifsFile->srch_inf.ntwrk_buf_start) { | 752 | if (cifsFile->srch_inf.ntwrk_buf_start) { |
| 750 | cFYI(1, ("freeing SMB ff cache buf on search rewind")); | 753 | cFYI(1, ("freeing SMB ff cache buf on search rewind")); |
| 751 | if (cifsFile->srch_inf.smallBuf) | 754 | if (cifsFile->srch_inf.smallBuf) |
