Skip to content

Commit 28405cb

Browse files
dhowellssmfrench
authored andcommitted
cifs: Replace SendReceiveBlockingLock() with SendReceive() plus flags
Replace the smb1 transport's SendReceiveBlockingLock() with SendReceive() plus a couple of flags. This will then allow that to pick up the transport changes there. The first flag, CIFS_INTERRUPTIBLE_WAIT, is added to indicate that the wait should be interruptible and the second, CIFS_WINDOWS_LOCK, indicates that we need to send a Lock command with unlock type rather than a Cancel. send_lock_cancel() is then called from cifs_lock_cancel() which is called from the main transport loop in compound_send_recv(). [!] I *think* the error code handling is probably right. Signed-off-by: David Howells <dhowells@redhat.com> Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.org> cc: Shyam Prasad N <sprasad@microsoft.com> cc: Tom Talpey <tom@talpey.com> cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent 62432a3 commit 28405cb

6 files changed

Lines changed: 79 additions & 216 deletions

File tree

fs/smb/client/cifsglob.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,8 +311,9 @@ struct cifs_open_parms;
311311
struct cifs_credits;
312312

313313
struct smb_version_operations {
314-
int (*send_cancel)(struct TCP_Server_Info *, struct smb_rqst *,
315-
struct mid_q_entry *);
314+
int (*send_cancel)(struct cifs_ses *ses, struct TCP_Server_Info *server,
315+
struct smb_rqst *rqst, struct mid_q_entry *mid,
316+
unsigned int xid);
316317
bool (*compare_fids)(struct cifsFileInfo *, struct cifsFileInfo *);
317318
/* setup request: allocate mid, sign message */
318319
struct mid_q_entry *(*setup_request)(struct cifs_ses *,
@@ -1689,6 +1690,7 @@ struct mid_q_entry {
16891690
__u16 credits_received; /* number of credits from the response */
16901691
__u32 pid; /* process id */
16911692
__u32 sequence_number; /* for CIFS signing */
1693+
unsigned int sr_flags; /* Flags passed to send_recv() */
16921694
unsigned long when_alloc; /* when mid was created */
16931695
#ifdef CONFIG_CIFS_STATS2
16941696
unsigned long when_sent; /* time when smb send finished */
@@ -1900,6 +1902,8 @@ enum cifs_writable_file_flags {
19001902
#define CIFS_TRANSFORM_REQ 0x0800 /* transform request before sending */
19011903
#define CIFS_NO_SRV_RSP 0x1000 /* there is no server response */
19021904
#define CIFS_COMPRESS_REQ 0x4000 /* compress request before sending */
1905+
#define CIFS_INTERRUPTIBLE_WAIT 0x8000 /* Interruptible wait (e.g. lock request) */
1906+
#define CIFS_WINDOWS_LOCK 0x10000 /* We're trying to get a Windows lock */
19031907

19041908
/* Security Flags: indicate type of session setup needed */
19051909
#define CIFSSEC_MAY_SIGN 0x00001

fs/smb/client/cifsproto.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,21 +130,19 @@ extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server,
130130
struct cifs_credits *credits);
131131

132132
static inline int
133-
send_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
134-
struct mid_q_entry *mid)
133+
send_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
134+
struct smb_rqst *rqst, struct mid_q_entry *mid,
135+
unsigned int xid)
135136
{
136137
return server->ops->send_cancel ?
137-
server->ops->send_cancel(server, rqst, mid) : 0;
138+
server->ops->send_cancel(ses, server, rqst, mid, xid) : 0;
138139
}
139140

140141
int wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ);
141142
extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
142143
struct kvec *, int /* nvec to send */,
143144
int * /* type of buf returned */, const int flags,
144145
struct kvec * /* resp vec */);
145-
int SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
146-
struct smb_hdr *in_buf, unsigned int in_len,
147-
struct smb_hdr *out_buf, int *pbytes_returned);
148146

149147
void smb2_query_server_interfaces(struct work_struct *work);
150148
void

fs/smb/client/cifssmb.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2059,7 +2059,7 @@ CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
20592059
/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
20602060
unsigned int in_len;
20612061
int bytes_returned;
2062-
int flags = 0;
2062+
int flags = CIFS_WINDOWS_LOCK | CIFS_INTERRUPTIBLE_WAIT;
20632063
__u16 count;
20642064

