]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
CIFS: make sure we have the right resume info before calling CIFSFindNext
authorSteve French <sfrench@us.ibm.com>
Sat, 11 Oct 2008 16:55:11 +0000 (16:55 +0000)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 22 Oct 2008 21:13:15 +0000 (14:13 -0700)
commit 0752f1522a9120f731232919f7ad904e9e22b8ce upstream

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>
Signed-off-by: Steve French <sfrench@us.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
fs/cifs/cifsglob.h
fs/cifs/cifssmb.c
fs/cifs/readdir.c

index 9cfcf326ead3e058025b772c0debed32fe28bbe9..646b04f35d4d001592227a383a7a972b4ddbf78d 100644 (file)
@@ -308,6 +308,7 @@ struct cifs_search_info {
        __u32 resume_key;
        char *ntwrk_buf_start;
        char *srch_entries_start;
+       char *last_entry;
        char *presume_name;
        unsigned int resume_name_len;
        bool endOfSearch:1;
index 4511b708f0f312d57677e2947276c2063f142446..0f7286c0776fdaef9158160676d26f23081cb442 100644 (file)
@@ -3638,6 +3638,8 @@ findFirstRetry:
                                        le16_to_cpu(parms->SearchCount);
                        psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
                                psrch_inf->entries_in_buffer;
+                       psrch_inf->last_entry = psrch_inf->srch_entries_start +
+                                       le16_to_cpu(parms->LastNameOffset);
                        *pnetfid = parms->SearchHandle;
                } else {
                        cifs_buf_release(pSMB);
@@ -3753,6 +3755,8 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
                                                le16_to_cpu(parms->SearchCount);
                        psrch_inf->index_of_last_entry +=
                                psrch_inf->entries_in_buffer;
+                       psrch_inf->last_entry = psrch_inf->srch_entries_start +
+                                       le16_to_cpu(parms->LastNameOffset);
 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
            psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
 
index 83f30695488303a785d24f02870fcfff612dd7e7..85ea3c6d4ed0c9262cee39accbb0cbf3c87ebf76 100644 (file)
@@ -640,6 +640,70 @@ static int is_dir_changed(struct file *file)
 
 }
 
