diff options
| -rw-r--r-- | fs/cifs/CHANGES | 6 | ||||
| -rw-r--r-- | fs/cifs/README | 8 | ||||
| -rw-r--r-- | fs/cifs/cifssmb.c | 2 | ||||
| -rw-r--r-- | fs/cifs/connect.c | 5 | ||||
| -rw-r--r-- | fs/cifs/file.c | 32 | ||||
| -rw-r--r-- | fs/cifs/ntlmssp.c | 14 | ||||
| -rw-r--r-- | fs/cifs/readdir.c | 43 |
7 files changed, 74 insertions, 36 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 8a2de038882e..1a27ecb46c9a 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
| @@ -1,7 +1,11 @@ | |||
| 1 | Version 1.42 | 1 | Version 1.42 |
| 2 | ------------ | 2 | ------------ |
| 3 | Fix slow oplock break when mounted to different servers at the same time and | 3 | Fix slow oplock break when mounted to different servers at the same time and |
| 4 | the tids match and we try to find matching fid on wrong server. | 4 | the tids match and we try to find matching fid on wrong server. Fix read |
| 5 | looping when signing required by server (2.6.16 kernel only). Fix readdir | ||
| 6 | vs. rename race which could cause each to hang. Return . and .. even | ||
| 7 | if server does not. Allow searches to skip first three entries and | ||
| 8 | begin at any location. Fix oops in find_writeable_file. | ||
| 5 | 9 | ||
| 6 | Version 1.41 | 10 | Version 1.41 |
| 7 | ------------ | 11 | ------------ |
diff --git a/fs/cifs/README b/fs/cifs/README index b2b4d0803761..0355003f4f0a 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
| @@ -511,6 +511,14 @@ LinuxExtensionsEnabled If set to one then the client will attempt to | |||
| 511 | support and want to map the uid and gid fields | 511 | support and want to map the uid and gid fields |
| 512 | to values supplied at mount (rather than the | 512 | to values supplied at mount (rather than the |
| 513 | actual values, then set this to zero. (default 1) | 513 | actual values, then set this to zero. (default 1) |
| 514 | Experimental When set to 1 used to enable certain experimental | ||
| 515 | features (currently enables multipage writes | ||
| 516 | when signing is enabled, the multipage write | ||
| 517 | performance enhancement was disabled when | ||
| 518 | signing turned on in case buffer was modified | ||
| 519 | just before it was sent, also this flag will | ||
| 520 | be used to use the new experimental sessionsetup | ||
| 521 | code). | ||
| 514 | 522 | ||
| 515 | These experimental features and tracing can be enabled by changing flags in | 523 | These experimental features and tracing can be enabled by changing flags in |
| 516 | /proc/fs/cifs (after the cifs module has been installed or built into the | 524 | /proc/fs/cifs (after the cifs module has been installed or built into the |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index d705500aa283..fd36892eda55 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -3119,7 +3119,7 @@ findFirstRetry: | |||
| 3119 | psrch_inf->endOfSearch = FALSE; | 3119 | psrch_inf->endOfSearch = FALSE; |
| 3120 | 3120 | ||
| 3121 | psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); | 3121 | psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); |
| 3122 | psrch_inf->index_of_last_entry = | 3122 | psrch_inf->index_of_last_entry = 2 /* skip . and .. */ + |
| 3123 | psrch_inf->entries_in_buffer; | 3123 | psrch_inf->entries_in_buffer; |
| 3124 | *pnetfid = parms->SearchHandle; | 3124 | *pnetfid = parms->SearchHandle; |
| 3125 | } else { | 3125 | } else { |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 0b86d5ca9014..aaf151cb5822 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -3447,7 +3447,10 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
| 3447 | pSesInfo->server->secMode, | 3447 | pSesInfo->server->secMode, |
| 3448 | pSesInfo->server->capabilities, | 3448 | pSesInfo->server->capabilities, |
| 3449 | pSesInfo->server->timeZone)); | 3449 | pSesInfo->server->timeZone)); |
| 3450 | if (extended_security | 3450 | if(experimEnabled > 1) |
| 3451 | rc = CIFS_SessSetup(xid, pSesInfo, CIFS_NTLM /* type */, | ||
| 3452 | &ntlmv2_flag, nls_info); | ||
| 3453 | else if (extended_security | ||
| 3451 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) | 3454 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) |
| 3452 | && (pSesInfo->server->secType == NTLMSSP)) { | 3455 | && (pSesInfo->server->secType == NTLMSSP)) { |
| 3453 | cFYI(1, ("New style sesssetup")); | 3456 | cFYI(1, ("New style sesssetup")); |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 1476725e6051..e152bf6afa60 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -904,8 +904,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
| 904 | if (rc != 0) | 904 | if (rc != 0) |
| 905 | break; | 905 | break; |
| 906 | } | 906 | } |
| 907 | /* BB FIXME We can not sign across two buffers yet */ | 907 | if(experimEnabled || (pTcon->ses->server->secMode & |
| 908 | if((pTcon->ses->server->secMode & | ||
| 909 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0) { | 908 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0) { |
| 910 | struct kvec iov[2]; | 909 | struct kvec iov[2]; |
| 911 | unsigned int len; | 910 | unsigned int len; |
| @@ -921,13 +920,13 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
| 921 | *poffset, &bytes_written, | 920 | *poffset, &bytes_written, |
| 922 | iov, 1, long_op); | 921 | iov, 1, long_op); |
| 923 | } else | 922 | } else |
| 924 | /* BB FIXME fixup indentation of line below */ | 923 | rc = CIFSSMBWrite(xid, pTcon, |
| 925 | rc = CIFSSMBWrite(xid, pTcon, | 924 | open_file->netfid, |
| 926 | open_file->netfid, | 925 | min_t(const int, cifs_sb->wsize, |
| 927 | min_t(const int, cifs_sb->wsize, | 926 | write_size - total_written), |
| 928 | write_size - total_written), | 927 | *poffset, &bytes_written, |
| 929 | *poffset, &bytes_written, | 928 | write_data + total_written, |
| 930 | write_data + total_written, NULL, long_op); | 929 | NULL, long_op); |
| 931 | } | 930 | } |
| 932 | if (rc || (bytes_written == 0)) { | 931 | if (rc || (bytes_written == 0)) { |
| 933 | if (total_written) | 932 | if (total_written) |
| @@ -966,6 +965,16 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) | |||
| 966 | struct cifsFileInfo *open_file; | 965 | struct cifsFileInfo *open_file; |
| 967 | int rc; | 966 | int rc; |
| 968 | 967 | ||
| 968 | /* Having a null inode here (because mapping->host was set to zero by | ||
| 969 | the VFS or MM) should not happen but we had reports of on oops (due to | ||
| 970 | it being zero) during stress testcases so we need to check for it */ | ||
| 971 | |||
| 972 | if(cifs_inode == NULL) { | ||
| 973 | cERROR(1,("Null inode passed to cifs_writeable_file")); | ||
| 974 | dump_stack(); | ||
| 975 | return NULL; | ||
| 976 | } | ||
| 977 | |||
| 969 | read_lock(&GlobalSMBSeslock); | 978 | read_lock(&GlobalSMBSeslock); |
| 970 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | 979 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { |
| 971 | if (open_file->closePend) | 980 | if (open_file->closePend) |
| @@ -1091,12 +1100,11 @@ static int cifs_writepages(struct address_space *mapping, | |||
| 1091 | if (cifs_sb->wsize < PAGE_CACHE_SIZE) | 1100 | if (cifs_sb->wsize < PAGE_CACHE_SIZE) |
| 1092 | return generic_writepages(mapping, wbc); | 1101 | return generic_writepages(mapping, wbc); |
| 1093 | 1102 | ||
| 1094 | /* BB FIXME we do not have code to sign across multiple buffers yet, | ||
| 1095 | so go to older writepage style write which we can sign if needed */ | ||
| 1096 | if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server)) | 1103 | if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server)) |
| 1097 | if(cifs_sb->tcon->ses->server->secMode & | 1104 | if(cifs_sb->tcon->ses->server->secMode & |
| 1098 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 1105 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
| 1099 | return generic_writepages(mapping, wbc); | 1106 | if(!experimEnabled) |
| 1107 | return generic_writepages(mapping, wbc); | ||
| 1100 | 1108 | ||
| 1101 | /* | 1109 | /* |
| 1102 | * BB: Is this meaningful for a non-block-device file system? | 1110 | * BB: Is this meaningful for a non-block-device file system? |
diff --git a/fs/cifs/ntlmssp.c b/fs/cifs/ntlmssp.c index 78866f925747..115359cc7a32 100644 --- a/fs/cifs/ntlmssp.c +++ b/fs/cifs/ntlmssp.c | |||
| @@ -121,6 +121,20 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, const int type, | |||
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | 123 | ||
| 124 | /* copy session key */ | ||
| 125 | |||
| 126 | /* if Unicode, align strings to two byte boundary */ | ||
| 127 | |||
| 128 | /* copy user name */ /* BB Do we need to special case null user name? */ | ||
| 129 | |||
| 130 | /* copy domain name */ | ||
| 131 | |||
| 132 | /* copy Linux version */ | ||
| 133 | |||
| 134 | /* copy network operating system name */ | ||
| 135 | |||
| 136 | /* update bcc and smb buffer length */ | ||
| 137 | |||
| 124 | /* rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buf_type, 0); */ | 138 | /* rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buf_type, 0); */ |
| 125 | /* SMB request buf freed in SendReceive2 */ | 139 | /* SMB request buf freed in SendReceive2 */ |
| 126 | 140 | ||
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 7b8591acc5ad..41c022e3c132 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
| @@ -590,6 +590,13 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
| 590 | first_entry_in_buffer = | 590 | first_entry_in_buffer = |
| 591 | cifsFile->srch_inf.index_of_last_entry - | 591 | cifsFile->srch_inf.index_of_last_entry - |
| 592 | cifsFile->srch_inf.entries_in_buffer; | 592 | cifsFile->srch_inf.entries_in_buffer; |
| 593 | |||
| 594 | /* if first entry in buf is zero then is first buffer | ||
| 595 | in search response data which means it is likely . and .. | ||
| 596 | will be in this buffer, although some servers do not return | ||
| 597 | . and .. for the root of a drive and for those we need | ||
| 598 | to start two entries earlier */ | ||
| 599 | |||
| 593 | /* dump_cifs_file_struct(file, "In fce ");*/ | 600 | /* dump_cifs_file_struct(file, "In fce ");*/ |
| 594 | if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && | 601 | if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && |
| 595 | is_dir_changed(file)) || | 602 | is_dir_changed(file)) || |
| @@ -632,23 +639,14 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
| 632 | char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + | 639 | char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + |
| 633 | smbCalcSize((struct smb_hdr *) | 640 | smbCalcSize((struct smb_hdr *) |
| 634 | cifsFile->srch_inf.ntwrk_buf_start); | 641 | cifsFile->srch_inf.ntwrk_buf_start); |
| 642 | |||
| 643 | current_entry = cifsFile->srch_inf.srch_entries_start; | ||
| 635 | first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry | 644 | first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry |
| 636 | - cifsFile->srch_inf.entries_in_buffer; | 645 | - cifsFile->srch_inf.entries_in_buffer; |
| 637 | pos_in_buf = index_to_find - first_entry_in_buffer; | 646 | pos_in_buf = index_to_find - first_entry_in_buffer; |
| 638 | cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); | 647 | cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); |
| 639 | current_entry = cifsFile->srch_inf.srch_entries_start; | ||
| 640 | for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { | 648 | for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { |
| 641 | /* go entry by entry figuring out which is first */ | 649 | /* go entry by entry figuring out which is first */ |
| 642 | /* if( . or ..) | ||
| 643 | skip */ | ||
| 644 | rc = cifs_entry_is_dot(current_entry,cifsFile); | ||
| 645 | if(rc == 1) /* is . or .. so skip */ { | ||
| 646 | cFYI(1,("Entry is .")); /* BB removeme BB */ | ||
| 647 | /* continue; */ | ||
| 648 | } else if (rc == 2 ) { | ||
| 649 | cFYI(1,("Entry is ..")); /* BB removeme BB */ | ||
| 650 | /* continue; */ | ||
| 651 | } | ||
| 652 | current_entry = nxt_dir_entry(current_entry,end_of_smb); | 650 | current_entry = nxt_dir_entry(current_entry,end_of_smb); |
| 653 | } | 651 | } |
| 654 | if((current_entry == NULL) && (i < pos_in_buf)) { | 652 | if((current_entry == NULL) && (i < pos_in_buf)) { |
| @@ -768,6 +766,11 @@ static int cifs_filldir(char *pfindEntry, struct file *file, | |||
| 768 | if(file->f_dentry == NULL) | 766 | if(file->f_dentry == NULL) |
| 769 | return -ENOENT; | 767 | return -ENOENT; |
| 770 | 768 | ||
| 769 | rc = cifs_entry_is_dot(pfindEntry,cifsF); | ||
| 770 | /* skip . and .. since we added them first */ | ||
| 771 | if(rc != 0) | ||
| 772 | return 0; | ||
| 773 | |||
| 771 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | 774 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); |
| 772 | 775 | ||
| 773 | qstring.name = scratch_buf; | 776 | qstring.name = scratch_buf; |
| @@ -896,22 +899,22 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
| 896 | 899 | ||
| 897 | switch ((int) file->f_pos) { | 900 | switch ((int) file->f_pos) { |
| 898 | case 0: | 901 | case 0: |
| 899 | /*if (filldir(direntry, ".", 1, file->f_pos, | 902 | if (filldir(direntry, ".", 1, file->f_pos, |
| 900 | file->f_dentry->d_inode->i_ino, DT_DIR) < 0) { | 903 | file->f_dentry->d_inode->i_ino, DT_DIR) < 0) { |
| 901 | cERROR(1, ("Filldir for current dir failed ")); | 904 | cERROR(1, ("Filldir for current dir failed")); |
| 902 | rc = -ENOMEM; | 905 | rc = -ENOMEM; |
| 903 | break; | 906 | break; |
| 904 | } | 907 | } |
| 905 | file->f_pos++; */ | 908 | file->f_pos++; |
| 906 | case 1: | 909 | case 1: |
| 907 | /* if (filldir(direntry, "..", 2, file->f_pos, | 910 | if (filldir(direntry, "..", 2, file->f_pos, |
| 908 | file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { | 911 | file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { |
| 909 | cERROR(1, ("Filldir for parent dir failed ")); | 912 | cERROR(1, ("Filldir for parent dir failed ")); |
| 910 | rc = -ENOMEM; | 913 | rc = -ENOMEM; |
| 911 | break; | 914 | break; |
| 912 | } | 915 | } |
| 913 | file->f_pos++; */ | 916 | file->f_pos++; |
| 914 | case 2: | 917 | default: |
| 915 | /* 1) If search is active, | 918 | /* 1) If search is active, |
| 916 | is in current search buffer? | 919 | is in current search buffer? |
| 917 | if it before then restart search | 920 | if it before then restart search |
| @@ -925,7 +928,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
| 925 | return rc; | 928 | return rc; |
| 926 | } | 929 | } |
| 927 | } | 930 | } |
| 928 | default: | ||
| 929 | if(file->private_data == NULL) { | 931 | if(file->private_data == NULL) { |
| 930 | rc = -EINVAL; | 932 | rc = -EINVAL; |
| 931 | FreeXid(xid); | 933 | FreeXid(xid); |
| @@ -945,8 +947,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
| 945 | kfree(cifsFile->search_resume_name); | 947 | kfree(cifsFile->search_resume_name); |
| 946 | cifsFile->search_resume_name = NULL; */ | 948 | cifsFile->search_resume_name = NULL; */ |
| 947 | 949 | ||
| 948 | /* BB account for . and .. in f_pos as special case */ | ||
| 949 | |||
| 950 | rc = find_cifs_entry(xid,pTcon, file, | 950 | rc = find_cifs_entry(xid,pTcon, file, |
| 951 | ¤t_entry,&num_to_fill); | 951 | ¤t_entry,&num_to_fill); |
| 952 | if(rc) { | 952 | if(rc) { |
| @@ -975,7 +975,8 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
| 975 | num_to_fill, i)); | 975 | num_to_fill, i)); |
| 976 | break; | 976 | break; |
| 977 | } | 977 | } |
| 978 | 978 | /* if buggy server returns . and .. late do | |
| 979 | we want to check for that here? */ | ||
| 979 | rc = cifs_filldir(current_entry, file, | 980 | rc = cifs_filldir(current_entry, file, |
| 980 | filldir, direntry,tmp_buf); | 981 | filldir, direntry,tmp_buf); |
| 981 | file->f_pos++; | 982 | file->f_pos++; |
