diff options
Diffstat (limited to 'fs/cifs/misc.c')
-rw-r--r-- | fs/cifs/misc.c | 84 |
1 files changed, 46 insertions, 38 deletions
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index dc61dff2c42a..d2ccce89062f 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -213,54 +213,61 @@ cifs_small_buf_release(void *buf_to_free) } /* - Find a free multiplex id (SMB mid). Otherwise there could be - mid collisions which might cause problems, demultiplexing the - wrong response to this request. Multiplex ids could collide if - one of a series requests takes much longer than the others, or - if a very large number of long lived requests (byte range - locks or FindNotify requests) are pending. No more than - 64K-1 requests can be outstanding at one time. If no - mids are available, return zero. A future optimization - could make the combination of mids and uid the key we use - to demultiplex on (rather than mid alone). - In addition to the above check, the cifs demultiplex - code already used the command code as a secondary - check of the frame and if signing is negotiated the - response would be discarded if the mid were the same - but the signature was wrong. Since the mid is not put in the - pending queue until later (when it is about to be dispatched) - we do have to limit the number of outstanding requests - to somewhat less than 64K-1 although it is hard to imagine - so many threads being in the vfs at one time. -*/ -__u16 GetNextMid(struct TCP_Server_Info *server) + * Find a free multiplex id (SMB mid). Otherwise there could be + * mid collisions which might cause problems, demultiplexing the + * wrong response to this request. Multiplex ids could collide if + * one of a series requests takes much longer than the others, or + * if a very large number of long lived requests (byte range + * locks or FindNotify requests) are pending. No more than + * 64K-1 requests can be outstanding at one time. If no + * mids are available, return zero. A future optimization + * could make the combination of mids and uid the key we use + * to demultiplex on (rather than mid alone). + * In addition to the above check, the cifs demultiplex + * code already used the command code as a secondary + * check of the frame and if signing is negotiated the + * response would be discarded if the mid were the same + * but the signature was wrong. Since the mid is not put in the + * pending queue until later (when it is about to be dispatched) + * we do have to limit the number of outstanding requests + * to somewhat less than 64K-1 although it is hard to imagine + * so many threads being in the vfs at one time. + */ +__u64 GetNextMid(struct TCP_Server_Info *server) { - __u16 mid = 0; - __u16 last_mid; + __u64 mid = 0; + __u16 last_mid, cur_mid; bool collision; spin_lock(&GlobalMid_Lock); - last_mid = server->CurrentMid; /* we do not want to loop forever */ - server->CurrentMid++; - /* This nested loop looks more expensive than it is. - In practice the list of pending requests is short, - fewer than 50, and the mids are likely to be unique - on the first pass through the loop unless some request - takes longer than the 64 thousand requests before it - (and it would also have to have been a request that - did not time out) */ - while (server->CurrentMid != last_mid) { + + /* mid is 16 bit only for CIFS/SMB */ + cur_mid = (__u16)((server->CurrentMid) & 0xffff); + /* we do not want to loop forever */ + last_mid = cur_mid; + cur_mid++; + + /* + * This nested loop looks more expensive than it is. + * In practice the list of pending requests is short, + * fewer than 50, and the mids are likely to be unique + * on the first pass through the loop unless some request + * takes longer than the 64 thousand requests before it + * (and it would also have to have been a request that + * did not time out). + */ + while (cur_mid != last_mid) { struct mid_q_entry *mid_entry; unsigned int num_mids; collision = false; - if (server->CurrentMid == 0) - server->CurrentMid++; + if (cur_mid == 0) + cur_mid++; num_mids = 0; list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) { ++num_mids; - if (mid_entry->mid == server->CurrentMid && + if (mid_entry->mid == cur_mid && mid_entry->midState == MID_REQUEST_SUBMITTED) { /* This mid is in use, try a different one */ collision = true; @@ -282,10 +289,11 @@ __u16 GetNextMid(struct TCP_Server_Info *server) server->tcpStatus = CifsNeedReconnect; if (!collision) { - mid = server->CurrentMid; + mid = (__u64)cur_mid; + server->CurrentMid = mid; break; } - server->CurrentMid++; + cur_mid++; } spin_unlock(&GlobalMid_Lock); return mid; |