aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2006-04-22 11:53:05 -0400
committerSteve French <sfrench@us.ibm.com>2006-04-22 11:53:05 -0400
commit60808233f374aebba26488d06a5f25443f6763c3 (patch)
treee2f85a165398f0c6c7432a7fa715d18efc3d8d5b /fs/cifs
parent45af7a0f2ebad1304cab956e15f0b37318226fcd (diff)
[CIFS] Readdir fixes to allow search to start at arbitrary position
in directory Also includes first part of fix to compensate for servers which forget to return . and .. as well as updates to changelog and cifs readme. Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/CHANGES6
-rw-r--r--fs/cifs/README8
-rw-r--r--fs/cifs/cifssmb.c2
-rw-r--r--fs/cifs/connect.c5
-rw-r--r--fs/cifs/file.c32
-rw-r--r--fs/cifs/ntlmssp.c14
-rw-r--r--fs/cifs/readdir.c43
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 @@
1Version 1.42 1Version 1.42
2------------ 2------------
3Fix slow oplock break when mounted to different servers at the same time and 3Fix slow oplock break when mounted to different servers at the same time and
4the tids match and we try to find matching fid on wrong server. 4the tids match and we try to find matching fid on wrong server. Fix read
5looping when signing required by server (2.6.16 kernel only). Fix readdir
6vs. rename race which could cause each to hang. Return . and .. even
7if server does not. Allow searches to skip first three entries and
8begin at any location. Fix oops in find_writeable_file.
5 9
6Version 1.41 10Version 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)
514Experimental 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
515These experimental features and tracing can be enabled by changing flags in 523These 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 &current_entry,&num_to_fill); 951 &current_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++;