diff options
author | Pavel Shilovsky <pshilovsky@samba.org> | 2012-05-23 06:01:59 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2012-06-01 13:35:19 -0400 |
commit | 88257360605f9362dc4d79326c268dd334f61c90 (patch) | |
tree | 81770ae1d528f0d19e9e3a7a78ed90cdf147d452 /fs/cifs/smb1ops.c | |
parent | 7f0adb53bcf5bdb92236cda8ec92ea5e40993028 (diff) |
CIFS: Move get_next_mid to ops struct
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org>
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/smb1ops.c')
-rw-r--r-- | fs/cifs/smb1ops.c | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index d9d615fbed3f..6dec38f5522d 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c | |||
@@ -125,6 +125,94 @@ cifs_get_credits_field(struct TCP_Server_Info *server) | |||
125 | return &server->credits; | 125 | return &server->credits; |
126 | } | 126 | } |
127 | 127 | ||
128 | /* | ||
129 | * Find a free multiplex id (SMB mid). Otherwise there could be | ||
130 | * mid collisions which might cause problems, demultiplexing the | ||
131 | * wrong response to this request. Multiplex ids could collide if | ||
132 | * one of a series requests takes much longer than the others, or | ||
133 | * if a very large number of long lived requests (byte range | ||
134 | * locks or FindNotify requests) are pending. No more than | ||
135 | * 64K-1 requests can be outstanding at one time. If no | ||
136 | * mids are available, return zero. A future optimization | ||
137 | * could make the combination of mids and uid the key we use | ||
138 | * to demultiplex on (rather than mid alone). | ||
139 | * In addition to the above check, the cifs demultiplex | ||
140 | * code already used the command code as a secondary | ||
141 | * check of the frame and if signing is negotiated the | ||
142 | * response would be discarded if the mid were the same | ||
143 | * but the signature was wrong. Since the mid is not put in the | ||
144 | * pending queue until later (when it is about to be dispatched) | ||
145 | * we do have to limit the number of outstanding requests | ||
146 | * to somewhat less than 64K-1 although it is hard to imagine | ||
147 | * so many threads being in the vfs at one time. | ||
148 | */ | ||
149 | static __u64 | ||
150 | cifs_get_next_mid(struct TCP_Server_Info *server) | ||
151 | { | ||
152 | __u64 mid = 0; | ||
153 | __u16 last_mid, cur_mid; | ||
154 | bool collision; | ||
155 | |||
156 | spin_lock(&GlobalMid_Lock); | ||
157 | |||
158 | /* mid is 16 bit only for CIFS/SMB */ | ||
159 | cur_mid = (__u16)((server->CurrentMid) & 0xffff); | ||
160 | /* we do not want to loop forever */ | ||
161 | last_mid = cur_mid; | ||
162 | cur_mid++; | ||
163 | |||
164 | /* | ||
165 | * This nested loop looks more expensive than it is. | ||
166 | * In practice the list of pending requests is short, | ||
167 | * fewer than 50, and the mids are likely to be unique | ||
168 | * on the first pass through the loop unless some request | ||
169 | * takes longer than the 64 thousand requests before it | ||
170 | * (and it would also have to have been a request that | ||
171 | * did not time out). | ||
172 | */ | ||
173 | while (cur_mid != last_mid) { | ||
174 | struct mid_q_entry *mid_entry; | ||
175 | unsigned int num_mids; | ||
176 | |||
177 | collision = false; | ||
178 | if (cur_mid == 0) | ||
179 | cur_mid++; | ||
180 | |||
181 | num_mids = 0; | ||
182 | list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) { | ||
183 | ++num_mids; | ||
184 | if (mid_entry->mid == cur_mid && | ||
185 | mid_entry->mid_state == MID_REQUEST_SUBMITTED) { | ||
186 | /* This mid is in use, try a different one */ | ||
187 | collision = true; | ||
188 | break; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | /* | ||
193 | * if we have more than 32k mids in the list, then something | ||
194 | * is very wrong. Possibly a local user is trying to DoS the | ||
195 | * box by issuing long-running calls and SIGKILL'ing them. If | ||
196 | * we get to 2^16 mids then we're in big trouble as this | ||
197 | * function could loop forever. | ||
198 | * | ||
199 | * Go ahead and assign out the mid in this situation, but force | ||
200 | * an eventual reconnect to clean out the pending_mid_q. | ||
201 | */ | ||
202 | if (num_mids > 32768) | ||
203 | server->tcpStatus = CifsNeedReconnect; | ||
204 | |||
205 | if (!collision) { | ||
206 | mid = (__u64)cur_mid; | ||
207 | server->CurrentMid = mid; | ||
208 | break; | ||
209 | } | ||
210 | cur_mid++; | ||
211 | } | ||
212 | spin_unlock(&GlobalMid_Lock); | ||
213 | return mid; | ||
214 | } | ||
215 | |||
128 | struct smb_version_operations smb1_operations = { | 216 | struct smb_version_operations smb1_operations = { |
129 | .send_cancel = send_nt_cancel, | 217 | .send_cancel = send_nt_cancel, |
130 | .compare_fids = cifs_compare_fids, | 218 | .compare_fids = cifs_compare_fids, |
@@ -133,6 +221,7 @@ struct smb_version_operations smb1_operations = { | |||
133 | .add_credits = cifs_add_credits, | 221 | .add_credits = cifs_add_credits, |
134 | .set_credits = cifs_set_credits, | 222 | .set_credits = cifs_set_credits, |
135 | .get_credits_field = cifs_get_credits_field, | 223 | .get_credits_field = cifs_get_credits_field, |
224 | .get_next_mid = cifs_get_next_mid, | ||
136 | .read_data_offset = cifs_read_data_offset, | 225 | .read_data_offset = cifs_read_data_offset, |
137 | .read_data_length = cifs_read_data_length, | 226 | .read_data_length = cifs_read_data_length, |
138 | .map_error = map_smb_to_linux_error, | 227 | .map_error = map_smb_to_linux_error, |