+static int cifs_save_resume_key(const char *current_entry,
+       struct cifsFileInfo *cifsFile)
+{
+       int rc = 0;
+       unsigned int len = 0;
+       __u16 level;
+       char *filename;
+
+       if ((cifsFile == NULL) || (current_entry == NULL))
+               return -EINVAL;
+
+       level = cifsFile->srch_inf.info_level;
+
+       if (level == SMB_FIND_FILE_UNIX) {
+               FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
+
+               filename = &pFindData->FileName[0];
+               if (cifsFile->srch_inf.unicode) {
+                       len = cifs_unicode_bytelen(filename);
+               } else {
+                       /* BB should we make this strnlen of PATH_MAX? */
+                       len = strnlen(filename, PATH_MAX);
+               }
+               cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
+       } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
+               FILE_DIRECTORY_INFO *pFindData =
+                       (FILE_DIRECTORY_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               len = le32_to_cpu(pFindData->FileNameLength);
+               cifsFile->srch_inf.resume_key = pFindData->FileIndex;
+       } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
+               FILE_FULL_DIRECTORY_INFO *pFindData =
+                       (FILE_FULL_DIRECTORY_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               len = le32_to_cpu(pFindData->FileNameLength);
+               cifsFile->srch_inf.resume_key = pFindData->FileIndex;
+       } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
+               SEARCH_ID_FULL_DIR_INFO *pFindData =
+                       (SEARCH_ID_FULL_DIR_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               len = le32_to_cpu(pFindData->FileNameLength);
+               cifsFile->srch_inf.resume_key = pFindData->FileIndex;
+       } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+               FILE_BOTH_DIRECTORY_INFO *pFindData =
+                       (FILE_BOTH_DIRECTORY_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               len = le32_to_cpu(pFindData->FileNameLength);
+               cifsFile->srch_inf.resume_key = pFindData->FileIndex;
+       } else if (level == SMB_FIND_FILE_INFO_STANDARD) {
+               FIND_FILE_STANDARD_INFO *pFindData =
+                       (FIND_FILE_STANDARD_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               /* one byte length, no name conversion */
+               len = (unsigned int)pFindData->FileNameLength;
+               cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
+       } else {
+               cFYI(1, ("Unknown findfirst level %d", level));
+               return -EINVAL;
+       }
+       cifsFile->srch_inf.resume_name_len = len;
+       cifsFile->srch_inf.presume_name = filename;
+       return rc;
+}
+
 /* find the corresponding entry in the search */
 /* Note that the SMB server returns search entries for . and .. which
    complicates logic here if we choose to parse for them and we do not
@@ -702,6 +766,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
        while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
              (rc == 0) && !cifsFile->srch_inf.endOfSearch) {
                cFYI(1, ("calling findnext2"));
+               cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile);
                rc = CIFSFindNext(xid, pTcon, cifsFile->netfid,
                                  &cifsFile->srch_inf);
                if (rc)
@@ -918,69 +983,6 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
        return rc;
 }
 
-static int cifs_save_resume_key(const char *current_entry,
-       struct cifsFileInfo *cifsFile)
-{
-       int rc = 0;
-       unsigned int len = 0;
-       __u16 level;
-       char *filename;
-
-       if ((cifsFile == NULL) || (current_entry == NULL))
-               return -EINVAL;
-
-       level = cifsFile->srch_inf.info_level;
-
-       if (level == SMB_FIND_FILE_UNIX) {
-               FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
-
-               filename = &pFindData->FileName[0];
-               if (cifsFile->srch_inf.unicode) {
-                       len = cifs_unicode_bytelen(filename);
-               } else {
-                       /* BB should we make this strnlen of PATH_MAX? */
-                       len = strnlen(filename, PATH_MAX);
-               }
-               cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
-       } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
-               FILE_DIRECTORY_INFO *pFindData =
-                       (FILE_DIRECTORY_INFO *)current_entry;
-               filename = &pFindData->FileName[0];
-               len = le32_to_cpu(pFindData->FileNameLength);
-               cifsFile->srch_inf.resume_key = pFindData->FileIndex;
-       } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
-               FILE_FULL_DIRECTORY_INFO *pFindData =
-                       (FILE_FULL_DIRECTORY_INFO *)current_entry;
-               filename = &pFindData->FileName[0];
-               len = le32_to_cpu(pFindData->FileNameLength);
-               cifsFile->srch_inf.resume_key = pFindData->FileIndex;
-       } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
-               SEARCH_ID_FULL_DIR_INFO *pFindData =
-                       (SEARCH_ID_FULL_DIR_INFO *)current_entry;
-               filename = &pFindData->FileName[0];
-               len = le32_to_cpu(pFindData->FileNameLength);
-               cifsFile->srch_inf.resume_key = pFindData->FileIndex;
-       } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
-               FILE_BOTH_DIRECTORY_INFO *pFindData =
-                       (FILE_BOTH_DIRECTORY_INFO *)current_entry;
-               filename = &pFindData->FileName[0];
-               len = le32_to_cpu(pFindData->FileNameLength);
-               cifsFile->srch_inf.resume_key = pFindData->FileIndex;
-       } else if (level == SMB_FIND_FILE_INFO_STANDARD) {
-               FIND_FILE_STANDARD_INFO *pFindData =
-                       (FIND_FILE_STANDARD_INFO *)current_entry;
-               filename = &pFindData->FileName[0];
-               /* one byte length, no name conversion */
-               len = (unsigned int)pFindData->FileNameLength;
-               cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
-       } else {
-               cFYI(1, ("Unknown findfirst level %d", level));
-               return -EINVAL;
-       }
-       cifsFile->srch_inf.resume_name_len = len;
-       cifsFile->srch_inf.presume_name = filename;
-       return rc;
-}
 
 int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 {