20652065
cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
@@ -2104,8 +2104,9 @@ CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
21042104
pSMB->ByteCount = cpu_to_le16(count);
21052105

21062106
if (waitFlag)
2107-
rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, in_len,
2108-
(struct smb_hdr *) pSMB, &bytes_returned);
2107+
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
2108+
(struct smb_hdr *) pSMB, &bytes_returned,
2109+
flags);
21092110
else
21102111
rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, in_len, flags);
21112112
cifs_small_buf_release(pSMB);
@@ -2130,7 +2131,7 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
21302131
struct cifs_posix_lock *parm_data;
21312132
unsigned int in_len;
21322133
int rc = 0;
2133-
int timeout = 0;
2134+
int sr_flags = CIFS_INTERRUPTIBLE_WAIT;
21342135
int bytes_returned = 0;
21352136
int resp_buf_type = 0;
21362137
__u16 params, param_offset, offset, byte_count, count;
@@ -2173,7 +2174,7 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
21732174

21742175
parm_data->lock_type = cpu_to_le16(lock_type);
21752176
if (waitFlag) {
2176-
timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
2177+
sr_flags |= CIFS_BLOCKING_OP; /* blocking operation, no timeout */
21772178
parm_data->lock_flags = cpu_to_le16(1);
21782179
pSMB->Timeout = cpu_to_le32(-1);
21792180
} else
@@ -2190,13 +2191,14 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
21902191
in_len += byte_count;
21912192
pSMB->ByteCount = cpu_to_le16(byte_count);
21922193
if (waitFlag) {
2193-
rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, in_len,
2194-
(struct smb_hdr *) pSMBr, &bytes_returned);
2194+
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len,
2195+
(struct smb_hdr *) pSMBr, &bytes_returned,
2196+
sr_flags);
21952197
} else {
21962198
iov[0].iov_base = (char *)pSMB;
21972199
iov[0].iov_len = in_len;
21982200
rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2199-
&resp_buf_type, timeout, &rsp_iov);
2201+
&resp_buf_type, sr_flags, &rsp_iov);
22002202
pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
22012203
}
22022204
cifs_small_buf_release(pSMB);

fs/smb/client/cifstransport.c

Lines changed: 5 additions & 194 deletions
Original file line numberDiff line numberDiff line change
@@ -239,13 +239,6 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
239239
return -EIO;
240240
}
241241

242-
spin_lock(&server->srv_lock);
243-
if (server->tcpStatus == CifsExiting) {
244-
spin_unlock(&server->srv_lock);
245-
return -ENOENT;
246-
}
247-
spin_unlock(&server->srv_lock);
248-
249242
/* Ensure that we do not send more than 50 overlapping requests
250243
to the same server. We may make this configurable later or
251244
use ses->maxReq */
@@ -261,193 +254,11 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
261254
if (rc < 0)
262255
return rc;
263256

