aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/smb1ops.c
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilovsky@samba.org>2012-05-23 06:01:59 -0400
committerSteve French <sfrench@us.ibm.com>2012-06-01 13:35:19 -0400
commit88257360605f9362dc4d79326c268dd334f61c90 (patch)
tree81770ae1d528f0d19e9e3a7a78ed90cdf147d452 /fs/cifs/smb1ops.c
parent7f0adb53bcf5bdb92236cda8ec92ea5e40993028 (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.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index d9d615fbed3..6dec38f5522 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 */
149static __u64
150cifs_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
128struct smb_version_operations smb1_operations = { 216struct 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,