Commit e519a8c2 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull smb3 updates from Steve French:

 - smb3/cifs fixes including for large i/o error cases

 - fixes for three xfstests

 - improved crediting (smb3 flow control)

 - improved tracing

* tag '5.1-rc-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6: (44 commits)
  fs: cifs: Kconfig: pedantic formatting
  smb3: request more credits on normal (non-large read/write) ops
  CIFS: Mask off signals when sending SMB packets
  CIFS: Return -EAGAIN instead of -ENOTSOCK
  CIFS: Only send SMB2_NEGOTIATE command on new TCP connections
  CIFS: Fix read after write for files with read caching
  smb3: for kerberos mounts display the credential uid used
  cifs: use correct format characters
  smb3: add dynamic trace point for query_info_enter/done
  smb3: add dynamic trace point for smb3_cmd_enter
  smb3: improve dynamic tracing of open and posix mkdir
  smb3: add missing read completion trace point
  smb3: Add tracepoints for read, write and query_dir enter
  smb3: add tracepoints for query dir
  smb3: Update POSIX negotiate context with POSIX ctxt GUID
  cifs: update internal module version number
  CIFS: Try to acquire credits at once for compound requests
  CIFS: Return error code when getting file handle for writeback
  CIFS: Move open file handling to writepages
  CIFS: Move unlocking pages from wdata_send_pages()
  ...
