Commit 033078a9 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull cifs updates from Steve French:
 "Three smb3 fixes for stable, patches for improved debugging and perf
  gathering, and much improved performance for most metadata operations
  (expanded use of compounding)"

* tag '4.20-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6: (46 commits)
  cifs: update internal module version number for cifs.ko to 2.14
  smb3: add debug for unexpected mid cancellation
  cifs: allow calling SMB2_xxx_free(NULL)
  smb3 - clean up debug output displaying network interfaces
  smb3: show number of current open files in /proc/fs/cifs/Stats
  cifs: add support for ioctl on directories
  cifs: fallback to older infolevels on findfirst queryinfo retry
  smb3: do not attempt cifs operation in smb3 query info error path
  smb3: send backup intent on compounded query info
  cifs: track writepages in vfs operation counters
  smb2: fix uninitialized variable bug in smb2_ioctl_query_info
  cifs: add IOCTL for QUERY_INFO passthrough to userspace
  cifs: minor clarification in comments
  CIFS: Print message when attempting a mount
  CIFS: Adds information-level logging function
  cifs: OFD locks do not conflict with eachothers
  CIFS: SMBD: Do not call ib_dereg_mr on invalidated memory registration
  CIFS: pass page offsets on SMB1 read/write
  fs/cifs: fix uninitialised variable warnings
  smb3: add tracepoint for sending lease break responses to server
  ...
