aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/CHANGES6
-rw-r--r--fs/cifs/cifsglob.h10
-rw-r--r--fs/cifs/cifssmb.c2
-rw-r--r--fs/cifs/file.c21
-rw-r--r--fs/cifs/misc.c3
-rw-r--r--fs/cifs/readdir.c5
-rw-r--r--fs/ecryptfs/keystore.c31
-rw-r--r--fs/hostfs/hostfs.h2
-rw-r--r--fs/hostfs/hostfs_kern.c4
-rw-r--r--fs/hostfs/hostfs_user.c2
-rw-r--r--fs/namei.c2
11 files changed, 55 insertions, 33 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
8sends, and also let tcp autotune the socket send and receive buffers. 8sends, and also let tcp autotune the socket send and receive buffers.
9This reduces the number of EAGAIN errors returned by TCP/IP in 9This reduces the number of EAGAIN errors returned by TCP/IP in
10high stress workloads (and the number of retries on socket writes 10high stress workloads (and the number of retries on socket writes
11when sending large SMBWriteX requests). 11when sending large SMBWriteX requests). Fix case in which a portion of
12data can in some cases not get written to the file on the server before the
13file is closed. Fix DFS parsing to properly handle path consumed field,
14and to handle certain codepage conversions better. Fix mount and
15umount race that can cause oops in mount or umount or reconnect.
12 16
13Version 1.54 17Version 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 */
608GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock; 608GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock;
609GLOBAL_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 */
617GLOBAL_EXTERN rwlock_t GlobalSMBSeslock;
610 618
611GLOBAL_EXTERN struct list_head GlobalOplock_Q; 619GLOBAL_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)
diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
index e22bc3961345..0d713b691941 100644
--- a/fs/ecryptfs/keystore.c
+++ b/fs/ecryptfs/keystore.c
@@ -1037,17 +1037,14 @@ static int
1037decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok, 1037decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
1038 struct ecryptfs_crypt_stat *crypt_stat) 1038 struct ecryptfs_crypt_stat *crypt_stat)
1039{ 1039{
1040 struct scatterlist dst_sg; 1040 struct scatterlist dst_sg[2];
1041 struct scatterlist src_sg; 1041 struct scatterlist src_sg[2];
1042 struct mutex *tfm_mutex; 1042 struct mutex *tfm_mutex;
1043 struct blkcipher_desc desc = { 1043 struct blkcipher_desc desc = {
1044 .flags = CRYPTO_TFM_REQ_MAY_SLEEP 1044 .flags = CRYPTO_TFM_REQ_MAY_SLEEP
1045 }; 1045 };
1046 int rc = 0; 1046 int rc = 0;
1047 1047
1048 sg_init_table(&dst_sg, 1);
1049 sg_init_table(&src_sg, 1);
1050
1051 if (unlikely(ecryptfs_verbosity > 0)) { 1048 if (unlikely(ecryptfs_verbosity > 0)) {
1052 ecryptfs_printk( 1049 ecryptfs_printk(
1053 KERN_DEBUG, "Session key encryption key (size [%d]):\n", 1050 KERN_DEBUG, "Session key encryption key (size [%d]):\n",
@@ -1066,8 +1063,8 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
1066 } 1063 }
1067 rc = virt_to_scatterlist(auth_tok->session_key.encrypted_key, 1064 rc = virt_to_scatterlist(auth_tok->session_key.encrypted_key,
1068 auth_tok->session_key.encrypted_key_size, 1065 auth_tok->session_key.encrypted_key_size,
1069 &src_sg, 1); 1066 src_sg, 2);
1070 if (rc != 1) { 1067 if (rc < 1 || rc > 2) {
1071 printk(KERN_ERR "Internal error whilst attempting to convert " 1068 printk(KERN_ERR "Internal error whilst attempting to convert "
1072 "auth_tok->session_key.encrypted_key to scatterlist; " 1069 "auth_tok->session_key.encrypted_key to scatterlist; "
1073 "expected rc = 1; got rc = [%d]. " 1070 "expected rc = 1; got rc = [%d]. "
@@ -1079,8 +1076,8 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
1079 auth_tok->session_key.encrypted_key_size; 1076 auth_tok->session_key.encrypted_key_size;
1080 rc = virt_to_scatterlist(auth_tok->session_key.decrypted_key, 1077 rc = virt_to_scatterlist(auth_tok->session_key.decrypted_key,
1081 auth_tok->session_key.decrypted_key_size, 1078 auth_tok->session_key.decrypted_key_size,
1082 &dst_sg, 1); 1079 dst_sg, 2);
1083 if (rc != 1) { 1080 if (rc < 1 || rc > 2) {
1084 printk(KERN_ERR "Internal error whilst attempting to convert " 1081 printk(KERN_ERR "Internal error whilst attempting to convert "
1085 "auth_tok->session_key.decrypted_key to scatterlist; " 1082 "auth_tok->session_key.decrypted_key to scatterlist; "
1086 "expected rc = 1; got rc = [%d]\n", rc); 1083 "expected rc = 1; got rc = [%d]\n", rc);
@@ -1096,7 +1093,7 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
1096 rc = -EINVAL; 1093 rc = -EINVAL;
1097 goto out; 1094 goto out;
1098 } 1095 }
1099 rc = crypto_blkcipher_decrypt(&desc, &dst_sg, &src_sg, 1096 rc = crypto_blkcipher_decrypt(&desc, dst_sg, src_sg,
1100 auth_tok->session_key.encrypted_key_size); 1097 auth_tok->session_key.encrypted_key_size);
1101 mutex_unlock(tfm_mutex); 1098 mutex_unlock(tfm_mutex);
1102 if (unlikely(rc)) { 1099 if (unlikely(rc)) {
@@ -1539,8 +1536,8 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
1539 size_t i; 1536 size_t i;
1540 size_t encrypted_session_key_valid = 0; 1537 size_t encrypted_session_key_valid = 0;
1541 char session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES]; 1538 char session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
1542 struct scatterlist dst_sg; 1539 struct scatterlist dst_sg[2];
1543 struct scatterlist src_sg; 1540 struct scatterlist src_sg[2];
1544 struct mutex *tfm_mutex = NULL; 1541 struct mutex *tfm_mutex = NULL;
1545 u8 cipher_code; 1542 u8 cipher_code;
1546 size_t packet_size_length; 1543 size_t packet_size_length;
@@ -1619,8 +1616,8 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
1619 ecryptfs_dump_hex(session_key_encryption_key, 16); 1616 ecryptfs_dump_hex(session_key_encryption_key, 16);
1620 } 1617 }
1621 rc = virt_to_scatterlist(crypt_stat->key, key_rec->enc_key_size, 1618 rc = virt_to_scatterlist(crypt_stat->key, key_rec->enc_key_size,
1622 &src_sg, 1); 1619 src_sg, 2);
1623 if (rc != 1) { 1620 if (rc < 1 || rc > 2) {
1624 ecryptfs_printk(KERN_ERR, "Error generating scatterlist " 1621 ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
1625 "for crypt_stat session key; expected rc = 1; " 1622 "for crypt_stat session key; expected rc = 1; "
1626 "got rc = [%d]. key_rec->enc_key_size = [%d]\n", 1623 "got rc = [%d]. key_rec->enc_key_size = [%d]\n",
@@ -1629,8 +1626,8 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
1629 goto out; 1626 goto out;
1630 } 1627 }
1631 rc = virt_to_scatterlist(key_rec->enc_key, key_rec->enc_key_size, 1628 rc = virt_to_scatterlist(key_rec->enc_key, key_rec->enc_key_size,
1632 &dst_sg, 1); 1629 dst_sg, 2);
1633 if (rc != 1) { 1630 if (rc < 1 || rc > 2) {
1634 ecryptfs_printk(KERN_ERR, "Error generating scatterlist " 1631 ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
1635 "for crypt_stat encrypted session key; " 1632 "for crypt_stat encrypted session key; "
1636 "expected rc = 1; got rc = [%d]. " 1633 "expected rc = 1; got rc = [%d]. "
@@ -1651,7 +1648,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
1651 rc = 0; 1648 rc = 0;
1652 ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes of the key\n", 1649 ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes of the key\n",
1653 crypt_stat->key_size); 1650 crypt_stat->key_size);
1654 rc = crypto_blkcipher_encrypt(&desc, &dst_sg, &src_sg, 1651 rc = crypto_blkcipher_encrypt(&desc, dst_sg, src_sg,
1655 (*key_rec).enc_key_size); 1652 (*key_rec).enc_key_size);
1656 mutex_unlock(tfm_mutex); 1653 mutex_unlock(tfm_mutex);
1657 if (rc) { 1654 if (rc) {
diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h
index 6ae9011b95eb..2f34f8f2134b 100644
--- a/fs/hostfs/hostfs.h
+++ b/fs/hostfs/hostfs.h
@@ -81,7 +81,7 @@ extern int do_rmdir(const char *file);
81extern int do_mknod(const char *file, int mode, unsigned int major, 81extern int do_mknod(const char *file, int mode, unsigned int major,
82 unsigned int minor); 82 unsigned int minor);
83extern int link_file(const char *from, const char *to); 83extern int link_file(const char *from, const char *to);
84extern int do_readlink(char *file, char *buf, int size); 84extern int hostfs_do_readlink(char *file, char *buf, int size);
85extern int rename_file(char *from, char *to); 85extern int rename_file(char *from, char *to);
86extern int do_statfs(char *root, long *bsize_out, long long *blocks_out, 86extern int do_statfs(char *root, long *bsize_out, long long *blocks_out,
87 long long *bfree_out, long long *bavail_out, 87 long long *bfree_out, long long *bavail_out,
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 7f34f4385de0..3a31451ac170 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -168,7 +168,7 @@ static char *follow_link(char *link)
168 if (name == NULL) 168 if (name == NULL)
169 goto out; 169 goto out;
170 170
171 n = do_readlink(link, name, len); 171 n = hostfs_do_readlink(link, name, len);
172 if (n < len) 172 if (n < len)
173 break; 173 break;
174 len *= 2; 174 len *= 2;
@@ -943,7 +943,7 @@ int hostfs_link_readpage(struct file *file, struct page *page)
943 name = inode_name(page->mapping->host, 0); 943 name = inode_name(page->mapping->host, 0);
944 if (name == NULL) 944 if (name == NULL)
945 return -ENOMEM; 945 return -ENOMEM;
946 err = do_readlink(name, buffer, PAGE_CACHE_SIZE); 946 err = hostfs_do_readlink(name, buffer, PAGE_CACHE_SIZE);
947 kfree(name); 947 kfree(name);
948 if (err == PAGE_CACHE_SIZE) 948 if (err == PAGE_CACHE_SIZE)
949 err = -E2BIG; 949 err = -E2BIG;
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c
index 53fd0a67c11a..b79424f93282 100644
--- a/fs/hostfs/hostfs_user.c
+++ b/fs/hostfs/hostfs_user.c
@@ -377,7 +377,7 @@ int link_file(const char *to, const char *from)
377 return 0; 377 return 0;
378} 378}
379 379
380int do_readlink(char *file, char *buf, int size) 380int hostfs_do_readlink(char *file, char *buf, int size)
381{ 381{
382 int n; 382 int n;
383 383
diff --git a/fs/namei.c b/fs/namei.c
index 09ce58e49e72..d34e0f9681c6 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1378,7 +1378,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
1378 if (IS_APPEND(dir)) 1378 if (IS_APPEND(dir))
1379 return -EPERM; 1379 return -EPERM;
1380 if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)|| 1380 if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)||
1381 IS_IMMUTABLE(victim->d_inode)) 1381 IS_IMMUTABLE(victim->d_inode) || IS_SWAPFILE(victim->d_inode))
1382 return -EPERM; 1382 return -EPERM;
1383 if (isdir) { 1383 if (isdir) {
1384 if (!S_ISDIR(victim->d_inode->i_mode)) 1384 if (!S_ISDIR(victim->d_inode->i_mode))