mirror of
https://github.com/torvalds/linux.git
synced 2024-11-14 16:12:02 +00:00
3 smb3 fixes for stable, patches for improved debugging and perf gathering, and much improved performance for most metadata operations (expanded use of compounding)
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAlvR8lcACgkQiiy9cAdy T1FNtgv/fpnMnf/4JPE40NgJ6CUcv4xsJ3bDzmezB5ZUgoNigtVeUMSBa8qCEBcg cdC243TOpwNGaWQ1yzRN4kyGq1cAE9B1xal4n7+xlii+ZpWXwrkOAiF27UTAIGTR ck3IfeS529QoQt9ReI4v+pWYKZOnlbWgF7iBflg0Snsz/JvICQ05wRA9VaXBJIz8 Pwb3SDPCrON1KRJzJVDjC6AaYhZqu2VLbSV9fOhZ5WVcHb/t0EUqsFvgMzhk2+tv Rh+9zNzcQWyYI8KtYQmWMMoSk7F8OGlARWXW0ROfOoQwC70zg35F+tGUahlWsIYD 19TLJy28g5Gqh0DZoPmtpNUdu1NCfy+vQcqaSNnAaQreMlqmV6ODxjvz3DeGL9lK Teo0V9dwWOZNFneFTpVsrWL4KQEZfDPDt1L6e3GOL5t6QLOZa5IuPVs8A9txqFCD kTAIQstESmXOrl+HpP64LcovV4BaD05st+fo7Cec16UDJjEqxCmHUSIYw3kFnCny 4UAITp4V =q4Qs -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
033078a9af
@ -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_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: ");
|
||||
if (iface->rdma_capable)
|
||||
seq_puts(m, "rdma ");
|
||||
@ -285,7 +285,7 @@ skip_rdma:
|
||||
if ((ses->serverDomain == NULL) ||
|
||||
(ses->serverOS == 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,
|
||||
ses->capabilities, ses->status);
|
||||
if (ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST)
|
||||
@ -296,16 +296,18 @@ skip_rdma:
|
||||
seq_printf(m,
|
||||
"\n%d) Name: %s Domain: %s Uses: %d OS:"
|
||||
" %s\n\tNOS: %s\tCapability: 0x%x\n\tSMB"
|
||||
" session status: %d\t",
|
||||
" session status: %d ",
|
||||
i, ses->serverName, ses->serverDomain,
|
||||
ses->ses_count, ses->serverOS, ses->serverNOS,
|
||||
ses->capabilities, ses->status);
|
||||
}
|
||||
if (server->rdma)
|
||||
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->tcpStatus, server->srv_count,
|
||||
server->tcpStatus,
|
||||
server->reconnect_instance,
|
||||
server->srv_count,
|
||||
server->sec_mode, in_flight(server));
|
||||
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
@ -352,7 +354,7 @@ skip_rdma:
|
||||
seq_printf(m, "\n\tServer interfaces: %zu\n",
|
||||
ses->iface_count);
|
||||
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]);
|
||||
}
|
||||
spin_unlock(&ses->iface_lock);
|
||||
@ -383,6 +385,9 @@ static ssize_t cifs_stats_proc_write(struct file *file,
|
||||
atomic_set(&totBufAllocCount, 0);
|
||||
atomic_set(&totSmBufAllocCount, 0);
|
||||
#endif /* CONFIG_CIFS_STATS2 */
|
||||
atomic_set(&tcpSesReconnectCount, 0);
|
||||
atomic_set(&tconInfoReconnectCount, 0);
|
||||
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
GlobalMaxActiveXid = 0;
|
||||
GlobalCurrentXid = 0;
|
||||
|
@ -47,6 +47,29 @@ extern int cifsFYI;
|
||||
*/
|
||||
#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 */
|
||||
#define cifs_dbg_func(ratefunc, type, fmt, ...) \
|
||||
do { \
|
||||
@ -81,6 +104,11 @@ do { \
|
||||
if (0) \
|
||||
pr_debug(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define cifs_info(fmt, ...) \
|
||||
do { \
|
||||
pr_info("CIFS: "fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#endif /* _H_CIFS_DEBUG */
|
||||
|
@ -304,12 +304,17 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
|
||||
*/
|
||||
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 */
|
||||
full_path = build_path_from_dentry_optional_prefix(mntpt, true);
|
||||
if (full_path == NULL)
|
||||
goto cdda_exit;
|
||||
|
||||
cifs_sb = CIFS_SB(mntpt->d_sb);
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink)) {
|
||||
mnt = ERR_CAST(tlink);
|
||||
|
@ -51,6 +51,7 @@
|
||||
*/
|
||||
#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_DFS 0x8000000 /* disable DFS resolving */
|
||||
|
||||
struct cifs_sb_info {
|
||||
struct rb_root tlink_tree;
|
||||
|
@ -43,8 +43,19 @@ struct smb_snapshot_array {
|
||||
/* snapshots[]; */
|
||||
} __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_IOC_COPYCHUNK_FILE _IOW(CIFS_IOCTL_MAGIC, 3, int)
|
||||
#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_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);
|
||||
MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server for "
|
||||
"CIFS/SMB1 dialect (N/A for SMB3) "
|
||||
"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_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)
|
||||
seq_puts(s, ",unix");
|
||||
else
|
||||
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)
|
||||
seq_puts(s, ",posixpaths");
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
|
||||
@ -707,7 +717,14 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
|
||||
struct cifs_mnt_data mnt_data;
|
||||
struct dentry *root;
|
||||
|
||||
cifs_dbg(FYI, "Devname: %s flags: %d\n", dev_name, flags);
|
||||
/*
|
||||
* 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);
|
||||
else
|
||||
cifs_info("Attempting to mount %s\n", dev_name);
|
||||
|
||||
volume_info = cifs_get_volume_info((char *)data, dev_name, is_smb3);
|
||||
if (IS_ERR(volume_info))
|
||||
@ -1418,6 +1435,11 @@ init_cifs(void)
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_set(&totBufAllocCount, 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 */
|
||||
|
||||
atomic_set(&midCount, 0);
|
||||
@ -1538,11 +1560,11 @@ exit_cifs(void)
|
||||
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_DESCRIPTION
|
||||
("VFS to access servers complying with the SNIA CIFS Specification "
|
||||
"e.g. Samba and Windows");
|
||||
("VFS to access SMB3 servers e.g. Samba, Macs, Azure and Windows (and "
|
||||
"also older servers complying with the SNIA CIFS Specification)");
|
||||
MODULE_VERSION(CIFS_VERSION);
|
||||
MODULE_SOFTDEP("pre: arc4");
|
||||
MODULE_SOFTDEP("pre: des");
|
||||
|
@ -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;
|
||||
#endif /* CONFIG_CIFS_NFSD_EXPORT */
|
||||
|
||||
#define CIFS_VERSION "2.13"
|
||||
#define CIFS_VERSION "2.14"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
|
||||
|
||||
#define SMB_PATH_MAX 260
|
||||
#define CIFS_PORT 445
|
||||
#define RFC1001_PORT 139
|
||||
|
||||
@ -465,6 +466,11 @@ struct smb_version_operations {
|
||||
enum securityEnum (*select_sectype)(struct TCP_Server_Info *,
|
||||
enum securityEnum);
|
||||
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 {
|
||||
@ -654,6 +660,7 @@ struct TCP_Server_Info {
|
||||
/* 16th byte of RFC1001 workstation name is always null */
|
||||
char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
|
||||
__u32 sequence_number; /* for signing, protected by srv_mutex */
|
||||
__u32 reconnect_instance; /* incremented on each reconnect */
|
||||
struct session_key session_key;
|
||||
unsigned long lstrp; /* when we got last response from this server */
|
||||
struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */
|
||||
@ -798,6 +805,7 @@ compare_mid(__u16 mid, const struct smb_hdr *smb)
|
||||
* a single wsize request with a single call.
|
||||
*/
|
||||
#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
|
||||
@ -924,6 +932,8 @@ struct cifs_tcon {
|
||||
struct list_head tcon_list;
|
||||
int tc_count;
|
||||
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;
|
||||
spinlock_t open_file_lock; /* protects list above */
|
||||
struct cifs_ses *ses; /* pointer to session associated with */
|
||||
@ -1072,7 +1082,8 @@ struct cifsLockInfo {
|
||||
__u64 offset;
|
||||
__u64 length;
|
||||
__u32 pid;
|
||||
__u32 type;
|
||||
__u16 type;
|
||||
__u16 flags;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1715,6 +1726,7 @@ GLOBAL_EXTERN atomic_t bufAllocCount; /* current number allocated */
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
GLOBAL_EXTERN atomic_t totBufAllocCount; /* total allocated over all time */
|
||||
GLOBAL_EXTERN atomic_t totSmBufAllocCount;
|
||||
extern unsigned int slow_rsp_threshold; /* number of secs before logging */
|
||||
#endif
|
||||
GLOBAL_EXTERN atomic_t smBufAllocCount;
|
||||
GLOBAL_EXTERN atomic_t midCount;
|
||||
|
@ -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 bool cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset,
|
||||
__u64 length, __u8 type,
|
||||
__u64 length, __u8 type, __u16 flags,
|
||||
struct cifsLockInfo **conf_lock,
|
||||
int rw_check);
|
||||
extern void cifs_add_pending_open(struct cifs_fid *fid,
|
||||
|
@ -1607,6 +1607,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
|
||||
struct smb_rqst rqst = { .rq_iov = rdata->iov,
|
||||
.rq_nvec = 2,
|
||||
.rq_pages = rdata->pages,
|
||||
.rq_offset = rdata->page_offset,
|
||||
.rq_npages = rdata->nr_pages,
|
||||
.rq_pagesz = rdata->pagesz,
|
||||
.rq_tailsz = rdata->tailsz };
|
||||
@ -2210,6 +2211,7 @@ cifs_async_writev(struct cifs_writedata *wdata,
|
||||
rqst.rq_iov = iov;
|
||||
rqst.rq_nvec = 2;
|
||||
rqst.rq_pages = wdata->pages;
|
||||
rqst.rq_offset = wdata->page_offset;
|
||||
rqst.rq_npages = wdata->nr_pages;
|
||||
rqst.rq_pagesz = wdata->pagesz;
|
||||
rqst.rq_tailsz = wdata->tailsz;
|
||||
@ -5027,6 +5029,13 @@ oldQFSInfoRetry:
|
||||
le16_to_cpu(response_data->BytesPerSector) *
|
||||
le32_to_cpu(response_data->
|
||||
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 =
|
||||
le32_to_cpu(response_data->TotalAllocationUnits);
|
||||
FSData->f_bfree = FSData->f_bavail =
|
||||
@ -5107,6 +5116,13 @@ QFSInfoRetry:
|
||||
le32_to_cpu(response_data->BytesPerSector) *
|
||||
le32_to_cpu(response_data->
|
||||
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 =
|
||||
le64_to_cpu(response_data->TotalAllocationUnits);
|
||||
FSData->f_bfree = FSData->f_bavail =
|
||||
@ -5470,6 +5486,13 @@ QFSPosixRetry:
|
||||
data_offset);
|
||||
FSData->f_bsize =
|
||||
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 =
|
||||
le64_to_cpu(response_data->TotalBlocks);
|
||||
FSData->f_bfree =
|
||||
|
@ -250,6 +250,7 @@ static const match_table_t cifs_mount_option_tokens = {
|
||||
{ Opt_ignore, "dev" },
|
||||
{ Opt_ignore, "mand" },
|
||||
{ Opt_ignore, "nomand" },
|
||||
{ Opt_ignore, "relatime" },
|
||||
{ Opt_ignore, "_netdev" },
|
||||
|
||||
{ Opt_err, NULL }
|
||||
@ -347,7 +348,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
||||
server->maxBuf = 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);
|
||||
|
||||
/* before reconnecting the tcp session, mark the smb session (uid)
|
||||
@ -2396,6 +2397,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
|
||||
volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
|
||||
tcp_ses->session_estab = false;
|
||||
tcp_ses->sequence_number = 0;
|
||||
tcp_ses->reconnect_instance = 0;
|
||||
tcp_ses->lstrp = jiffies;
|
||||
spin_lock_init(&tcp_ses->req_lock);
|
||||
INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
|
||||
@ -3085,10 +3087,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
|
||||
if (rc)
|
||||
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;
|
||||
/* check if SMB2 or later, CIFS does not support persistent handles */
|
||||
if (volume_info->persistent) {
|
||||
@ -3663,6 +3661,8 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
|
||||
cifs_sb->actimeo = pvolume_info->actimeo;
|
||||
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)
|
||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
|
||||
if (pvolume_info->setuids)
|
||||
@ -3819,6 +3819,9 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
|
||||
struct dfs_info3_param *referrals = 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);
|
||||
if (IS_ERR(full_path))
|
||||
return PTR_ERR(full_path);
|
||||
|
@ -334,6 +334,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
|
||||
server->ops->set_fid(cfile, fid, oplock);
|
||||
|
||||
list_add(&cfile->tlist, &tcon->openFileList);
|
||||
atomic_inc(&tcon->num_local_opens);
|
||||
|
||||
/* if readable file instance put first in list*/
|
||||
if (file->f_mode & FMODE_READ)
|
||||
@ -395,6 +396,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
|
||||
/* remove it from the lists */
|
||||
list_del(&cifs_file->flist);
|
||||
list_del(&cifs_file->tlist);
|
||||
atomic_dec(&tcon->num_local_opens);
|
||||
|
||||
if (list_empty(&cifsi->openFileList)) {
|
||||
cifs_dbg(FYI, "closing last open instance for inode %p\n",
|
||||
@ -864,7 +866,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
|
||||
}
|
||||
|
||||
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 =
|
||||
kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
|
||||
@ -874,6 +876,7 @@ cifs_lock_init(__u64 offset, __u64 length, __u8 type)
|
||||
lock->length = length;
|
||||
lock->type = type;
|
||||
lock->pid = current->tgid;
|
||||
lock->flags = flags;
|
||||
INIT_LIST_HEAD(&lock->blist);
|
||||
init_waitqueue_head(&lock->block_q);
|
||||
return lock;
|
||||
@ -896,7 +899,8 @@ cifs_del_lock_waiters(struct cifsLockInfo *lock)
|
||||
/* @rw_check : 0 - no op, 1 - read, 2 - write */
|
||||
static bool
|
||||
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 *li;
|
||||
@ -918,6 +922,10 @@ cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset,
|
||||
((server->ops->compare_fids(cfile, cur_cfile) &&
|
||||
current->tgid == li->pid) || type == li->type))
|
||||
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)
|
||||
*conf_lock = li;
|
||||
return true;
|
||||
@ -927,8 +935,8 @@ cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset,
|
||||
|
||||
bool
|
||||
cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length,
|
||||
__u8 type, struct cifsLockInfo **conf_lock,
|
||||
int rw_check)
|
||||
__u8 type, __u16 flags,
|
||||
struct cifsLockInfo **conf_lock, int rw_check)
|
||||
{
|
||||
bool rc = false;
|
||||
struct cifs_fid_locks *cur;
|
||||
@ -936,7 +944,8 @@ cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length,
|
||||
|
||||
list_for_each_entry(cur, &cinode->llist, llist) {
|
||||
rc = cifs_find_fid_lock_conflict(cur, offset, length, type,
|
||||
cfile, conf_lock, rw_check);
|
||||
flags, cfile, conf_lock,
|
||||
rw_check);
|
||||
if (rc)
|
||||
break;
|
||||
}
|
||||
@ -964,7 +973,8 @@ cifs_lock_test(struct cifsFileInfo *cfile, __u64 offset, __u64 length,
|
||||
down_read(&cinode->lock_sem);
|
||||
|
||||
exist = cifs_find_lock_conflict(cfile, offset, length, type,
|
||||
&conf_lock, CIFS_LOCK_OP);
|
||||
flock->fl_flags, &conf_lock,
|
||||
CIFS_LOCK_OP);
|
||||
if (exist) {
|
||||
flock->fl_start = conf_lock->offset;
|
||||
flock->fl_end = conf_lock->offset + conf_lock->length - 1;
|
||||
@ -1011,7 +1021,8 @@ try_again:
|
||||
down_write(&cinode->lock_sem);
|
||||
|
||||
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) {
|
||||
list_add_tail(&lock->llist, &cfile->llist->locks);
|
||||
up_write(&cinode->lock_sem);
|
||||
@ -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");
|
||||
if (flock->fl_flags &
|
||||
(~(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);
|
||||
|
||||
*type = server->vals->large_lock_type;
|
||||
@ -1584,7 +1595,8 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
|
||||
if (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)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -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,
|
||||
tcon->ses->server);
|
||||
|
||||
cifs_sb = CIFS_FILE_SB(file);
|
||||
netfid = cfile->fid.netfid;
|
||||
cinode = CIFS_I(file_inode(file));
|
||||
@ -2098,6 +2109,7 @@ static int cifs_writepages(struct address_space *mapping,
|
||||
pgoff_t end, index;
|
||||
struct cifs_writedata *wdata;
|
||||
int rc = 0;
|
||||
unsigned int xid;
|
||||
|
||||
/*
|
||||
* If wsize is smaller than the page cache size, default to writing
|
||||
@ -2106,6 +2118,7 @@ static int cifs_writepages(struct address_space *mapping,
|
||||
if (cifs_sb->wsize < PAGE_SIZE)
|
||||
return generic_writepages(mapping, wbc);
|
||||
|
||||
xid = get_xid();
|
||||
if (wbc->range_cyclic) {
|
||||
index = mapping->writeback_index; /* Start from prev offset */
|
||||
end = -1;
|
||||
@ -2199,6 +2212,7 @@ retry:
|
||||
if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
|
||||
mapping->writeback_index = index;
|
||||
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -2817,8 +2831,8 @@ cifs_writev(struct kiocb *iocb, struct iov_iter *from)
|
||||
goto out;
|
||||
|
||||
if (!cifs_find_lock_conflict(cfile, iocb->ki_pos, iov_iter_count(from),
|
||||
server->vals->exclusive_lock_type, NULL,
|
||||
CIFS_WRITE_OP))
|
||||
server->vals->exclusive_lock_type, 0,
|
||||
NULL, CIFS_WRITE_OP))
|
||||
rc = __generic_file_write_iter(iocb, from);
|
||||
else
|
||||
rc = -EACCES;
|
||||
@ -3388,7 +3402,7 @@ cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to)
|
||||
down_read(&cinode->lock_sem);
|
||||
if (!cifs_find_lock_conflict(cfile, iocb->ki_pos, iov_iter_count(to),
|
||||
tcon->ses->server->vals->shared_lock_type,
|
||||
NULL, CIFS_READ_OP))
|
||||
0, NULL, CIFS_READ_OP))
|
||||
rc = generic_file_read_iter(iocb, to);
|
||||
up_read(&cinode->lock_sem);
|
||||
return rc;
|
||||
@ -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 TCP_Server_Info *server;
|
||||
pid_t pid;
|
||||
unsigned int xid;
|
||||
|
||||
xid = get_xid();
|
||||
/*
|
||||
* Reads as many pages as possible from fscache. Returns -ENOBUFS
|
||||
* immediately if the cookie is negative
|
||||
@ -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,
|
||||
&num_pages);
|
||||
if (rc == 0)
|
||||
if (rc == 0) {
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
|
||||
pid = open_file->pid;
|
||||
@ -3798,6 +3816,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
|
||||
*/
|
||||
if (unlikely(rsize < PAGE_SIZE)) {
|
||||
add_credits_and_wake_if(server, credits, 0);
|
||||
free_xid(xid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3862,6 +3881,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
|
||||
* allocator.
|
||||
*/
|
||||
cifs_fscache_readpages_cancel(mapping->host, page_list);
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -3889,8 +3909,12 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
|
||||
else
|
||||
cifs_dbg(FYI, "Bytes read %d\n", rc);
|
||||
|
||||
file_inode(file)->i_atime =
|
||||
current_time(file_inode(file));
|
||||
/* we do not want atime to be less than mtime, it broke some apps */
|
||||
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)
|
||||
memset(read_data + rc, 0, PAGE_SIZE - rc);
|
||||
|
@ -162,7 +162,11 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
|
||||
cifs_revalidate_cache(inode, fattr);
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
inode->i_atime = fattr->cf_atime;
|
||||
/* 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_mtime = fattr->cf_mtime;
|
||||
inode->i_ctime = fattr->cf_ctime;
|
||||
inode->i_rdev = fattr->cf_rdev;
|
||||
@ -777,38 +781,53 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
|
||||
} else if (rc == -EREMOTE) {
|
||||
cifs_create_dfs_fattr(&fattr, sb);
|
||||
rc = 0;
|
||||
} else if (rc == -EACCES && backup_cred(cifs_sb)) {
|
||||
srchinf = kzalloc(sizeof(struct cifs_search_info),
|
||||
GFP_KERNEL);
|
||||
if (srchinf == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto cgii_exit;
|
||||
}
|
||||
} 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->endOfSearch = false;
|
||||
srchinf = kzalloc(sizeof(struct cifs_search_info),
|
||||
GFP_KERNEL);
|
||||
if (srchinf == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto cgii_exit;
|
||||
}
|
||||
|
||||
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;
|
||||
else /* no srvino useful for fallback to some netapp */
|
||||
srchinf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
|
||||
|
||||
srchflgs = CIFS_SEARCH_CLOSE_ALWAYS |
|
||||
CIFS_SEARCH_CLOSE_AT_END |
|
||||
CIFS_SEARCH_BACKUP_SEARCH;
|
||||
srchflgs = CIFS_SEARCH_CLOSE_ALWAYS |
|
||||
CIFS_SEARCH_CLOSE_AT_END |
|
||||
CIFS_SEARCH_BACKUP_SEARCH;
|
||||
|
||||
rc = CIFSFindFirst(xid, tcon, full_path,
|
||||
cifs_sb, NULL, srchflgs, srchinf, false);
|
||||
if (!rc) {
|
||||
data =
|
||||
(FILE_ALL_INFO *)srchinf->srch_entries_start;
|
||||
rc = CIFSFindFirst(xid, tcon, full_path,
|
||||
cifs_sb, NULL, srchflgs, srchinf, false);
|
||||
if (!rc) {
|
||||
data = (FILE_ALL_INFO *)srchinf->srch_entries_start;
|
||||
|
||||
cifs_dir_info_to_fattr(&fattr,
|
||||
(FILE_DIRECTORY_INFO *)data, cifs_sb);
|
||||
fattr.cf_uniqueid = le64_to_cpu(
|
||||
((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId);
|
||||
validinum = true;
|
||||
cifs_dir_info_to_fattr(&fattr,
|
||||
(FILE_DIRECTORY_INFO *)data, cifs_sb);
|
||||
fattr.cf_uniqueid = le64_to_cpu(
|
||||
((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId);
|
||||
validinum = true;
|
||||
|
||||
cifs_buf_release(srchinf->ntwrk_buf_start);
|
||||
}
|
||||
kfree(srchinf);
|
||||
if (rc)
|
||||
goto cgii_exit;
|
||||
cifs_buf_release(srchinf->ntwrk_buf_start);
|
||||
}
|
||||
kfree(srchinf);
|
||||
if (rc)
|
||||
goto cgii_exit;
|
||||
} else
|
||||
goto cgii_exit;
|
||||
|
||||
|
@ -32,8 +32,51 @@
|
||||
#include "cifs_debug.h"
|
||||
#include "cifsfs.h"
|
||||
#include "cifs_ioctl.h"
|
||||
#include "smb2proto.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,
|
||||
unsigned long srcfd)
|
||||
{
|
||||
@ -123,7 +166,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
|
||||
struct inode *inode = file_inode(filep);
|
||||
int rc = -ENOTTY; /* strange error - but the precedent */
|
||||
unsigned int xid;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifsFileInfo *pSMBFile = filep->private_data;
|
||||
struct cifs_tcon *tcon;
|
||||
__u64 ExtAttrBits = 0;
|
||||
@ -131,7 +173,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
|
||||
|
||||
xid = get_xid();
|
||||
|
||||
cifs_sb = CIFS_SB(inode->i_sb);
|
||||
cifs_dbg(FYI, "cifs ioctl 0x%x\n", command);
|
||||
switch (command) {
|
||||
case FS_IOC_GETFLAGS:
|
||||
@ -196,6 +237,9 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
|
||||
case CIFS_IOC_COPYCHUNK_FILE:
|
||||
rc = cifs_ioctl_copychunk(xid, filep, arg);
|
||||
break;
|
||||
case CIFS_QUERY_INFO:
|
||||
rc = cifs_ioctl_query_info(xid, filep, arg);
|
||||
break;
|
||||
case CIFS_IOC_SET_INTEGRITY:
|
||||
if (pSMBFile == NULL)
|
||||
break;
|
||||
|
@ -123,6 +123,8 @@ tconInfoAlloc(void)
|
||||
ret_buf->crfid.fid = kzalloc(sizeof(struct cifs_fid),
|
||||
GFP_KERNEL);
|
||||
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;
|
||||
}
|
||||
|
@ -33,7 +33,7 @@
|
||||
|
||||
/*
|
||||
* 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_INFO 2
|
||||
|
@ -38,54 +38,83 @@
|
||||
#include "smb2proto.h"
|
||||
|
||||
static int
|
||||
smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *full_path,
|
||||
__u32 desired_access, __u32 create_disposition,
|
||||
__u32 create_options, void *data, int command)
|
||||
smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *full_path,
|
||||
__u32 desired_access, __u32 create_disposition,
|
||||
__u32 create_options, void *ptr, int command)
|
||||
{
|
||||
int rc, tmprc = 0;
|
||||
int rc;
|
||||
__le16 *utf16_path = NULL;
|
||||
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
struct cifs_open_parms oparms;
|
||||
struct cifs_fid fid;
|
||||
bool use_cached_root_handle = false;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
int num_rqst = 0;
|
||||
struct smb_rqst rqst[3];
|
||||
int resp_buftype[3];
|
||||
struct kvec rsp_iov[3];
|
||||
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
||||
struct kvec qi_iov[1];
|
||||
struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
|
||||
struct kvec close_iov[1];
|
||||
struct smb2_query_info_rsp *qi_rsp = NULL;
|
||||
int flags = 0;
|
||||
__u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0};
|
||||
unsigned int size[2];
|
||||
void *data[2];
|
||||
struct smb2_file_rename_info rename_info;
|
||||
struct smb2_file_link_info link_info;
|
||||
int len;
|
||||
|
||||
if ((strcmp(full_path, "") == 0) && (create_options == 0) &&
|
||||
(desired_access == FILE_READ_ATTRIBUTES) &&
|
||||
(create_disposition == FILE_OPEN) &&
|
||||
(tcon->nohandlecache == false)) {
|
||||
rc = open_shroot(xid, tcon, &fid);
|
||||
if (rc == 0)
|
||||
use_cached_root_handle = true;
|
||||
}
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
if (use_cached_root_handle == false) {
|
||||
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
||||
if (!utf16_path)
|
||||
return -ENOMEM;
|
||||
memset(rqst, 0, sizeof(rqst));
|
||||
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
||||
memset(rsp_iov, 0, sizeof(rsp_iov));
|
||||
|
||||
oparms.tcon = tcon;
|
||||
oparms.desired_access = desired_access;
|
||||
oparms.disposition = create_disposition;
|
||||
oparms.create_options = create_options;
|
||||
oparms.fid = &fid;
|
||||
oparms.reconnect = false;
|
||||
/* Open */
|
||||
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
||||
if (!utf16_path)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL,
|
||||
NULL);
|
||||
if (rc) {
|
||||
kfree(utf16_path);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
oparms.tcon = tcon;
|
||||
oparms.desired_access = desired_access;
|
||||
oparms.disposition = create_disposition;
|
||||
oparms.create_options = create_options;
|
||||
if (backup_cred(cifs_sb))
|
||||
oparms.create_options |= CREATE_OPEN_BACKUP_INTENT;
|
||||
oparms.fid = &fid;
|
||||
oparms.reconnect = false;
|
||||
|
||||
memset(&open_iov, 0, sizeof(open_iov));
|
||||
rqst[num_rqst].rq_iov = open_iov;
|
||||
rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
||||
rc = SMB2_open_init(tcon, &rqst[num_rqst], &oplock, &oparms,
|
||||
utf16_path);
|
||||
kfree(utf16_path);
|
||||
if (rc)
|
||||
goto finished;
|
||||
|
||||
smb2_set_next_command(server, &rqst[num_rqst++]);
|
||||
|
||||
/* Operation */
|
||||
switch (command) {
|
||||
case SMB2_OP_DELETE:
|
||||
break;
|
||||
case SMB2_OP_QUERY_INFO:
|
||||
tmprc = SMB2_query_info(xid, tcon, fid.persistent_fid,
|
||||
fid.volatile_fid,
|
||||
(struct smb2_file_all_info *)data);
|
||||
memset(&qi_iov, 0, sizeof(qi_iov));
|
||||
rqst[num_rqst].rq_iov = qi_iov;
|
||||
rqst[num_rqst].rq_nvec = 1;
|
||||
|
||||
rc = SMB2_query_info_init(tcon, &rqst[num_rqst], COMPOUND_FID,
|
||||
COMPOUND_FID, FILE_ALL_INFORMATION,
|
||||
SMB2_O_INFO_FILE, 0,
|
||||
sizeof(struct smb2_file_all_info) +
|
||||
PATH_MAX * 2, 0, NULL);
|
||||
smb2_set_next_command(server, &rqst[num_rqst]);
|
||||
smb2_set_related(&rqst[num_rqst++]);
|
||||
break;
|
||||
case SMB2_OP_DELETE:
|
||||
break;
|
||||
case SMB2_OP_MKDIR:
|
||||
/*
|
||||
@ -94,39 +123,156 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
*/
|
||||
break;
|
||||
case SMB2_OP_RMDIR:
|
||||
tmprc = SMB2_rmdir(xid, tcon, fid.persistent_fid,
|
||||
fid.volatile_fid);
|
||||
break;
|
||||
case SMB2_OP_RENAME:
|
||||
tmprc = SMB2_rename(xid, tcon, fid.persistent_fid,
|
||||
fid.volatile_fid, (__le16 *)data);
|
||||
break;
|
||||
case SMB2_OP_HARDLINK:
|
||||
tmprc = SMB2_set_hardlink(xid, tcon, fid.persistent_fid,
|
||||
fid.volatile_fid, (__le16 *)data);
|
||||
memset(&si_iov, 0, sizeof(si_iov));
|
||||
rqst[num_rqst].rq_iov = si_iov;
|
||||
rqst[num_rqst].rq_nvec = 1;
|
||||
|
||||
size[0] = 8;
|
||||
data[0] = &delete_pending[0];
|
||||
|
||||
rc = SMB2_set_info_init(tcon, &rqst[num_rqst], COMPOUND_FID,
|
||||
COMPOUND_FID, current->tgid,
|
||||
FILE_DISPOSITION_INFORMATION,
|
||||
SMB2_O_INFO_FILE, 0, data, size);
|
||||
smb2_set_next_command(server, &rqst[num_rqst]);
|
||||
smb2_set_related(&rqst[num_rqst++]);
|
||||
break;
|
||||
case SMB2_OP_SET_EOF:
|
||||
tmprc = SMB2_set_eof(xid, tcon, fid.persistent_fid,
|
||||
fid.volatile_fid, current->tgid,
|
||||
(__le64 *)data, false);
|
||||
memset(&si_iov, 0, sizeof(si_iov));
|
||||
rqst[num_rqst].rq_iov = si_iov;
|
||||
rqst[num_rqst].rq_nvec = 1;
|
||||
|
||||
size[0] = 8; /* sizeof __le64 */
|
||||
data[0] = ptr;
|
||||
|
||||
rc = SMB2_set_info_init(tcon, &rqst[num_rqst], COMPOUND_FID,
|
||||
COMPOUND_FID, current->tgid,
|
||||
FILE_END_OF_FILE_INFORMATION,
|
||||
SMB2_O_INFO_FILE, 0, data, size);
|
||||
smb2_set_next_command(server, &rqst[num_rqst]);
|
||||
smb2_set_related(&rqst[num_rqst++]);
|
||||
break;
|
||||
case SMB2_OP_SET_INFO:
|
||||
tmprc = SMB2_set_info(xid, tcon, fid.persistent_fid,
|
||||
fid.volatile_fid,
|
||||
(FILE_BASIC_INFO *)data);
|
||||
memset(&si_iov, 0, sizeof(si_iov));
|
||||
rqst[num_rqst].rq_iov = si_iov;
|
||||
rqst[num_rqst].rq_nvec = 1;
|
||||
|
||||
|
||||
size[0] = sizeof(FILE_BASIC_INFO);
|
||||
data[0] = ptr;
|
||||
|
||||
rc = SMB2_set_info_init(tcon, &rqst[num_rqst], COMPOUND_FID,
|
||||
COMPOUND_FID, current->tgid,
|
||||
FILE_BASIC_INFORMATION,
|
||||
SMB2_O_INFO_FILE, 0, data, size);
|
||||
smb2_set_next_command(server, &rqst[num_rqst]);
|
||||
smb2_set_related(&rqst[num_rqst++]);
|
||||
break;
|
||||
case SMB2_OP_RENAME:
|
||||
memset(&si_iov, 0, sizeof(si_iov));
|
||||
rqst[num_rqst].rq_iov = si_iov;
|
||||
rqst[num_rqst].rq_nvec = 2;
|
||||
|
||||
len = (2 * UniStrnlen((wchar_t *)ptr, PATH_MAX));
|
||||
|
||||
rename_info.ReplaceIfExists = 1;
|
||||
rename_info.RootDirectory = 0;
|
||||
rename_info.FileNameLength = cpu_to_le32(len);
|
||||
|
||||
size[0] = sizeof(struct smb2_file_rename_info);
|
||||
data[0] = &rename_info;
|
||||
|
||||
size[1] = len + 2 /* null */;
|
||||
data[1] = (__le16 *)ptr;
|
||||
|
||||
rc = SMB2_set_info_init(tcon, &rqst[num_rqst], COMPOUND_FID,
|
||||
COMPOUND_FID, current->tgid,
|
||||
FILE_RENAME_INFORMATION,
|
||||
SMB2_O_INFO_FILE, 0, data, size);
|
||||
smb2_set_next_command(server, &rqst[num_rqst]);
|
||||
smb2_set_related(&rqst[num_rqst++]);
|
||||
break;
|
||||
case SMB2_OP_HARDLINK:
|
||||
memset(&si_iov, 0, sizeof(si_iov));
|
||||
rqst[num_rqst].rq_iov = si_iov;
|
||||
rqst[num_rqst].rq_nvec = 2;
|
||||
|
||||
len = (2 * UniStrnlen((wchar_t *)ptr, PATH_MAX));
|
||||
|
||||
link_info.ReplaceIfExists = 0;
|
||||
link_info.RootDirectory = 0;
|
||||
link_info.FileNameLength = cpu_to_le32(len);
|
||||
|
||||
size[0] = sizeof(struct smb2_file_link_info);
|
||||
data[0] = &link_info;
|
||||
|
||||
size[1] = len + 2 /* null */;
|
||||
data[1] = (__le16 *)ptr;
|
||||
|
||||
rc = SMB2_set_info_init(tcon, &rqst[num_rqst], COMPOUND_FID,
|
||||
COMPOUND_FID, current->tgid,
|
||||
FILE_LINK_INFORMATION,
|
||||
SMB2_O_INFO_FILE, 0, data, size);
|
||||
smb2_set_next_command(server, &rqst[num_rqst]);
|
||||
smb2_set_related(&rqst[num_rqst++]);
|
||||
break;
|
||||
default:
|
||||
cifs_dbg(VFS, "Invalid command\n");
|
||||
rc = -EINVAL;
|
||||
}
|
||||
if (rc)
|
||||
goto finished;
|
||||
|
||||
/* Close */
|
||||
memset(&close_iov, 0, sizeof(close_iov));
|
||||
rqst[num_rqst].rq_iov = close_iov;
|
||||
rqst[num_rqst].rq_nvec = 1;
|
||||
rc = SMB2_close_init(tcon, &rqst[num_rqst], COMPOUND_FID,
|
||||
COMPOUND_FID);
|
||||
smb2_set_related(&rqst[num_rqst++]);
|
||||
if (rc)
|
||||
goto finished;
|
||||
|
||||
rc = compound_send_recv(xid, ses, flags, num_rqst, rqst,
|
||||
resp_buftype, rsp_iov);
|
||||
|
||||
finished:
|
||||
SMB2_open_free(&rqst[0]);
|
||||
switch (command) {
|
||||
case SMB2_OP_QUERY_INFO:
|
||||
if (rc == 0) {
|
||||
qi_rsp = (struct smb2_query_info_rsp *)
|
||||
rsp_iov[1].iov_base;
|
||||
rc = smb2_validate_and_copy_iov(
|
||||
le16_to_cpu(qi_rsp->OutputBufferOffset),
|
||||
le32_to_cpu(qi_rsp->OutputBufferLength),
|
||||
&rsp_iov[1], sizeof(struct smb2_file_all_info),
|
||||
ptr);
|
||||
}
|
||||
if (rqst[1].rq_iov)
|
||||
SMB2_query_info_free(&rqst[1]);
|
||||
if (rqst[2].rq_iov)
|
||||
SMB2_close_free(&rqst[2]);
|
||||
break;
|
||||
case SMB2_OP_DELETE:
|
||||
case SMB2_OP_MKDIR:
|
||||
if (rqst[1].rq_iov)
|
||||
SMB2_close_free(&rqst[1]);
|
||||
break;
|
||||
case SMB2_OP_HARDLINK:
|
||||
case SMB2_OP_RENAME:
|
||||
case SMB2_OP_RMDIR:
|
||||
case SMB2_OP_SET_EOF:
|
||||
case SMB2_OP_SET_INFO:
|
||||
if (rqst[1].rq_iov)
|
||||
SMB2_set_info_free(&rqst[1]);
|
||||
if (rqst[2].rq_iov)
|
||||
SMB2_close_free(&rqst[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (use_cached_root_handle)
|
||||
close_shroot(&tcon->crfid);
|
||||
else
|
||||
rc = SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
if (tmprc)
|
||||
rc = tmprc;
|
||||
kfree(utf16_path);
|
||||
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
||||
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
||||
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -147,6 +293,7 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
{
|
||||
int rc;
|
||||
struct smb2_file_all_info *smb2_data;
|
||||
__u32 create_options = 0;
|
||||
|
||||
*adjust_tz = false;
|
||||
*symlink = false;
|
||||
@ -155,17 +302,21 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
GFP_KERNEL);
|
||||
if (smb2_data == NULL)
|
||||
return -ENOMEM;
|
||||
if (backup_cred(cifs_sb))
|
||||
create_options |= CREATE_OPEN_BACKUP_INTENT;
|
||||
|
||||
rc = smb2_open_op_close(xid, tcon, cifs_sb, full_path,
|
||||
FILE_READ_ATTRIBUTES, FILE_OPEN, 0,
|
||||
smb2_data, SMB2_OP_QUERY_INFO);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
FILE_READ_ATTRIBUTES, FILE_OPEN, create_options,
|
||||
smb2_data, SMB2_OP_QUERY_INFO);
|
||||
if (rc == -EOPNOTSUPP) {
|
||||
*symlink = true;
|
||||
create_options |= OPEN_REPARSE_POINT;
|
||||
|
||||
/* Failed on a symbolic link - query a reparse point info */
|
||||
rc = smb2_open_op_close(xid, tcon, cifs_sb, full_path,
|
||||
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||
OPEN_REPARSE_POINT, smb2_data,
|
||||
SMB2_OP_QUERY_INFO);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||
create_options, smb2_data,
|
||||
SMB2_OP_QUERY_INFO);
|
||||
}
|
||||
if (rc)
|
||||
goto out;
|
||||
@ -180,9 +331,9 @@ int
|
||||
smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
return smb2_open_op_close(xid, tcon, cifs_sb, name,
|
||||
FILE_WRITE_ATTRIBUTES, FILE_CREATE,
|
||||
CREATE_NOT_FILE, NULL, SMB2_OP_MKDIR);
|
||||
return smb2_compound_op(xid, tcon, cifs_sb, name,
|
||||
FILE_WRITE_ATTRIBUTES, FILE_CREATE,
|
||||
CREATE_NOT_FILE, NULL, SMB2_OP_MKDIR);
|
||||
}
|
||||
|
||||
void
|
||||
@ -199,9 +350,9 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name,
|
||||
cifs_i = CIFS_I(inode);
|
||||
dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
|
||||
data.Attributes = cpu_to_le32(dosattrs);
|
||||
tmprc = smb2_open_op_close(xid, tcon, cifs_sb, name,
|
||||
FILE_WRITE_ATTRIBUTES, FILE_CREATE,
|
||||
CREATE_NOT_FILE, &data, SMB2_OP_SET_INFO);
|
||||
tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
|
||||
FILE_WRITE_ATTRIBUTES, FILE_CREATE,
|
||||
CREATE_NOT_FILE, &data, SMB2_OP_SET_INFO);
|
||||
if (tmprc == 0)
|
||||
cifs_i->cifsAttrs = dosattrs;
|
||||
}
|
||||
@ -210,18 +361,18 @@ int
|
||||
smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
|
||||
CREATE_NOT_FILE,
|
||||
NULL, SMB2_OP_RMDIR);
|
||||
return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
|
||||
CREATE_NOT_FILE,
|
||||
NULL, SMB2_OP_RMDIR);
|
||||
}
|
||||
|
||||
int
|
||||
smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
|
||||
CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
|
||||
NULL, SMB2_OP_DELETE);
|
||||
return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
|
||||
CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
|
||||
NULL, SMB2_OP_DELETE);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -238,8 +389,8 @@ smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
goto smb2_rename_path;
|
||||
}
|
||||
|
||||
rc = smb2_open_op_close(xid, tcon, cifs_sb, from_name, access,
|
||||
FILE_OPEN, 0, smb2_to_name, command);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
|
||||
FILE_OPEN, 0, smb2_to_name, command);
|
||||
smb2_rename_path:
|
||||
kfree(smb2_to_name);
|
||||
return rc;
|
||||
@ -269,9 +420,10 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, bool set_alloc)
|
||||
{
|
||||
__le64 eof = cpu_to_le64(size);
|
||||
return smb2_open_op_close(xid, tcon, cifs_sb, full_path,
|
||||
FILE_WRITE_DATA, FILE_OPEN, 0, &eof,
|
||||
SMB2_OP_SET_EOF);
|
||||
|
||||
return smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
FILE_WRITE_DATA, FILE_OPEN, 0, &eof,
|
||||
SMB2_OP_SET_EOF);
|
||||
}
|
||||
|
||||
int
|
||||
@ -291,9 +443,9 @@ smb2_set_file_info(struct inode *inode, const char *full_path,
|
||||
if (IS_ERR(tlink))
|
||||
return PTR_ERR(tlink);
|
||||
|
||||
rc = smb2_open_op_close(xid, tlink_tcon(tlink), cifs_sb, full_path,
|
||||
FILE_WRITE_ATTRIBUTES, FILE_OPEN, 0, buf,
|
||||
SMB2_OP_SET_INFO);
|
||||
rc = smb2_compound_op(xid, tlink_tcon(tlink), cifs_sb, full_path,
|
||||
FILE_WRITE_ATTRIBUTES, FILE_OPEN, 0, buf,
|
||||
SMB2_OP_SET_INFO);
|
||||
cifs_put_tlink(tlink);
|
||||
return rc;
|
||||
}
|
||||
|
@ -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_FVE_PARTIAL_METADATA, -EIO, "STATUS_FVE_PARTIAL_METADATA"},
|
||||
{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_INFO_LENGTH_MISMATCH, -EIO, "STATUS_INFO_LENGTH_MISMATCH"},
|
||||
{STATUS_ACCESS_VIOLATION, -EACCES, "STATUS_ACCESS_VIOLATION"},
|
||||
|
@ -74,6 +74,12 @@ smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
|
||||
int *val, rc = 0;
|
||||
spin_lock(&server->req_lock);
|
||||
val = server->ops->get_credits_field(server, optype);
|
||||
|
||||
/* eg found case where write overlapping reconnect messed up credits */
|
||||
if (((optype & CIFS_OP_MASK) == CIFS_NEG_OP) && (*val != 0))
|
||||
trace_smb3_reconnect_with_invalid_credits(server->CurrentMid,
|
||||
server->hostname, *val);
|
||||
|
||||
*val += add;
|
||||
if (*val > 65000) {
|
||||
*val = 65000; /* Don't get near 64K credits, avoid srv bugs */
|
||||
@ -104,7 +110,12 @@ smb2_set_credits(struct TCP_Server_Info *server, const int val)
|
||||
{
|
||||
spin_lock(&server->req_lock);
|
||||
server->credits = val;
|
||||
if (val == 1)
|
||||
server->reconnect_instance++;
|
||||
spin_unlock(&server->req_lock);
|
||||
/* don't log while holding the lock */
|
||||
if (val == 1)
|
||||
cifs_dbg(FYI, "set credits to 1 due to smb2 reconnect\n");
|
||||
}
|
||||
|
||||
static int *
|
||||
@ -269,6 +280,31 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
|
||||
return wsize;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
|
||||
{
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
unsigned int wsize;
|
||||
|
||||
/* start with specified wsize, or default */
|
||||
wsize = volume_info->wsize ? volume_info->wsize : SMB3_DEFAULT_IOSIZE;
|
||||
wsize = min_t(unsigned int, wsize, server->max_write);
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
if (server->rdma) {
|
||||
if (server->sign)
|
||||
wsize = min_t(unsigned int,
|
||||
wsize, server->smbd_conn->max_fragmented_send_size);
|
||||
else
|
||||
wsize = min_t(unsigned int,
|
||||
wsize, server->smbd_conn->max_readwrite_size);
|
||||
}
|
||||
#endif
|
||||
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
|
||||
wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE);
|
||||
|
||||
return wsize;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
|
||||
{
|
||||
@ -295,6 +331,31 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
|
||||
return rsize;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
|
||||
{
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
unsigned int rsize;
|
||||
|
||||
/* start with specified rsize, or default */
|
||||
rsize = volume_info->rsize ? volume_info->rsize : SMB3_DEFAULT_IOSIZE;
|
||||
rsize = min_t(unsigned int, rsize, server->max_read);
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
if (server->rdma) {
|
||||
if (server->sign)
|
||||
rsize = min_t(unsigned int,
|
||||
rsize, server->smbd_conn->max_fragmented_recv_size);
|
||||
else
|
||||
rsize = min_t(unsigned int,
|
||||
rsize, server->smbd_conn->max_readwrite_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
|
||||
rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE);
|
||||
|
||||
return rsize;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
|
||||
@ -962,6 +1023,9 @@ smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
|
||||
seq_printf(m, "\nBytes read: %llu Bytes written: %llu",
|
||||
(long long)(tcon->bytes_read),
|
||||
(long long)(tcon->bytes_written));
|
||||
seq_printf(m, "\nOpen files: %d total (local), %d open on server",
|
||||
atomic_read(&tcon->num_local_opens),
|
||||
atomic_read(&tcon->num_remote_opens));
|
||||
seq_printf(m, "\nTreeConnects: %d total %d failed",
|
||||
atomic_read(&sent[SMB2_TREE_CONNECT_HE]),
|
||||
atomic_read(&failed[SMB2_TREE_CONNECT_HE]));
|
||||
@ -1057,6 +1121,131 @@ req_res_key_exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
smb2_ioctl_query_info(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
__le16 *path, int is_dir,
|
||||
unsigned long p)
|
||||
{
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
char __user *arg = (char __user *)p;
|
||||
struct smb_query_info qi;
|
||||
struct smb_query_info __user *pqi;
|
||||
int rc = 0;
|
||||
int flags = 0;
|
||||
struct smb2_query_info_rsp *rsp = NULL;
|
||||
void *buffer = NULL;
|
||||
struct smb_rqst rqst[3];
|
||||
int resp_buftype[3];
|
||||
struct kvec rsp_iov[3];
|
||||
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
||||
struct cifs_open_parms oparms;
|
||||
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
struct cifs_fid fid;
|
||||
struct kvec qi_iov[1];
|
||||
struct kvec close_iov[1];
|
||||
|
||||
memset(rqst, 0, sizeof(rqst));
|
||||
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
||||
memset(rsp_iov, 0, sizeof(rsp_iov));
|
||||
|
||||
if (copy_from_user(&qi, arg, sizeof(struct smb_query_info)))
|
||||
return -EFAULT;
|
||||
|
||||
if (qi.output_buffer_length > 1024)
|
||||
return -EINVAL;
|
||||
|
||||
if (!ses || !(ses->server))
|
||||
return -EIO;
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
buffer = kmalloc(qi.output_buffer_length, GFP_KERNEL);
|
||||
if (buffer == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(buffer, arg + sizeof(struct smb_query_info),
|
||||
qi.output_buffer_length)) {
|
||||
rc = -EFAULT;
|
||||
goto iqinf_exit;
|
||||
}
|
||||
|
||||
/* Open */
|
||||
memset(&open_iov, 0, sizeof(open_iov));
|
||||
rqst[0].rq_iov = open_iov;
|
||||
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
||||
|
||||
memset(&oparms, 0, sizeof(oparms));
|
||||
oparms.tcon = tcon;
|
||||
oparms.desired_access = FILE_READ_ATTRIBUTES | READ_CONTROL;
|
||||
oparms.disposition = FILE_OPEN;
|
||||
if (is_dir)
|
||||
oparms.create_options = CREATE_NOT_FILE;
|
||||
else
|
||||
oparms.create_options = CREATE_NOT_DIR;
|
||||
oparms.fid = &fid;
|
||||
oparms.reconnect = false;
|
||||
|
||||
rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, path);
|
||||
if (rc)
|
||||
goto iqinf_exit;
|
||||
smb2_set_next_command(ses->server, &rqst[0]);
|
||||
|
||||
/* Query */
|
||||
memset(&qi_iov, 0, sizeof(qi_iov));
|
||||
rqst[1].rq_iov = qi_iov;
|
||||
rqst[1].rq_nvec = 1;
|
||||
|
||||
rc = SMB2_query_info_init(tcon, &rqst[1], COMPOUND_FID, COMPOUND_FID,
|
||||
qi.file_info_class, qi.info_type,
|
||||
qi.additional_information,
|
||||
qi.input_buffer_length,
|
||||
qi.output_buffer_length, buffer);
|
||||
if (rc)
|
||||
goto iqinf_exit;
|
||||
smb2_set_next_command(ses->server, &rqst[1]);
|
||||
smb2_set_related(&rqst[1]);
|
||||
|
||||
/* Close */
|
||||
memset(&close_iov, 0, sizeof(close_iov));
|
||||
rqst[2].rq_iov = close_iov;
|
||||
rqst[2].rq_nvec = 1;
|
||||
|
||||
rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
|
||||
if (rc)
|
||||
goto iqinf_exit;
|
||||
smb2_set_related(&rqst[2]);
|
||||
|
||||
rc = compound_send_recv(xid, ses, flags, 3, rqst,
|
||||
resp_buftype, rsp_iov);
|
||||
if (rc)
|
||||
goto iqinf_exit;
|
||||
pqi = (struct smb_query_info __user *)arg;
|
||||
rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
|
||||
if (le32_to_cpu(rsp->OutputBufferLength) < qi.input_buffer_length)
|
||||
qi.input_buffer_length = le32_to_cpu(rsp->OutputBufferLength);
|
||||
if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length,
|
||||
sizeof(qi.input_buffer_length))) {
|
||||
rc = -EFAULT;
|
||||
goto iqinf_exit;
|
||||
}
|
||||
if (copy_to_user(pqi + 1, rsp->Buffer, qi.input_buffer_length)) {
|
||||
rc = -EFAULT;
|
||||
goto iqinf_exit;
|
||||
}
|
||||
|
||||
iqinf_exit:
|
||||
kfree(buffer);
|
||||
SMB2_open_free(&rqst[0]);
|
||||
SMB2_query_info_free(&rqst[1]);
|
||||
SMB2_close_free(&rqst[2]);
|
||||
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
||||
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
||||
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
smb2_copychunk_range(const unsigned int xid,
|
||||
struct cifsFileInfo *srcfile,
|
||||
@ -1301,7 +1490,7 @@ smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
}
|
||||
|
||||
return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
|
||||
cfile->fid.volatile_fid, cfile->pid, &eof, false);
|
||||
cfile->fid.volatile_fid, cfile->pid, &eof);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1556,7 +1745,7 @@ smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
|
||||
CIFS_CACHE_READ(cinode) ? 1 : 0);
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
smb2_set_related(struct smb_rqst *rqst)
|
||||
{
|
||||
struct smb2_sync_hdr *shdr;
|
||||
@ -1567,7 +1756,7 @@ smb2_set_related(struct smb_rqst *rqst)
|
||||
|
||||
char smb2_padding[7] = {0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
static void
|
||||
void
|
||||
smb2_set_next_command(struct TCP_Server_Info *server, struct smb_rqst *rqst)
|
||||
{
|
||||
struct smb2_sync_hdr *shdr;
|
||||
@ -1610,7 +1799,7 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
memset(rqst, 0, sizeof(rqst));
|
||||
memset(resp_buftype, 0, sizeof(resp_buftype));
|
||||
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
||||
memset(rsp_iov, 0, sizeof(rsp_iov));
|
||||
|
||||
memset(&open_iov, 0, sizeof(open_iov));
|
||||
@ -1636,7 +1825,8 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
rc = SMB2_query_info_init(tcon, &rqst[1], COMPOUND_FID, COMPOUND_FID,
|
||||
FS_FULL_SIZE_INFORMATION,
|
||||
SMB2_O_INFO_FILESYSTEM, 0,
|
||||
sizeof(struct smb2_fs_full_size_info));
|
||||
sizeof(struct smb2_fs_full_size_info), 0,
|
||||
NULL);
|
||||
if (rc)
|
||||
goto qfs_exit;
|
||||
smb2_set_next_command(server, &rqst[1]);
|
||||
@ -3303,6 +3493,7 @@ struct smb_version_operations smb20_operations = {
|
||||
.set_acl = set_smb2_acl,
|
||||
#endif /* CIFS_ACL */
|
||||
.next_header = smb2_next_header,
|
||||
.ioctl_query_info = smb2_ioctl_query_info,
|
||||
};
|
||||
|
||||
struct smb_version_operations smb21_operations = {
|
||||
@ -3398,6 +3589,7 @@ struct smb_version_operations smb21_operations = {
|
||||
.set_acl = set_smb2_acl,
|
||||
#endif /* CIFS_ACL */
|
||||
.next_header = smb2_next_header,
|
||||
.ioctl_query_info = smb2_ioctl_query_info,
|
||||
};
|
||||
|
||||
struct smb_version_operations smb30_operations = {
|
||||
@ -3425,8 +3617,8 @@ struct smb_version_operations smb30_operations = {
|
||||
.downgrade_oplock = smb2_downgrade_oplock,
|
||||
.need_neg = smb2_need_neg,
|
||||
.negotiate = smb2_negotiate,
|
||||
.negotiate_wsize = smb2_negotiate_wsize,
|
||||
.negotiate_rsize = smb2_negotiate_rsize,
|
||||
.negotiate_wsize = smb3_negotiate_wsize,
|
||||
.negotiate_rsize = smb3_negotiate_rsize,
|
||||
.sess_setup = SMB2_sess_setup,
|
||||
.logoff = SMB2_logoff,
|
||||
.tree_connect = SMB2_tcon,
|
||||
@ -3502,6 +3694,7 @@ struct smb_version_operations smb30_operations = {
|
||||
.set_acl = set_smb2_acl,
|
||||
#endif /* CIFS_ACL */
|
||||
.next_header = smb2_next_header,
|
||||
.ioctl_query_info = smb2_ioctl_query_info,
|
||||
};
|
||||
|
||||
struct smb_version_operations smb311_operations = {
|
||||
@ -3529,8 +3722,8 @@ struct smb_version_operations smb311_operations = {
|
||||
.downgrade_oplock = smb2_downgrade_oplock,
|
||||
.need_neg = smb2_need_neg,
|
||||
.negotiate = smb2_negotiate,
|
||||
.negotiate_wsize = smb2_negotiate_wsize,
|
||||
.negotiate_rsize = smb2_negotiate_rsize,
|
||||
.negotiate_wsize = smb3_negotiate_wsize,
|
||||
.negotiate_rsize = smb3_negotiate_rsize,
|
||||
.sess_setup = SMB2_sess_setup,
|
||||
.logoff = SMB2_logoff,
|
||||
.tree_connect = SMB2_tcon,
|
||||
@ -3607,6 +3800,7 @@ struct smb_version_operations smb311_operations = {
|
||||
.set_acl = set_smb2_acl,
|
||||
#endif /* CIFS_ACL */
|
||||
.next_header = smb2_next_header,
|
||||
.ioctl_query_info = smb2_ioctl_query_info,
|
||||
};
|
||||
|
||||
struct smb_version_values smb20_values = {
|
||||
|
@ -1478,7 +1478,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
|
||||
|
||||
/* SMB2 TREE_CONNECT request must be called with TreeId == 0 */
|
||||
tcon->tid = 0;
|
||||
|
||||
atomic_set(&tcon->num_remote_opens, 0);
|
||||
rc = smb2_plain_req_init(SMB2_TREE_CONNECT, tcon, (void **) &req,
|
||||
&total_len);
|
||||
if (rc) {
|
||||
@ -2243,10 +2243,12 @@ SMB2_open_free(struct smb_rqst *rqst)
|
||||
{
|
||||
int i;
|
||||
|
||||
cifs_small_buf_release(rqst->rq_iov[0].iov_base);
|
||||
for (i = 1; i < rqst->rq_nvec; i++)
|
||||
if (rqst->rq_iov[i].iov_base != smb2_padding)
|
||||
kfree(rqst->rq_iov[i].iov_base);
|
||||
if (rqst && rqst->rq_iov) {
|
||||
cifs_small_buf_release(rqst->rq_iov[0].iov_base);
|
||||
for (i = 1; i < rqst->rq_nvec; i++)
|
||||
if (rqst->rq_iov[i].iov_base != smb2_padding)
|
||||
kfree(rqst->rq_iov[i].iov_base);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
@ -2261,7 +2263,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct kvec iov[SMB2_CREATE_IOV_SIZE];
|
||||
struct kvec rsp_iov = {NULL, 0};
|
||||
int resp_buftype;
|
||||
int resp_buftype = CIFS_NO_BUFFER;
|
||||
int rc = 0;
|
||||
int flags = 0;
|
||||
|
||||
@ -2303,6 +2305,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
||||
ses->Suid, oparms->create_options,
|
||||
oparms->desired_access);
|
||||
|
||||
atomic_inc(&tcon->num_remote_opens);
|
||||
oparms->fid->persistent_fid = rsp->PersistentFileId;
|
||||
oparms->fid->volatile_fid = rsp->VolatileFileId;
|
||||
|
||||
@ -2474,13 +2477,13 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
||||
goto ioctl_exit;
|
||||
}
|
||||
|
||||
*out_data = kmalloc(*plen, GFP_KERNEL);
|
||||
*out_data = kmemdup((char *)rsp + le32_to_cpu(rsp->OutputOffset),
|
||||
*plen, GFP_KERNEL);
|
||||
if (*out_data == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto ioctl_exit;
|
||||
}
|
||||
|
||||
memcpy(*out_data, (char *)rsp + le32_to_cpu(rsp->OutputOffset), *plen);
|
||||
ioctl_exit:
|
||||
free_rsp_buf(resp_buftype, rsp);
|
||||
return rc;
|
||||
@ -2535,7 +2538,8 @@ SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
|
||||
void
|
||||
SMB2_close_free(struct smb_rqst *rqst)
|
||||
{
|
||||
cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */
|
||||
if (rqst && rqst->rq_iov)
|
||||
cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */
|
||||
}
|
||||
|
||||
int
|
||||
@ -2547,7 +2551,7 @@ SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct kvec iov[1];
|
||||
struct kvec rsp_iov;
|
||||
int resp_buftype;
|
||||
int resp_buftype = CIFS_NO_BUFFER;
|
||||
int rc = 0;
|
||||
|
||||
cifs_dbg(FYI, "Close\n");
|
||||
@ -2577,6 +2581,8 @@ SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
goto close_exit;
|
||||
}
|
||||
|
||||
atomic_dec(&tcon->num_remote_opens);
|
||||
|
||||
/* BB FIXME - decode close response, update inode for caching */
|
||||
|
||||
close_exit:
|
||||
@ -2627,10 +2633,10 @@ smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
|
||||
* If SMB buffer fields are valid, copy into temporary buffer to hold result.
|
||||
* Caller must free buffer.
|
||||
*/
|
||||
static int
|
||||
validate_and_copy_iov(unsigned int offset, unsigned int buffer_length,
|
||||
struct kvec *iov, unsigned int minbufsize,
|
||||
char *data)
|
||||
int
|
||||
smb2_validate_and_copy_iov(unsigned int offset, unsigned int buffer_length,
|
||||
struct kvec *iov, unsigned int minbufsize,
|
||||
char *data)
|
||||
{
|
||||
char *begin_of_buf = offset + (char *)iov->iov_base;
|
||||
int rc;
|
||||
@ -2651,7 +2657,7 @@ int
|
||||
SMB2_query_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
|
||||
u64 persistent_fid, u64 volatile_fid,
|
||||
u8 info_class, u8 info_type, u32 additional_info,
|
||||
size_t output_len)
|
||||
size_t output_len, size_t input_len, void *input)
|
||||
{
|
||||
struct smb2_query_info_req *req;
|
||||
struct kvec *iov = rqst->rq_iov;
|
||||
@ -2669,23 +2675,25 @@ SMB2_query_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
|
||||
req->VolatileFileId = volatile_fid;
|
||||
req->AdditionalInformation = cpu_to_le32(additional_info);
|
||||
|
||||
/*
|
||||
* We do not use the input buffer (do not send extra byte)
|
||||
*/
|
||||
req->InputBufferOffset = 0;
|
||||
|
||||
req->OutputBufferLength = cpu_to_le32(output_len);
|
||||
if (input_len) {
|
||||
req->InputBufferLength = cpu_to_le32(input_len);
|
||||
/* total_len for smb query request never close to le16 max */
|
||||
req->InputBufferOffset = cpu_to_le16(total_len - 1);
|
||||
memcpy(req->Buffer, input, input_len);
|
||||
}
|
||||
|
||||
iov[0].iov_base = (char *)req;
|
||||
/* 1 for Buffer */
|
||||
iov[0].iov_len = total_len - 1;
|
||||
iov[0].iov_len = total_len - 1 + input_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
SMB2_query_info_free(struct smb_rqst *rqst)
|
||||
{
|
||||
cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */
|
||||
if (rqst && rqst->rq_iov)
|
||||
cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2699,7 +2707,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct kvec iov[1];
|
||||
struct kvec rsp_iov;
|
||||
int rc = 0;
|
||||
int resp_buftype;
|
||||
int resp_buftype = CIFS_NO_BUFFER;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
int flags = 0;
|
||||
|
||||
@ -2718,7 +2726,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
|
||||
rc = SMB2_query_info_init(tcon, &rqst, persistent_fid, volatile_fid,
|
||||
info_class, info_type, additional_info,
|
||||
output_len);
|
||||
output_len, 0, NULL);
|
||||
if (rc)
|
||||
goto qinf_exit;
|
||||
|
||||
@ -2746,9 +2754,9 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
}
|
||||
}
|
||||
|
||||
rc = validate_and_copy_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
||||
le32_to_cpu(rsp->OutputBufferLength),
|
||||
&rsp_iov, min_len, *data);
|
||||
rc = smb2_validate_and_copy_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
||||
le32_to_cpu(rsp->OutputBufferLength),
|
||||
&rsp_iov, min_len, *data);
|
||||
|
||||
qinf_exit:
|
||||
SMB2_query_info_free(&rqst);
|
||||
@ -3754,45 +3762,22 @@ qdir_exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
int
|
||||
SMB2_set_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
|
||||
u64 persistent_fid, u64 volatile_fid, u32 pid, u8 info_class,
|
||||
u8 info_type, u32 additional_info, unsigned int num,
|
||||
u8 info_type, u32 additional_info,
|
||||
void **data, unsigned int *size)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_set_info_req *req;
|
||||
struct smb2_set_info_rsp *rsp = NULL;
|
||||
struct kvec *iov;
|
||||
struct kvec rsp_iov;
|
||||
int rc = 0;
|
||||
int resp_buftype;
|
||||
unsigned int i;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
int flags = 0;
|
||||
unsigned int total_len;
|
||||
|
||||
if (!ses || !(ses->server))
|
||||
return -EIO;
|
||||
|
||||
if (!num)
|
||||
return -EINVAL;
|
||||
|
||||
iov = kmalloc_array(num, sizeof(struct kvec), GFP_KERNEL);
|
||||
if (!iov)
|
||||
return -ENOMEM;
|
||||
struct kvec *iov = rqst->rq_iov;
|
||||
unsigned int i, total_len;
|
||||
int rc;
|
||||
|
||||
rc = smb2_plain_req_init(SMB2_SET_INFO, tcon, (void **) &req, &total_len);
|
||||
if (rc) {
|
||||
kfree(iov);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
req->sync_hdr.ProcessId = cpu_to_le32(pid);
|
||||
|
||||
req->InfoType = info_type;
|
||||
req->FileInfoClass = info_class;
|
||||
req->PersistentFileId = persistent_fid;
|
||||
@ -3810,19 +3795,66 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
/* 1 for Buffer */
|
||||
iov[0].iov_len = total_len - 1;
|
||||
|
||||
for (i = 1; i < num; i++) {
|
||||
for (i = 1; i < rqst->rq_nvec; i++) {
|
||||
le32_add_cpu(&req->BufferLength, size[i]);
|
||||
iov[i].iov_base = (char *)data[i];
|
||||
iov[i].iov_len = size[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
SMB2_set_info_free(struct smb_rqst *rqst)
|
||||
{
|
||||
if (rqst && rqst->rq_iov)
|
||||
cifs_buf_release(rqst->rq_iov[0].iov_base); /* request */
|
||||
}
|
||||
|
||||
static int
|
||||
send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, u32 pid, u8 info_class,
|
||||
u8 info_type, u32 additional_info, unsigned int num,
|
||||
void **data, unsigned int *size)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_set_info_rsp *rsp = NULL;
|
||||
struct kvec *iov;
|
||||
struct kvec rsp_iov;
|
||||
int rc = 0;
|
||||
int resp_buftype;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
int flags = 0;
|
||||
|
||||
if (!ses || !(ses->server))
|
||||
return -EIO;
|
||||
|
||||
if (!num)
|
||||
return -EINVAL;
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
iov = kmalloc_array(num, sizeof(struct kvec), GFP_KERNEL);
|
||||
if (!iov)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(&rqst, 0, sizeof(struct smb_rqst));
|
||||
rqst.rq_iov = iov;
|
||||
rqst.rq_nvec = num;
|
||||
|
||||
rc = SMB2_set_info_init(tcon, &rqst, persistent_fid, volatile_fid, pid,
|
||||
info_class, info_type, additional_info,
|
||||
data, size);
|
||||
if (rc) {
|
||||
kfree(iov);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags,
|
||||
&rsp_iov);
|
||||
cifs_buf_release(req);
|
||||
SMB2_set_info_free(&rqst);
|
||||
rsp = (struct smb2_set_info_rsp *)rsp_iov.iov_base;
|
||||
|
||||
if (rc != 0) {
|
||||
@ -3836,89 +3868,9 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, __le16 *target_file)
|
||||
{
|
||||
struct smb2_file_rename_info info;
|
||||
void **data;
|
||||
unsigned int size[2];
|
||||
int rc;
|
||||
int len = (2 * UniStrnlen((wchar_t *)target_file, PATH_MAX));
|
||||
|
||||
data = kmalloc_array(2, sizeof(void *), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
info.ReplaceIfExists = 1; /* 1 = replace existing target with new */
|
||||
/* 0 = fail if target already exists */
|
||||
info.RootDirectory = 0; /* MBZ for network ops (why does spec say?) */
|
||||
info.FileNameLength = cpu_to_le32(len);
|
||||
|
||||
data[0] = &info;
|
||||
size[0] = sizeof(struct smb2_file_rename_info);
|
||||
|
||||
data[1] = target_file;
|
||||
size[1] = len + 2 /* null */;
|
||||
|
||||
rc = send_set_info(xid, tcon, persistent_fid, volatile_fid,
|
||||
current->tgid, FILE_RENAME_INFORMATION, SMB2_O_INFO_FILE,
|
||||
0, 2, data, size);
|
||||
kfree(data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
SMB2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid)
|
||||
{
|
||||
__u8 delete_pending = 1;
|
||||
void *data;
|
||||
unsigned int size;
|
||||
|
||||
data = &delete_pending;
|
||||
size = 1; /* sizeof __u8 */
|
||||
|
||||
return send_set_info(xid, tcon, persistent_fid, volatile_fid,
|
||||
current->tgid, FILE_DISPOSITION_INFORMATION, SMB2_O_INFO_FILE,
|
||||
0, 1, &data, &size);
|
||||
}
|
||||
|
||||
int
|
||||
SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, __le16 *target_file)
|
||||
{
|
||||
struct smb2_file_link_info info;
|
||||
void **data;
|
||||
unsigned int size[2];
|
||||
int rc;
|
||||
int len = (2 * UniStrnlen((wchar_t *)target_file, PATH_MAX));
|
||||
|
||||
data = kmalloc_array(2, sizeof(void *), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
info.ReplaceIfExists = 0; /* 1 = replace existing link with new */
|
||||
/* 0 = fail if link already exists */
|
||||
info.RootDirectory = 0; /* MBZ for network ops (why does spec say?) */
|
||||
info.FileNameLength = cpu_to_le32(len);
|
||||
|
||||
data[0] = &info;
|
||||
size[0] = sizeof(struct smb2_file_link_info);
|
||||
|
||||
data[1] = target_file;
|
||||
size[1] = len + 2 /* null */;
|
||||
|
||||
rc = send_set_info(xid, tcon, persistent_fid, volatile_fid,
|
||||
current->tgid, FILE_LINK_INFORMATION, SMB2_O_INFO_FILE,
|
||||
0, 2, data, size);
|
||||
kfree(data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
||||
u64 volatile_fid, u32 pid, __le64 *eof, bool is_falloc)
|
||||
u64 volatile_fid, u32 pid, __le64 *eof)
|
||||
{
|
||||
struct smb2_file_eof_info info;
|
||||
void *data;
|
||||
@ -3929,27 +3881,11 @@ SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
||||
data = &info;
|
||||
size = sizeof(struct smb2_file_eof_info);
|
||||
|
||||
if (is_falloc)
|
||||
return send_set_info(xid, tcon, persistent_fid, volatile_fid,
|
||||
pid, FILE_ALLOCATION_INFORMATION, SMB2_O_INFO_FILE,
|
||||
0, 1, &data, &size);
|
||||
else
|
||||
return send_set_info(xid, tcon, persistent_fid, volatile_fid,
|
||||
return send_set_info(xid, tcon, persistent_fid, volatile_fid,
|
||||
pid, FILE_END_OF_FILE_INFORMATION, SMB2_O_INFO_FILE,
|
||||
0, 1, &data, &size);
|
||||
}
|
||||
|
||||
int
|
||||
SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, FILE_BASIC_INFO *buf)
|
||||
{
|
||||
unsigned int size;
|
||||
size = sizeof(FILE_BASIC_INFO);
|
||||
return send_set_info(xid, tcon, persistent_fid, volatile_fid,
|
||||
current->tgid, FILE_BASIC_INFORMATION, SMB2_O_INFO_FILE,
|
||||
0, 1, (void **)&buf, &size);
|
||||
}
|
||||
|
||||
int
|
||||
SMB2_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid,
|
||||
@ -4350,6 +4286,8 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct kvec iov[1];
|
||||
struct kvec rsp_iov;
|
||||
int resp_buf_type;
|
||||
__u64 *please_key_high;
|
||||
__u64 *please_key_low;
|
||||
|
||||
cifs_dbg(FYI, "SMB2_lease_break\n");
|
||||
rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK, tcon, (void **) &req,
|
||||
@ -4379,10 +4317,16 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov);
|
||||
cifs_small_buf_release(req);
|
||||
|
||||
please_key_low = (__u64 *)req->LeaseKey;
|
||||
please_key_high = (__u64 *)(req->LeaseKey+8);
|
||||
if (rc) {
|
||||
cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE);
|
||||
trace_smb3_lease_err(le32_to_cpu(lease_state), tcon->tid,
|
||||
ses->Suid, *please_key_low, *please_key_high, rc);
|
||||
cifs_dbg(FYI, "Send error in Lease Break = %d\n", rc);
|
||||
}
|
||||
} else
|
||||
trace_smb3_lease_done(le32_to_cpu(lease_state), tcon->tid,
|
||||
ses->Suid, *please_key_low, *please_key_high);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -613,6 +613,8 @@ struct smb2_tree_disconnect_rsp {
|
||||
#define SVHDX_OPEN_DEVICE_CONTEX 0x9CCBCF9E04C1E643980E158DA1F6EC83
|
||||
#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.
|
||||
@ -650,7 +652,7 @@ struct smb2_create_rsp {
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 89 */
|
||||
__u8 OplockLevel;
|
||||
__u8 Reserved;
|
||||
__u8 Flag; /* 0x01 if reparse point */
|
||||
__le32 CreateAction;
|
||||
__le64 CreationTime;
|
||||
__le64 LastAccessTime;
|
||||
@ -1174,6 +1176,15 @@ struct smb2_query_info_rsp {
|
||||
__u8 Buffer[1];
|
||||
} __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_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 33 */
|
||||
|
@ -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 unsigned long smb_rqst_len(struct TCP_Server_Info *server,
|
||||
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
|
||||
@ -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,
|
||||
u64 persistent_fid, u64 volatile_fid,
|
||||
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 int SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_file_id, u64 volatile_file_id,
|
||||
@ -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,
|
||||
u64 persistent_fid, u64 volatile_fid, int index,
|
||||
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,
|
||||
u64 persistent_fid, u64 volatile_fid, u32 pid,
|
||||
__le64 *eof, bool is_fallocate);
|
||||
extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid,
|
||||
FILE_BASIC_INFO *buf);
|
||||
__le64 *eof);
|
||||
extern int SMB2_set_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
|
||||
u64 persistent_fid, u64 volatile_fid, u32 pid,
|
||||
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,
|
||||
u64 persistent_fid, u64 volatile_fid,
|
||||
struct cifs_ntsd *pnntsd, int pacllen, int aclflag);
|
||||
@ -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 smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
|
||||
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(
|
||||
struct smb2_fs_full_size_info *pfs_inf,
|
||||
struct kstatfs *kst);
|
||||
|
@ -2295,8 +2295,12 @@ static void smbd_mr_recovery_work(struct work_struct *work)
|
||||
int rc;
|
||||
|
||||
list_for_each_entry(smbdirect_mr, &info->mr_list, list) {
|
||||
if (smbdirect_mr->state == MR_INVALIDATED ||
|
||||
smbdirect_mr->state == MR_ERROR) {
|
||||
if (smbdirect_mr->state == MR_INVALIDATED)
|
||||
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 */
|
||||
rc = ib_dereg_mr(smbdirect_mr->mr);
|
||||
@ -2320,25 +2324,21 @@ static void smbd_mr_recovery_work(struct work_struct *work)
|
||||
smbd_disconnect_rdma_connection(info);
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
/* This MR is being used, don't recover it */
|
||||
continue;
|
||||
|
||||
if (smbdirect_mr->state == MR_INVALIDATED)
|
||||
ib_dma_unmap_sg(
|
||||
info->id->device, smbdirect_mr->sgl,
|
||||
smbdirect_mr->sgl_count,
|
||||
smbdirect_mr->dir);
|
||||
smbdirect_mr->state = MR_READY;
|
||||
|
||||
smbdirect_mr->state = MR_READY;
|
||||
|
||||
/* smbdirect_mr->state is updated by this function
|
||||
* and is read and updated by I/O issuing CPUs trying
|
||||
* to get a MR, the call to atomic_inc_return
|
||||
* implicates a memory barrier and guarantees this
|
||||
* value is updated before waking up any calls to
|
||||
* get_mr() from the I/O issuing CPUs
|
||||
*/
|
||||
if (atomic_inc_return(&info->mr_ready_count) == 1)
|
||||
wake_up_interruptible(&info->wait_mr);
|
||||
}
|
||||
/* smbdirect_mr->state is updated by this function
|
||||
* and is read and updated by I/O issuing CPUs trying
|
||||
* to get a MR, the call to atomic_inc_return
|
||||
* implicates a memory barrier and guarantees this
|
||||
* value is updated before waking up any calls to
|
||||
* get_mr() from the I/O issuing CPUs
|
||||
*/
|
||||
if (atomic_inc_return(&info->mr_ready_count) == 1)
|
||||
wake_up_interruptible(&info->wait_mr);
|
||||
}
|
||||
}
|
||||
|
||||
|
109
fs/cifs/trace.h
109
fs/cifs/trace.h
@ -460,6 +460,85 @@ DEFINE_EVENT(smb3_open_done_class, smb3_##name, \
|
||||
DEFINE_SMB3_OPEN_DONE_EVENT(open_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,
|
||||
TP_PROTO(__u64 currmid,
|
||||
char *hostname),
|
||||
@ -486,6 +565,36 @@ DEFINE_EVENT(smb3_reconnect_class, smb3_##name, \
|
||||
DEFINE_SMB3_RECONNECT_EVENT(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 */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
|
@ -113,9 +113,18 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
|
||||
cifs_small_buf_release(midEntry->resp_buf);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
now = jiffies;
|
||||
/* commands taking longer than one second are indications that
|
||||
something is wrong, unless it is quite a slow link or server */
|
||||
if (time_after(now, midEntry->when_alloc + HZ) &&
|
||||
/*
|
||||
* commands taking longer than one second (default) can be indications
|
||||
* 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)) {
|
||||
/* smb2slowcmd[NUMBER_OF_SMB2_COMMANDS] counts by command */
|
||||
if ((le16_to_cpu(midEntry->command) < NUMBER_OF_SMB2_COMMANDS) &&
|
||||
@ -128,7 +137,7 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
|
||||
if (cifsFYI & CIFS_TIMER) {
|
||||
pr_debug(" CIFS slow rsp: cmd %d mid %llu",
|
||||
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_sent,
|
||||
now - midEntry->when_received);
|
||||
@ -786,7 +795,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
int i, j, rc = 0;
|
||||
int timeout, optype;
|
||||
struct mid_q_entry *midQ[MAX_COMPOUND];
|
||||
unsigned int credits = 1;
|
||||
unsigned int credits = 0;
|
||||
char *buf;
|
||||
|
||||
timeout = flags & CIFS_TIMEOUT_MASK;
|
||||
@ -851,21 +860,24 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
|
||||
mutex_unlock(&ses->server->srv_mutex);
|
||||
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Compounding is never used during session establish.
|
||||
*/
|
||||
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP))
|
||||
smb311_update_preauth_hash(ses, rqst[0].rq_iov,
|
||||
rqst[0].rq_nvec);
|
||||
|
||||
if (timeout == CIFS_ASYNC_OP)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < num_rqst; i++) {
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP))
|
||||
smb311_update_preauth_hash(ses, rqst[i].rq_iov,
|
||||
rqst[i].rq_nvec);
|
||||
|
||||
if (timeout == CIFS_ASYNC_OP)
|
||||
goto out;
|
||||
|
||||
rc = wait_for_response(ses->server, midQ[i]);
|
||||
if (rc != 0) {
|
||||
cifs_dbg(FYI, "Cancelling wait for mid %llu\n",
|
||||
midQ[i]->mid);
|
||||
cifs_dbg(VFS, "Cancelling wait for mid %llu cmd: %d\n",
|
||||
midQ[i]->mid, le16_to_cpu(midQ[i]->command));
|
||||
send_cancel(ses->server, &rqst[i], midQ[i]);
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) {
|
||||
@ -877,10 +889,21 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
}
|
||||
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);
|
||||
if (rc != 0) {
|
||||
add_credits(ses->server, 1, optype);
|
||||
add_credits(ses->server, credits, optype);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -901,23 +924,26 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
else
|
||||
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,
|
||||
flags & CIFS_LOG_ERROR);
|
||||
|
||||
/* mark it so buf will not be freed by cifs_delete_mid */
|
||||
if ((flags & CIFS_NO_RESP) == 0)
|
||||
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:
|
||||
/*
|
||||
* This will dequeue all mids. After this it is important that the
|
||||
|
Loading…
Reference in New Issue
Block a user