parents 7abe8493 38f876bb
...@@ -132,7 +132,7 @@ cifs_dump_iface(struct seq_file *m, struct cifs_server_iface *iface) ...@@ -132,7 +132,7 @@ cifs_dump_iface(struct seq_file *m, struct cifs_server_iface *iface)
struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr; struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr;
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&iface->sockaddr; struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&iface->sockaddr;
seq_printf(m, "\t\tSpeed: %zu bps\n", iface->speed); seq_printf(m, "\tSpeed: %zu bps\n", iface->speed);
seq_puts(m, "\t\tCapabilities: "); seq_puts(m, "\t\tCapabilities: ");
if (iface->rdma_capable) if (iface->rdma_capable)
seq_puts(m, "rdma "); seq_puts(m, "rdma ");
...@@ -285,7 +285,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) ...@@ -285,7 +285,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
if ((ses->serverDomain == NULL) || if ((ses->serverDomain == NULL) ||
(ses->serverOS == NULL) || (ses->serverOS == NULL) ||
(ses->serverNOS == NULL)) { (ses->serverNOS == NULL)) {
seq_printf(m, "\n%d) Name: %s Uses: %d Capability: 0x%x\tSession Status: %d\t", seq_printf(m, "\n%d) Name: %s Uses: %d Capability: 0x%x\tSession Status: %d ",
i, ses->serverName, ses->ses_count, i, ses->serverName, ses->ses_count,
ses->capabilities, ses->status); ses->capabilities, ses->status);
if (ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST) if (ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST)
...@@ -296,16 +296,18 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) ...@@ -296,16 +296,18 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
seq_printf(m, seq_printf(m,
"\n%d) Name: %s Domain: %s Uses: %d OS:" "\n%d) Name: %s Domain: %s Uses: %d OS:"
" %s\n\tNOS: %s\tCapability: 0x%x\n\tSMB" " %s\n\tNOS: %s\tCapability: 0x%x\n\tSMB"
" session status: %d\t", " session status: %d ",
i, ses->serverName, ses->serverDomain, i, ses->serverName, ses->serverDomain,
ses->ses_count, ses->serverOS, ses->serverNOS, ses->ses_count, ses->serverOS, ses->serverNOS,
ses->capabilities, ses->status); ses->capabilities, ses->status);
} }
if (server->rdma) if (server->rdma)
seq_printf(m, "RDMA\n\t"); seq_printf(m, "RDMA\n\t");
seq_printf(m, "TCP status: %d\n\tLocal Users To " seq_printf(m, "TCP status: %d Instance: %d\n\tLocal Users To "
"Server: %d SecMode: 0x%x Req On Wire: %d", "Server: %d SecMode: 0x%x Req On Wire: %d",
server->tcpStatus, server->srv_count, server->tcpStatus,
server->reconnect_instance,
server->srv_count,
server->sec_mode, in_flight(server)); server->sec_mode, in_flight(server));
#ifdef CONFIG_CIFS_STATS2 #ifdef CONFIG_CIFS_STATS2
...@@ -352,7 +354,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) ...@@ -352,7 +354,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
seq_printf(m, "\n\tServer interfaces: %zu\n", seq_printf(m, "\n\tServer interfaces: %zu\n",
ses->iface_count); ses->iface_count);
for (j = 0; j < ses->iface_count; j++) { for (j = 0; j < ses->iface_count; j++) {
seq_printf(m, "\t%d)\n", j); seq_printf(m, "\t%d)", j);
cifs_dump_iface(m, &ses->iface_list[j]); cifs_dump_iface(m, &ses->iface_list[j]);
} }
spin_unlock(&ses->iface_lock); spin_unlock(&ses->iface_lock);
...@@ -383,6 +385,9 @@ static ssize_t cifs_stats_proc_write(struct file *file, ...@@ -383,6 +385,9 @@ static ssize_t cifs_stats_proc_write(struct file *file,
atomic_set(&totBufAllocCount, 0); atomic_set(&totBufAllocCount, 0);
atomic_set(&totSmBufAllocCount, 0); atomic_set(&totSmBufAllocCount, 0);
#endif /* CONFIG_CIFS_STATS2 */ #endif /* CONFIG_CIFS_STATS2 */
atomic_set(&tcpSesReconnectCount, 0);
atomic_set(&tconInfoReconnectCount, 0);
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
GlobalMaxActiveXid = 0; GlobalMaxActiveXid = 0;
GlobalCurrentXid = 0; GlobalCurrentXid = 0;
......
...@@ -47,6 +47,29 @@ extern int cifsFYI; ...@@ -47,6 +47,29 @@ extern int cifsFYI;
*/ */
#ifdef CONFIG_CIFS_DEBUG #ifdef CONFIG_CIFS_DEBUG
/*
* When adding tracepoints and debug messages we have various choices.
* Some considerations:
*
* Use cifs_dbg(VFS, ...) for things we always want logged, and the user to see
* cifs_info(...) slightly less important, admin can filter via loglevel > 6
* cifs_dbg(FYI, ...) minor debugging messages, off by default
* trace_smb3_* ftrace functions are preferred for complex debug messages
* intended for developers or experienced admins, off by default
*/
/* Information level messages, minor events */
#define cifs_info_func(ratefunc, fmt, ...) \
do { \
pr_info_ ## ratefunc("CIFS: " fmt, ##__VA_ARGS__); \
} while (0)
#define cifs_info(fmt, ...) \
do { \
cifs_info_func(ratelimited, fmt, ##__VA_ARGS__); \
} while (0)
/* information message: e.g., configuration, major event */ /* information message: e.g., configuration, major event */
#define cifs_dbg_func(ratefunc, type, fmt, ...) \ #define cifs_dbg_func(ratefunc, type, fmt, ...) \
do { \ do { \
...@@ -81,6 +104,11 @@ do { \ ...@@ -81,6 +104,11 @@ do { \
if (0) \ if (0) \
pr_debug(fmt, ##__VA_ARGS__); \ pr_debug(fmt, ##__VA_ARGS__); \
} while (0) } while (0)
#define cifs_info(fmt, ...) \
do { \
pr_info("CIFS: "fmt, ##__VA_ARGS__); \
} while (0)
#endif #endif
#endif /* _H_CIFS_DEBUG */ #endif /* _H_CIFS_DEBUG */
...@@ -304,12 +304,17 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) ...@@ -304,12 +304,17 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
*/ */
mnt = ERR_PTR(-ENOMEM); mnt = ERR_PTR(-ENOMEM);
cifs_sb = CIFS_SB(mntpt->d_sb);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) {
mnt = ERR_PTR(-EREMOTE);
goto cdda_exit;
}
/* always use tree name prefix */ /* always use tree name prefix */
full_path = build_path_from_dentry_optional_prefix(mntpt, true); full_path = build_path_from_dentry_optional_prefix(mntpt, true);
if (full_path == NULL) if (full_path == NULL)
goto cdda_exit; goto cdda_exit;
cifs_sb = CIFS_SB(mntpt->d_sb);
tlink = cifs_sb_tlink(cifs_sb); tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink)) { if (IS_ERR(tlink)) {
mnt = ERR_CAST(tlink); mnt = ERR_CAST(tlink);
......
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
*/ */
#define CIFS_MOUNT_UID_FROM_ACL 0x2000000 /* try to get UID via special SID */ #define CIFS_MOUNT_UID_FROM_ACL 0x2000000 /* try to get UID via special SID */
#define CIFS_MOUNT_NO_HANDLE_CACHE 0x4000000 /* disable caching dir handles */ #define CIFS_MOUNT_NO_HANDLE_CACHE 0x4000000 /* disable caching dir handles */
#define CIFS_MOUNT_NO_DFS 0x8000000 /* disable DFS resolving */
struct cifs_sb_info { struct cifs_sb_info {
struct rb_root tlink_tree; struct rb_root tlink_tree;
......
...@@ -43,8 +43,19 @@ struct smb_snapshot_array { ...@@ -43,8 +43,19 @@ struct smb_snapshot_array {
/* snapshots[]; */ /* snapshots[]; */
} __packed; } __packed;
struct smb_query_info {
__u32 info_type;
__u32 file_info_class;
__u32 additional_information;
__u32 flags;
__u32 input_buffer_length;
__u32 output_buffer_length;
/* char buffer[]; */
} __packed;
#define CIFS_IOCTL_MAGIC 0xCF #define CIFS_IOCTL_MAGIC 0xCF
#define CIFS_IOC_COPYCHUNK_FILE _IOW(CIFS_IOCTL_MAGIC, 3, int) #define CIFS_IOC_COPYCHUNK_FILE _IOW(CIFS_IOCTL_MAGIC, 3, int)
#define CIFS_IOC_SET_INTEGRITY _IO(CIFS_IOCTL_MAGIC, 4) #define CIFS_IOC_SET_INTEGRITY _IO(CIFS_IOCTL_MAGIC, 4)
#define CIFS_IOC_GET_MNT_INFO _IOR(CIFS_IOCTL_MAGIC, 5, struct smb_mnt_fs_info) #define CIFS_IOC_GET_MNT_INFO _IOR(CIFS_IOCTL_MAGIC, 5, struct smb_mnt_fs_info)
#define CIFS_ENUMERATE_SNAPSHOTS _IOR(CIFS_IOCTL_MAGIC, 6, struct smb_snapshot_array) #define CIFS_ENUMERATE_SNAPSHOTS _IOR(CIFS_IOCTL_MAGIC, 6, struct smb_snapshot_array)
#define CIFS_QUERY_INFO _IOWR(CIFS_IOCTL_MAGIC, 7, struct smb_query_info)
...@@ -81,6 +81,14 @@ module_param(cifs_max_pending, uint, 0444); ...@@ -81,6 +81,14 @@ module_param(cifs_max_pending, uint, 0444);
MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server for " MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server for "
"CIFS/SMB1 dialect (N/A for SMB3) " "CIFS/SMB1 dialect (N/A for SMB3) "
"Default: 32767 Range: 2 to 32767."); "Default: 32767 Range: 2 to 32767.");
#ifdef CONFIG_CIFS_STATS2
unsigned int slow_rsp_threshold = 1;
module_param(slow_rsp_threshold, uint, 0644);
MODULE_PARM_DESC(slow_rsp_threshold, "Amount of time (in seconds) to wait "
"before logging that a response is delayed. "
"Default: 1 (if set to 0 disables msg).");
#endif /* STATS2 */
module_param(enable_oplocks, bool, 0644); module_param(enable_oplocks, bool, 0644);
MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks. Default: y/Y/1"); MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks. Default: y/Y/1");
...@@ -492,6 +500,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root) ...@@ -492,6 +500,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
seq_puts(s, ",unix"); seq_puts(s, ",unix");
else else
seq_puts(s, ",nounix"); seq_puts(s, ",nounix");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
seq_puts(s, ",nodfs");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
seq_puts(s, ",posixpaths"); seq_puts(s, ",posixpaths");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
...@@ -707,7 +717,14 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, ...@@ -707,7 +717,14 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
struct cifs_mnt_data mnt_data; struct cifs_mnt_data mnt_data;
struct dentry *root; struct dentry *root;
/*
* Prints in Kernel / CIFS log the attempted mount operation
* If CIFS_DEBUG && cifs_FYI
*/
if (cifsFYI)
cifs_dbg(FYI, "Devname: %s flags: %d\n", dev_name, flags); cifs_dbg(FYI, "Devname: %s flags: %d\n", dev_name, flags);
else
cifs_info("Attempting to mount %s\n", dev_name);
volume_info = cifs_get_volume_info((char *)data, dev_name, is_smb3); volume_info = cifs_get_volume_info((char *)data, dev_name, is_smb3);
if (IS_ERR(volume_info)) if (IS_ERR(volume_info))
...@@ -1418,6 +1435,11 @@ init_cifs(void) ...@@ -1418,6 +1435,11 @@ init_cifs(void)
#ifdef CONFIG_CIFS_STATS2 #ifdef CONFIG_CIFS_STATS2
atomic_set(&totBufAllocCount, 0); atomic_set(&totBufAllocCount, 0);
atomic_set(&totSmBufAllocCount, 0); atomic_set(&totSmBufAllocCount, 0);
if (slow_rsp_threshold < 1)
cifs_dbg(FYI, "slow_response_threshold msgs disabled\n");
else if (slow_rsp_threshold > 32767)
cifs_dbg(VFS,
"slow response threshold set higher than recommended (0 to 32767)\n");
#endif /* CONFIG_CIFS_STATS2 */ #endif /* CONFIG_CIFS_STATS2 */
atomic_set(&midCount, 0); atomic_set(&midCount, 0);
...@@ -1538,11 +1560,11 @@ exit_cifs(void) ...@@ -1538,11 +1560,11 @@ exit_cifs(void)
cifs_proc_clean(); cifs_proc_clean();
} }
MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>"); MODULE_AUTHOR("Steve French");
MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */ MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */
MODULE_DESCRIPTION MODULE_DESCRIPTION
("VFS to access servers complying with the SNIA CIFS Specification " ("VFS to access SMB3 servers e.g. Samba, Macs, Azure and Windows (and "
"e.g. Samba and Windows"); "also older servers complying with the SNIA CIFS Specification)");
MODULE_VERSION(CIFS_VERSION); MODULE_VERSION(CIFS_VERSION);
MODULE_SOFTDEP("pre: arc4"); MODULE_SOFTDEP("pre: arc4");
MODULE_SOFTDEP("pre: des"); MODULE_SOFTDEP("pre: des");
......
...@@ -148,5 +148,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); ...@@ -148,5 +148,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.13" #define CIFS_VERSION "2.14"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ #define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
#define SMB_PATH_MAX 260
#define CIFS_PORT 445 #define CIFS_PORT 445
#define RFC1001_PORT 139 #define RFC1001_PORT 139
...@@ -465,6 +466,11 @@ struct smb_version_operations { ...@@ -465,6 +466,11 @@ struct smb_version_operations {
enum securityEnum (*select_sectype)(struct TCP_Server_Info *, enum securityEnum (*select_sectype)(struct TCP_Server_Info *,
enum securityEnum); enum securityEnum);
int (*next_header)(char *); int (*next_header)(char *);
/* ioctl passthrough for query_info */
int (*ioctl_query_info)(const unsigned int xid,
struct cifs_tcon *tcon,
__le16 *path, int is_dir,
unsigned long p);
}; };
struct smb_version_values { struct smb_version_values {
...@@ -654,6 +660,7 @@ struct TCP_Server_Info { ...@@ -654,6 +660,7 @@ struct TCP_Server_Info {
/* 16th byte of RFC1001 workstation name is always null */ /* 16th byte of RFC1001 workstation name is always null */
char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
__u32 sequence_number; /* for signing, protected by srv_mutex */ __u32 sequence_number; /* for signing, protected by srv_mutex */
__u32 reconnect_instance; /* incremented on each reconnect */
struct session_key session_key; struct session_key session_key;
unsigned long lstrp; /* when we got last response from this server */ unsigned long lstrp; /* when we got last response from this server */
struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */ struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */
...@@ -798,6 +805,7 @@ compare_mid(__u16 mid, const struct smb_hdr *smb) ...@@ -798,6 +805,7 @@ compare_mid(__u16 mid, const struct smb_hdr *smb)
* a single wsize request with a single call. * a single wsize request with a single call.
*/ */
#define CIFS_DEFAULT_IOSIZE (1024 * 1024) #define CIFS_DEFAULT_IOSIZE (1024 * 1024)
#define SMB3_DEFAULT_IOSIZE (4 * 1024 * 1024)
/* /*
* Windows only supports a max of 60kb reads and 65535 byte writes. Default to * Windows only supports a max of 60kb reads and 65535 byte writes. Default to
...@@ -924,6 +932,8 @@ struct cifs_tcon { ...@@ -924,6 +932,8 @@ struct cifs_tcon {
struct list_head tcon_list; struct list_head tcon_list;
int tc_count; int tc_count;
struct list_head rlist; /* reconnect list */ struct list_head rlist; /* reconnect list */
atomic_t num_local_opens; /* num of all opens including disconnected */
atomic_t num_remote_opens; /* num of all network opens on server */
struct list_head openFileList; struct list_head openFileList;
spinlock_t open_file_lock; /* protects list above */ spinlock_t open_file_lock; /* protects list above */
struct cifs_ses *ses; /* pointer to session associated with */ struct cifs_ses *ses; /* pointer to session associated with */
...@@ -1072,7 +1082,8 @@ struct cifsLockInfo { ...@@ -1072,7 +1082,8 @@ struct cifsLockInfo {
__u64 offset; __u64 offset;
__u64 length; __u64 length;
__u32 pid; __u32 pid;
__u32 type; __u16 type;
__u16 flags;
}; };
/* /*
...@@ -1715,6 +1726,7 @@ GLOBAL_EXTERN atomic_t bufAllocCount; /* current number allocated */ ...@@ -1715,6 +1726,7 @@ GLOBAL_EXTERN atomic_t bufAllocCount; /* current number allocated */
#ifdef CONFIG_CIFS_STATS2 #ifdef CONFIG_CIFS_STATS2
GLOBAL_EXTERN atomic_t totBufAllocCount; /* total allocated over all time */ GLOBAL_EXTERN atomic_t totBufAllocCount; /* total allocated over all time */
GLOBAL_EXTERN atomic_t totSmBufAllocCount; GLOBAL_EXTERN atomic_t totSmBufAllocCount;
extern unsigned int slow_rsp_threshold; /* number of secs before logging */
#endif #endif
GLOBAL_EXTERN atomic_t smBufAllocCount; GLOBAL_EXTERN atomic_t smBufAllocCount;
GLOBAL_EXTERN atomic_t midCount; GLOBAL_EXTERN atomic_t midCount;
......
...@@ -219,7 +219,7 @@ extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon); ...@@ -219,7 +219,7 @@ extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon);
extern void cifs_reopen_persistent_handles(struct cifs_tcon *tcon); extern void cifs_reopen_persistent_handles(struct cifs_tcon *tcon);
extern bool cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, extern bool cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset,
__u64 length, __u8 type, __u64 length, __u8 type, __u16 flags,
struct cifsLockInfo **conf_lock, struct cifsLockInfo **conf_lock,
int rw_check); int rw_check);
extern void cifs_add_pending_open(struct cifs_fid *fid, extern void cifs_add_pending_open(struct cifs_fid *fid,
......
...@@ -1607,6 +1607,7 @@ cifs_readv_callback(struct mid_q_entry *mid) ...@@ -1607,6 +1607,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
struct smb_rqst rqst = { .rq_iov = rdata->iov, struct smb_rqst rqst = { .rq_iov = rdata->iov,
.rq_nvec = 2, .rq_nvec = 2,
.rq_pages = rdata->pages, .rq_pages = rdata->pages,
.rq_offset = rdata->page_offset,
.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 };
...@@ -2210,6 +2211,7 @@ cifs_async_writev(struct cifs_writedata *wdata, ...@@ -2210,6 +2211,7 @@ cifs_async_writev(struct cifs_writedata *wdata,
rqst.rq_iov = iov; rqst.rq_iov = iov;
rqst.rq_nvec = 2; rqst.rq_nvec = 2;
rqst.rq_pages = wdata->pages; rqst.rq_pages = wdata->pages;
rqst.rq_offset = wdata->page_offset;
rqst.rq_npages = wdata->nr_pages; rqst.rq_npages = wdata->nr_pages;
rqst.rq_pagesz = wdata->pagesz; rqst.rq_pagesz = wdata->pagesz;
rqst.rq_tailsz = wdata->tailsz; rqst.rq_tailsz = wdata->tailsz;
...@@ -5027,6 +5029,13 @@ SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5027,6 +5029,13 @@ SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
le16_to_cpu(response_data->BytesPerSector) * le16_to_cpu(response_data->BytesPerSector) *
le32_to_cpu(response_data-> le32_to_cpu(response_data->
SectorsPerAllocationUnit); SectorsPerAllocationUnit);
/*
* much prefer larger but if server doesn't report
* a valid size than 4K is a reasonable minimum
*/
if (FSData->f_bsize < 512)
FSData->f_bsize = 4096;
FSData->f_blocks = FSData->f_blocks =
le32_to_cpu(response_data->TotalAllocationUnits); le32_to_cpu(response_data->TotalAllocationUnits);
FSData->f_bfree = FSData->f_bavail = FSData->f_bfree = FSData->f_bavail =
...@@ -5107,6 +5116,13 @@ CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5107,6 +5116,13 @@ CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
le32_to_cpu(response_data->BytesPerSector) * le32_to_cpu(response_data->BytesPerSector) *
le32_to_cpu(response_data-> le32_to_cpu(response_data->
SectorsPerAllocationUnit); SectorsPerAllocationUnit);
/*
* much prefer larger but if server doesn't report
* a valid size than 4K is a reasonable minimum
*/
if (FSData->f_bsize < 512)
FSData->f_bsize = 4096;
FSData->f_blocks = FSData->f_blocks =
le64_to_cpu(response_data->TotalAllocationUnits); le64_to_cpu(response_data->TotalAllocationUnits);
FSData->f_bfree = FSData->f_bavail = FSData->f_bfree = FSData->f_bavail =
...@@ -5470,6 +5486,13 @@ CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5470,6 +5486,13 @@ CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
data_offset); data_offset);
FSData->f_bsize = FSData->f_bsize =
le32_to_cpu(response_data->BlockSize); le32_to_cpu(response_data->BlockSize);
/*
* much prefer larger but if server doesn't report
* a valid size than 4K is a reasonable minimum
*/
if (FSData->f_bsize < 512)
FSData->f_bsize = 4096;
FSData->f_blocks = FSData->f_blocks =
le64_to_cpu(response_data->TotalBlocks); le64_to_cpu(response_data->TotalBlocks);
FSData->f_bfree = FSData->f_bfree =
......
...@@ -250,6 +250,7 @@ static const match_table_t cifs_mount_option_tokens = { ...@@ -250,6 +250,7 @@ static const match_table_t cifs_mount_option_tokens = {
{ Opt_ignore, "dev" }, { Opt_ignore, "dev" },
{ Opt_ignore, "mand" }, { Opt_ignore, "mand" },
{ Opt_ignore, "nomand" }, { Opt_ignore, "nomand" },
{ Opt_ignore, "relatime" },
{ Opt_ignore, "_netdev" }, { Opt_ignore, "_netdev" },
{ Opt_err, NULL } { Opt_err, NULL }
...@@ -347,7 +348,7 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -347,7 +348,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
server->maxBuf = 0; server->maxBuf = 0;
server->max_read = 0; server->max_read = 0;
cifs_dbg(FYI, "Reconnecting tcp session\n"); cifs_dbg(FYI, "Mark tcp session as need reconnect\n");
trace_smb3_reconnect(server->CurrentMid, server->hostname); trace_smb3_reconnect(server->CurrentMid, server->hostname);
/* before reconnecting the tcp session, mark the smb session (uid) /* before reconnecting the tcp session, mark the smb session (uid)
...@@ -2396,6 +2397,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) ...@@ -2396,6 +2397,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->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);
...@@ -3085,10 +3087,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) ...@@ -3085,10 +3087,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
if (rc) if (rc)
goto out_fail; goto out_fail;
if (volume_info->nodfs) {
tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
cifs_dbg(FYI, "DFS disabled (%d)\n", tcon->Flags);
}
tcon->use_persistent = false; tcon->use_persistent = false;
/* check if SMB2 or later, CIFS does not support persistent handles */ /* check if SMB2 or later, CIFS does not support persistent handles */
if (volume_info->persistent) { if (volume_info->persistent) {
...@@ -3663,6 +3661,8 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info, ...@@ -3663,6 +3661,8 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
cifs_sb->actimeo = pvolume_info->actimeo; cifs_sb->actimeo = pvolume_info->actimeo;
cifs_sb->local_nls = pvolume_info->local_nls; cifs_sb->local_nls = pvolume_info->local_nls;
if (pvolume_info->nodfs)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_DFS;
if (pvolume_info->noperm) if (pvolume_info->noperm)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
if (pvolume_info->setuids) if (pvolume_info->setuids)
...@@ -3819,6 +3819,9 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, ...@@ -3819,6 +3819,9 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
struct dfs_info3_param *referrals = NULL; struct dfs_info3_param *referrals = NULL;
char *full_path = NULL, *ref_path = NULL, *mdata = NULL; char *full_path = NULL, *ref_path = NULL, *mdata = NULL;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
return -EREMOTE;
full_path = build_unc_path_to_root(volume_info, cifs_sb); full_path = build_unc_path_to_root(volume_info, cifs_sb);
if (IS_ERR(full_path)) if (IS_ERR(full_path))
return PTR_ERR(full_path); return PTR_ERR(full_path);
......
...@@ -334,6 +334,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, ...@@ -334,6 +334,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
server->ops->set_fid(cfile, fid, oplock); server->ops->set_fid(cfile, fid, oplock);
list_add(&cfile->tlist, &tcon->openFileList); list_add(&cfile->tlist, &tcon->openFileList);
atomic_inc(&tcon->num_local_opens);
/* if readable file instance put first in list*/ /* if readable file instance put first in list*/
if (file->f_mode & FMODE_READ) if (file->f_mode & FMODE_READ)
...@@ -395,6 +396,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) ...@@ -395,6 +396,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
/* remove it from the lists */ /* remove it from the lists */
list_del(&cifs_file->flist); list_del(&cifs_file->flist);
list_del(&cifs_file->tlist); list_del(&cifs_file->tlist);
atomic_dec(&tcon->num_local_opens);
if (list_empty(&cifsi->openFileList)) { if (list_empty(&cifsi->openFileList)) {
cifs_dbg(FYI, "closing last open instance for inode %p\n", cifs_dbg(FYI, "closing last open instance for inode %p\n",
...@@ -864,7 +866,7 @@ int cifs_closedir(struct inode *inode, struct file *file) ...@@ -864,7 +866,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
} }
static struct cifsLockInfo * static struct cifsLockInfo *
cifs_lock_init(__u64 offset, __u64 length, __u8 type) cifs_lock_init(__u64 offset, __u64 length, __u8 type, __u16 flags)
{ {
struct cifsLockInfo *lock = struct cifsLockInfo *lock =
kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL); kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
...@@ -874,6 +876,7 @@ cifs_lock_init(__u64 offset, __u64 length, __u8 type) ...@@ -874,6 +876,7 @@ cifs_lock_init(__u64 offset, __u64 length, __u8 type)
lock->length = length; lock->length = length;
lock->type = type; lock->type = type;
lock->pid = current->tgid; lock->pid = current->tgid;
lock->flags = flags;
INIT_LIST_HEAD(&lock->blist); INIT_LIST_HEAD(&lock->blist);
init_waitqueue_head(&lock->block_q); init_waitqueue_head(&lock->block_q);
return lock; return lock;
...@@ -896,7 +899,8 @@ cifs_del_lock_waiters(struct cifsLockInfo *lock) ...@@ -896,7 +899,8 @@ cifs_del_lock_waiters(struct cifsLockInfo *lock)
/* @rw_check : 0 - no op, 1 - read, 2 - write */ /* @rw_check : 0 - no op, 1 - read, 2 - write */
static bool static bool
cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset,
__u64 length, __u8 type, struct cifsFileInfo *cfile, __u64 length, __u8 type, __u16 flags,
struct cifsFileInfo *cfile,
struct cifsLockInfo **conf_lock, int rw_check) struct cifsLockInfo **conf_lock, int rw_check)
{ {
struct cifsLockInfo *li; struct cifsLockInfo *li;
...@@ -918,6 +922,10 @@ cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, ...@@ -918,6 +922,10 @@ cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset,
((server->ops->compare_fids(cfile, cur_cfile) && ((server->ops->compare_fids(cfile, cur_cfile) &&
current->tgid == li->pid) || type == li->type)) current->tgid == li->pid) || type == li->type))
continue; continue;
if (rw_check == CIFS_LOCK_OP &&
(flags & FL_OFDLCK) && (li->flags & FL_OFDLCK) &&
server->ops->compare_fids(cfile, cur_cfile))
continue;
if (conf_lock) if (conf_lock)
*conf_lock = li; *conf_lock = li;
return true; return true;
...@@ -927,8 +935,8 @@ cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, ...@@ -927,8 +935,8 @@ cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset,
bool bool
cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length, cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length,
__u8 type, struct cifsLockInfo **conf_lock, __u8 type, __u16 flags,
int rw_check) struct cifsLockInfo **conf_lock, int rw_check)
{ {
bool rc = false; bool rc = false;
struct cifs_fid_locks *cur; struct cifs_fid_locks *cur;
...@@ -936,7 +944,8 @@ cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length, ...@@ -936,7 +944,8 @@ cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length,
list_for_each_entry(cur, &cinode->llist, llist) { list_for_each_entry(cur, &cinode->llist, llist) {
rc = cifs_find_fid_lock_conflict(cur, offset, length, type, rc = cifs_find_fid_lock_conflict(cur, offset, length, type,
cfile, conf_lock, rw_check); flags, cfile, conf_lock,
rw_check);
if (rc) if (rc)
break; break;
} }
...@@ -964,7 +973,8 @@ cifs_lock_test(struct cifsFileInfo *cfile, __u64 offset, __u64 length, ...@@ -964,7 +973,8 @@ cifs_lock_test(struct cifsFileInfo *cfile, __u64 offset, __u64 length,
down_read(&cinode->lock_sem); down_read(&cinode->lock_sem);
exist = cifs_find_lock_conflict(cfile, offset, length, type, exist = cifs_find_lock_conflict(cfile, offset, length, type,
&conf_lock, CIFS_LOCK_OP); flock->fl_flags, &conf_lock,
CIFS_LOCK_OP);
if (exist) { if (exist) {
flock->fl_start = conf_lock->offset; flock->fl_start = conf_lock->offset;
flock->fl_end = conf_lock->offset + conf_lock->length - 1; flock->fl_end = conf_lock->offset + conf_lock->length - 1;
...@@ -1011,7 +1021,8 @@ cifs_lock_add_if(struct cifsFileInfo *cfile, struct cifsLockInfo *lock, ...@@ -1011,7 +1021,8 @@ cifs_lock_add_if(struct cifsFileInfo *cfile, struct cifsLockInfo *lock,
down_write(&cinode->lock_sem); down_write(&cinode->lock_sem);
exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length, exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length,
lock->type, &conf_lock, CIFS_LOCK_OP); lock->type, lock->flags, &conf_lock,
CIFS_LOCK_OP);
if (!exist && cinode->can_cache_brlcks) { if (!exist && cinode->can_cache_brlcks) {
list_add_tail(&lock->llist, &cfile->llist->locks); list_add_tail(&lock->llist, &cfile->llist->locks);
up_write(&cinode->lock_sem); up_write(&cinode->lock_sem);
...@@ -1321,7 +1332,7 @@ cifs_read_flock(struct file_lock *flock, __u32 *type, int *lock, int *unlock, ...@@ -1321,7 +1332,7 @@ cifs_read_flock(struct file_lock *flock, __u32 *type, int *lock, int *unlock,
cifs_dbg(FYI, "Lease on file - not implemented yet\n"); cifs_dbg(FYI, "Lease on file - not implemented yet\n");
if (flock->fl_flags & if (flock->fl_flags &
(~(FL_POSIX | FL_FLOCK | FL_SLEEP | (~(FL_POSIX | FL_FLOCK | FL_SLEEP |
FL_ACCESS | FL_LEASE | FL_CLOSE))) FL_ACCESS | FL_LEASE | FL_CLOSE | FL_OFDLCK)))
cifs_dbg(FYI, "Unknown lock flags 0x%x\n", flock->fl_flags); cifs_dbg(FYI, "Unknown lock flags 0x%x\n", flock->fl_flags);
*type = server->vals->large_lock_type; *type = server->vals->large_lock_type;
...@@ -1584,7 +1595,8 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type, ...@@ -1584,7 +1595,8 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
if (lock) { if (lock) {
struct cifsLockInfo *lock; struct cifsLockInfo *lock;
lock = cifs_lock_init(flock->fl_start, length, type); lock = cifs_lock_init(flock->fl_start, length, type,
flock->fl_flags);
if (!lock) if (!lock)
return -ENOMEM; return -ENOMEM;
...@@ -1653,7 +1665,6 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock) ...@@ -1653,7 +1665,6 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
cifs_read_flock(flock, &type, &lock, &unlock, &wait_flag, cifs_read_flock(flock, &type, &lock, &unlock, &wait_flag,
tcon->ses->server); tcon->ses->server);
cifs_sb = CIFS_FILE_SB(file); cifs_sb = CIFS_FILE_SB(file);
netfid = cfile->fid.netfid; netfid = cfile->fid.netfid;
cinode = CIFS_I(file_inode(file)); cinode = CIFS_I(file_inode(file));
...@@ -2098,6 +2109,7 @@ static int cifs_writepages(struct address_space *mapping, ...@@ -2098,6 +2109,7 @@ static int cifs_writepages(struct address_space *mapping,
pgoff_t end, index; pgoff_t end, index;
struct cifs_writedata *wdata; struct cifs_writedata *wdata;
int rc = 0; int rc = 0;
unsigned int xid;
/* /*
* If wsize is smaller than the page cache size, default to writing * If wsize is smaller than the page cache size, default to writing
...@@ -2106,6 +2118,7 @@ static int cifs_writepages(struct address_space *mapping, ...@@ -2106,6 +2118,7 @@ static int cifs_writepages(struct address_space *mapping,
if (cifs_sb->wsize < PAGE_SIZE) if (cifs_sb->wsize < PAGE_SIZE)
return generic_writepages(mapping, wbc); return generic_writepages(mapping, wbc);
xid = get_xid();
if (wbc->range_cyclic) { if (wbc->range_cyclic) {
index = mapping->writeback_index; /* Start from prev offset */ index = mapping->writeback_index; /* Start from prev offset */
end = -1; end = -1;
...@@ -2199,6 +2212,7 @@ static int cifs_writepages(struct address_space *mapping, ...@@ -2199,6 +2212,7 @@ static int cifs_writepages(struct address_space *mapping,
if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
mapping->writeback_index = index; mapping->writeback_index = index;
free_xid(xid);
return rc; return rc;
} }
...@@ -2817,8 +2831,8 @@ cifs_writev(struct kiocb *iocb, struct iov_iter *from) ...@@ -2817,8 +2831,8 @@ cifs_writev(struct kiocb *iocb, struct iov_iter *from)
goto out; goto out;
if (!cifs_find_lock_conflict(cfile, iocb->ki_pos, iov_iter_count(from), if (!cifs_find_lock_conflict(cfile, iocb->ki_pos, iov_iter_count(from),
server->vals->exclusive_lock_type, NULL, server->vals->exclusive_lock_type, 0,
CIFS_WRITE_OP)) NULL, CIFS_WRITE_OP))
rc = __generic_file_write_iter(iocb, from); rc = __generic_file_write_iter(iocb, from);
else else
rc = -EACCES; rc = -EACCES;
...@@ -3388,7 +3402,7 @@ cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to) ...@@ -3388,7 +3402,7 @@ cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to)
down_read(&cinode->lock_sem); down_read(&cinode->lock_sem);
if (!cifs_find_lock_conflict(cfile, iocb->ki_pos, iov_iter_count(to), if (!cifs_find_lock_conflict(cfile, iocb->ki_pos, iov_iter_count(to),
tcon->ses->server->vals->shared_lock_type, tcon->ses->server->vals->shared_lock_type,
NULL, CIFS_READ_OP)) 0, NULL, CIFS_READ_OP))
rc = generic_file_read_iter(iocb, to); rc = generic_file_read_iter(iocb, to);
up_read(&cinode->lock_sem); up_read(&cinode->lock_sem);
return rc; return rc;
...@@ -3743,7 +3757,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -3743,7 +3757,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file); struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
struct TCP_Server_Info *server; struct TCP_Server_Info *server;
pid_t pid; pid_t pid;
unsigned int xid;
xid = get_xid();
/* /*
* Reads as many pages as possible from fscache. Returns -ENOBUFS * Reads as many pages as possible from fscache. Returns -ENOBUFS
* immediately if the cookie is negative * immediately if the cookie is negative
...@@ -3753,8 +3769,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -3753,8 +3769,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
*/ */
rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list, rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
&num_pages); &num_pages);
if (rc == 0) if (rc == 0) {
free_xid(xid);
return rc; return rc;
}
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
pid = open_file->pid; pid = open_file->pid;
...@@ -3798,6 +3816,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -3798,6 +3816,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
*/ */
if (unlikely(rsize < PAGE_SIZE)) { if (unlikely(rsize < PAGE_SIZE)) {
add_credits_and_wake_if(server, credits, 0); add_credits_and_wake_if(server, credits, 0);
free_xid(xid);
return 0; return 0;
} }
...@@ -3862,6 +3881,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -3862,6 +3881,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
* allocator. * allocator.
*/ */
cifs_fscache_readpages_cancel(mapping->host, page_list); cifs_fscache_readpages_cancel(mapping->host, page_list);
free_xid(xid);
return rc; return rc;
} }
...@@ -3889,8 +3909,12 @@ static int cifs_readpage_worker(struct file *file, struct page *page, ...@@ -3889,8 +3909,12 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
else else
cifs_dbg(FYI, "Bytes read %d\n", rc); cifs_dbg(FYI, "Bytes read %d\n", rc);
file_inode(file)->i_atime = /* we do not want atime to be less than mtime, it broke some apps */
current_time(file_inode(file)); file_inode(file)->i_atime = current_time(file_inode(file));
if (timespec64_compare(&(file_inode(file)->i_atime), &(file_inode(file)->i_mtime)))
file_inode(file)->i_atime = file_inode(file)->i_mtime;
else
file_inode(file)->i_atime = current_time(file_inode(file));
if (PAGE_SIZE > rc) if (PAGE_SIZE > rc)
memset(read_data + rc, 0, PAGE_SIZE - rc); memset(read_data + rc, 0, PAGE_SIZE - rc);
......
...@@ -162,6 +162,10 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) ...@@ -162,6 +162,10 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
cifs_revalidate_cache(inode, fattr); cifs_revalidate_cache(inode, fattr);
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
/* we do not want atime to be less than mtime, it broke some apps */
if (timespec64_compare(&fattr->cf_atime, &fattr->cf_mtime))
inode->i_atime = fattr->cf_mtime;
else
inode->i_atime = fattr->cf_atime; inode->i_atime = fattr->cf_atime;
inode->i_mtime = fattr->cf_mtime; inode->i_mtime = fattr->cf_mtime;
inode->i_ctime = fattr->cf_ctime; inode->i_ctime = fattr->cf_ctime;
...@@ -777,7 +781,15 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, ...@@ -777,7 +781,15 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
} else if (rc == -EREMOTE) { } else if (rc == -EREMOTE) {
cifs_create_dfs_fattr(&fattr, sb); cifs_create_dfs_fattr(&fattr, sb);
rc = 0; rc = 0;
} else if (rc == -EACCES && backup_cred(cifs_sb)) { } else if ((rc == -EACCES) && backup_cred(cifs_sb) &&
(strcmp(server->vals->version_string, SMB1_VERSION_STRING)
== 0)) {
/*
* For SMB2 and later the backup intent flag is already
* sent if needed on open and there is no path based
* FindFirst operation to use to retry with
*/
srchinf = kzalloc(sizeof(struct cifs_search_info), srchinf = kzalloc(sizeof(struct cifs_search_info),
GFP_KERNEL); GFP_KERNEL);
if (srchinf == NULL) { if (srchinf == NULL) {
...@@ -786,7 +798,15 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, ...@@ -786,7 +798,15 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
} }
srchinf->endOfSearch = false; srchinf->endOfSearch = false;
if (tcon->unix_ext)
srchinf->info_level = SMB_FIND_FILE_UNIX;
else if ((tcon->ses->capabilities &
tcon->ses->server->vals->cap_nt_find) == 0)
srchinf->info_level = SMB_FIND_FILE_INFO_STANDARD;
else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
srchinf->info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; srchinf->info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
else /* no srvino useful for fallback to some netapp */
srchinf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
srchflgs = CIFS_SEARCH_CLOSE_ALWAYS | srchflgs = CIFS_SEARCH_CLOSE_ALWAYS |
CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_CLOSE_AT_END |
...@@ -795,8 +815,7 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, ...@@ -795,8 +815,7 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
rc = CIFSFindFirst(xid, tcon, full_path, rc = CIFSFindFirst(xid, tcon, full_path,
cifs_sb, NULL, srchflgs, srchinf, false); cifs_sb, NULL, srchflgs, srchinf, false);
if (!rc) { if (!rc) {
data = data = (FILE_ALL_INFO *)srchinf->srch_entries_start;
(FILE_ALL_INFO *)srchinf->srch_entries_start;
cifs_dir_info_to_fattr(&fattr, cifs_dir_info_to_fattr(&fattr,
(FILE_DIRECTORY_INFO *)data, cifs_sb); (FILE_DIRECTORY_INFO *)data, cifs_sb);
......
...@@ -32,8 +32,51 @@ ...@@ -32,8 +32,51 @@
#include "cifs_debug.h" #include "cifs_debug.h"
#include "cifsfs.h" #include "cifsfs.h"
#include "cifs_ioctl.h" #include "cifs_ioctl.h"
#include "smb2proto.h"
#include <linux/btrfs.h> #include <linux/btrfs.h>
static long cifs_ioctl_query_info(unsigned int xid, struct file *filep,
unsigned long p)
{
struct inode *inode = file_inode(filep);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
struct dentry *dentry = filep->f_path.dentry;
unsigned char *path;
__le16 *utf16_path = NULL, root_path;
int rc = 0;
path = build_path_from_dentry(dentry);
if (path == NULL)
return -ENOMEM;
cifs_dbg(FYI, "%s %s\n", __func__, path);
if (!path[0]) {
root_path = 0;
utf16_path = &root_path;
} else {
utf16_path = cifs_convert_path_to_utf16(path + 1, cifs_sb);
if (!utf16_path) {
rc = -ENOMEM;
goto ici_exit;
}
}
if (tcon->ses->server->ops->ioctl_query_info)
rc = tcon->ses->server->ops->ioctl_query_info(
xid, tcon, utf16_path,
filep->private_data ? 0 : 1, p);
else
rc = -EOPNOTSUPP;
ici_exit:
if (utf16_path != &root_path)
kfree(utf16_path);
kfree(path);
return rc;
}
static long cifs_ioctl_copychunk(unsigned int xid, struct file *dst_file, static long cifs_ioctl_copychunk(unsigned int xid, struct file *dst_file,
unsigned long srcfd) unsigned long srcfd)
{ {
...@@ -123,7 +166,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) ...@@ -123,7 +166,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
struct inode *inode = file_inode(filep); struct inode *inode = file_inode(filep);
int rc = -ENOTTY; /* strange error - but the precedent */ int rc = -ENOTTY; /* strange error - but the precedent */
unsigned int xid; unsigned int xid;
struct cifs_sb_info *cifs_sb;
struct cifsFileInfo *pSMBFile = filep->private_data; struct cifsFileInfo *pSMBFile = filep->private_data;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
__u64 ExtAttrBits = 0; __u64 ExtAttrBits = 0;
...@@ -131,7 +173,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) ...@@ -131,7 +173,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
xid = get_xid(); xid = get_xid();
cifs_sb = CIFS_SB(inode->i_sb);
cifs_dbg(FYI, "cifs ioctl 0x%x\n", command); cifs_dbg(FYI, "cifs ioctl 0x%x\n", command);
switch (command) { switch (command) {
case FS_IOC_GETFLAGS: case FS_IOC_GETFLAGS:
...@@ -196,6 +237,9 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) ...@@ -196,6 +237,9 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
case CIFS_IOC_COPYCHUNK_FILE: case CIFS_IOC_COPYCHUNK_FILE:
rc = cifs_ioctl_copychunk(xid, filep, arg); rc = cifs_ioctl_copychunk(xid, filep, arg);
break; break;
case CIFS_QUERY_INFO:
rc = cifs_ioctl_query_info(xid, filep, arg);
break;
case CIFS_IOC_SET_INTEGRITY: case CIFS_IOC_SET_INTEGRITY:
if (pSMBFile == NULL) if (pSMBFile == NULL)
break; break;
......
...@@ -123,6 +123,8 @@ tconInfoAlloc(void) ...@@ -123,6 +123,8 @@ tconInfoAlloc(void)
ret_buf->crfid.fid = kzalloc(sizeof(struct cifs_fid), ret_buf->crfid.fid = kzalloc(sizeof(struct cifs_fid),
GFP_KERNEL); GFP_KERNEL);
spin_lock_init(&ret_buf->stat_lock); spin_lock_init(&ret_buf->stat_lock);
atomic_set(&ret_buf->num_local_opens, 0);
atomic_set(&ret_buf->num_remote_opens, 0);
} }
return ret_buf; return ret_buf;
} }
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
/* /*
* Identifiers for functions that use the open, operation, close pattern * Identifiers for functions that use the open, operation, close pattern
* in smb2inode.c:smb2_open_op_close() * in smb2inode.c:smb2_compound_op()
*/ */
#define SMB2_OP_SET_DELETE 1 #define SMB2_OP_SET_DELETE 1
#define SMB2_OP_SET_INFO 2 #define SMB2_OP_SET_INFO 2
......
This diff is collapsed.
...@@ -288,7 +288,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = { ...@@ -288,7 +288,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
{STATUS_FLT_BUFFER_TOO_SMALL, -ENOBUFS, "STATUS_FLT_BUFFER_TOO_SMALL"}, {STATUS_FLT_BUFFER_TOO_SMALL, -ENOBUFS, "STATUS_FLT_BUFFER_TOO_SMALL"},
{STATUS_FVE_PARTIAL_METADATA, -EIO, "STATUS_FVE_PARTIAL_METADATA"}, {STATUS_FVE_PARTIAL_METADATA, -EIO, "STATUS_FVE_PARTIAL_METADATA"},
{STATUS_UNSUCCESSFUL, -EIO, "STATUS_UNSUCCESSFUL"}, {STATUS_UNSUCCESSFUL, -EIO, "STATUS_UNSUCCESSFUL"},
{STATUS_NOT_IMPLEMENTED, -ENOSYS, "STATUS_NOT_IMPLEMENTED"}, {STATUS_NOT_IMPLEMENTED, -EOPNOTSUPP, "STATUS_NOT_IMPLEMENTED"},
{STATUS_INVALID_INFO_CLASS, -EIO, "STATUS_INVALID_INFO_CLASS"}, {STATUS_INVALID_INFO_CLASS, -EIO, "STATUS_INVALID_INFO_CLASS"},
{STATUS_INFO_LENGTH_MISMATCH, -EIO, "STATUS_INFO_LENGTH_MISMATCH"}, {STATUS_INFO_LENGTH_MISMATCH, -EIO, "STATUS_INFO_LENGTH_MISMATCH"},
{STATUS_ACCESS_VIOLATION, -EACCES, "STATUS_ACCESS_VIOLATION"}, {STATUS_ACCESS_VIOLATION, -EACCES, "STATUS_ACCESS_VIOLATION"},
......
This diff is collapsed.
This diff is collapsed.
...@@ -613,6 +613,8 @@ struct smb2_tree_disconnect_rsp { ...@@ -613,6 +613,8 @@ struct smb2_tree_disconnect_rsp {
#define SVHDX_OPEN_DEVICE_CONTEX 0x9CCBCF9E04C1E643980E158DA1F6EC83 #define SVHDX_OPEN_DEVICE_CONTEX 0x9CCBCF9E04C1E643980E158DA1F6EC83
#define SMB2_CREATE_TAG_POSIX 0x93AD25509CB411E7B42383DE968BCD7C #define SMB2_CREATE_TAG_POSIX 0x93AD25509CB411E7B42383DE968BCD7C
/* Flag (SMB3 open response) values */
#define SMB2_CREATE_FLAG_REPARSEPOINT 0x01
/* /*
* Maximum number of iovs we need for an open/create request. * Maximum number of iovs we need for an open/create request.
...@@ -650,7 +652,7 @@ struct smb2_create_rsp { ...@@ -650,7 +652,7 @@ struct smb2_create_rsp {
struct smb2_sync_hdr sync_hdr; struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 89 */ __le16 StructureSize; /* Must be 89 */
__u8 OplockLevel; __u8 OplockLevel;
__u8 Reserved; __u8 Flag; /* 0x01 if reparse point */
__le32 CreateAction; __le32 CreateAction;
__le64 CreationTime; __le64 CreationTime;
__le64 LastAccessTime; __le64 LastAccessTime;
...@@ -1174,6 +1176,15 @@ struct smb2_query_info_rsp { ...@@ -1174,6 +1176,15 @@ struct smb2_query_info_rsp {
__u8 Buffer[1]; __u8 Buffer[1];
} __packed; } __packed;
/*
* Maximum number of iovs we need for a set-info request.
* The largest one is rename/hardlink
* [0] : struct smb2_set_info_req + smb2_file_[rename|link]_info
* [1] : path
* [2] : compound padding
*/
#define SMB2_SET_INFO_IOV_SIZE 3
struct smb2_set_info_req { struct smb2_set_info_req {
struct smb2_sync_hdr sync_hdr; struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 33 */ __le16 StructureSize; /* Must be 33 */
......
...@@ -116,6 +116,9 @@ extern void smb2_reconnect_server(struct work_struct *work); ...@@ -116,6 +116,9 @@ extern void smb2_reconnect_server(struct work_struct *work);
extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server); extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
extern unsigned long smb_rqst_len(struct TCP_Server_Info *server, extern unsigned long smb_rqst_len(struct TCP_Server_Info *server,
struct smb_rqst *rqst); struct smb_rqst *rqst);
extern void smb2_set_next_command(struct TCP_Server_Info *server,
struct smb_rqst *rqst);
extern void smb2_set_related(struct smb_rqst *rqst);
/* /*
* SMB2 Worker functions - most of protocol specific implementation details * SMB2 Worker functions - most of protocol specific implementation details
...@@ -160,7 +163,8 @@ extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -160,7 +163,8 @@ extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
extern int SMB2_query_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, extern int SMB2_query_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
u64 persistent_fid, u64 volatile_fid, u64 persistent_fid, u64 volatile_fid,
u8 info_class, u8 info_type, u8 info_class, u8 info_type,
u32 additional_info, size_t output_len); u32 additional_info, size_t output_len,
size_t input_len, void *input);
extern void SMB2_query_info_free(struct smb_rqst *rqst); extern void SMB2_query_info_free(struct smb_rqst *rqst);
extern int SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_file_id, u64 volatile_file_id, u64 persistent_file_id, u64 volatile_file_id,
...@@ -179,20 +183,14 @@ extern int SMB2_echo(struct TCP_Server_Info *server); ...@@ -179,20 +183,14 @@ extern int SMB2_echo(struct TCP_Server_Info *server);
extern int SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, int index, u64 persistent_fid, u64 volatile_fid, int index,
struct cifs_search_info *srch_inf); struct cifs_search_info *srch_inf);
extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid,
__le16 *target_file);
extern int SMB2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid);
extern int SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid,
__le16 *target_file);
extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, u32 pid, u64 persistent_fid, u64 volatile_fid, u32 pid,
__le64 *eof, bool is_fallocate); __le64 *eof);
extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_set_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
u64 persistent_fid, u64 volatile_fid, u64 persistent_fid, u64 volatile_fid, u32 pid,
FILE_BASIC_INFO *buf); u8 info_class, u8 info_type, u32 additional_info,
void **data, unsigned int *size);
extern void SMB2_set_info_free(struct smb_rqst *rqst);
extern int SMB2_set_acl(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, u64 persistent_fid, u64 volatile_fid,
struct cifs_ntsd *pnntsd, int pacllen, int aclflag); struct cifs_ntsd *pnntsd, int pacllen, int aclflag);
...@@ -232,6 +230,10 @@ extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *, ...@@ -232,6 +230,10 @@ extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
extern int smb3_encryption_required(const struct cifs_tcon *tcon); extern int smb3_encryption_required(const struct cifs_tcon *tcon);
extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length, extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
struct kvec *iov, unsigned int min_buf_size); struct kvec *iov, unsigned int min_buf_size);
extern int smb2_validate_and_copy_iov(unsigned int offset,
unsigned int buffer_length,
struct kvec *iov,
unsigned int minbufsize, char *data);
extern void smb2_copy_fs_info_to_kstatfs( extern void smb2_copy_fs_info_to_kstatfs(
struct smb2_fs_full_size_info *pfs_inf, struct smb2_fs_full_size_info *pfs_inf,
struct kstatfs *kst); struct kstatfs *kst);
......
...@@ -2295,8 +2295,12 @@ static void smbd_mr_recovery_work(struct work_struct *work) ...@@ -2295,8 +2295,12 @@ static void smbd_mr_recovery_work(struct work_struct *work)
int rc; int rc;
list_for_each_entry(smbdirect_mr, &info->mr_list, list) { list_for_each_entry(smbdirect_mr, &info->mr_list, list) {
if (smbdirect_mr->state == MR_INVALIDATED || if (smbdirect_mr->state == MR_INVALIDATED)
smbdirect_mr->state == MR_ERROR) { ib_dma_unmap_sg(
info->id->device, smbdirect_mr->sgl,
smbdirect_mr->sgl_count,
smbdirect_mr->dir);
else if (smbdirect_mr->state == MR_ERROR) {
/* recover this MR entry */ /* recover this MR entry */
rc = ib_dereg_mr(smbdirect_mr->mr); rc = ib_dereg_mr(smbdirect_mr->mr);
...@@ -2320,12 +2324,9 @@ static void smbd_mr_recovery_work(struct work_struct *work) ...@@ -2320,12 +2324,9 @@ static void smbd_mr_recovery_work(struct work_struct *work)
smbd_disconnect_rdma_connection(info); smbd_disconnect_rdma_connection(info);
continue; continue;
} }
} else
if (smbdirect_mr->state == MR_INVALIDATED) /* This MR is being used, don't recover it */
ib_dma_unmap_sg( continue;
info->id->device, smbdirect_mr->sgl,
smbdirect_mr->sgl_count,
smbdirect_mr->dir);
smbdirect_mr->state = MR_READY; smbdirect_mr->state = MR_READY;
...@@ -2339,7 +2340,6 @@ static void smbd_mr_recovery_work(struct work_struct *work) ...@@ -2339,7 +2340,6 @@ static void smbd_mr_recovery_work(struct work_struct *work)
if (atomic_inc_return(&info->mr_ready_count) == 1) if (atomic_inc_return(&info->mr_ready_count) == 1)
wake_up_interruptible(&info->wait_mr); wake_up_interruptible(&info->wait_mr);
} }
}
} }
static void destroy_mr_list(struct smbd_connection *info) static void destroy_mr_list(struct smbd_connection *info)
......
...@@ -460,6 +460,85 @@ DEFINE_EVENT(smb3_open_done_class, smb3_##name, \ ...@@ -460,6 +460,85 @@ DEFINE_EVENT(smb3_open_done_class, smb3_##name, \
DEFINE_SMB3_OPEN_DONE_EVENT(open_done); DEFINE_SMB3_OPEN_DONE_EVENT(open_done);
DEFINE_SMB3_OPEN_DONE_EVENT(posix_mkdir_done); DEFINE_SMB3_OPEN_DONE_EVENT(posix_mkdir_done);
DECLARE_EVENT_CLASS(smb3_lease_done_class,
TP_PROTO(__u32 lease_state,
__u32 tid,
__u64 sesid,
__u64 lease_key_low,
__u64 lease_key_high),
TP_ARGS(lease_state, tid, sesid, lease_key_low, lease_key_high),
TP_STRUCT__entry(
__field(__u32, lease_state)
__field(__u32, tid)
__field(__u64, sesid)
__field(__u64, lease_key_low)
__field(__u64, lease_key_high)
),
TP_fast_assign(
__entry->lease_state = lease_state;
__entry->tid = tid;
__entry->sesid = sesid;
__entry->lease_key_low = lease_key_low;
__entry->lease_key_high = lease_key_high;
),
TP_printk("sid=0x%llx tid=0x%x lease_key=0x%llx%llx lease_state=0x%x",
__entry->sesid, __entry->tid, __entry->lease_key_high,
__entry->lease_key_low, __entry->lease_state)
)
#define DEFINE_SMB3_LEASE_DONE_EVENT(name) \
DEFINE_EVENT(smb3_lease_done_class, smb3_##name, \
TP_PROTO(__u32 lease_state, \
__u32 tid, \
__u64 sesid, \
__u64 lease_key_low, \
__u64 lease_key_high), \
TP_ARGS(lease_state, tid, sesid, lease_key_low, lease_key_high))
DEFINE_SMB3_LEASE_DONE_EVENT(lease_done);
DECLARE_EVENT_CLASS(smb3_lease_err_class,
TP_PROTO(__u32 lease_state,
__u32 tid,
__u64 sesid,
__u64 lease_key_low,
__u64 lease_key_high,
int rc),
TP_ARGS(lease_state, tid, sesid, lease_key_low, lease_key_high, rc),
TP_STRUCT__entry(
__field(__u32, lease_state)
__field(__u32, tid)
__field(__u64, sesid)
__field(__u64, lease_key_low)
__field(__u64, lease_key_high)
__field(int, rc)
),
TP_fast_assign(
__entry->lease_state = lease_state;
__entry->tid = tid;
__entry->sesid = sesid;
__entry->lease_key_low = lease_key_low;
__entry->lease_key_high = lease_key_high;
__entry->rc = rc;
),
TP_printk("sid=0x%llx tid=0x%x lease_key=0x%llx%llx lease_state=0x%x rc=%d",
__entry->sesid, __entry->tid, __entry->lease_key_high,
__entry->lease_key_low, __entry->lease_state, __entry->rc)
)
#define DEFINE_SMB3_LEASE_ERR_EVENT(name) \
DEFINE_EVENT(smb3_lease_err_class, smb3_##name, \
TP_PROTO(__u32 lease_state, \
__u32 tid, \
__u64 sesid, \
__u64 lease_key_low, \
__u64 lease_key_high, \
int rc), \
TP_ARGS(lease_state, tid, sesid, lease_key_low, lease_key_high, rc))
DEFINE_SMB3_LEASE_ERR_EVENT(lease_err);
DECLARE_EVENT_CLASS(smb3_reconnect_class, DECLARE_EVENT_CLASS(smb3_reconnect_class,
TP_PROTO(__u64 currmid, TP_PROTO(__u64 currmid,
char *hostname), char *hostname),
...@@ -486,6 +565,36 @@ DEFINE_EVENT(smb3_reconnect_class, smb3_##name, \ ...@@ -486,6 +565,36 @@ DEFINE_EVENT(smb3_reconnect_class, smb3_##name, \
DEFINE_SMB3_RECONNECT_EVENT(reconnect); DEFINE_SMB3_RECONNECT_EVENT(reconnect);
DEFINE_SMB3_RECONNECT_EVENT(partial_send_reconnect); DEFINE_SMB3_RECONNECT_EVENT(partial_send_reconnect);
DECLARE_EVENT_CLASS(smb3_credit_class,
TP_PROTO(__u64 currmid,
char *hostname,
int credits),
TP_ARGS(currmid, hostname, credits),
TP_STRUCT__entry(
__field(__u64, currmid)
__field(char *, hostname)
__field(int, credits)
),
TP_fast_assign(
__entry->currmid = currmid;
__entry->hostname = hostname;
__entry->credits = credits;
),
TP_printk("server=%s current_mid=0x%llx credits=%d",
__entry->hostname,
__entry->currmid,
__entry->credits)
)
#define DEFINE_SMB3_CREDIT_EVENT(name) \
DEFINE_EVENT(smb3_credit_class, smb3_##name, \
TP_PROTO(__u64 currmid, \
char *hostname, \
int credits), \
TP_ARGS(currmid, hostname, credits))
DEFINE_SMB3_CREDIT_EVENT(reconnect_with_invalid_credits);
#endif /* _CIFS_TRACE_H */ #endif /* _CIFS_TRACE_H */
#undef TRACE_INCLUDE_PATH #undef TRACE_INCLUDE_PATH
......
...@@ -113,9 +113,18 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) ...@@ -113,9 +113,18 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
cifs_small_buf_release(midEntry->resp_buf); cifs_small_buf_release(midEntry->resp_buf);
#ifdef CONFIG_CIFS_STATS2 #ifdef CONFIG_CIFS_STATS2
now = jiffies; now = jiffies;
/* commands taking longer than one second are indications that /*
something is wrong, unless it is quite a slow link or server */ * commands taking longer than one second (default) can be indications
if (time_after(now, midEntry->when_alloc + HZ) && * that something is wrong, unless it is quite a slow link or a very
* busy server. Note that this calc is unlikely or impossible to wrap
* as long as slow_rsp_threshold is not set way above recommended max
* value (32767 ie 9 hours) and is generally harmless even if wrong
* since only affects debug counters - so leaving the calc as simple
* comparison rather than doing multiple conversions and overflow
* checks
*/
if ((slow_rsp_threshold != 0) &&
time_after(now, midEntry->when_alloc + (slow_rsp_threshold * HZ)) &&
(midEntry->command != command)) { (midEntry->command != command)) {
/* smb2slowcmd[NUMBER_OF_SMB2_COMMANDS] counts by command */ /* smb2slowcmd[NUMBER_OF_SMB2_COMMANDS] counts by command */
if ((le16_to_cpu(midEntry->command) < NUMBER_OF_SMB2_COMMANDS) && if ((le16_to_cpu(midEntry->command) < NUMBER_OF_SMB2_COMMANDS) &&
...@@ -128,7 +137,7 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) ...@@ -128,7 +137,7 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
if (cifsFYI & CIFS_TIMER) { if (cifsFYI & CIFS_TIMER) {
pr_debug(" CIFS slow rsp: cmd %d mid %llu", pr_debug(" CIFS slow rsp: cmd %d mid %llu",
midEntry->command, midEntry->mid); midEntry->command, midEntry->mid);
pr_info(" A: 0x%lx S: 0x%lx R: 0x%lx\n", cifs_info(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
now - midEntry->when_alloc, now - midEntry->when_alloc,
now - midEntry->when_sent, now - midEntry->when_sent,
now - midEntry->when_received); now - midEntry->when_received);
...@@ -786,7 +795,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -786,7 +795,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
int i, j, rc = 0; int i, j, rc = 0;
int timeout, optype; int timeout, optype;
struct mid_q_entry *midQ[MAX_COMPOUND]; struct mid_q_entry *midQ[MAX_COMPOUND];
unsigned int credits = 1; unsigned int credits = 0;
char *buf; char *buf;
timeout = flags & CIFS_TIMEOUT_MASK; timeout = flags & CIFS_TIMEOUT_MASK;
...@@ -851,21 +860,24 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -851,21 +860,24 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
mutex_unlock(&ses->server->srv_mutex); mutex_unlock(&ses->server->srv_mutex);
for (i = 0; i < num_rqst; i++) {
if (rc < 0) if (rc < 0)
goto out; goto out;
/*
* Compounding is never used during session establish.
*/
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP))
smb311_update_preauth_hash(ses, rqst[i].rq_iov, smb311_update_preauth_hash(ses, rqst[0].rq_iov,
rqst[i].rq_nvec); rqst[0].rq_nvec);
if (timeout == CIFS_ASYNC_OP) if (timeout == CIFS_ASYNC_OP)
goto out; goto out;
for (i = 0; i < num_rqst; i++) {
rc = wait_for_response(ses->server, midQ[i]); rc = wait_for_response(ses->server, midQ[i]);
if (rc != 0) { if (rc != 0) {
cifs_dbg(FYI, "Cancelling wait for mid %llu\n", cifs_dbg(VFS, "Cancelling wait for mid %llu cmd: %d\n",
midQ[i]->mid); midQ[i]->mid, le16_to_cpu(midQ[i]->command));
send_cancel(ses->server, &rqst[i], midQ[i]); send_cancel(ses->server, &rqst[i], midQ[i]);
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) { if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) {
...@@ -877,10 +889,21 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -877,10 +889,21 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
} }
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
} }
}
for (i = 0; i < num_rqst; i++)
if (midQ[i]->resp_buf)
credits += ses->server->ops->get_credits(midQ[i]);
if (!credits)
credits = 1;
for (i = 0; i < num_rqst; i++) {
if (rc < 0)
goto out;
rc = cifs_sync_mid_result(midQ[i], ses->server); rc = cifs_sync_mid_result(midQ[i], ses->server);
if (rc != 0) { if (rc != 0) {
add_credits(ses->server, 1, optype); add_credits(ses->server, credits, optype);
return rc; return rc;
} }
...@@ -901,23 +924,26 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -901,23 +924,26 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
else else
resp_buf_type[i] = CIFS_SMALL_BUFFER; resp_buf_type[i] = CIFS_SMALL_BUFFER;
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) {
struct kvec iov = {
.iov_base = resp_iov[i].iov_base,
.iov_len = resp_iov[i].iov_len
};
smb311_update_preauth_hash(ses, &iov, 1);
}
credits = ses->server->ops->get_credits(midQ[i]);
rc = ses->server->ops->check_receive(midQ[i], ses->server, rc = ses->server->ops->check_receive(midQ[i], ses->server,
flags & CIFS_LOG_ERROR); flags & CIFS_LOG_ERROR);
/* mark it so buf will not be freed by cifs_delete_mid */ /* mark it so buf will not be freed by cifs_delete_mid */
if ((flags & CIFS_NO_RESP) == 0) if ((flags & CIFS_NO_RESP) == 0)
midQ[i]->resp_buf = NULL; midQ[i]->resp_buf = NULL;
} }
/*
* Compounding is never used during session establish.
*/
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) {
struct kvec iov = {
.iov_base = resp_iov[0].iov_base,
.iov_len = resp_iov[0].iov_len
};
smb311_update_preauth_hash(ses, &iov, 1);
}
out: out:
/* /*
* This will dequeue all mids. After this it is important that the * This will dequeue all mids. After this it is important that the
......
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