Skip to content

Commit bf2785a

Browse files
committed
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs fixes from Steve French. * 'for-next' of git://git.samba.org/sfrench/cifs-2.6: CIFS: Move get_next_mid to ops struct CIFS: Make accessing is_valid_oplock/dump_detail ops struct field safe CIFS: Improve identation in cifs_unlock_range CIFS: Fix possible wrong memory allocation
2 parents a3fe778 + 8825736 commit bf2785a

File tree

8 files changed

+167
-143
lines changed

8 files changed

+167
-143
lines changed

fs/cifs/cifsglob.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ struct smb_version_operations {
174174
void (*add_credits)(struct TCP_Server_Info *, const unsigned int);
175175
void (*set_credits)(struct TCP_Server_Info *, const int);
176176
int * (*get_credits_field)(struct TCP_Server_Info *);
177+
__u64 (*get_next_mid)(struct TCP_Server_Info *);
177178
/* data offset from read response message */
178179
unsigned int (*read_data_offset)(char *);
179180
/* data length from read response message */
@@ -399,6 +400,12 @@ set_credits(struct TCP_Server_Info *server, const int val)
399400
server->ops->set_credits(server, val);
400401
}
401402

403+
static inline __u64
404+
get_next_mid(struct TCP_Server_Info *server)
405+
{
406+
return server->ops->get_next_mid(server);
407+
}
408+
402409
/*
403410
* Macros to allow the TCP_Server_Info->net field and related code to drop out
404411
* when CONFIG_NET_NS isn't set.

fs/cifs/cifsproto.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@ extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
114114
void **request_buf);
115115
extern int CIFS_SessSetup(unsigned int xid, struct cifs_ses *ses,
116116
const struct nls_table *nls_cp);
117-
extern __u64 GetNextMid(struct TCP_Server_Info *server);
118117
extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
119118
extern u64 cifs_UnixTimeToNT(struct timespec);
120119
extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,

fs/cifs/cifssmb.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ small_smb_init_no_tc(const int smb_command, const int wct,
268268
return rc;
269269

270270
buffer = (struct smb_hdr *)*request_buf;
271-
buffer->Mid = GetNextMid(ses->server);
271+
buffer->Mid = get_next_mid(ses->server);
272272
if (ses->capabilities & CAP_UNICODE)
273273
buffer->Flags2 |= SMBFLG2_UNICODE;
274274
if (ses->capabilities & CAP_STATUS32)
@@ -402,7 +402,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
402402

403403
cFYI(1, "secFlags 0x%x", secFlags);
404404

405-
pSMB->hdr.Mid = GetNextMid(server);
405+
pSMB->hdr.Mid = get_next_mid(server);
406406
pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
407407

408408
if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
@@ -782,7 +782,7 @@ CIFSSMBLogoff(const int xid, struct cifs_ses *ses)
782782
return rc;
783783
}
784784

785-
pSMB->hdr.Mid = GetNextMid(ses->server);
785+
pSMB->hdr.Mid = get_next_mid(ses->server);
786786

787787
if (ses->server->sec_mode &
788788
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
@@ -4762,7 +4762,7 @@ CIFSGetDFSRefer(const int xid, struct cifs_ses *ses,
47624762

47634763
/* server pointer checked in called function,
47644764
but should never be null here anyway */
4765-
pSMB->hdr.Mid = GetNextMid(ses->server);
4765+
pSMB->hdr.Mid = get_next_mid(ses->server);
47664766
pSMB->hdr.Tid = ses->ipc_tid;
47674767
pSMB->hdr.Uid = ses->Suid;
47684768
if (ses->capabilities & CAP_STATUS32)

fs/cifs/connect.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,13 +1058,15 @@ cifs_demultiplex_thread(void *p)
10581058
if (mid_entry != NULL) {
10591059
if (!mid_entry->multiRsp || mid_entry->multiEnd)
10601060
mid_entry->callback(mid_entry);
1061-
} else if (!server->ops->is_oplock_break(buf, server)) {
1061+
} else if (!server->ops->is_oplock_break ||
1062+
!server->ops->is_oplock_break(buf, server)) {
10621063
cERROR(1, "No task to wake, unknown frame received! "
10631064
"NumMids %d", atomic_read(&midCount));
10641065
cifs_dump_mem("Received Data is: ", buf,
10651066
HEADER_SIZE(server));
10661067
#ifdef CONFIG_CIFS_DEBUG2
1067-
server->ops->dump_detail(buf);
1068+
if (server->ops->dump_detail)
1069+
server->ops->dump_detail(buf);
10681070
cifs_dump_mids(server);
10691071
#endif /* CIFS_DEBUG2 */
10701072

@@ -3938,7 +3940,7 @@ CIFSTCon(unsigned int xid, struct cifs_ses *ses,
39383940
header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
39393941
NULL /*no tid */ , 4 /*wct */ );
39403942

3941-
smb_buffer->Mid = GetNextMid(ses->server);
3943+
smb_buffer->Mid = get_next_mid(ses->server);
39423944
smb_buffer->Uid = ses->Suid;
39433945
pSMB = (TCONX_REQ *) smb_buffer;
39443946
pSMBr = (TCONX_RSP *) smb_buffer_response;

fs/cifs/file.c

Lines changed: 60 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -876,7 +876,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
876876
struct cifsLockInfo *li, *tmp;
877877
struct cifs_tcon *tcon;
878878
struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
879-
unsigned int num, max_num;
879+
unsigned int num, max_num, max_buf;
880880
LOCKING_ANDX_RANGE *buf, *cur;
881881
int types[] = {LOCKING_ANDX_LARGE_FILES,
882882
LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES};
@@ -892,8 +892,19 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
892892
return rc;
893893
}
894894

