aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2008-10-07 16:03:33 -0400
committerSteve French <sfrench@us.ibm.com>2008-10-07 16:03:33 -0400
commit0752f1522a9120f731232919f7ad904e9e22b8ce (patch)
tree3abf826e49b8e550863254f135ec573d7fd1107c
parent6050247d8089037d6d8ea0f3c62fe4a931c1ab14 (diff)
[CIFS] make sure we have the right resume info before calling CIFSFindNext
When we do a seekdir() or equivalent, we usually end up doing a FindFirst call and then call FindNext until we get to the offset that we want. The problem is that when we call FindNext, the code usually doesn't have the proper info (mostly, the filename of the entry from the last search) to resume the search. Add a "last_entry" field to the cifs_search_info that points to the last entry in the search. We calculate this pointer by using the LastNameOffset field from the search parms that are returned. We then use that info to do a cifs_save_resume_key before we call CIFSFindNext. This patch allows CIFS to reliably pass the "telldir" connectathon test. Signed-off-by: Jeff Layton <jlayton@redhat.com> CC: Stable <stable@kernel.org> Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r--fs/cifs/cifsglob.h1
-rw-r--r--fs/cifs/cifssmb.c4
-rw-r--r--fs/cifs/readdir.c128
3 files changed, 70 insertions, 63 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 8dfd6f24d488..0d22479d99b7 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -309,6 +309,7 @@ struct cifs_search_info {
309 __u32 resume_key; 309 __u32 resume_key;
310 char *ntwrk_buf_start; 310 char *ntwrk_buf_start;
311 char *srch_entries_start; 311 char *srch_entries_start;
312 char *last_entry;
312 char *presume_name; 313 char *presume_name;
313 unsigned int resume_name_len; 314 unsigned int resume_name_len;
314 bool endOfSearch:1; 315 bool endOfSearch:1;
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 7504d1514c77..7b00a16e1352 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -3636,6 +3636,8 @@ findFirstRetry:
3636 le16_to_cpu(parms->SearchCount); 3636 le16_to_cpu(parms->SearchCount);
3637 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ + 3637 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3638 psrch_inf->entries_in_buffer; 3638 psrch_inf->entries_in_buffer;
3639 psrch_inf->last_entry = psrch_inf->srch_entries_start +
3640 le16_to_cpu(parms->LastNameOffset);
3639 *pnetfid = parms->SearchHandle; 3641 *pnetfid = parms->SearchHandle;
3640 } else { 3642 } else {
3641 cifs_buf_release(pSMB); 3643 cifs_buf_release(pSMB);
@@ -3751,6 +3753,8 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3751 le16_to_cpu(parms->SearchCount); 3753 le16_to_cpu(parms->SearchCount);
3752 psrch_inf->index_of_last_entry += 3754 psrch_inf->index_of_last_entry +=
3753 psrch_inf->entries_in_buffer; 3755 psrch_inf->entries_in_buffer;
3756 psrch_inf->last_entry = psrch_inf->srch_entries_start +
3757 le16_to_cpu(parms->LastNameOffset);
3754/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d", 3758/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3755 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */ 3759 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
3756 3760
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 5f40ed3473f5..765adf12d54f 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -640,6 +640,70 @@ static int is_dir_changed(struct file *file)
640 640
641} 641}
642 642
643static int cifs_save_resume_key(const char *current_entry,
644 struct cifsFileInfo *cifsFile)
645{
646 int rc = 0;
647 unsigned int len = 0;
648 __u16 level;
649 char *filename;
650
651 if ((cifsFile == NULL) || (current_entry == NULL))
652 return -EINVAL;
653
654 level = cifsFile->srch_inf.info_level;
655
656 if (level == SMB_FIND_FILE_UNIX) {
657 FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
658
659 filename = &pFindData->FileName[0];
660 if (cifsFile->srch_inf.unicode) {
661 len = cifs_unicode_bytelen(filename);
662 } else {
663 /* BB should we make this strnlen of PATH_MAX? */
664 len = strnlen(filename, PATH_MAX);
665 }
666 cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
667 } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
668 FILE_DIRECTORY_INFO *pFindData =
669 (FILE_DIRECTORY_INFO *)current_entry;
670 filename = &pFindData->FileName[0];
671 len = le32_to_cpu(pFindData->FileNameLength);
672 cifsFile->srch_inf.resume_key = pFindData->FileIndex;
673 } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
674 FILE_FULL_DIRECTORY_INFO *pFindData =
675 (FILE_FULL_DIRECTORY_INFO *)current_entry;
676 filename = &pFindData->FileName[0];
677 len = le32_to_cpu(pFindData->FileNameLength);
678 cifsFile->srch_inf.resume_key = pFindData->FileIndex;
679 } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
680 SEARCH_ID_FULL_DIR_INFO *pFindData =
681 (SEARCH_ID_FULL_DIR_INFO *)current_entry;
682 filename = &pFindData->FileName[0];
683 len = le32_to_cpu(pFindData->FileNameLength);
684 cifsFile->srch_inf.resume_key = pFindData->FileIndex;
685 } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
686 FILE_BOTH_DIRECTORY_INFO *pFindData =
687 (FILE_BOTH_DIRECTORY_INFO *)current_entry;
688 filename = &pFindData->FileName[0];
689 len = le32_to_cpu(pFindData->FileNameLength);
690 cifsFile->srch_inf.resume_key = pFindData->FileIndex;
691 } else if (level == SMB_FIND_FILE_INFO_STANDARD) {
692 FIND_FILE_STANDARD_INFO *pFindData =
693 (FIND_FILE_STANDARD_INFO *)current_entry;
694 filename = &pFindData->FileName[0];
695 /* one byte length, no name conversion */
696 len = (unsigned int)pFindData->FileNameLength;
697 cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
698 } else {
699 cFYI(1, ("Unknown findfirst level %d", level));
700 return -EINVAL;
701 }
702 cifsFile->srch_inf.resume_name_len = len;
703 cifsFile->srch_inf.presume_name = filename;
704 return rc;
705}
706
643/* find the corresponding entry in the search */ 707/* find the corresponding entry in the search */
644/* Note that the SMB server returns search entries for . and .. which 708/* Note that the SMB server returns search entries for . and .. which
645 complicates logic here if we choose to parse for them and we do not 709 complicates logic here if we choose to parse for them and we do not
@@ -703,6 +767,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
703 while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && 767 while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
704 (rc == 0) && !cifsFile->srch_inf.endOfSearch) { 768 (rc == 0) && !cifsFile->srch_inf.endOfSearch) {
705 cFYI(1, ("calling findnext2")); 769 cFYI(1, ("calling findnext2"));
770 cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile);
706 rc = CIFSFindNext(xid, pTcon, cifsFile->netfid, 771 rc = CIFSFindNext(xid, pTcon, cifsFile->netfid,
707 &cifsFile->srch_inf); 772 &cifsFile->srch_inf);
708 if (rc) 773 if (rc)
@@ -919,69 +984,6 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
919 return rc; 984 return rc;
920} 985}
921 986
922static int cifs_save_resume_key(const char *current_entry,
923 struct cifsFileInfo *cifsFile)
924{
925 int rc = 0;
926 unsigned int len = 0;
927 __u16 level;
928 char *filename;
929
930 if ((cifsFile == NULL) || (current_entry == NULL))
931 return -EINVAL;
932
933 level = cifsFile->srch_inf.info_level;
934
935 if (level == SMB_FIND_FILE_UNIX) {
936 FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
937
938 filename = &pFindData->FileName[0];
939 if (cifsFile->srch_inf.unicode) {
940 len = cifs_unicode_bytelen(filename);
941 } else {
942 /* BB should we make this strnlen of PATH_MAX? */
943 len = strnlen(filename, PATH_MAX);
944 }
945 cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
946 } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
947 FILE_DIRECTORY_INFO *pFindData =
948 (FILE_DIRECTORY_INFO *)current_entry;
949 filename = &pFindData->FileName[0];
950 len = le32_to_cpu(pFindData->FileNameLength);
951 cifsFile->srch_inf.resume_key = pFindData->FileIndex;
952 } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
953 FILE_FULL_DIRECTORY_INFO *pFindData =
954 (FILE_FULL_DIRECTORY_INFO *)current_entry;
955 filename = &pFindData->FileName[0];
956 len = le32_to_cpu(pFindData->FileNameLength);
957 cifsFile->srch_inf.resume_key = pFindData->FileIndex;
958 } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
959 SEARCH_ID_FULL_DIR_INFO *pFindData =
960 (SEARCH_ID_FULL_DIR_INFO *)current_entry;
961 filename = &pFindData->FileName[0];
962 len = le32_to_cpu(pFindData->FileNameLength);
963 cifsFile->srch_inf.resume_key = pFindData->FileIndex;
964 } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
965 FILE_BOTH_DIRECTORY_INFO *pFindData =
966 (FILE_BOTH_DIRECTORY_INFO *)current_entry;
967 filename = &pFindData->FileName[0];
968 len = le32_to_cpu(pFindData->FileNameLength);
969 cifsFile->srch_inf.resume_key = pFindData->FileIndex;
970 } else if (level == SMB_FIND_FILE_INFO_STANDARD) {
971 FIND_FILE_STANDARD_INFO *pFindData =
972 (FIND_FILE_STANDARD_INFO *)current_entry;
973 filename = &pFindData->FileName[0];
974 /* one byte length, no name conversion */
975 len = (unsigned int)pFindData->FileNameLength;
976 cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
977 } else {
978 cFYI(1, ("Unknown findfirst level %d", level));
979 return -EINVAL;
980 }
981 cifsFile->srch_inf.resume_name_len = len;
982 cifsFile->srch_inf.presume_name = filename;
983 return rc;
984}
985 987
986int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) 988int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
987{ 989{