]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/2.6.25.19/cifs-make-sure-we-have-the-right-resume-info-before-calling-cifsfindnext.patch
drop queue-4.14/mips-make-sure-dt-memory-regions-are-valid.patch
[thirdparty/kernel/stable-queue.git] / releases / 2.6.25.19 / cifs-make-sure-we-have-the-right-resume-info-before-calling-cifsfindnext.patch
1 From jejb@kernel.org Wed Oct 15 14:35:35 2008
2 From: Steve French <sfrench@us.ibm.com>
3 Date: Sat, 11 Oct 2008 16:55:11 GMT
4 Subject: CIFS: make sure we have the right resume info before calling CIFSFindNext
5 To: jejb@kernel.org, stable@kernel.org
6 Message-ID: <200810111655.m9BGtBTL013214@hera.kernel.org>
7
8 From: Steve French <sfrench@us.ibm.com>
9
10 commit 0752f1522a9120f731232919f7ad904e9e22b8ce upstream
11
12 When we do a seekdir() or equivalent, we usually end up doing a
13 FindFirst call and then call FindNext until we get to the offset that we
14 want. The problem is that when we call FindNext, the code usually
15 doesn't have the proper info (mostly, the filename of the entry from the
16 last search) to resume the search.
17
18 Add a "last_entry" field to the cifs_search_info that points to the last
19 entry in the search. We calculate this pointer by using the
20 LastNameOffset field from the search parms that are returned. We then
21 use that info to do a cifs_save_resume_key before we call CIFSFindNext.
22
23 This patch allows CIFS to reliably pass the "telldir" connectathon test.
24
25 Signed-off-by: Jeff Layton <jlayton@redhat.com>
26 Signed-off-by: Steve French <sfrench@us.ibm.com>
27 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
28
29 ---
30 fs/cifs/cifsglob.h | 1
31 fs/cifs/cifssmb.c | 4 +
32 fs/cifs/readdir.c | 128 ++++++++++++++++++++++++++---------------------------
33 3 files changed, 70 insertions(+), 63 deletions(-)
34
35 --- a/fs/cifs/cifsglob.h
36 +++ b/fs/cifs/cifsglob.h
37 @@ -315,6 +315,7 @@ struct cifs_search_info {
38 __u32 resume_key;
39 char *ntwrk_buf_start;
40 char *srch_entries_start;
41 + char *last_entry;
42 char *presume_name;
43 unsigned int resume_name_len;
44 unsigned endOfSearch:1;
45 --- a/fs/cifs/cifssmb.c
46 +++ b/fs/cifs/cifssmb.c
47 @@ -3598,6 +3598,8 @@ findFirstRetry:
48 le16_to_cpu(parms->SearchCount);
49 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
50 psrch_inf->entries_in_buffer;
51 + psrch_inf->last_entry = psrch_inf->srch_entries_start +
52 + le16_to_cpu(parms->LastNameOffset);
53 *pnetfid = parms->SearchHandle;
54 } else {
55 cifs_buf_release(pSMB);
56 @@ -3712,6 +3714,8 @@ int CIFSFindNext(const int xid, struct c
57 le16_to_cpu(parms->SearchCount);
58 psrch_inf->index_of_last_entry +=
59 psrch_inf->entries_in_buffer;
60 + psrch_inf->last_entry = psrch_inf->srch_entries_start +
61 + le16_to_cpu(parms->LastNameOffset);
62 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
63 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
64
65 --- a/fs/cifs/readdir.c
66 +++ b/fs/cifs/readdir.c
67 @@ -633,6 +633,70 @@ static int is_dir_changed(struct file *f
68
69 }
70
71 +static int cifs_save_resume_key(const char *current_entry,
72 + struct cifsFileInfo *cifsFile)
73 +{
74 + int rc = 0;
75 + unsigned int len = 0;
76 + __u16 level;
77 + char *filename;
78 +
79 + if ((cifsFile == NULL) || (current_entry == NULL))
80 + return -EINVAL;
81 +
82 + level = cifsFile->srch_inf.info_level;
83 +
84 + if (level == SMB_FIND_FILE_UNIX) {
85 + FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
86 +
87 + filename = &pFindData->FileName[0];
88 + if (cifsFile->srch_inf.unicode) {
89 + len = cifs_unicode_bytelen(filename);
90 + } else {
91 + /* BB should we make this strnlen of PATH_MAX? */
92 + len = strnlen(filename, PATH_MAX);
93 + }
94 + cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
95 + } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
96 + FILE_DIRECTORY_INFO *pFindData =
97 + (FILE_DIRECTORY_INFO *)current_entry;
98 + filename = &pFindData->FileName[0];
99 + len = le32_to_cpu(pFindData->FileNameLength);
100 + cifsFile->srch_inf.resume_key = pFindData->FileIndex;
101 + } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
102 + FILE_FULL_DIRECTORY_INFO *pFindData =
103 + (FILE_FULL_DIRECTORY_INFO *)current_entry;
104 + filename = &pFindData->FileName[0];
105 + len = le32_to_cpu(pFindData->FileNameLength);
106 + cifsFile->srch_inf.resume_key = pFindData->FileIndex;
107 + } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
108 + SEARCH_ID_FULL_DIR_INFO *pFindData =
109 + (SEARCH_ID_FULL_DIR_INFO *)current_entry;
110 + filename = &pFindData->FileName[0];
111 + len = le32_to_cpu(pFindData->FileNameLength);
112 + cifsFile->srch_inf.resume_key = pFindData->FileIndex;
113 + } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
114 + FILE_BOTH_DIRECTORY_INFO *pFindData =
115 + (FILE_BOTH_DIRECTORY_INFO *)current_entry;
116 + filename = &pFindData->FileName[0];
117 + len = le32_to_cpu(pFindData->FileNameLength);
118 + cifsFile->srch_inf.resume_key = pFindData->FileIndex;
119 + } else if (level == SMB_FIND_FILE_INFO_STANDARD) {
120 + FIND_FILE_STANDARD_INFO *pFindData =
121 + (FIND_FILE_STANDARD_INFO *)current_entry;
122 + filename = &pFindData->FileName[0];
123 + /* one byte length, no name conversion */
124 + len = (unsigned int)pFindData->FileNameLength;
125 + cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
126 + } else {
127 + cFYI(1, ("Unknown findfirst level %d", level));
128 + return -EINVAL;
129 + }
130 + cifsFile->srch_inf.resume_name_len = len;
131 + cifsFile->srch_inf.presume_name = filename;
132 + return rc;
133 +}
134 +
135 /* find the corresponding entry in the search */
136 /* Note that the SMB server returns search entries for . and .. which
137 complicates logic here if we choose to parse for them and we do not
138 @@ -694,6 +758,7 @@ static int find_cifs_entry(const int xid
139 while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
140 (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)) {
141 cFYI(1, ("calling findnext2"));
142 + cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile);
143 rc = CIFSFindNext(xid, pTcon, cifsFile->netfid,
144 &cifsFile->srch_inf);
145 if (rc)
146 @@ -910,69 +975,6 @@ static int cifs_filldir(char *pfindEntry
147 return rc;
148 }
149
150 -static int cifs_save_resume_key(const char *current_entry,
151 - struct cifsFileInfo *cifsFile)
152 -{
153 - int rc = 0;
154 - unsigned int len = 0;
155 - __u16 level;
156 - char *filename;
157 -
158 - if ((cifsFile == NULL) || (current_entry == NULL))
159 - return -EINVAL;
160 -
161 - level = cifsFile->srch_inf.info_level;
162 -
163 - if (level == SMB_FIND_FILE_UNIX) {
164 - FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
165 -
166 - filename = &pFindData->FileName[0];
167 - if (cifsFile->srch_inf.unicode) {
168 - len = cifs_unicode_bytelen(filename);
169 - } else {
170 - /* BB should we make this strnlen of PATH_MAX? */
171 - len = strnlen(filename, PATH_MAX);
172 - }
173 - cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
174 - } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
175 - FILE_DIRECTORY_INFO *pFindData =
176 - (FILE_DIRECTORY_INFO *)current_entry;
177 - filename = &pFindData->FileName[0];
178 - len = le32_to_cpu(pFindData->FileNameLength);
179 - cifsFile->srch_inf.resume_key = pFindData->FileIndex;
180 - } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
181 - FILE_FULL_DIRECTORY_INFO *pFindData =
182 - (FILE_FULL_DIRECTORY_INFO *)current_entry;
183 - filename = &pFindData->FileName[0];
184 - len = le32_to_cpu(pFindData->FileNameLength);
185 - cifsFile->srch_inf.resume_key = pFindData->FileIndex;
186 - } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
187 - SEARCH_ID_FULL_DIR_INFO *pFindData =
188 - (SEARCH_ID_FULL_DIR_INFO *)current_entry;
189 - filename = &pFindData->FileName[0];
190 - len = le32_to_cpu(pFindData->FileNameLength);
191 - cifsFile->srch_inf.resume_key = pFindData->FileIndex;
192 - } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
193 - FILE_BOTH_DIRECTORY_INFO *pFindData =
194 - (FILE_BOTH_DIRECTORY_INFO *)current_entry;
195 - filename = &pFindData->FileName[0];
196 - len = le32_to_cpu(pFindData->FileNameLength);
197 - cifsFile->srch_inf.resume_key = pFindData->FileIndex;
198 - } else if (level == SMB_FIND_FILE_INFO_STANDARD) {
199 - FIND_FILE_STANDARD_INFO *pFindData =
200 - (FIND_FILE_STANDARD_INFO *)current_entry;
201 - filename = &pFindData->FileName[0];
202 - /* one byte length, no name conversion */
203 - len = (unsigned int)pFindData->FileNameLength;
204 - cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
205 - } else {
206 - cFYI(1, ("Unknown findfirst level %d", level));
207 - return -EINVAL;
208 - }
209 - cifsFile->srch_inf.resume_name_len = len;
210 - cifsFile->srch_inf.presume_name = filename;
211 - return rc;
212 -}
213
214 int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
215 {