895-
max_num = (tcon->ses->server->maxBuf - sizeof(struct smb_hdr)) /
896-
sizeof(LOCKING_ANDX_RANGE);
895+
/*
896+
* Accessing maxBuf is racy with cifs_reconnect - need to store value
897+
* and check it for zero before using.
898+
*/
899+
max_buf = tcon->ses->server->maxBuf;
900+
if (!max_buf) {
901+
mutex_unlock(&cinode->lock_mutex);
902+
FreeXid(xid);
903+
return -EINVAL;
904+
}
905+
906+
max_num = (max_buf - sizeof(struct smb_hdr)) /
907+
sizeof(LOCKING_ANDX_RANGE);
897908
buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
898909
if (!buf) {
899910
mutex_unlock(&cinode->lock_mutex);
@@ -1218,7 +1229,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid)
12181229
int types[] = {LOCKING_ANDX_LARGE_FILES,
12191230
LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES};
12201231
unsigned int i;
1221-
unsigned int max_num, num;
1232+
unsigned int max_num, num, max_buf;
12221233
LOCKING_ANDX_RANGE *buf, *cur;
12231234
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
12241235
struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
@@ -1228,8 +1239,16 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid)
12281239

12291240
INIT_LIST_HEAD(&tmp_llist);
12301241