264-
*pbytes_returned = resp_iov.iov_len;
265-
if (resp_iov.iov_len)
266-
memcpy(out_buf, resp_iov.iov_base, resp_iov.iov_len);
267-
free_rsp_buf(resp_buf_type, resp_iov.iov_base);
268-
return rc;
269-
}
270-
271-
/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
272-
blocking lock to return. */
273-
274-
static int
275-
send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon,
276-
struct smb_hdr *in_buf, unsigned int in_len,
277-
struct smb_hdr *out_buf)
278-
{
279-
int bytes_returned;
280-
struct cifs_ses *ses = tcon->ses;
281-
LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
282-
283-
/* We just modify the current in_buf to change
284-
the type of lock from LOCKING_ANDX_SHARED_LOCK
285-
or LOCKING_ANDX_EXCLUSIVE_LOCK to
286-
LOCKING_ANDX_CANCEL_LOCK. */
287-
288-
pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
289-
pSMB->Timeout = 0;
290-
pSMB->hdr.Mid = get_next_mid(ses->server);
291-
292-
return SendReceive(xid, ses, in_buf, in_len, out_buf,
293-
&bytes_returned, 0);
294-
}
295-
296-
int SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
297-
struct smb_hdr *in_buf, unsigned int in_len,
298-
struct smb_hdr *out_buf, int *pbytes_returned)
299-
{
300-
int rc = 0;
301-
int rstart = 0;
302-
struct mid_q_entry *mid;
303-
struct cifs_ses *ses;
304-
struct kvec iov = { .iov_base = in_buf, .iov_len = in_len };
305-
struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
306-
unsigned int instance;
307-
struct TCP_Server_Info *server;
308-
309-
if (WARN_ON_ONCE(in_len > 0xffffff))
310-
return -EIO;
311-
if (tcon == NULL || tcon->ses == NULL) {
312-
cifs_dbg(VFS, "Null smb session\n");
313-
return -EIO;
314-
}
315-
ses = tcon->ses;
316-
server = ses->server;
317-
318-
if (server == NULL) {
319-
cifs_dbg(VFS, "Null tcp session\n");
320-
return -EIO;
321-
}
322-
323-
spin_lock(&server->srv_lock);
324-
if (server->tcpStatus == CifsExiting) {
325-
spin_unlock(&server->srv_lock);
326-
return -ENOENT;
327-
}
328-
spin_unlock(&server->srv_lock);
329-
330-
/* Ensure that we do not send more than 50 overlapping requests
331-
to the same server. We may make this configurable later or
332-
use ses->maxReq */
333-
334-
if (in_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
335-
cifs_tcon_dbg(VFS, "Invalid length, greater than maximum frame, %d\n",
336-
in_len);
337-
return -EIO;
338-
}
339-
340-
rc = wait_for_free_request(server, CIFS_BLOCKING_OP, &instance);
341-
if (rc)
342-
return rc;
343-
344-
/* make sure that we sign in the same order that we send on this socket
345-
and avoid races inside tcp sendmsg code that could cause corruption
346-
of smb data */
347-
348-
cifs_server_lock(server);
349-
350-
rc = allocate_mid(ses, in_buf, &mid);
351-
if (rc) {
352-
cifs_server_unlock(server);
353-
return rc;
354-
}
355-
356-
rc = cifs_sign_rqst(&rqst, server, &mid->sequence_number);
357-
if (rc) {
358-
delete_mid(mid);
359-
cifs_server_unlock(server);
360-
return rc;
361-
}
362-
363-
mid->mid_state = MID_REQUEST_SUBMITTED;
364-
rc = __smb_send_rqst(server, 1, &rqst);
365-
cifs_save_when_sent(mid);
366-
367-
if (rc < 0)
368-
server->sequence_number -= 2;
369-
370-
cifs_server_unlock(server);
371-
372-
if (rc < 0) {
373-
delete_mid(mid);
374-
return rc;
375-
}
376-
377-
/* Wait for a reply - allow signals to interrupt. */
378-
rc = wait_event_interruptible(server->response_q,
379-
(!(mid->mid_state == MID_REQUEST_SUBMITTED ||
380-
mid->mid_state == MID_RESPONSE_RECEIVED)) ||
381-
((server->tcpStatus != CifsGood) &&
382-
(server->tcpStatus != CifsNew)));
383-
384-
/* Were we interrupted by a signal ? */
385-
spin_lock(&server->srv_lock);
386-
if ((rc == -ERESTARTSYS) &&
387-
(mid->mid_state == MID_REQUEST_SUBMITTED ||
388-
mid->mid_state == MID_RESPONSE_RECEIVED) &&
389-
((server->tcpStatus == CifsGood) ||
390-
(server->tcpStatus == CifsNew))) {
391-
spin_unlock(&server->srv_lock);
392-
393-
if (in_buf->Command == SMB_COM_TRANSACTION2) {
394-
/* POSIX lock. We send a NT_CANCEL SMB to cause the
395-
blocking lock to return. */
396-
rc = send_cancel(server, &rqst, mid);
397-
if (rc) {
398-
delete_mid(mid);
399-
return rc;
400-
}
401-
} else {
402-
/* Windows lock. We send a LOCKINGX_CANCEL_LOCK
403-
to cause the blocking lock to return. */
404-
405-
rc = send_lock_cancel(xid, tcon, in_buf, in_len, out_buf);
406-
407-
/* If we get -ENOLCK back the lock may have
408-
already been removed. Don't exit in this case. */
409-
if (rc && rc != -ENOLCK) {
410-
delete_mid(mid);
411-
return rc;
412-
}
413-
}
414-
415-
rc = wait_for_response(server, mid);
416-
if (rc) {
417-
send_cancel(server, &rqst, mid);
418-
spin_lock(&mid->mid_lock);
419-
if (mid->callback) {
420-
/* no longer considered to be "in-flight" */
421-
mid->callback = release_mid;
422-
spin_unlock(&mid->mid_lock);
423-
return rc;
424-
}
425-
spin_unlock(&mid->mid_lock);
426-
}
427-
428-
/* We got the response - restart system call. */
429-
rstart = 1;
430-
spin_lock(&server->srv_lock);
431-
}
432-
spin_unlock(&server->srv_lock);
433-
434-
rc = cifs_sync_mid_result(mid, server);
435-
if (rc != 0)
436-
return rc;
437-
438-
/* rcvd frame is ok */
439-
if (out_buf == NULL || mid->mid_state != MID_RESPONSE_READY) {
440-
rc = -EIO;
441-
cifs_tcon_dbg(VFS, "Bad MID state?\n");
442-
goto out;
257+
if (out_buf) {
258+
*pbytes_returned = resp_iov.iov_len;
259+
if (resp_iov.iov_len)
260+
memcpy(out_buf, resp_iov.iov_base, resp_iov.iov_len);
443261
}
444-
445-
*pbytes_returned = mid->response_pdu_len;
446-
memcpy(out_buf, mid->resp_buf, *pbytes_returned);
447-
rc = cifs_check_receive(mid, server, 0);
448-
out:
449-
delete_mid(mid);
450-
if (rstart && rc == -EACCES)
451-
return -ERESTARTSYS;
262+
free_rsp_buf(resp_buf_type, resp_iov.iov_base);
452263
return rc;
453264
}

fs/smb/client/smb1ops.c

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@
3030
* SMB_COM_NT_CANCEL request and then sends it.
3131
*/
3232
static int
33-
send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
34-
struct mid_q_entry *mid)
33+
send_nt_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
34+
struct smb_rqst *rqst, struct mid_q_entry *mid,
35+
unsigned int xid)
3536
{
3637
struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
3738
struct kvec iov[1];
@@ -71,6 +72,46 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
7172
return rc;
7273
}
7374