parents d1cae948 50cfad78
...@@ -117,25 +117,25 @@ config CIFS_UPCALL ...@@ -117,25 +117,25 @@ config CIFS_UPCALL
secure Kerberos authentication is required). If unsure, say Y. secure Kerberos authentication is required). If unsure, say Y.
config CIFS_XATTR config CIFS_XATTR
bool "CIFS extended attributes" bool "CIFS extended attributes"
depends on CIFS depends on CIFS
help help
Extended attributes are name:value pairs associated with inodes by Extended attributes are name:value pairs associated with inodes by
the kernel or by users (see the attr(5) manual page for details). the kernel or by users (see the attr(5) manual page for details).
CIFS maps the name of extended attributes beginning with the user CIFS maps the name of extended attributes beginning with the user
namespace prefix to SMB/CIFS EAs. EAs are stored on Windows namespace prefix to SMB/CIFS EAs. EAs are stored on Windows
servers without the user namespace prefix, but their names are servers without the user namespace prefix, but their names are
seen by Linux cifs clients prefaced by the user namespace prefix. seen by Linux cifs clients prefaced by the user namespace prefix.
The system namespace (used by some filesystems to store ACLs) is The system namespace (used by some filesystems to store ACLs) is
not supported at this time. not supported at this time.
If unsure, say Y. If unsure, say Y.
config CIFS_POSIX config CIFS_POSIX
bool "CIFS POSIX Extensions" bool "CIFS POSIX Extensions"
depends on CIFS && CIFS_ALLOW_INSECURE_LEGACY && CIFS_XATTR depends on CIFS && CIFS_ALLOW_INSECURE_LEGACY && CIFS_XATTR
help help
Enabling this option will cause the cifs client to attempt to Enabling this option will cause the cifs client to attempt to
negotiate a newer dialect with servers, such as Samba 3.0.5 negotiate a newer dialect with servers, such as Samba 3.0.5
or later, that optionally can handle more POSIX like (rather or later, that optionally can handle more POSIX like (rather
than Windows like) file behavior. It also enables than Windows like) file behavior. It also enables
...@@ -144,61 +144,62 @@ config CIFS_POSIX ...@@ -144,61 +144,62 @@ config CIFS_POSIX
CIFS POSIX ACL support. If unsure, say N. CIFS POSIX ACL support. If unsure, say N.
config CIFS_ACL config CIFS_ACL
bool "Provide CIFS ACL support" bool "Provide CIFS ACL support"
depends on CIFS_XATTR && KEYS depends on CIFS_XATTR && KEYS
help help
Allows fetching CIFS/NTFS ACL from the server. The DACL blob Allows fetching CIFS/NTFS ACL from the server. The DACL blob
is handed over to the application/caller. See the man is handed over to the application/caller. See the man
page for getcifsacl for more information. If unsure, say Y. page for getcifsacl for more information. If unsure, say Y.
config CIFS_DEBUG config CIFS_DEBUG
bool "Enable CIFS debugging routines" bool "Enable CIFS debugging routines"
default y default y
depends on CIFS depends on CIFS
help help
Enabling this option adds helpful debugging messages to Enabling this option adds helpful debugging messages to
the cifs code which increases the size of the cifs module. the cifs code which increases the size of the cifs module.
If unsure, say Y. If unsure, say Y.
config CIFS_DEBUG2 config CIFS_DEBUG2
bool "Enable additional CIFS debugging routines" bool "Enable additional CIFS debugging routines"
depends on CIFS_DEBUG depends on CIFS_DEBUG
help help
Enabling this option adds a few more debugging routines Enabling this option adds a few more debugging routines
to the cifs code which slightly increases the size of to the cifs code which slightly increases the size of
the cifs module and can cause additional logging of debug the cifs module and can cause additional logging of debug
messages in some error paths, slowing performance. This messages in some error paths, slowing performance. This
option can be turned off unless you are debugging option can be turned off unless you are debugging
cifs problems. If unsure, say N. cifs problems. If unsure, say N.
config CIFS_DEBUG_DUMP_KEYS config CIFS_DEBUG_DUMP_KEYS
bool "Dump encryption keys for offline decryption (Unsafe)" bool "Dump encryption keys for offline decryption (Unsafe)"
depends on CIFS_DEBUG depends on CIFS_DEBUG
help help
Enabling this will dump the encryption and decryption keys Enabling this will dump the encryption and decryption keys
used to communicate on an encrypted share connection on the used to communicate on an encrypted share connection on the
console. This allows Wireshark to decrypt and dissect console. This allows Wireshark to decrypt and dissect
encrypted network captures. Enable this carefully. encrypted network captures. Enable this carefully.
If unsure, say N. If unsure, say N.
config CIFS_DFS_UPCALL config CIFS_DFS_UPCALL
bool "DFS feature support" bool "DFS feature support"
depends on CIFS && KEYS depends on CIFS && KEYS
select DNS_RESOLVER select DNS_RESOLVER
help help
Distributed File System (DFS) support is used to access shares Distributed File System (DFS) support is used to access shares
transparently in an enterprise name space, even if the share transparently in an enterprise name space, even if the share
moves to a different server. This feature also enables moves to a different server. This feature also enables
an upcall mechanism for CIFS which contacts userspace helper an upcall mechanism for CIFS which contacts userspace helper
utilities to provide server name resolution (host names to utilities to provide server name resolution (host names to
IP addresses) which is needed in order to reconnect to IP addresses) which is needed in order to reconnect to
servers if their addresses change or for implicit mounts of servers if their addresses change or for implicit mounts of
DFS junction points. If unsure, say Y. DFS junction points. If unsure, say Y.
config CIFS_NFSD_EXPORT config CIFS_NFSD_EXPORT
bool "Allow nfsd to export CIFS file system" bool "Allow nfsd to export CIFS file system"
depends on CIFS && BROKEN depends on CIFS && BROKEN
help help
Allows NFS server to export a CIFS mounted share (nfsd over cifs) Allows NFS server to export a CIFS mounted share (nfsd over cifs)
config CIFS_SMB_DIRECT config CIFS_SMB_DIRECT
bool "SMB Direct support (Experimental)" bool "SMB Direct support (Experimental)"
...@@ -209,10 +210,9 @@ config CIFS_SMB_DIRECT ...@@ -209,10 +210,9 @@ config CIFS_SMB_DIRECT
say N. say N.
config CIFS_FSCACHE config CIFS_FSCACHE
bool "Provide CIFS client caching support" bool "Provide CIFS client caching support"
depends on CIFS=m && FSCACHE || CIFS=y && FSCACHE=y depends on CIFS=m && FSCACHE || CIFS=y && FSCACHE=y
help help
Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data
to be cached locally on disk through the general filesystem cache to be cached locally on disk through the general filesystem cache
manager. If unsure, say N. manager. If unsure, say N.
...@@ -285,9 +285,9 @@ static void dump_referral(const struct dfs_info3_param *ref) ...@@ -285,9 +285,9 @@ static void dump_referral(const struct dfs_info3_param *ref)
{ {
cifs_dbg(FYI, "DFS: ref path: %s\n", ref->path_name); cifs_dbg(FYI, "DFS: ref path: %s\n", ref->path_name);
cifs_dbg(FYI, "DFS: node path: %s\n", ref->node_name); cifs_dbg(FYI, "DFS: node path: %s\n", ref->node_name);
cifs_dbg(FYI, "DFS: fl: %hd, srv_type: %hd\n", cifs_dbg(FYI, "DFS: fl: %d, srv_type: %d\n",
ref->flags, ref->server_type); ref->flags, ref->server_type);
cifs_dbg(FYI, "DFS: ref_flags: %hd, path_consumed: %hd\n", cifs_dbg(FYI, "DFS: ref_flags: %d, path_consumed: %d\n",
ref->ref_flag, ref->path_consumed); ref->ref_flag, ref->path_consumed);
} }
......
...@@ -58,6 +58,7 @@ struct cifs_sb_info { ...@@ -58,6 +58,7 @@ struct cifs_sb_info {
spinlock_t tlink_tree_lock; spinlock_t tlink_tree_lock;
struct tcon_link *master_tlink; struct tcon_link *master_tlink;
struct nls_table *local_nls; struct nls_table *local_nls;
unsigned int bsize;
unsigned int rsize; unsigned int rsize;
unsigned int wsize; unsigned int wsize;
unsigned long actimeo; /* attribute cache timeout (jiffies) */ unsigned long actimeo; /* attribute cache timeout (jiffies) */
......
...@@ -381,7 +381,7 @@ cifs_show_security(struct seq_file *s, struct cifs_ses *ses) ...@@ -381,7 +381,7 @@ cifs_show_security(struct seq_file *s, struct cifs_ses *ses)
seq_puts(s, "ntlm"); seq_puts(s, "ntlm");
break; break;
case Kerberos: case Kerberos:
seq_puts(s, "krb5"); seq_printf(s, "krb5,cruid=%u", from_kuid_munged(&init_user_ns,ses->cred_uid));
break; break;
case RawNTLMSSP: case RawNTLMSSP:
seq_puts(s, "ntlmssp"); seq_puts(s, "ntlmssp");
...@@ -554,6 +554,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root) ...@@ -554,6 +554,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
seq_printf(s, ",rsize=%u", cifs_sb->rsize); seq_printf(s, ",rsize=%u", cifs_sb->rsize);
seq_printf(s, ",wsize=%u", cifs_sb->wsize); seq_printf(s, ",wsize=%u", cifs_sb->wsize);
seq_printf(s, ",bsize=%u", cifs_sb->bsize);
seq_printf(s, ",echo_interval=%lu", seq_printf(s, ",echo_interval=%lu",
tcon->ses->server->echo_interval / HZ); tcon->ses->server->echo_interval / HZ);
if (tcon->snapshot_time) if (tcon->snapshot_time)
......
...@@ -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.17" #define CIFS_VERSION "2.18"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */
...@@ -216,6 +216,7 @@ struct cifs_io_parms; ...@@ -216,6 +216,7 @@ struct cifs_io_parms;
struct cifs_search_info; struct cifs_search_info;
struct cifsInodeInfo; struct cifsInodeInfo;
struct cifs_open_parms; struct cifs_open_parms;
struct cifs_credits;
struct smb_version_operations { struct smb_version_operations {
int (*send_cancel)(struct TCP_Server_Info *, struct smb_rqst *, int (*send_cancel)(struct TCP_Server_Info *, struct smb_rqst *,
...@@ -230,12 +231,15 @@ struct smb_version_operations { ...@@ -230,12 +231,15 @@ struct smb_version_operations {
/* check response: verify signature, map error */ /* check response: verify signature, map error */
int (*check_receive)(struct mid_q_entry *, struct TCP_Server_Info *, int (*check_receive)(struct mid_q_entry *, struct TCP_Server_Info *,
bool); bool);
void (*add_credits)(struct TCP_Server_Info *, const unsigned int, void (*add_credits)(struct TCP_Server_Info *server,
const int); const struct cifs_credits *credits,
const int optype);
void (*set_credits)(struct TCP_Server_Info *, const int); void (*set_credits)(struct TCP_Server_Info *, const int);
int * (*get_credits_field)(struct TCP_Server_Info *, const int); int * (*get_credits_field)(struct TCP_Server_Info *, const int);
unsigned int (*get_credits)(struct mid_q_entry *); unsigned int (*get_credits)(struct mid_q_entry *);
__u64 (*get_next_mid)(struct TCP_Server_Info *); __u64 (*get_next_mid)(struct TCP_Server_Info *);
void (*revert_current_mid)(struct TCP_Server_Info *server,
const unsigned int val);
/* data offset from read response message */ /* data offset from read response message */
unsigned int (*read_data_offset)(char *); unsigned int (*read_data_offset)(char *);
/* /*
...@@ -383,8 +387,8 @@ struct smb_version_operations { ...@@ -383,8 +387,8 @@ struct smb_version_operations {
struct cifs_fid *); struct cifs_fid *);
/* calculate a size of SMB message */ /* calculate a size of SMB message */
unsigned int (*calc_smb_size)(void *buf, struct TCP_Server_Info *ptcpi); unsigned int (*calc_smb_size)(void *buf, struct TCP_Server_Info *ptcpi);
/* check for STATUS_PENDING and process it in a positive case */ /* check for STATUS_PENDING and process the response if yes */
bool (*is_status_pending)(char *, struct TCP_Server_Info *, int); bool (*is_status_pending)(char *buf, struct TCP_Server_Info *server);
/* check for STATUS_NETWORK_SESSION_EXPIRED */ /* check for STATUS_NETWORK_SESSION_EXPIRED */
bool (*is_session_expired)(char *); bool (*is_session_expired)(char *);
/* send oplock break response */ /* send oplock break response */
...@@ -452,7 +456,11 @@ struct smb_version_operations { ...@@ -452,7 +456,11 @@ struct smb_version_operations {
unsigned int (*wp_retry_size)(struct inode *); unsigned int (*wp_retry_size)(struct inode *);
/* get mtu credits */ /* get mtu credits */
int (*wait_mtu_credits)(struct TCP_Server_Info *, unsigned int, int (*wait_mtu_credits)(struct TCP_Server_Info *, unsigned int,
unsigned int *, unsigned int *); unsigned int *, struct cifs_credits *);
/* adjust previously taken mtu credits to request size */
int (*adjust_credits)(struct TCP_Server_Info *server,
struct cifs_credits *credits,
const unsigned int payload_size);
/* check if we need to issue closedir */ /* check if we need to issue closedir */
bool (*dir_needs_close)(struct cifsFileInfo *); bool (*dir_needs_close)(struct cifsFileInfo *);
long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t, long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t,
...@@ -557,6 +565,7 @@ struct smb_vol { ...@@ -557,6 +565,7 @@ struct smb_vol {
bool resilient:1; /* noresilient not required since not fored for CA */ bool resilient:1; /* noresilient not required since not fored for CA */
bool domainauto:1; bool domainauto:1;
bool rdma:1; bool rdma:1;
unsigned int bsize;
unsigned int rsize; unsigned int rsize;
unsigned int wsize; unsigned int wsize;
bool sockopt_tcp_nodelay:1; bool sockopt_tcp_nodelay:1;
...@@ -710,6 +719,11 @@ struct TCP_Server_Info { ...@@ -710,6 +719,11 @@ struct TCP_Server_Info {
int nr_targets; int nr_targets;
}; };
struct cifs_credits {
unsigned int value;
unsigned int instance;
};
static inline unsigned int static inline unsigned int
in_flight(struct TCP_Server_Info *server) in_flight(struct TCP_Server_Info *server)
{ {
...@@ -731,18 +745,18 @@ has_credits(struct TCP_Server_Info *server, int *credits) ...@@ -731,18 +745,18 @@ has_credits(struct TCP_Server_Info *server, int *credits)
} }
static inline void static inline void
add_credits(struct TCP_Server_Info *server, const unsigned int add, add_credits(struct TCP_Server_Info *server, const struct cifs_credits *credits,
const int optype) const int optype)
{ {
server->ops->add_credits(server, add, optype); server->ops->add_credits(server, credits, optype);
} }
static inline void static inline void
add_credits_and_wake_if(struct TCP_Server_Info *server, const unsigned int add, add_credits_and_wake_if(struct TCP_Server_Info *server,
const int optype) const struct cifs_credits *credits, const int optype)
{ {
if (add) { if (credits->value) {
server->ops->add_credits(server, add, optype); server->ops->add_credits(server, credits, optype);
wake_up(&server->request_q); wake_up(&server->request_q);
} }
} }
...@@ -753,6 +767,14 @@ set_credits(struct TCP_Server_Info *server, const int val) ...@@ -753,6 +767,14 @@ set_credits(struct TCP_Server_Info *server, const int val)
server->ops->set_credits(server, val); server->ops->set_credits(server, val);
} }
static inline int
adjust_credits(struct TCP_Server_Info *server, struct cifs_credits *credits,
const unsigned int payload_size)
{
return server->ops->adjust_credits ?
server->ops->adjust_credits(server, credits, payload_size) : 0;
}
static inline __le64 static inline __le64
get_next_mid64(struct TCP_Server_Info *server) get_next_mid64(struct TCP_Server_Info *server)
{ {
...@@ -770,6 +792,22 @@ get_next_mid(struct TCP_Server_Info *server) ...@@ -770,6 +792,22 @@ get_next_mid(struct TCP_Server_Info *server)
return cpu_to_le16(mid); return cpu_to_le16(mid);
} }
static inline void
revert_current_mid(struct TCP_Server_Info *server, const unsigned int val)
{
if (server->ops->revert_current_mid)
server->ops->revert_current_mid(server, val);
}
static inline void
revert_current_mid_from_hdr(struct TCP_Server_Info *server,
const struct smb2_sync_hdr *shdr)
{
unsigned int num = le16_to_cpu(shdr->CreditCharge);
return revert_current_mid(server, num > 0 ? num : 1);
}
static inline __u16 static inline __u16
get_mid(const struct smb_hdr *smb) get_mid(const struct smb_hdr *smb)
{ {
...@@ -1234,7 +1272,7 @@ struct cifs_readdata { ...@@ -1234,7 +1272,7 @@ struct cifs_readdata {
unsigned int pagesz; unsigned int pagesz;
unsigned int page_offset; unsigned int page_offset;
unsigned int tailsz; unsigned int tailsz;
unsigned int credits; struct cifs_credits credits;
unsigned int nr_pages; unsigned int nr_pages;
struct page **pages; struct page **pages;
}; };
...@@ -1260,7 +1298,7 @@ struct cifs_writedata { ...@@ -1260,7 +1298,7 @@ struct cifs_writedata {
unsigned int pagesz; unsigned int pagesz;
unsigned int page_offset; unsigned int page_offset;
unsigned int tailsz; unsigned int tailsz;
unsigned int credits; struct cifs_credits credits;
unsigned int nr_pages; unsigned int nr_pages;
struct page **pages; struct page **pages;
}; };
...@@ -1422,6 +1460,7 @@ struct mid_q_entry { ...@@ -1422,6 +1460,7 @@ struct mid_q_entry {
struct kref refcount; struct kref refcount;
struct TCP_Server_Info *server; /* server corresponding to this mid */ struct TCP_Server_Info *server; /* server corresponding to this mid */
__u64 mid; /* multiplex id */ __u64 mid; /* multiplex id */
__u16 credits; /* number of credits consumed by this mid */
__u32 pid; /* process id */ __u32 pid; /* process id */
__u32 sequence_number; /* for CIFS signing */ __u32 sequence_number; /* for CIFS signing */
unsigned long when_alloc; /* when mid was created */ unsigned long when_alloc; /* when mid was created */
......
...@@ -93,7 +93,8 @@ extern int cifs_discard_remaining_data(struct TCP_Server_Info *server); ...@@ -93,7 +93,8 @@ extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
extern int cifs_call_async(struct TCP_Server_Info *server, extern int cifs_call_async(struct TCP_Server_Info *server,
struct smb_rqst *rqst, struct smb_rqst *rqst,
mid_receive_t *receive, mid_callback_t *callback, mid_receive_t *receive, mid_callback_t *callback,
mid_handle_t *handle, void *cbdata, const int flags); mid_handle_t *handle, void *cbdata, const int flags,
const struct cifs_credits *exist_credits);
extern int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, extern int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
struct smb_rqst *rqst, int *resp_buf_type, struct smb_rqst *rqst, int *resp_buf_type,
const int flags, struct kvec *resp_iov); const int flags, struct kvec *resp_iov);
...@@ -115,7 +116,7 @@ extern int cifs_check_receive(struct mid_q_entry *mid, ...@@ -115,7 +116,7 @@ extern int cifs_check_receive(struct mid_q_entry *mid,
struct TCP_Server_Info *server, bool log_error); struct TCP_Server_Info *server, bool log_error);
extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server, extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server,
unsigned int size, unsigned int *num, unsigned int size, unsigned int *num,
unsigned int *credits); struct cifs_credits *credits);
extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *, extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
struct kvec *, int /* nvec to send */, struct kvec *, int /* nvec to send */,
int * /* type of buf returned */, const int flags, int * /* type of buf returned */, const int flags,
...@@ -133,6 +134,9 @@ extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); ...@@ -133,6 +134,9 @@ extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
unsigned int bytes_written); unsigned int bytes_written);
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool); extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
extern int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode,
bool fsuid_only,
struct cifsFileInfo **ret_file);
extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool); extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
extern unsigned int smbCalcSize(void *buf, struct TCP_Server_Info *server); extern unsigned int smbCalcSize(void *buf, struct TCP_Server_Info *server);
extern int decode_negTokenInit(unsigned char *security_blob, int length, extern int decode_negTokenInit(unsigned char *security_blob, int length,
......
...@@ -139,8 +139,8 @@ static int __cifs_reconnect_tcon(const struct nls_table *nlsc, ...@@ -139,8 +139,8 @@ static int __cifs_reconnect_tcon(const struct nls_table *nlsc,
return -ENOMEM; return -ENOMEM;
if (tcon->ipc) { if (tcon->ipc) {
snprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$",
tcon->ses->server->hostname); tcon->ses->server->hostname);
rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc); rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
goto out; goto out;
} }
...@@ -172,7 +172,7 @@ static int __cifs_reconnect_tcon(const struct nls_table *nlsc, ...@@ -172,7 +172,7 @@ static int __cifs_reconnect_tcon(const struct nls_table *nlsc,
continue; continue;
} }
snprintf(tree, MAX_TREE_SIZE, "\\%s", tgt); scnprintf(tree, MAX_TREE_SIZE, "\\%s", tgt);
rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc); rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
if (!rc) if (!rc)
...@@ -822,9 +822,10 @@ static void ...@@ -822,9 +822,10 @@ static void
cifs_echo_callback(struct mid_q_entry *mid) cifs_echo_callback(struct mid_q_entry *mid)
{ {
struct TCP_Server_Info *server = mid->callback_data; struct TCP_Server_Info *server = mid->callback_data;
struct cifs_credits credits = { .value = 1, .instance = 0 };
DeleteMidQEntry(mid); DeleteMidQEntry(mid);
add_credits(server, 1, CIFS_ECHO_OP); add_credits(server, &credits, CIFS_ECHO_OP);
} }
int int
...@@ -859,7 +860,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server) ...@@ -859,7 +860,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
iov[1].iov_base = (char *)smb + 4; iov[1].iov_base = (char *)smb + 4;
rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL, rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
server, CIFS_ASYNC_OP | CIFS_ECHO_OP); server, CIFS_ASYNC_OP | CIFS_ECHO_OP, NULL);
if (rc) if (rc)
cifs_dbg(FYI, "Echo request failed: %d\n", rc); cifs_dbg(FYI, "Echo request failed: %d\n", rc);
...@@ -1605,16 +1606,17 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) ...@@ -1605,16 +1606,17 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
} }
if (server->ops->is_status_pending && if (server->ops->is_status_pending &&
server->ops->is_status_pending(buf, server, 0)) { server->ops->is_status_pending(buf, server)) {
cifs_discard_remaining_data(server); cifs_discard_remaining_data(server);
return -1; return -1;
} }
/* set up first two iov for signature check and to get credits */ /* set up first two iov for signature check and to get credits */
rdata->iov[0].iov_base = buf; rdata->iov[0].iov_base = buf;
rdata->iov[0].iov_len = 4; rdata->iov[0].iov_len = server->vals->header_preamble_size;
rdata->iov[1].iov_base = buf + 4; rdata->iov[1].iov_base = buf + server->vals->header_preamble_size;
rdata->iov[1].iov_len = server->total_read - 4; rdata->iov[1].iov_len =
server->total_read - server->vals->header_preamble_size;
cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n", cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
rdata->iov[0].iov_base, rdata->iov[0].iov_len); rdata->iov[0].iov_base, rdata->iov[0].iov_len);
cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n", cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
...@@ -1713,6 +1715,7 @@ cifs_readv_callback(struct mid_q_entry *mid) ...@@ -1713,6 +1715,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
.rq_npages = rdata->nr_pages, .rq_npages = rdata->nr_pages,
.rq_pagesz = rdata->pagesz, .rq_pagesz = rdata->pagesz,
.rq_tailsz = rdata->tailsz }; .rq_tailsz = rdata->tailsz };
struct cifs_credits credits = { .value = 1, .instance = 0 };
cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n", cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
__func__, mid->mid, mid->mid_state, rdata->result, __func__, mid->mid, mid->mid_state, rdata->result,
...@@ -1750,7 +1753,7 @@ cifs_readv_callback(struct mid_q_entry *mid) ...@@ -1750,7 +1753,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
queue_work(cifsiod_wq, &rdata->work); queue_work(cifsiod_wq, &rdata->work);
DeleteMidQEntry(mid); DeleteMidQEntry(mid);
add_credits(server, 1, 0); add_credits(server, &credits, 0);
} }
/* cifs_async_readv - send an async write, and set up mid to handle result */ /* cifs_async_readv - send an async write, and set up mid to handle result */
...@@ -1809,7 +1812,7 @@ cifs_async_readv(struct cifs_readdata *rdata) ...@@ -1809,7 +1812,7 @@ cifs_async_readv(struct cifs_readdata *rdata)
kref_get(&rdata->refcount); kref_get(&rdata->refcount);
rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive, rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
cifs_readv_callback, NULL, rdata, 0); cifs_readv_callback, NULL, rdata, 0, NULL);
if (rc == 0) if (rc == 0)
cifs_stats_inc(&tcon->stats.cifs_stats.num_reads); cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
...@@ -2123,14 +2126,18 @@ cifs_writev_requeue(struct cifs_writedata *wdata) ...@@ -2123,14 +2126,18 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
wdata2->tailsz = tailsz; wdata2->tailsz = tailsz;
wdata2->bytes = cur_len; wdata2->bytes = cur_len;
wdata2->cfile = find_writable_file(CIFS_I(inode), false); rc = cifs_get_writable_file(CIFS_I(inode), false,
&wdata2->cfile);
if (!wdata2->cfile) { if (!wdata2->cfile) {
cifs_dbg(VFS, "No writable handles for inode\n"); cifs_dbg(VFS, "No writable handle to retry writepages rc=%d\n",
rc = -EBADF; rc);
break; if (!is_retryable_error(rc))
rc = -EBADF;
} else {
wdata2->pid = wdata2->cfile->pid;
rc = server->ops->async_writev(wdata2,
cifs_writedata_release);
} }
wdata2->pid = wdata2->cfile->pid;
rc = server->ops->async_writev(wdata2, cifs_writedata_release);
for (j = 0; j < nr_pages; j++) { for (j = 0; j < nr_pages; j++) {
unlock_page(wdata2->pages[j]); unlock_page(wdata2->pages[j]);
...@@ -2145,6 +2152,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata) ...@@ -2145,6 +2152,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
kref_put(&wdata2->refcount, cifs_writedata_release); kref_put(&wdata2->refcount, cifs_writedata_release);
if (is_retryable_error(rc)) if (is_retryable_error(rc))
continue; continue;
i += nr_pages;
break; break;
} }
...@@ -2152,6 +2160,13 @@ cifs_writev_requeue(struct cifs_writedata *wdata) ...@@ -2152,6 +2160,13 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
i += nr_pages; i += nr_pages;
} while (i < wdata->nr_pages); } while (i < wdata->nr_pages);
/* cleanup remaining pages from the original wdata */
for (; i < wdata->nr_pages; i++) {
SetPageError(wdata->pages[i]);
end_page_writeback(wdata->pages[i]);
put_page(wdata->pages[i]);
}
if (rc != 0 && !is_retryable_error(rc)) if (rc != 0 && !is_retryable_error(rc))
mapping_set_error(inode->i_mapping, rc); mapping_set_error(inode->i_mapping, rc);
kref_put(&wdata->refcount, cifs_writedata_release); kref_put(&wdata->refcount, cifs_writedata_release);
...@@ -2226,6 +2241,7 @@ cifs_writev_callback(struct mid_q_entry *mid) ...@@ -2226,6 +2241,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
unsigned int written; unsigned int written;
WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf; WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
struct cifs_credits credits = { .value = 1, .instance = 0 };
switch (mid->mid_state) { switch (mid->mid_state) {
case MID_RESPONSE_RECEIVED: case MID_RESPONSE_RECEIVED:
...@@ -2261,7 +2277,7 @@ cifs_writev_callback(struct mid_q_entry *mid) ...@@ -2261,7 +2277,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
queue_work(cifsiod_wq, &wdata->work); queue_work(cifsiod_wq, &wdata->work);
DeleteMidQEntry(mid); DeleteMidQEntry(mid);
add_credits(tcon->ses->server, 1, 0); add_credits(tcon->ses->server, &credits, 0);
} }
/* cifs_async_writev - send an async write, and set up mid to handle result */ /* cifs_async_writev - send an async write, and set up mid to handle result */
...@@ -2339,7 +2355,7 @@ cifs_async_writev(struct cifs_writedata *wdata, ...@@ -2339,7 +2355,7 @@ cifs_async_writev(struct cifs_writedata *wdata,
kref_get(&wdata->refcount); kref_get(&wdata->refcount);
rc = cifs_call_async(tcon->ses->server, &rqst, NULL, rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
cifs_writev_callback, NULL, wdata, 0); cifs_writev_callback, NULL, wdata, 0, NULL);
if (rc == 0) if (rc == 0)
cifs_stats_inc(&tcon->stats.cifs_stats.num_writes); cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
......
...@@ -102,7 +102,7 @@ enum { ...@@ -102,7 +102,7 @@ enum {
Opt_backupuid, Opt_backupgid, Opt_uid, Opt_backupuid, Opt_backupgid, Opt_uid,
Opt_cruid, Opt_gid, Opt_file_mode, Opt_cruid, Opt_gid, Opt_file_mode,
Opt_dirmode, Opt_port, Opt_dirmode, Opt_port,
Opt_rsize, Opt_wsize, Opt_actimeo, Opt_blocksize, Opt_rsize, Opt_wsize, Opt_actimeo,
Opt_echo_interval, Opt_max_credits, Opt_echo_interval, Opt_max_credits,
Opt_snapshot, Opt_snapshot,
...@@ -204,6 +204,7 @@ static const match_table_t cifs_mount_option_tokens = { ...@@ -204,6 +204,7 @@ static const match_table_t cifs_mount_option_tokens = {
{ Opt_dirmode, "dirmode=%s" }, { Opt_dirmode, "dirmode=%s" },
{ Opt_dirmode, "dir_mode=%s" }, { Opt_dirmode, "dir_mode=%s" },
{ Opt_port, "port=%s" }, { Opt_port, "port=%s" },
{ Opt_blocksize, "bsize=%s" },
{ Opt_rsize, "rsize=%s" }, { Opt_rsize, "rsize=%s" },
{ Opt_wsize, "wsize=%s" }, { Opt_wsize, "wsize=%s" },
{ Opt_actimeo, "actimeo=%s" }, { Opt_actimeo, "actimeo=%s" },
...@@ -348,7 +349,7 @@ static int reconn_set_ipaddr(struct TCP_Server_Info *server) ...@@ -348,7 +349,7 @@ static int reconn_set_ipaddr(struct TCP_Server_Info *server)
cifs_dbg(FYI, "%s: failed to create UNC path\n", __func__); cifs_dbg(FYI, "%s: failed to create UNC path\n", __func__);
return -ENOMEM; return -ENOMEM;
} }
snprintf(unc, len, "\\\\%s", server->hostname); scnprintf(unc, len, "\\\\%s", server->hostname);
rc = dns_resolve_server_name_to_ip(unc, &ipaddr); rc = dns_resolve_server_name_to_ip(unc, &ipaddr);
kfree(unc); kfree(unc);
...@@ -592,6 +593,7 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -592,6 +593,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
msleep(3000); msleep(3000);
} else { } else {
atomic_inc(&tcpSesReconnectCount); atomic_inc(&tcpSesReconnectCount);
set_credits(server, 1);
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
if (server->tcpStatus != CifsExiting) if (server->tcpStatus != CifsExiting)
server->tcpStatus = CifsNeedNegotiate; server->tcpStatus = CifsNeedNegotiate;
...@@ -1053,7 +1055,7 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid) ...@@ -1053,7 +1055,7 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
} }
if (server->ops->is_status_pending && if (server->ops->is_status_pending &&
server->ops->is_status_pending(buf, server, length)) server->ops->is_status_pending(buf, server))
return -1; return -1;
if (!mid) if (!mid)
...@@ -1063,6 +1065,26 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid) ...@@ -1063,6 +1065,26 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
return 0; return 0;
} }
static void
smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
{
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buffer;
/*
* SMB1 does not use credits.
*/
if (server->vals->header_preamble_size)
return;
if (shdr->CreditRequest) {
spin_lock(&server->req_lock);
server->credits += le16_to_cpu(shdr->CreditRequest);
spin_unlock(&server->req_lock);
wake_up(&server->request_q);
}
}
static int static int
cifs_demultiplex_thread(void *p) cifs_demultiplex_thread(void *p)
{ {
...@@ -1192,6 +1214,7 @@ cifs_demultiplex_thread(void *p) ...@@ -1192,6 +1214,7 @@ cifs_demultiplex_thread(void *p)
} else if (server->ops->is_oplock_break && } else if (server->ops->is_oplock_break &&
server->ops->is_oplock_break(bufs[i], server->ops->is_oplock_break(bufs[i],
server)) { server)) {
smb2_add_credits_from_hdr(bufs[i], server);
cifs_dbg(FYI, "Received oplock break\n"); cifs_dbg(FYI, "Received oplock break\n");
} else { } else {
cifs_dbg(VFS, "No task to wake, unknown frame " cifs_dbg(VFS, "No task to wake, unknown frame "
...@@ -1203,6 +1226,7 @@ cifs_demultiplex_thread(void *p) ...@@ -1203,6 +1226,7 @@ cifs_demultiplex_thread(void *p)
if (server->ops->dump_detail) if (server->ops->dump_detail)
server->ops->dump_detail(bufs[i], server->ops->dump_detail(bufs[i],
server); server);
smb2_add_credits_from_hdr(bufs[i], server);
cifs_dump_mids(server); cifs_dump_mids(server);
#endif /* CIFS_DEBUG2 */ #endif /* CIFS_DEBUG2 */
} }
...@@ -1486,6 +1510,11 @@ cifs_parse_devname(const char *devname, struct smb_vol *vol) ...@@ -1486,6 +1510,11 @@ cifs_parse_devname(const char *devname, struct smb_vol *vol)
const char *delims = "/\\"; const char *delims = "/\\";
size_t len; size_t len;
if (unlikely(!devname || !*devname)) {
cifs_dbg(VFS, "Device name not specified.\n");
return -EINVAL;
}
/* make sure we have a valid UNC double delimiter prefix */ /* make sure we have a valid UNC double delimiter prefix */
len = strspn(devname, delims); len = strspn(devname, delims);
if (len != 2) if (len != 2)
...@@ -1571,7 +1600,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, ...@@ -1571,7 +1600,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
vol->cred_uid = current_uid(); vol->cred_uid = current_uid();
vol->linux_uid = current_uid(); vol->linux_uid = current_uid();
vol->linux_gid = current_gid(); vol->linux_gid = current_gid();
vol->bsize = 1024 * 1024; /* can improve cp performance significantly */
/* /*
* default to SFM style remapping of seven reserved characters * default to SFM style remapping of seven reserved characters
* unless user overrides it or we negotiate CIFS POSIX where * unless user overrides it or we negotiate CIFS POSIX where
...@@ -1944,6 +1973,26 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, ...@@ -1944,6 +1973,26 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
} }
port = (unsigned short)option; port = (unsigned short)option;
break; break;
case Opt_blocksize:
if (get_option_ul(args, &option)) {
cifs_dbg(VFS, "%s: Invalid blocksize value\n",
__func__);
goto cifs_parse_mount_err;
}
/*
* inode blocksize realistically should never need to be
* less than 16K or greater than 16M and default is 1MB.
* Note that small inode block sizes (e.g. 64K) can lead
* to very poor performance of common tools like cp and scp
*/
if ((option < CIFS_MAX_MSGSIZE) ||
(option > (4 * SMB3_DEFAULT_IOSIZE))) {
cifs_dbg(VFS, "%s: Invalid blocksize\n",
__func__);
goto cifs_parse_mount_err;
}
vol->bsize = option;
break;
case Opt_rsize: case Opt_rsize:
if (get_option_ul(args, &option)) { if (get_option_ul(args, &option)) {
cifs_dbg(VFS, "%s: Invalid rsize value\n", cifs_dbg(VFS, "%s: Invalid rsize value\n",
...@@ -2609,7 +2658,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) ...@@ -2609,7 +2658,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
tcp_ses->session_estab = false; tcp_ses->session_estab = false;
tcp_ses->sequence_number = 0; tcp_ses->sequence_number = 0;
tcp_ses->reconnect_instance = 0; tcp_ses->reconnect_instance = 1;
tcp_ses->lstrp = jiffies; tcp_ses->lstrp = jiffies;
spin_lock_init(&tcp_ses->req_lock); spin_lock_init(&tcp_ses->req_lock);
INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
...@@ -2770,7 +2819,7 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb_vol *volume_info) ...@@ -2770,7 +2819,7 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb_vol *volume_info)
if (tcon == NULL) if (tcon == NULL)
return -ENOMEM; return -ENOMEM;
snprintf(unc, sizeof(unc), "\\\\%s\\IPC$", ses->server->hostname); scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", ses->server->hostname);
/* cannot fail */ /* cannot fail */
nls_codepage = load_nls_default(); nls_codepage = load_nls_default();
...@@ -3839,6 +3888,7 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info, ...@@ -3839,6 +3888,7 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
spin_lock_init(&cifs_sb->tlink_tree_lock); spin_lock_init(&cifs_sb->tlink_tree_lock);
cifs_sb->tlink_tree = RB_ROOT; cifs_sb->tlink_tree = RB_ROOT;
cifs_sb->bsize = pvolume_info->bsize;
/* /*
* Temporarily set r/wsize for matching superblock. If we end up using * Temporarily set r/wsize for matching superblock. If we end up using
* new sb then client will later negotiate it downward if needed. * new sb then client will later negotiate it downward if needed.
...@@ -4198,7 +4248,7 @@ static int update_vol_info(const struct dfs_cache_tgt_iterator *tgt_it, ...@@ -4198,7 +4248,7 @@ static int update_vol_info(const struct dfs_cache_tgt_iterator *tgt_it,
new_unc = kmalloc(len, GFP_KERNEL); new_unc = kmalloc(len, GFP_KERNEL);
if (!new_unc) if (!new_unc)
return -ENOMEM; return -ENOMEM;
snprintf(new_unc, len, "\\%s", tgt); scnprintf(new_unc, len, "\\%s", tgt);
kfree(vol->UNC); kfree(vol->UNC);
vol->UNC = new_unc; vol->UNC = new_unc;
...@@ -4902,8 +4952,6 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses) ...@@ -4902,8 +4952,6 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses)
if (!server->ops->need_neg(server)) if (!server->ops->need_neg(server))
return 0; return 0;
set_credits(server, 1);
rc = server->ops->negotiate(xid, ses); rc = server->ops->negotiate(xid, ses);
if (rc == 0) { if (rc == 0) {
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
......
This diff is collapsed.
...@@ -2080,7 +2080,7 @@ int cifs_getattr(const struct path *path, struct kstat *stat, ...@@ -2080,7 +2080,7 @@ int cifs_getattr(const struct path *path, struct kstat *stat,
return rc; return rc;
generic_fillattr(inode, stat); generic_fillattr(inode, stat);
stat->blksize = CIFS_MAX_MSGSIZE; stat->blksize = cifs_sb->bsize;
stat->ino = CIFS_I(inode)->uniqueid; stat->ino = CIFS_I(inode)->uniqueid;
/* old CIFS Unix Extensions doesn't return create time */ /* old CIFS Unix Extensions doesn't return create time */
......
...@@ -103,9 +103,9 @@ parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len, ...@@ -103,9 +103,9 @@ parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len,
return rc; return rc;
} }
snprintf(md5_str2, sizeof(md5_str2), scnprintf(md5_str2, sizeof(md5_str2),
CIFS_MF_SYMLINK_MD5_FORMAT, CIFS_MF_SYMLINK_MD5_FORMAT,
CIFS_MF_SYMLINK_MD5_ARGS(md5_hash)); CIFS_MF_SYMLINK_MD5_ARGS(md5_hash));
if (strncmp(md5_str1, md5_str2, 17) != 0) if (strncmp(md5_str1, md5_str2, 17) != 0)
return -EINVAL; return -EINVAL;
...@@ -142,10 +142,10 @@ format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str) ...@@ -142,10 +142,10 @@ format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str)
return rc; return rc;
} }
snprintf(buf, buf_len, scnprintf(buf, buf_len,
CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT, CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT,
link_len, link_len,
CIFS_MF_SYMLINK_MD5_ARGS(md5_hash)); CIFS_MF_SYMLINK_MD5_ARGS(md5_hash));
ofs = CIFS_MF_SYMLINK_LINK_OFFSET; ofs = CIFS_MF_SYMLINK_LINK_OFFSET;
memcpy(buf + ofs, link_str, link_len); memcpy(buf + ofs, link_str, link_len);
......
...@@ -117,11 +117,11 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer) ...@@ -117,11 +117,11 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer)
} }
static void static void
cifs_add_credits(struct TCP_Server_Info *server, const unsigned int add, cifs_add_credits(struct TCP_Server_Info *server,
const int optype) const struct cifs_credits *credits, const int optype)
{ {
spin_lock(&server->req_lock); spin_lock(&server->req_lock);
server->credits += add; server->credits += credits->value;
server->in_flight--; server->in_flight--;
spin_unlock(&server->req_lock); spin_unlock(&server->req_lock);
wake_up(&server->request_q); wake_up(&server->request_q);
...@@ -308,7 +308,7 @@ coalesce_t2(char *second_buf, struct smb_hdr *target_hdr) ...@@ -308,7 +308,7 @@ coalesce_t2(char *second_buf, struct smb_hdr *target_hdr)
remaining = tgt_total_cnt - total_in_tgt; remaining = tgt_total_cnt - total_in_tgt;
if (remaining < 0) { if (remaining < 0) {
cifs_dbg(FYI, "Server sent too much data. tgt_total_cnt=%hu total_in_tgt=%hu\n", cifs_dbg(FYI, "Server sent too much data. tgt_total_cnt=%hu total_in_tgt=%u\n",
tgt_total_cnt, total_in_tgt); tgt_total_cnt, total_in_tgt);
return -EPROTO; return -EPROTO;
} }
......
...@@ -517,7 +517,6 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp, ...@@ -517,7 +517,6 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
__u8 lease_state; __u8 lease_state;
struct list_head *tmp; struct list_head *tmp;
struct cifsFileInfo *cfile; struct cifsFileInfo *cfile;
struct TCP_Server_Info *server = tcon->ses->server;
struct cifs_pending_open *open; struct cifs_pending_open *open;
struct cifsInodeInfo *cinode; struct cifsInodeInfo *cinode;
int ack_req = le32_to_cpu(rsp->Flags & int ack_req = le32_to_cpu(rsp->Flags &
...@@ -537,13 +536,25 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp, ...@@ -537,13 +536,25 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
cifs_dbg(FYI, "lease key match, lease break 0x%x\n", cifs_dbg(FYI, "lease key match, lease break 0x%x\n",
le32_to_cpu(rsp->NewLeaseState)); le32_to_cpu(rsp->NewLeaseState));
server->ops->set_oplock_level(cinode, lease_state, 0, NULL);
if (ack_req) if (ack_req)
cfile->oplock_break_cancelled = false; cfile->oplock_break_cancelled = false;
else else
cfile->oplock_break_cancelled = true; cfile->oplock_break_cancelled = true;
set_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags);
/*
* Set or clear flags depending on the lease state being READ.
* HANDLE caching flag should be added when the client starts
* to defer closing remote file handles with HANDLE leases.
*/
if (lease_state & SMB2_LEASE_READ_CACHING_HE)
set_bit(CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
&cinode->flags);
else
clear_bit(CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
&cinode->flags);
queue_work(cifsoplockd_wq, &cfile->oplock_break); queue_work(cifsoplockd_wq, &cfile->oplock_break);
kfree(lw); kfree(lw);
return true; return true;
...@@ -648,13 +659,6 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) ...@@ -648,13 +659,6 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
if (rsp->sync_hdr.Command != SMB2_OPLOCK_BREAK) if (rsp->sync_hdr.Command != SMB2_OPLOCK_BREAK)
return false; return false;
if (rsp->sync_hdr.CreditRequest) {
spin_lock(&server->req_lock);
server->credits += le16_to_cpu(rsp->sync_hdr.CreditRequest);
spin_unlock(&server->req_lock);
wake_up(&server->request_q);
}
if (rsp->StructureSize != if (rsp->StructureSize !=
smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) { smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) {
if (le16_to_cpu(rsp->StructureSize) == 44) if (le16_to_cpu(rsp->StructureSize) == 44)
......
...@@ -67,10 +67,13 @@ change_conf(struct TCP_Server_Info *server) ...@@ -67,10 +67,13 @@ change_conf(struct TCP_Server_Info *server)
} }
static void static void
smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add, smb2_add_credits(struct TCP_Server_Info *server,
const int optype) const struct cifs_credits *credits, const int optype)
{ {
int *val, rc = -1; int *val, rc = -1;
unsigned int add = credits->value;
unsigned int instance = credits->instance;
bool reconnect_detected = false;
spin_lock(&server->req_lock); spin_lock(&server->req_lock);
val = server->ops->get_credits_field(server, optype); val = server->ops->get_credits_field(server, optype);
...@@ -79,8 +82,11 @@ smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add, ...@@ -79,8 +82,11 @@ smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
if (((optype & CIFS_OP_MASK) == CIFS_NEG_OP) && (*val != 0)) if (((optype & CIFS_OP_MASK) == CIFS_NEG_OP) && (*val != 0))
trace_smb3_reconnect_with_invalid_credits(server->CurrentMid, trace_smb3_reconnect_with_invalid_credits(server->CurrentMid,
server->hostname, *val); server->hostname, *val);
if ((instance == 0) || (instance == server->reconnect_instance))
*val += add;
else
reconnect_detected = true;
*val += add;
if (*val > 65000) { if (*val > 65000) {
*val = 65000; /* Don't get near 64K credits, avoid srv bugs */ *val = 65000; /* Don't get near 64K credits, avoid srv bugs */
printk_once(KERN_WARNING "server overflowed SMB3 credits\n"); printk_once(KERN_WARNING "server overflowed SMB3 credits\n");
...@@ -102,7 +108,12 @@ smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add, ...@@ -102,7 +108,12 @@ smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
spin_unlock(&server->req_lock); spin_unlock(&server->req_lock);
wake_up(&server->request_q); wake_up(&server->request_q);
if (server->tcpStatus == CifsNeedReconnect) if (reconnect_detected)
cifs_dbg(FYI, "trying to put %d credits from the old server instance %d\n",
add, instance);
if (server->tcpStatus == CifsNeedReconnect
|| server->tcpStatus == CifsExiting)
return; return;
switch (rc) { switch (rc) {
...@@ -163,7 +174,7 @@ smb2_get_credits(struct mid_q_entry *mid) ...@@ -163,7 +174,7 @@ smb2_get_credits(struct mid_q_entry *mid)
static int static int
smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
unsigned int *num, unsigned int *credits) unsigned int *num, struct cifs_credits *credits)
{ {
int rc = 0; int rc = 0;
unsigned int scredits; unsigned int scredits;
...@@ -189,7 +200,8 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, ...@@ -189,7 +200,8 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
/* can deadlock with reopen */ /* can deadlock with reopen */
if (scredits <= 8) { if (scredits <= 8) {
*num = SMB2_MAX_BUFFER_SIZE; *num = SMB2_MAX_BUFFER_SIZE;
*credits = 0; credits->value = 0;
credits->instance = 0;
break; break;
} }
...@@ -198,8 +210,10 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, ...@@ -198,8 +210,10 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
*num = min_t(unsigned int, size, *num = min_t(unsigned int, size,
scredits * SMB2_MAX_BUFFER_SIZE); scredits * SMB2_MAX_BUFFER_SIZE);
*credits = DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE); credits->value =
server->credits -= *credits; DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE);
credits->instance = server->reconnect_instance;
server->credits -= credits->value;
server->in_flight++; server->in_flight++;
break; break;
} }
...@@ -208,6 +222,38 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, ...@@ -208,6 +222,38 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
return rc; return rc;
} }
static int
smb2_adjust_credits(struct TCP_Server_Info *server,
struct cifs_credits *credits,
const unsigned int payload_size)
{
int new_val = DIV_ROUND_UP(payload_size, SMB2_MAX_BUFFER_SIZE);
if (!credits->value || credits->value == new_val)
return 0;
if (credits->value < new_val) {
WARN_ONCE(1, "request has less credits (%d) than required (%d)",
credits->value, new_val);
return -ENOTSUPP;
}
spin_lock(&server->req_lock);
if (server->reconnect_instance != credits->instance) {
spin_unlock(&server->req_lock);
cifs_dbg(VFS, "trying to return %d credits to old session\n",
credits->value - new_val);
return -EAGAIN;
}
server->credits += credits->value - new_val;
spin_unlock(&server->req_lock);
wake_up(&server->request_q);
credits->value = new_val;
return 0;
}
static __u64 static __u64
smb2_get_next_mid(struct TCP_Server_Info *server) smb2_get_next_mid(struct TCP_Server_Info *server)
{ {
...@@ -219,6 +265,15 @@ smb2_get_next_mid(struct TCP_Server_Info *server) ...@@ -219,6 +265,15 @@ smb2_get_next_mid(struct TCP_Server_Info *server)
return mid; return mid;
} }
static void
smb2_revert_current_mid(struct TCP_Server_Info *server, const unsigned int val)
{
spin_lock(&GlobalMid_Lock);
if (server->CurrentMid >= val)
server->CurrentMid -= val;
spin_unlock(&GlobalMid_Lock);
}
static struct mid_q_entry * static struct mid_q_entry *
smb2_find_mid(struct TCP_Server_Info *server, char *buf) smb2_find_mid(struct TCP_Server_Info *server, char *buf)
{ {
...@@ -940,6 +995,16 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -940,6 +995,16 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
memset(rsp_iov, 0, sizeof(rsp_iov)); memset(rsp_iov, 0, sizeof(rsp_iov));
if (ses->server->ops->query_all_EAs) {
if (!ea_value) {
rc = ses->server->ops->query_all_EAs(xid, tcon, path,
ea_name, NULL, 0,
cifs_sb);
if (rc == -ENODATA)
goto sea_exit;
}
}
/* Open */ /* Open */
memset(&open_iov, 0, sizeof(open_iov)); memset(&open_iov, 0, sizeof(open_iov));
rqst[0].rq_iov = open_iov; rqst[0].rq_iov = open_iov;
...@@ -1753,14 +1818,14 @@ smb2_close_dir(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -1753,14 +1818,14 @@ smb2_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
* the number of credits and return true. Otherwise - return false. * the number of credits and return true. Otherwise - return false.
*/ */
static bool static bool
smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length) smb2_is_status_pending(char *buf, struct TCP_Server_Info *server)
{ {
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf; struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
if (shdr->Status != STATUS_PENDING) if (shdr->Status != STATUS_PENDING)
return false; return false;
if (!length) { if (shdr->CreditRequest) {
spin_lock(&server->req_lock); spin_lock(&server->req_lock);
server->credits += le16_to_cpu(shdr->CreditRequest); server->credits += le16_to_cpu(shdr->CreditRequest);
spin_unlock(&server->req_lock); spin_unlock(&server->req_lock);
...@@ -2594,6 +2659,15 @@ smb2_downgrade_oplock(struct TCP_Server_Info *server, ...@@ -2594,6 +2659,15 @@ smb2_downgrade_oplock(struct TCP_Server_Info *server,
server->ops->set_oplock_level(cinode, 0, 0, NULL); server->ops->set_oplock_level(cinode, 0, 0, NULL);
} }
static void
smb21_downgrade_oplock(struct TCP_Server_Info *server,
struct cifsInodeInfo *cinode, bool set_level2)
{
server->ops->set_oplock_level(cinode,
set_level2 ? SMB2_LEASE_READ_CACHING_HE :
0, 0, NULL);
}
static void static void
smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock, smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
unsigned int epoch, bool *purge_cache) unsigned int epoch, bool *purge_cache)
...@@ -3210,15 +3284,15 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, ...@@ -3210,15 +3284,15 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
} }
if (server->ops->is_status_pending && if (server->ops->is_status_pending &&
server->ops->is_status_pending(buf, server, 0)) server->ops->is_status_pending(buf, server))
return -1; return -1;
/* set up first two iov to get credits */ /* set up first two iov to get credits */
rdata->iov[0].iov_base = buf; rdata->iov[0].iov_base = buf;
rdata->iov[0].iov_len = 4; rdata->iov[0].iov_len = 0;
rdata->iov[1].iov_base = buf + 4; rdata->iov[1].iov_base = buf;
rdata->iov[1].iov_len = rdata->iov[1].iov_len =
min_t(unsigned int, buf_len, server->vals->read_rsp_size) - 4; min_t(unsigned int, buf_len, server->vals->read_rsp_size);
cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n", cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
rdata->iov[0].iov_base, rdata->iov[0].iov_len); rdata->iov[0].iov_base, rdata->iov[0].iov_len);
cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n", cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
...@@ -3541,6 +3615,7 @@ struct smb_version_operations smb20_operations = { ...@@ -3541,6 +3615,7 @@ struct smb_version_operations smb20_operations = {
.get_credits = smb2_get_credits, .get_credits = smb2_get_credits,
.wait_mtu_credits = cifs_wait_mtu_credits, .wait_mtu_credits = cifs_wait_mtu_credits,
.get_next_mid = smb2_get_next_mid, .get_next_mid = smb2_get_next_mid,
.revert_current_mid = smb2_revert_current_mid,
.read_data_offset = smb2_read_data_offset, .read_data_offset = smb2_read_data_offset,
.read_data_length = smb2_read_data_length, .read_data_length = smb2_read_data_length,
.map_error = map_smb2_to_linux_error, .map_error = map_smb2_to_linux_error,
...@@ -3635,7 +3710,9 @@ struct smb_version_operations smb21_operations = { ...@@ -3635,7 +3710,9 @@ struct smb_version_operations smb21_operations = {
.get_credits_field = smb2_get_credits_field, .get_credits_field = smb2_get_credits_field,
.get_credits = smb2_get_credits, .get_credits = smb2_get_credits,
.wait_mtu_credits = smb2_wait_mtu_credits, .wait_mtu_credits = smb2_wait_mtu_credits,
.adjust_credits = smb2_adjust_credits,
.get_next_mid = smb2_get_next_mid, .get_next_mid = smb2_get_next_mid,
.revert_current_mid = smb2_revert_current_mid,
.read_data_offset = smb2_read_data_offset, .read_data_offset = smb2_read_data_offset,
.read_data_length = smb2_read_data_length, .read_data_length = smb2_read_data_length,
.map_error = map_smb2_to_linux_error, .map_error = map_smb2_to_linux_error,
...@@ -3646,7 +3723,7 @@ struct smb_version_operations smb21_operations = { ...@@ -3646,7 +3723,7 @@ struct smb_version_operations smb21_operations = {
.print_stats = smb2_print_stats, .print_stats = smb2_print_stats,
.is_oplock_break = smb2_is_valid_oplock_break, .is_oplock_break = smb2_is_valid_oplock_break,
.handle_cancelled_mid = smb2_handle_cancelled_mid, .handle_cancelled_mid = smb2_handle_cancelled_mid,
.downgrade_oplock = smb2_downgrade_oplock, .downgrade_oplock = smb21_downgrade_oplock,
.need_neg = smb2_need_neg, .need_neg = smb2_need_neg,
.negotiate = smb2_negotiate, .negotiate = smb2_negotiate,
.negotiate_wsize = smb2_negotiate_wsize, .negotiate_wsize = smb2_negotiate_wsize,
...@@ -3731,7 +3808,9 @@ struct smb_version_operations smb30_operations = { ...@@ -3731,7 +3808,9 @@ struct smb_version_operations smb30_operations = {
.get_credits_field = smb2_get_credits_field, .get_credits_field = smb2_get_credits_field,
.get_credits = smb2_get_credits, .get_credits = smb2_get_credits,
.wait_mtu_credits = smb2_wait_mtu_credits, .wait_mtu_credits = smb2_wait_mtu_credits,
.adjust_credits = smb2_adjust_credits,
.get_next_mid = smb2_get_next_mid, .get_next_mid = smb2_get_next_mid,
.revert_current_mid = smb2_revert_current_mid,
.read_data_offset = smb2_read_data_offset, .read_data_offset = smb2_read_data_offset,
.read_data_length = smb2_read_data_length, .read_data_length = smb2_read_data_length,
.map_error = map_smb2_to_linux_error, .map_error = map_smb2_to_linux_error,
...@@ -3743,7 +3822,7 @@ struct smb_version_operations smb30_operations = { ...@@ -3743,7 +3822,7 @@ struct smb_version_operations smb30_operations = {
.dump_share_caps = smb2_dump_share_caps, .dump_share_caps = smb2_dump_share_caps,
.is_oplock_break = smb2_is_valid_oplock_break, .is_oplock_break = smb2_is_valid_oplock_break,
.handle_cancelled_mid = smb2_handle_cancelled_mid, .handle_cancelled_mid = smb2_handle_cancelled_mid,
.downgrade_oplock = smb2_downgrade_oplock, .downgrade_oplock = smb21_downgrade_oplock,
.need_neg = smb2_need_neg, .need_neg = smb2_need_neg,
.negotiate = smb2_negotiate, .negotiate = smb2_negotiate,
.negotiate_wsize = smb3_negotiate_wsize, .negotiate_wsize = smb3_negotiate_wsize,
...@@ -3836,7 +3915,9 @@ struct smb_version_operations smb311_operations = { ...@@ -3836,7 +3915,9 @@ struct smb_version_operations smb311_operations = {
.get_credits_field = smb2_get_credits_field, .get_credits_field = smb2_get_credits_field,
.get_credits = smb2_get_credits, .get_credits = smb2_get_credits,
.wait_mtu_credits = smb2_wait_mtu_credits, .wait_mtu_credits = smb2_wait_mtu_credits,
.adjust_credits = smb2_adjust_credits,
.get_next_mid = smb2_get_next_mid, .get_next_mid = smb2_get_next_mid,
.revert_current_mid = smb2_revert_current_mid,
.read_data_offset = smb2_read_data_offset, .read_data_offset = smb2_read_data_offset,
.read_data_length = smb2_read_data_length, .read_data_length = smb2_read_data_length,
.map_error = map_smb2_to_linux_error, .map_error = map_smb2_to_linux_error,
...@@ -3848,7 +3929,7 @@ struct smb_version_operations smb311_operations = { ...@@ -3848,7 +3929,7 @@ struct smb_version_operations smb311_operations = {
.dump_share_caps = smb2_dump_share_caps, .dump_share_caps = smb2_dump_share_caps,
.is_oplock_break = smb2_is_valid_oplock_break, .is_oplock_break = smb2_is_valid_oplock_break,
.handle_cancelled_mid = smb2_handle_cancelled_mid, .handle_cancelled_mid = smb2_handle_cancelled_mid,
.downgrade_oplock = smb2_downgrade_oplock, .downgrade_oplock = smb21_downgrade_oplock,
.need_neg = smb2_need_neg, .need_neg = smb2_need_neg,
.negotiate = smb2_negotiate, .negotiate = smb2_negotiate,
.negotiate_wsize = smb3_negotiate_wsize, .negotiate_wsize = smb3_negotiate_wsize,
......
This diff is collapsed.
...@@ -288,12 +288,12 @@ struct smb2_encryption_neg_context { ...@@ -288,12 +288,12 @@ struct smb2_encryption_neg_context {
__le16 Ciphers[1]; /* Ciphers[0] since only one used now */ __le16 Ciphers[1]; /* Ciphers[0] since only one used now */
} __packed; } __packed;
#define POSIX_CTXT_DATA_LEN 8 #define POSIX_CTXT_DATA_LEN 16
struct smb2_posix_neg_context { struct smb2_posix_neg_context {
__le16 ContextType; /* 0x100 */ __le16 ContextType; /* 0x100 */
__le16 DataLength; __le16 DataLength;
__le32 Reserved; __le32 Reserved;
__le64 Reserved1; /* In case needed for future (eg version or caps) */ __u8 Name[16]; /* POSIX ctxt GUID 93AD25509CB411E7B42383DE968BCD7C */
} __packed; } __packed;
struct smb2_negotiate_rsp { struct smb2_negotiate_rsp {
......
...@@ -576,6 +576,7 @@ smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr, ...@@ -576,6 +576,7 @@ smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr,
struct TCP_Server_Info *server) struct TCP_Server_Info *server)
{ {
struct mid_q_entry *temp; struct mid_q_entry *temp;
unsigned int credits = le16_to_cpu(shdr->CreditCharge);
if (server == NULL) { if (server == NULL) {
cifs_dbg(VFS, "Null TCP session in smb2_mid_entry_alloc\n"); cifs_dbg(VFS, "Null TCP session in smb2_mid_entry_alloc\n");
...@@ -586,6 +587,7 @@ smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr, ...@@ -586,6 +587,7 @@ smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr,
memset(temp, 0, sizeof(struct mid_q_entry)); memset(temp, 0, sizeof(struct mid_q_entry));
kref_init(&temp->refcount); kref_init(&temp->refcount);
temp->mid = le64_to_cpu(shdr->MessageId); temp->mid = le64_to_cpu(shdr->MessageId);
temp->credits = credits > 0 ? credits : 1;
temp->pid = current->pid; temp->pid = current->pid;
temp->command = shdr->Command; /* Always LE */ temp->command = shdr->Command; /* Always LE */
temp->when_alloc = jiffies; temp->when_alloc = jiffies;
...@@ -600,6 +602,8 @@ smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr, ...@@ -600,6 +602,8 @@ smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr,
atomic_inc(&midCount); atomic_inc(&midCount);
temp->mid_state = MID_REQUEST_ALLOCATED; temp->mid_state = MID_REQUEST_ALLOCATED;
trace_smb3_cmd_enter(shdr->TreeId, shdr->SessionId,
le16_to_cpu(shdr->Command), temp->mid);
return temp; return temp;
} }
...@@ -615,6 +619,10 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_sync_hdr *shdr, ...@@ -615,6 +619,10 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_sync_hdr *shdr,
return -EAGAIN; return -EAGAIN;
} }
if (ses->server->tcpStatus == CifsNeedNegotiate &&
shdr->Command != SMB2_NEGOTIATE)
return -EAGAIN;
if (ses->status == CifsNew) { if (ses->status == CifsNew) {
if ((shdr->Command != SMB2_SESSION_SETUP) && if ((shdr->Command != SMB2_SESSION_SETUP) &&
(shdr->Command != SMB2_NEGOTIATE)) (shdr->Command != SMB2_NEGOTIATE))
...@@ -634,6 +642,7 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_sync_hdr *shdr, ...@@ -634,6 +642,7 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_sync_hdr *shdr,
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
list_add_tail(&(*mid)->qhead, &ses->server->pending_mid_q); list_add_tail(&(*mid)->qhead, &ses->server->pending_mid_q);
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
return 0; return 0;
} }
...@@ -674,13 +683,18 @@ smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst) ...@@ -674,13 +683,18 @@ smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
smb2_seq_num_into_buf(ses->server, shdr); smb2_seq_num_into_buf(ses->server, shdr);
rc = smb2_get_mid_entry(ses, shdr, &mid); rc = smb2_get_mid_entry(ses, shdr, &mid);
if (rc) if (rc) {
revert_current_mid_from_hdr(ses->server, shdr);
return ERR_PTR(rc); return ERR_PTR(rc);
}
rc = smb2_sign_rqst(rqst, ses->server); rc = smb2_sign_rqst(rqst, ses->server);
if (rc) { if (rc) {
revert_current_mid_from_hdr(ses->server, shdr);
cifs_delete_mid(mid); cifs_delete_mid(mid);
return ERR_PTR(rc); return ERR_PTR(rc);
} }
return mid; return mid;
} }
...@@ -692,14 +706,21 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst) ...@@ -692,14 +706,21 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
(struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base; (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base;
struct mid_q_entry *mid; struct mid_q_entry *mid;
if (server->tcpStatus == CifsNeedNegotiate &&
shdr->Command != SMB2_NEGOTIATE)
return ERR_PTR(-EAGAIN);
smb2_seq_num_into_buf(server, shdr); smb2_seq_num_into_buf(server, shdr);
mid = smb2_mid_entry_alloc(shdr, server); mid = smb2_mid_entry_alloc(shdr, server);
if (mid == NULL) if (mid == NULL) {
revert_current_mid_from_hdr(server, shdr);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
}
rc = smb2_sign_rqst(rqst, server); rc = smb2_sign_rqst(rqst, server);
if (rc) { if (rc) {
revert_current_mid_from_hdr(server, shdr);
DeleteMidQEntry(mid); DeleteMidQEntry(mid);
return ERR_PTR(rc); return ERR_PTR(rc);
} }
......
...@@ -1550,7 +1550,7 @@ static int allocate_caches_and_workqueue(struct smbd_connection *info) ...@@ -1550,7 +1550,7 @@ static int allocate_caches_and_workqueue(struct smbd_connection *info)
char name[MAX_NAME_LEN]; char name[MAX_NAME_LEN];
int rc; int rc;
snprintf(name, MAX_NAME_LEN, "smbd_request_%p", info); scnprintf(name, MAX_NAME_LEN, "smbd_request_%p", info);
info->request_cache = info->request_cache =
kmem_cache_create( kmem_cache_create(
name, name,
...@@ -1566,7 +1566,7 @@ static int allocate_caches_and_workqueue(struct smbd_connection *info) ...@@ -1566,7 +1566,7 @@ static int allocate_caches_and_workqueue(struct smbd_connection *info)
if (!info->request_mempool) if (!info->request_mempool)
goto out1; goto out1;
snprintf(name, MAX_NAME_LEN, "smbd_response_%p", info); scnprintf(name, MAX_NAME_LEN, "smbd_response_%p", info);
info->response_cache = info->response_cache =
kmem_cache_create( kmem_cache_create(
name, name,
...@@ -1582,7 +1582,7 @@ static int allocate_caches_and_workqueue(struct smbd_connection *info) ...@@ -1582,7 +1582,7 @@ static int allocate_caches_and_workqueue(struct smbd_connection *info)
if (!info->response_mempool) if (!info->response_mempool)
goto out3; goto out3;
snprintf(name, MAX_NAME_LEN, "smbd_%p", info); scnprintf(name, MAX_NAME_LEN, "smbd_%p", info);
info->workqueue = create_workqueue(name); info->workqueue = create_workqueue(name);
if (!info->workqueue) if (!info->workqueue)
goto out4; goto out4;
......
...@@ -58,6 +58,7 @@ DEFINE_EVENT(smb3_rw_err_class, smb3_##name, \ ...@@ -58,6 +58,7 @@ DEFINE_EVENT(smb3_rw_err_class, smb3_##name, \
DEFINE_SMB3_RW_ERR_EVENT(write_err); DEFINE_SMB3_RW_ERR_EVENT(write_err);
DEFINE_SMB3_RW_ERR_EVENT(read_err); DEFINE_SMB3_RW_ERR_EVENT(read_err);
DEFINE_SMB3_RW_ERR_EVENT(query_dir_err);
/* For logging successful read or write */ /* For logging successful read or write */
...@@ -100,8 +101,12 @@ DEFINE_EVENT(smb3_rw_done_class, smb3_##name, \ ...@@ -100,8 +101,12 @@ DEFINE_EVENT(smb3_rw_done_class, smb3_##name, \
__u32 len), \ __u32 len), \
TP_ARGS(xid, fid, tid, sesid, offset, len)) TP_ARGS(xid, fid, tid, sesid, offset, len))
DEFINE_SMB3_RW_DONE_EVENT(write_enter);
DEFINE_SMB3_RW_DONE_EVENT(read_enter);
DEFINE_SMB3_RW_DONE_EVENT(query_dir_enter);
DEFINE_SMB3_RW_DONE_EVENT(write_done); DEFINE_SMB3_RW_DONE_EVENT(write_done);
DEFINE_SMB3_RW_DONE_EVENT(read_done); DEFINE_SMB3_RW_DONE_EVENT(read_done);
DEFINE_SMB3_RW_DONE_EVENT(query_dir_done);
/* /*
* For handle based calls other than read and write, and get/set info * For handle based calls other than read and write, and get/set info
...@@ -148,6 +153,48 @@ DEFINE_SMB3_FD_ERR_EVENT(close_err); ...@@ -148,6 +153,48 @@ DEFINE_SMB3_FD_ERR_EVENT(close_err);
/* /*
* For handle based query/set info calls * For handle based query/set info calls
*/ */
DECLARE_EVENT_CLASS(smb3_inf_enter_class,
TP_PROTO(unsigned int xid,
__u64 fid,
__u32 tid,
__u64 sesid,
__u8 infclass,
__u32 type),
TP_ARGS(xid, fid, tid, sesid, infclass, type),
TP_STRUCT__entry(
__field(unsigned int, xid)
__field(__u64, fid)
__field(__u32, tid)
__field(__u64, sesid)
__field(__u8, infclass)
__field(__u32, type)
),
TP_fast_assign(
__entry->xid = xid;
__entry->fid = fid;
__entry->tid = tid;
__entry->sesid = sesid;
__entry->infclass = infclass;
__entry->type = type;
),
TP_printk("xid=%u sid=0x%llx tid=0x%x fid=0x%llx class=%u type=0x%x",
__entry->xid, __entry->sesid, __entry->tid, __entry->fid,
__entry->infclass, __entry->type)
)
#define DEFINE_SMB3_INF_ENTER_EVENT(name) \
DEFINE_EVENT(smb3_inf_enter_class, smb3_##name, \
TP_PROTO(unsigned int xid, \
__u64 fid, \
__u32 tid, \
__u64 sesid, \
__u8 infclass, \
__u32 type), \
TP_ARGS(xid, fid, tid, sesid, infclass, type))
DEFINE_SMB3_INF_ENTER_EVENT(query_info_enter);
DEFINE_SMB3_INF_ENTER_EVENT(query_info_done);
DECLARE_EVENT_CLASS(smb3_inf_err_class, DECLARE_EVENT_CLASS(smb3_inf_err_class,
TP_PROTO(unsigned int xid, TP_PROTO(unsigned int xid,
__u64 fid, __u64 fid,
...@@ -270,6 +317,7 @@ DEFINE_EVENT(smb3_cmd_done_class, smb3_##name, \ ...@@ -270,6 +317,7 @@ DEFINE_EVENT(smb3_cmd_done_class, smb3_##name, \
__u64 mid), \ __u64 mid), \
TP_ARGS(tid, sesid, cmd, mid)) TP_ARGS(tid, sesid, cmd, mid))
DEFINE_SMB3_CMD_DONE_EVENT(cmd_enter);
DEFINE_SMB3_CMD_DONE_EVENT(cmd_done); DEFINE_SMB3_CMD_DONE_EVENT(cmd_done);
DEFINE_SMB3_CMD_DONE_EVENT(ses_expired); DEFINE_SMB3_CMD_DONE_EVENT(ses_expired);
...@@ -406,8 +454,47 @@ DEFINE_SMB3_TCON_EVENT(tcon); ...@@ -406,8 +454,47 @@ DEFINE_SMB3_TCON_EVENT(tcon);
/* /*
* For smb2/smb3 open call * For smb2/smb3 open (including create and mkdir) calls
*/ */
DECLARE_EVENT_CLASS(smb3_open_enter_class,
TP_PROTO(unsigned int xid,
__u32 tid,
__u64 sesid,
int create_options,
int desired_access),
TP_ARGS(xid, tid, sesid, create_options, desired_access),
TP_STRUCT__entry(
__field(unsigned int, xid)
__field(__u32, tid)
__field(__u64, sesid)
__field(int, create_options)
__field(int, desired_access)
),
TP_fast_assign(
__entry->xid = xid;
__entry->tid = tid;
__entry->sesid = sesid;
__entry->create_options = create_options;
__entry->desired_access = desired_access;
),
TP_printk("xid=%u sid=0x%llx tid=0x%x cr_opts=0x%x des_access=0x%x",
__entry->xid, __entry->sesid, __entry->tid,
__entry->create_options, __entry->desired_access)
)
#define DEFINE_SMB3_OPEN_ENTER_EVENT(name) \
DEFINE_EVENT(smb3_open_enter_class, smb3_##name, \
TP_PROTO(unsigned int xid, \
__u32 tid, \
__u64 sesid, \
int create_options, \
int desired_access), \
TP_ARGS(xid, tid, sesid, create_options, desired_access))
DEFINE_SMB3_OPEN_ENTER_EVENT(open_enter);
DEFINE_SMB3_OPEN_ENTER_EVENT(posix_mkdir_enter);
DECLARE_EVENT_CLASS(smb3_open_err_class, DECLARE_EVENT_CLASS(smb3_open_err_class,
TP_PROTO(unsigned int xid, TP_PROTO(unsigned int xid,
__u32 tid, __u32 tid,
......
This diff is collapsed.
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