1231-
max_num = (tcon->ses->server->maxBuf - sizeof(struct smb_hdr)) /
1232-
sizeof(LOCKING_ANDX_RANGE);
1242+
/*
1243+
* Accessing maxBuf is racy with cifs_reconnect - need to store value
1244+
* and check it for zero before using.
1245+
*/
1246+
max_buf = tcon->ses->server->maxBuf;
1247+
if (!max_buf)
1248+
return -EINVAL;
1249+
1250+
max_num = (max_buf - sizeof(struct smb_hdr)) /
1251+
sizeof(LOCKING_ANDX_RANGE);
12331252
buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
12341253
if (!buf)
12351254
return -ENOMEM;
@@ -1247,54 +1266,49 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid)
12471266
continue;
12481267
if (types[i] != li->type)
12491268
continue;
1250-
if (!cinode->can_cache_brlcks) {
1251-
cur->Pid = cpu_to_le16(li->pid);
1252-
cur->LengthLow = cpu_to_le32((u32)li->length);
1253-
cur->LengthHigh =
1254-
cpu_to_le32((u32)(li->length>>32));
1255-
cur->OffsetLow = cpu_to_le32((u32)li->offset);
1256-
cur->OffsetHigh =
1257-
cpu_to_le32((u32)(li->offset>>32));
1258-
/*
1259-
* We need to save a lock here to let us add
1260-
* it again to the file's list if the unlock
1261-
* range request fails on the server.
1262-
*/
1263-
list_move(&li->llist, &tmp_llist);
1264-
if (++num == max_num) {
1265-
stored_rc = cifs_lockv(xid, tcon,
1266-
cfile->netfid,
1267-
li->type, num,
1268-
0, buf);
1269-
if (stored_rc) {
1270-
/*
1271-
* We failed on the unlock range
1272-
* request - add all locks from
1273-
* the tmp list to the head of
1274-
* the file's list.
1275-
*/
1276-
cifs_move_llist(&tmp_llist,
1277-
&cfile->llist);
1278-
rc = stored_rc;
1279-
} else
1280-
/*
1281-
* The unlock range request
1282-
* succeed - free the tmp list.
1283-
*/
1284-
cifs_free_llist(&tmp_llist);
1285-
cur = buf;
1286-
num = 0;
1287-
} else
1288-
cur++;
1289-
} else {
1269+
if (cinode->can_cache_brlcks) {
12901270
/*
12911271
* We can cache brlock requests - simply remove
12921272
* a lock from the file's list.
12931273
*/
12941274
list_del(&li->llist);
12951275
cifs_del_lock_waiters(li);
12961276
kfree(li);
1277+
continue;
12971278
}
1279+
cur->Pid = cpu_to_le16(li->pid);
1280+
cur->LengthLow = cpu_to_le32((u32)li->length);
1281+
cur->LengthHigh = cpu_to_le32((u32)(li->length>>32));
1282+
cur->OffsetLow = cpu_to_le32((u32)li->offset);
1283+
cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32));
1284+
/*
1285+
* We need to save a lock here to let us add it again to
1286+
* the file's list if the unlock range request fails on
1287+
* the server.
1288+
*/
1289+
list_move(&li->llist, &tmp_llist);
1290+
if (++num == max_num) {
1291+
stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
1292+
li->type, num, 0, buf);
1293+
if (stored_rc) {
1294+
/*
1295+
* We failed on the unlock range
1296+
* request - add all locks from the tmp
1297+
* list to the head of the file's list.
1298+
*/
1299+
cifs_move_llist(&tmp_llist,
1300+
&cfile->llist);
1301+
rc = stored_rc;
1302+
} else
1303+
/*
1304+
* The unlock range request succeed -
1305+
* free the tmp list.
1306+
*/
1307+
cifs_free_llist(&tmp_llist);
1308+
cur = buf;
1309+
num = 0;
1310+
} else
1311+
cur++;
12981312
}
12991313
if (num) {
13001314
stored_rc = cifs_lockv(xid, tcon, cfile->netfid,

fs/cifs/misc.c

Lines changed: 1 addition & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -212,93 +212,6 @@ cifs_small_buf_release(void *buf_to_free)
212212
return;
213213
}
214214

215-
/*
216-
* Find a free multiplex id (SMB mid). Otherwise there could be
217-
* mid collisions which might cause problems, demultiplexing the
218-
* wrong response to this request. Multiplex ids could collide if
219-
* one of a series requests takes much longer than the others, or
220-
* if a very large number of long lived requests (byte range
221-
* locks or FindNotify requests) are pending. No more than
222-
* 64K-1 requests can be outstanding at one time. If no
223-
* mids are available, return zero. A future optimization
224-
* could make the combination of mids and uid the key we use
225-
* to demultiplex on (rather than mid alone).
226-
* In addition to the above check, the cifs demultiplex
227-
* code already used the command code as a secondary
228-
* check of the frame and if signing is negotiated the
229-
* response would be discarded if the mid were the same
230-
* but the signature was wrong. Since the mid is not put in the
231-
* pending queue until later (when it is about to be dispatched)
232-
* we do have to limit the number of outstanding requests
233-
* to somewhat less than 64K-1 although it is hard to imagine
234-
* so many threads being in the vfs at one time.
235-
*/
236-
__u64 GetNextMid(struct TCP_Server_Info *server)
237-
{
238-
__u64 mid = 0;
239-
__u16 last_mid, cur_mid;
240-
bool collision;
241-
242-
spin_lock(&GlobalMid_Lock);
243-
244-
/* mid is 16 bit only for CIFS/SMB */
245-
cur_mid = (__u16)((server->CurrentMid) & 0xffff);
246-
/* we do not want to loop forever */
247-
last_mid = cur_mid;
248-
cur_mid++;
249-
250-
/*
251-
* This nested loop looks more expensive than it is.
252-
* In practice the list of pending requests is short,
253-
* fewer than 50, and the mids are likely to be unique
254-
* on the first pass through the loop unless some request
255-
* takes longer than the 64 thousand requests before it
256-
* (and it would also have to have been a request that
257-
* did not time out).
258-
*/
259-
while (cur_mid != last_mid) {
260-
struct mid_q_entry *mid_entry;
261-
unsigned int num_mids;
262-
263-
collision = false;
264-
if (cur_mid == 0)
265-
cur_mid++;
266-
267-
num_mids = 0;
268-
list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
269-
++num_mids;
270-
if (mid_entry->mid == cur_mid &&
271-
mid_entry->mid_state == MID_REQUEST_SUBMITTED) {
272-
/* This mid is in use, try a different one */
273-
collision = true;
274-
break;
275-
}
276-
}
277-
278-
/*
279-
* if we have more than 32k mids in the list, then something
280-
* is very wrong. Possibly a local user is trying to DoS the
281-
* box by issuing long-running calls and SIGKILL'ing them. If
282-
* we get to 2^16 mids then we're in big trouble as this
283-
* function could loop forever.
284-
*
285-
* Go ahead and assign out the mid in this situation, but force
286-
* an eventual reconnect to clean out the pending_mid_q.
287-
*/
288-
if (num_mids > 32768)
289-
server->tcpStatus = CifsNeedReconnect;
290-
291-
if (!collision) {
292-
mid = (__u64)cur_mid;
293-
server->CurrentMid = mid;
294-
break;
295-
}
296-
cur_mid++;
297-
}
298-
spin_unlock(&GlobalMid_Lock);
299-
return mid;
300-
}
301-
302215
/* NB: MID can not be set if treeCon not passed in, in that
303216
case it is responsbility of caller to set the mid */
304217
void
@@ -334,7 +247,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
334247

335248
/* Uid is not converted */
336249
buffer->Uid = treeCon->ses->Suid;
337-
buffer->Mid = GetNextMid(treeCon->ses->server);
250+
buffer->Mid = get_next_mid(treeCon->ses->server);
338251
}
339252
if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
340253
buffer->Flags2 |= SMBFLG2_DFS;

0 commit comments

Comments
 (0)