75+
/*
76+
* Send a LOCKINGX_CANCEL_LOCK to cause the Windows blocking lock to
77+
* return.
78+
*/
79+
static int
80+
send_lock_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
81+
struct smb_rqst *rqst, struct mid_q_entry *mid,
82+
unsigned int xid)
83+
{
84+
struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
85+
unsigned int in_len = rqst->rq_iov[0].iov_len;
86+
LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
87+
int rc;
88+
89+
/* We just modify the current in_buf to change
90+
* the type of lock from LOCKING_ANDX_SHARED_LOCK
91+
* or LOCKING_ANDX_EXCLUSIVE_LOCK to
92+
* LOCKING_ANDX_CANCEL_LOCK.
93+
*/
94+
pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
95+
pSMB->Timeout = 0;
96+
pSMB->hdr.Mid = get_next_mid(ses->server);
97+
98+
rc = SendReceive(xid, ses, in_buf, in_len, NULL, NULL, 0);
99+
if (rc == -ENOLCK)
100+
rc = 0; /* If we get back -ENOLCK, it probably means we managed
101+
* to cancel the lock command before it took effect.
102+
*/
103+
return rc;
104+
}
105+
106+
static int cifs_send_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
107+
struct smb_rqst *rqst, struct mid_q_entry *mid,
108+
unsigned int xid)
109+
{
110+
if (mid->sr_flags & CIFS_WINDOWS_LOCK)
111+
return send_lock_cancel(ses, server, rqst, mid, xid);
112+
return send_nt_cancel(ses, server, rqst, mid, xid);
113+
}
114+
74115
static bool
75116
cifs_compare_fids(struct cifsFileInfo *ob1, struct cifsFileInfo *ob2)
76117
{
@@ -1397,7 +1438,7 @@ cifs_is_network_name_deleted(char *buf, struct TCP_Server_Info *server)
13971438
}
13981439

13991440
struct smb_version_operations smb1_operations = {
1400-
.send_cancel = send_nt_cancel,
1441+
.send_cancel = cifs_send_cancel,
14011442
.compare_fids = cifs_compare_fids,
14021443
.setup_request = cifs_setup_request,
14031444
.setup_async_request = cifs_setup_async_request,

0 commit comments

Comments
 (0)