diff options
author | Steve French <sfrench@us.ibm.com> | 2006-04-22 11:53:05 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2006-04-22 11:53:05 -0400 |
commit | 60808233f374aebba26488d06a5f25443f6763c3 (patch) | |
tree | e2f85a165398f0c6c7432a7fa715d18efc3d8d5b /fs | |
parent | 45af7a0f2ebad1304cab956e15f0b37318226fcd (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')
-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++; |