Commit 38104c00 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '5.1-rc1-cifs-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull smb3 fixes from Steve French:

 - two fixes for stable for guest mount problems with smb3.1.1

 - two fixes for crediting (SMB3 flow control) on resent requests

 - a byte range lock leak fix

 - two fixes for incorrect rc mappings

* tag '5.1-rc1-cifs-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: update internal module version number
  SMB3: Fix SMB3.1.1 guest mounts to Samba
  cifs: Fix slab-out-of-bounds when tracing SMB tcon
  cifs: allow guest mounts to work for smb3.11
  fix incorrect error code mapping for OBJECTID_NOT_FOUND
  cifs: fix that return -EINVAL when do dedupe operation
  CIFS: Fix an issue with re-sending rdata when transport returning -EAGAIN
  CIFS: Fix an issue with re-sending wdata when transport returning -EAGAIN
parents e0046bb3 cf7d624f
...@@ -1008,7 +1008,7 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off, ...@@ -1008,7 +1008,7 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off,
unsigned int xid; unsigned int xid;
int rc; int rc;
if (remap_flags & ~REMAP_FILE_ADVISORY) if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
return -EINVAL; return -EINVAL;
cifs_dbg(FYI, "clone range\n"); cifs_dbg(FYI, "clone range\n");
......
...@@ -150,5 +150,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); ...@@ -150,5 +150,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
extern const struct export_operations cifs_export_ops; extern const struct export_operations cifs_export_ops;
#endif /* CONFIG_CIFS_NFSD_EXPORT */ #endif /* CONFIG_CIFS_NFSD_EXPORT */
#define CIFS_VERSION "2.18" #define CIFS_VERSION "2.19"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */
...@@ -2632,43 +2632,56 @@ cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list, ...@@ -2632,43 +2632,56 @@ cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list,
struct TCP_Server_Info *server = struct TCP_Server_Info *server =
tlink_tcon(wdata->cfile->tlink)->ses->server; tlink_tcon(wdata->cfile->tlink)->ses->server;
/*
* Wait for credits to resend this wdata.
* Note: we are attempting to resend the whole wdata not in segments
*/
do { do {
rc = server->ops->wait_mtu_credits(server, wdata->bytes, &wsize, if (wdata->cfile->invalidHandle) {
&credits); rc = cifs_reopen_file(wdata->cfile, false);
if (rc == -EAGAIN)
continue;
else if (rc)
break;
}
if (rc)
goto out;
if (wsize < wdata->bytes) { /*
add_credits_and_wake_if(server, &credits, 0); * Wait for credits to resend this wdata.
msleep(1000); * Note: we are attempting to resend the whole wdata not in
} * segments
} while (wsize < wdata->bytes); */
do {
rc = server->ops->wait_mtu_credits(server, wdata->bytes,
&wsize, &credits);
if (rc)
goto fail;
if (wsize < wdata->bytes) {
add_credits_and_wake_if(server, &credits, 0);
msleep(1000);
}
} while (wsize < wdata->bytes);
wdata->credits = credits;
wdata->credits = credits; rc = adjust_credits(server, &wdata->credits, wdata->bytes);
rc = -EAGAIN;
while (rc == -EAGAIN) { if (!rc) {
rc = 0; if (wdata->cfile->invalidHandle)
if (wdata->cfile->invalidHandle) rc = -EAGAIN;
rc = cifs_reopen_file(wdata->cfile, false); else
if (!rc) rc = server->ops->async_writev(wdata,
rc = server->ops->async_writev(wdata,
cifs_uncached_writedata_release); cifs_uncached_writedata_release);
} }
if (!rc) { /* If the write was successfully sent, we are done */
list_add_tail(&wdata->list, wdata_list); if (!rc) {
return 0; list_add_tail(&wdata->list, wdata_list);
} return 0;
}
add_credits_and_wake_if(server, &wdata->credits, 0); /* Roll back credits and retry if needed */
out: add_credits_and_wake_if(server, &wdata->credits, 0);
kref_put(&wdata->refcount, cifs_uncached_writedata_release); } while (rc == -EAGAIN);
fail:
kref_put(&wdata->refcount, cifs_uncached_writedata_release);
return rc; return rc;
} }
...@@ -2896,12 +2909,12 @@ static void collect_uncached_write_data(struct cifs_aio_ctx *ctx) ...@@ -2896,12 +2909,12 @@ static void collect_uncached_write_data(struct cifs_aio_ctx *ctx)
wdata->bytes, &tmp_from, wdata->bytes, &tmp_from,
ctx->cfile, cifs_sb, &tmp_list, ctx->cfile, cifs_sb, &tmp_list,
ctx); ctx);
kref_put(&wdata->refcount,
cifs_uncached_writedata_release);
} }
list_splice(&tmp_list, &ctx->list); list_splice(&tmp_list, &ctx->list);
kref_put(&wdata->refcount,
cifs_uncached_writedata_release);
goto restart_loop; goto restart_loop;
} }
} }
...@@ -3348,44 +3361,55 @@ static int cifs_resend_rdata(struct cifs_readdata *rdata, ...@@ -3348,44 +3361,55 @@ static int cifs_resend_rdata(struct cifs_readdata *rdata,
struct TCP_Server_Info *server = struct TCP_Server_Info *server =
tlink_tcon(rdata->cfile->tlink)->ses->server; tlink_tcon(rdata->cfile->tlink)->ses->server;
/*
* Wait for credits to resend this rdata.
* Note: we are attempting to resend the whole rdata not in segments
*/
do { do {
rc = server->ops->wait_mtu_credits(server, rdata->bytes, if (rdata->cfile->invalidHandle) {
rc = cifs_reopen_file(rdata->cfile, true);
if (rc == -EAGAIN)
continue;
else if (rc)
break;
}
/*
* Wait for credits to resend this rdata.
* Note: we are attempting to resend the whole rdata not in
* segments
*/
do {
rc = server->ops->wait_mtu_credits(server, rdata->bytes,
&rsize, &credits); &rsize, &credits);
if (rc) if (rc)
goto out; goto fail;
if (rsize < rdata->bytes) { if (rsize < rdata->bytes) {
add_credits_and_wake_if(server, &credits, 0); add_credits_and_wake_if(server, &credits, 0);
msleep(1000); msleep(1000);
} }
} while (rsize < rdata->bytes); } while (rsize < rdata->bytes);
rdata->credits = credits;
rdata->credits = credits; rc = adjust_credits(server, &rdata->credits, rdata->bytes);
rc = -EAGAIN; if (!rc) {
while (rc == -EAGAIN) { if (rdata->cfile->invalidHandle)
rc = 0; rc = -EAGAIN;
if (rdata->cfile->invalidHandle) else
rc = cifs_reopen_file(rdata->cfile, true); rc = server->ops->async_readv(rdata);
if (!rc) }
rc = server->ops->async_readv(rdata);
}
if (!rc) { /* If the read was successfully sent, we are done */
/* Add to aio pending list */ if (!rc) {
list_add_tail(&rdata->list, rdata_list); /* Add to aio pending list */
return 0; list_add_tail(&rdata->list, rdata_list);
} return 0;
}
add_credits_and_wake_if(server, &rdata->credits, 0); /* Roll back credits and retry if needed */
out: add_credits_and_wake_if(server, &rdata->credits, 0);
kref_put(&rdata->refcount, } while (rc == -EAGAIN);
cifs_uncached_readdata_release);
fail:
kref_put(&rdata->refcount, cifs_uncached_readdata_release);
return rc; return rc;
} }
......
...@@ -1036,7 +1036,8 @@ static const struct status_to_posix_error smb2_error_map_table[] = { ...@@ -1036,7 +1036,8 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
{STATUS_UNFINISHED_CONTEXT_DELETED, -EIO, {STATUS_UNFINISHED_CONTEXT_DELETED, -EIO,
"STATUS_UNFINISHED_CONTEXT_DELETED"}, "STATUS_UNFINISHED_CONTEXT_DELETED"},
{STATUS_NO_TGT_REPLY, -EIO, "STATUS_NO_TGT_REPLY"}, {STATUS_NO_TGT_REPLY, -EIO, "STATUS_NO_TGT_REPLY"},
{STATUS_OBJECTID_NOT_FOUND, -EIO, "STATUS_OBJECTID_NOT_FOUND"}, /* Note that ENOATTTR and ENODATA are the same errno */
{STATUS_OBJECTID_NOT_FOUND, -ENODATA, "STATUS_OBJECTID_NOT_FOUND"},
{STATUS_NO_IP_ADDRESSES, -EIO, "STATUS_NO_IP_ADDRESSES"}, {STATUS_NO_IP_ADDRESSES, -EIO, "STATUS_NO_IP_ADDRESSES"},
{STATUS_WRONG_CREDENTIAL_HANDLE, -EIO, {STATUS_WRONG_CREDENTIAL_HANDLE, -EIO,
"STATUS_WRONG_CREDENTIAL_HANDLE"}, "STATUS_WRONG_CREDENTIAL_HANDLE"},
......
...@@ -1628,9 +1628,16 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, ...@@ -1628,9 +1628,16 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
iov[1].iov_base = unc_path; iov[1].iov_base = unc_path;
iov[1].iov_len = unc_path_len; iov[1].iov_len = unc_path_len;
/* 3.11 tcon req must be signed if not encrypted. See MS-SMB2 3.2.4.1.1 */ /*
* 3.11 tcon req must be signed if not encrypted. See MS-SMB2 3.2.4.1.1
* unless it is guest or anonymous user. See MS-SMB2 3.2.5.3.1
* (Samba servers don't always set the flag so also check if null user)
*/
if ((ses->server->dialect == SMB311_PROT_ID) && if ((ses->server->dialect == SMB311_PROT_ID) &&
!smb3_encryption_required(tcon)) !smb3_encryption_required(tcon) &&
!(ses->session_flags &
(SMB2_SESSION_FLAG_IS_GUEST|SMB2_SESSION_FLAG_IS_NULL)) &&
((ses->user_name != NULL) || (ses->sectype == Kerberos)))
req->sync_hdr.Flags |= SMB2_FLAGS_SIGNED; req->sync_hdr.Flags |= SMB2_FLAGS_SIGNED;
memset(&rqst, 0, sizeof(struct smb_rqst)); memset(&rqst, 0, sizeof(struct smb_rqst));
......
...@@ -549,19 +549,19 @@ DECLARE_EVENT_CLASS(smb3_tcon_class, ...@@ -549,19 +549,19 @@ DECLARE_EVENT_CLASS(smb3_tcon_class,
__field(unsigned int, xid) __field(unsigned int, xid)
__field(__u32, tid) __field(__u32, tid)
__field(__u64, sesid) __field(__u64, sesid)
__field(const char *, unc_name) __string(name, unc_name)
__field(int, rc) __field(int, rc)
), ),
TP_fast_assign( TP_fast_assign(
__entry->xid = xid; __entry->xid = xid;
__entry->tid = tid; __entry->tid = tid;
__entry->sesid = sesid; __entry->sesid = sesid;
__entry->unc_name = unc_name; __assign_str(name, unc_name);
__entry->rc = rc; __entry->rc = rc;
), ),
TP_printk("xid=%u sid=0x%llx tid=0x%x unc_name=%s rc=%d", TP_printk("xid=%u sid=0x%llx tid=0x%x unc_name=%s rc=%d",
__entry->xid, __entry->sesid, __entry->tid, __entry->xid, __entry->sesid, __entry->tid,
__entry->unc_name, __entry->rc) __get_str(name), __entry->rc)
) )
#define DEFINE_SMB3_TCON_EVENT(name) \ #define DEFINE_SMB3_TCON_EVENT(name) \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment