mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 04:02:20 +00:00
Various smb client fixes, including multichannel and for SMB3.1.1 POSIX extensions
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmWsTxUACgkQiiy9cAdy T1GrcwwAl6fLD+A6r7GHFQ7LiA7KxXhQrnsdOibtWH0QRPqaiiNq2ctLg9+6pM16 vuTqsLF/sglJyjm1X5qP+xne2GFS5o7y6Vnpsj0cxoogt6I9f+q/uPrdIafJL9or N2RaWvKINuiKpHoz3jwrnDTjhvWGrc95tYKKUBRvfQF94gWQbBfLjEBP7KbU14BL jNJ+Zi4ZvEn1ITZNdiE8cqquCQuVG+lrQuqhzn9d9tDTU7rhkOan3jE7yyJPVSce 4HqtHvxnWUvOfNUyp8/bGYQhkTWEh2vy2Jo+mIPSwzwj0xSxYl3SITWo8F2mIV3U MY12FQlJLzkUhkSj0oOgkMltOe35IjPEDgBCRvjj7qm33FbCparIKLs1lx8rfghj pwzbgG3OX8yB3bIyyTmVRYl31uztN0RehYas8g4KPbVcF7w9HjHjsiemxBDTnOkb A9jxfwan8RJcO+e4e4OG7+AKMZxQt1dwf99Bo2nWhVQmV/aYJyswBCGp9hGBfrB4 0PGp7zlz =vwnz -----END PGP SIGNATURE----- Merge tag 'v6.8-rc-part2-smb-client' of git://git.samba.org/sfrench/cifs-2.6 Pull smb client updates from Steve French: "Various smb client fixes, including multichannel and for SMB3.1.1 POSIX extensions: - debugging improvement (display start time for stats) - two reparse point handling fixes - various multichannel improvements and fixes - SMB3.1.1 POSIX extensions open/create parsing fix - retry (reconnect) improvement including new retrans mount parm, and handling of two additional return codes that need to be retried on - two minor cleanup patches and another to remove duplicate query info code - two documentation cleanup, and one reviewer email correction" * tag 'v6.8-rc-part2-smb-client' of git://git.samba.org/sfrench/cifs-2.6: cifs: update iface_last_update on each query-and-update cifs: handle servers that still advertise multichannel after disabling cifs: new mount option called retrans cifs: reschedule periodic query for server interfaces smb: client: don't clobber ->i_rdev from cached reparse points smb: client: get rid of smb311_posix_query_path_info() smb: client: parse owner/group when creating reparse points smb: client: fix parsing of SMB3.1.1 POSIX create context cifs: update known bugs mentioned in kernel docs for cifs cifs: new nt status codes from MS-SMB2 cifs: pick channel for tcon and tdis cifs: open_cached_dir should not rely on primary channel smb3: minor documentation updates Update MAINTAINERS email address cifs: minor comment cleanup smb3: show beginning time for per share stats cifs: remove redundant variable tcon_exist
This commit is contained in:
commit
7a39682022
@ -2,7 +2,8 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
Version 2.14 December 21, 2018
|
||||
As of 6.7 kernel. See https://wiki.samba.org/index.php/LinuxCIFSKernel
|
||||
for list of features added by release
|
||||
|
||||
A Partial List of Missing Features
|
||||
==================================
|
||||
@ -12,22 +13,22 @@ for visible, important contributions to this module. Here
|
||||
is a partial list of the known problems and missing features:
|
||||
|
||||
a) SMB3 (and SMB3.1.1) missing optional features:
|
||||
multichannel performance optimizations, algorithmic channel selection,
|
||||
directory leases optimizations,
|
||||
support for faster packet signing (GMAC),
|
||||
support for compression over the network,
|
||||
T10 copy offload ie "ODX" (copy chunk, and "Duplicate Extents" ioctl
|
||||
are currently the only two server side copy mechanisms supported)
|
||||
|
||||
- multichannel (partially integrated), integration of multichannel with RDMA
|
||||
- directory leases (improved metadata caching). Currently only implemented for root dir
|
||||
- T10 copy offload ie "ODX" (copy chunk, and "Duplicate Extents" ioctl
|
||||
currently the only two server side copy mechanisms supported)
|
||||
b) Better optimized compounding and error handling for sparse file support,
|
||||
perhaps addition of new optional SMB3.1.1 fsctls to make collapse range
|
||||
and insert range more atomic
|
||||
|
||||
b) improved sparse file support (fiemap and SEEK_HOLE are implemented
|
||||
but additional features would be supportable by the protocol such
|
||||
as FALLOC_FL_COLLAPSE_RANGE and FALLOC_FL_INSERT_RANGE)
|
||||
|
||||
c) Directory entry caching relies on a 1 second timer, rather than
|
||||
using Directory Leases, currently only the root file handle is cached longer
|
||||
by leveraging Directory Leases
|
||||
c) Support for SMB3.1.1 over QUIC (and perhaps other socket based protocols
|
||||
like SCTP)
|
||||
|
||||
d) quota support (needs minor kernel change since quota calls otherwise
|
||||
won't make it to network filesystems or deviceless filesystems).
|
||||
won't make it to network filesystems or deviceless filesystems).
|
||||
|
||||
e) Additional use cases can be optimized to use "compounding" (e.g.
|
||||
open/query/close and open/setinfo/close) to reduce the number of
|
||||
@ -92,23 +93,20 @@ t) split cifs and smb3 support into separate modules so legacy (and less
|
||||
|
||||
v) Additional testing of POSIX Extensions for SMB3.1.1
|
||||
|
||||
w) Add support for additional strong encryption types, and additional spnego
|
||||
authentication mechanisms (see MS-SMB2). GCM-256 is now partially implemented.
|
||||
w) Support for the Mac SMB3.1.1 extensions to improve interop with Apple servers
|
||||
|
||||
x) Finish support for SMB3.1.1 compression
|
||||
x) Support for additional authentication options (e.g. IAKERB, peer-to-peer
|
||||
Kerberos, SCRAM and others supported by existing servers)
|
||||
|
||||
y) Improved tracing, more eBPF trace points, better scripts for performance
|
||||
analysis
|
||||
|
||||
Known Bugs
|
||||
==========
|
||||
|
||||
See https://bugzilla.samba.org - search on product "CifsVFS" for
|
||||
current bug list. Also check http://bugzilla.kernel.org (Product = File System, Component = CIFS)
|
||||
|
||||
1) existing symbolic links (Windows reparse points) are recognized but
|
||||
can not be created remotely. They are implemented for Samba and those that
|
||||
support the CIFS Unix extensions, although earlier versions of Samba
|
||||
overly restrict the pathnames.
|
||||
2) follow_link and readdir code does not follow dfs junctions
|
||||
but recognizes them
|
||||
and xfstest results e.g. https://wiki.samba.org/index.php/Xfstest-results-smb3
|
||||
|
||||
Misc testing to do
|
||||
==================
|
||||
|
@ -81,7 +81,7 @@ much older and less secure than the default dialect SMB3 which includes
|
||||
many advanced security features such as downgrade attack detection
|
||||
and encrypted shares and stronger signing and authentication algorithms.
|
||||
There are additional mount options that may be helpful for SMB3 to get
|
||||
improved POSIX behavior (NB: can use vers=3.0 to force only SMB3, never 2.1):
|
||||
improved POSIX behavior (NB: can use vers=3 to force SMB3 or later, never 2.1):
|
||||
|
||||
``mfsymlinks`` and either ``cifsacl`` or ``modefromsid`` (usually with ``idsfromsid``)
|
||||
|
||||
@ -715,6 +715,7 @@ DebugData Displays information about active CIFS sessions and
|
||||
Stats Lists summary resource usage information as well as per
|
||||
share statistics.
|
||||
open_files List all the open file handles on all active SMB sessions.
|
||||
mount_params List of all mount parameters available for the module
|
||||
======================= =======================================================
|
||||
|
||||
Configuration pseudo-files:
|
||||
@ -864,6 +865,11 @@ i.e.::
|
||||
|
||||
echo "value" > /sys/module/cifs/parameters/<param>
|
||||
|
||||
More detailed descriptions of the available module parameters and their values
|
||||
can be seen by doing:
|
||||
|
||||
modinfo cifs (or modinfo smb3)
|
||||
|
||||
================= ==========================================================
|
||||
1. enable_oplocks Enable or disable oplocks. Oplocks are enabled by default.
|
||||
[Y/y/1]. To disable use any of [N/n/0].
|
||||
|
@ -5236,7 +5236,7 @@ X: drivers/clk/clkdev.c
|
||||
COMMON INTERNET FILE SYSTEM CLIENT (CIFS and SMB3)
|
||||
M: Steve French <sfrench@samba.org>
|
||||
R: Paulo Alcantara <pc@manguebit.com> (DFS, global name space)
|
||||
R: Ronnie Sahlberg <lsahlber@redhat.com> (directory leases, sparse files)
|
||||
R: Ronnie Sahlberg <ronniesahlberg@gmail.com> (directory leases, sparse files)
|
||||
R: Shyam Prasad N <sprasad@microsoft.com> (multichannel)
|
||||
R: Tom Talpey <tom@talpey.com> (RDMA, smbdirect)
|
||||
L: linux-cifs@vger.kernel.org
|
||||
|
@ -151,7 +151,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ses = tcon->ses;
|
||||
server = ses->server;
|
||||
server = cifs_pick_channel(ses);
|
||||
cfids = tcon->cfids;
|
||||
|
||||
if (!server->ops->new_lease_key)
|
||||
|
@ -659,6 +659,7 @@ static ssize_t cifs_stats_proc_write(struct file *file,
|
||||
spin_lock(&tcon->stat_lock);
|
||||
tcon->bytes_read = 0;
|
||||
tcon->bytes_written = 0;
|
||||
tcon->stats_from_time = ktime_get_real_seconds();
|
||||
spin_unlock(&tcon->stat_lock);
|
||||
if (server->ops->clear_stats)
|
||||
server->ops->clear_stats(tcon);
|
||||
@ -737,8 +738,9 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
|
||||
seq_printf(m, "\n%d) %s", i, tcon->tree_name);
|
||||
if (tcon->need_reconnect)
|
||||
seq_puts(m, "\tDISCONNECTED ");
|
||||
seq_printf(m, "\nSMBs: %d",
|
||||
atomic_read(&tcon->num_smbs_sent));
|
||||
seq_printf(m, "\nSMBs: %d since %ptTs UTC",
|
||||
atomic_read(&tcon->num_smbs_sent),
|
||||
&tcon->stats_from_time);
|
||||
if (server->ops->print_stats)
|
||||
server->ops->print_stats(m, tcon);
|
||||
}
|
||||
|
@ -681,6 +681,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
|
||||
seq_printf(s, ",rasize=%u", cifs_sb->ctx->rasize);
|
||||
if (tcon->ses->server->min_offload)
|
||||
seq_printf(s, ",esize=%u", tcon->ses->server->min_offload);
|
||||
if (tcon->ses->server->retrans)
|
||||
seq_printf(s, ",retrans=%u", tcon->ses->server->retrans);
|
||||
seq_printf(s, ",echo_interval=%lu",
|
||||
tcon->ses->server->echo_interval / HZ);
|
||||
|
||||
|
@ -204,6 +204,8 @@ struct cifs_open_info_data {
|
||||
};
|
||||
} reparse;
|
||||
char *symlink_target;
|
||||
struct cifs_sid posix_owner;
|
||||
struct cifs_sid posix_group;
|
||||
union {
|
||||
struct smb2_file_all_info fi;
|
||||
struct smb311_posix_qinfo posix_fi;
|
||||
@ -751,6 +753,7 @@ struct TCP_Server_Info {
|
||||
unsigned int max_read;
|
||||
unsigned int max_write;
|
||||
unsigned int min_offload;
|
||||
unsigned int retrans;
|
||||
__le16 compress_algorithm;
|
||||
__u16 signing_algorithm;
|
||||
__le16 cipher_type;
|
||||
@ -1207,6 +1210,7 @@ struct cifs_tcon {
|
||||
__u64 bytes_read;
|
||||
__u64 bytes_written;
|
||||
spinlock_t stat_lock; /* protects the two fields above */
|
||||
time64_t stats_from_time;
|
||||
FILE_SYSTEM_DEVICE_INFO fsDevInfo;
|
||||
FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */
|
||||
FILE_SYSTEM_UNIX_INFO fsUnixInfo;
|
||||
|
@ -1574,6 +1574,9 @@ static int match_server(struct TCP_Server_Info *server,
|
||||
if (server->min_offload != ctx->min_offload)
|
||||
return 0;
|
||||
|
||||
if (server->retrans != ctx->retrans)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1798,6 +1801,7 @@ smbd_connected:
|
||||
goto out_err_crypto_release;
|
||||
}
|
||||
tcp_ses->min_offload = ctx->min_offload;
|
||||
tcp_ses->retrans = ctx->retrans;
|
||||
/*
|
||||
* at this point we are the only ones with the pointer
|
||||
* to the struct since the kernel thread not created yet
|
||||
|
@ -139,6 +139,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = {
|
||||
fsparam_u32("dir_mode", Opt_dirmode),
|
||||
fsparam_u32("port", Opt_port),
|
||||
fsparam_u32("min_enc_offload", Opt_min_enc_offload),
|
||||
fsparam_u32("retrans", Opt_retrans),
|
||||
fsparam_u32("esize", Opt_min_enc_offload),
|
||||
fsparam_u32("bsize", Opt_blocksize),
|
||||
fsparam_u32("rasize", Opt_rasize),
|
||||
@ -1064,6 +1065,9 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
|
||||
case Opt_min_enc_offload:
|
||||
ctx->min_offload = result.uint_32;
|
||||
break;
|
||||
case Opt_retrans:
|
||||
ctx->retrans = result.uint_32;
|
||||
break;
|
||||
case Opt_blocksize:
|
||||
/*
|
||||
* inode blocksize realistically should never need to be
|
||||
@ -1619,6 +1623,8 @@ int smb3_init_fs_context(struct fs_context *fc)
|
||||
ctx->backupuid_specified = false; /* no backup intent for a user */
|
||||
ctx->backupgid_specified = false; /* no backup intent for a group */
|
||||
|
||||
ctx->retrans = 1;
|
||||
|
||||
/*
|
||||
* short int override_uid = -1;
|
||||
* short int override_gid = -1;
|
||||
|
@ -118,6 +118,7 @@ enum cifs_param {
|
||||
Opt_file_mode,
|
||||
Opt_dirmode,
|
||||
Opt_min_enc_offload,
|
||||
Opt_retrans,
|
||||
Opt_blocksize,
|
||||
Opt_rasize,
|
||||
Opt_rsize,
|
||||
@ -245,6 +246,7 @@ struct smb3_fs_context {
|
||||
unsigned int rsize;
|
||||
unsigned int wsize;
|
||||
unsigned int min_offload;
|
||||
unsigned int retrans;
|
||||
bool sockopt_tcp_nodelay:1;
|
||||
/* attribute cache timemout for files and directories in jiffies */
|
||||
unsigned long acregmax;
|
||||
|
@ -665,8 +665,6 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
|
||||
/* Fill a cifs_fattr struct with info from POSIX info struct */
|
||||
static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
|
||||
struct cifs_open_info_data *data,
|
||||
struct cifs_sid *owner,
|
||||
struct cifs_sid *group,
|
||||
struct super_block *sb)
|
||||
{
|
||||
struct smb311_posix_qinfo *info = &data->posix_fi;
|
||||
@ -722,8 +720,8 @@ out_reparse:
|
||||
fattr->cf_symlink_target = data->symlink_target;
|
||||
data->symlink_target = NULL;
|
||||
}
|
||||
sid_to_id(cifs_sb, owner, fattr, SIDOWNER);
|
||||
sid_to_id(cifs_sb, group, fattr, SIDGROUP);
|
||||
sid_to_id(cifs_sb, &data->posix_owner, fattr, SIDOWNER);
|
||||
sid_to_id(cifs_sb, &data->posix_group, fattr, SIDGROUP);
|
||||
|
||||
cifs_dbg(FYI, "POSIX query info: mode 0x%x uniqueid 0x%llx nlink %d\n",
|
||||
fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink);
|
||||
@ -1070,9 +1068,7 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
|
||||
const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
const char *full_path,
|
||||
struct cifs_fattr *fattr,
|
||||
struct cifs_sid *owner,
|
||||
struct cifs_sid *group)
|
||||
struct cifs_fattr *fattr)
|
||||
{
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
@ -1117,7 +1113,7 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
|
||||
}
|
||||
|
||||
if (tcon->posix_extensions)
|
||||
smb311_posix_info_to_fattr(fattr, data, owner, group, sb);
|
||||
smb311_posix_info_to_fattr(fattr, data, sb);
|
||||
else
|
||||
cifs_open_info_to_fattr(fattr, data, sb);
|
||||
out:
|
||||
@ -1171,8 +1167,7 @@ static int cifs_get_fattr(struct cifs_open_info_data *data,
|
||||
*/
|
||||
if (cifs_open_data_reparse(data)) {
|
||||
rc = reparse_info_to_fattr(data, sb, xid, tcon,
|
||||
full_path, fattr,
|
||||
NULL, NULL);
|
||||
full_path, fattr);
|
||||
} else {
|
||||
cifs_open_info_to_fattr(fattr, data, sb);
|
||||
}
|
||||
@ -1317,10 +1312,10 @@ static int smb311_posix_get_fattr(struct cifs_open_info_data *data,
|
||||
const unsigned int xid)
|
||||
{
|
||||
struct cifs_open_info_data tmp_data = {};
|
||||
struct TCP_Server_Info *server;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
struct cifs_tcon *tcon;
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_sid owner, group;
|
||||
int tmprc;
|
||||
int rc = 0;
|
||||
|
||||
@ -1328,14 +1323,14 @@ static int smb311_posix_get_fattr(struct cifs_open_info_data *data,
|
||||
if (IS_ERR(tlink))
|
||||
return PTR_ERR(tlink);
|
||||
tcon = tlink_tcon(tlink);
|
||||
server = tcon->ses->server;
|
||||
|
||||
/*
|
||||
* 1. Fetch file metadata if not provided (data)
|
||||
*/
|
||||
if (!data) {
|
||||
rc = smb311_posix_query_path_info(xid, tcon, cifs_sb,
|
||||
full_path, &tmp_data,
|
||||
&owner, &group);
|
||||
rc = server->ops->query_path_info(xid, tcon, cifs_sb,
|
||||
full_path, &tmp_data);
|
||||
data = &tmp_data;
|
||||
}
|
||||
|
||||
@ -1347,11 +1342,9 @@ static int smb311_posix_get_fattr(struct cifs_open_info_data *data,
|
||||
case 0:
|
||||
if (cifs_open_data_reparse(data)) {
|
||||
rc = reparse_info_to_fattr(data, sb, xid, tcon,
|
||||
full_path, fattr,
|
||||
&owner, &group);
|
||||
full_path, fattr);
|
||||
} else {
|
||||
smb311_posix_info_to_fattr(fattr, data,
|
||||
&owner, &group, sb);
|
||||
smb311_posix_info_to_fattr(fattr, data, sb);
|
||||
}
|
||||
break;
|
||||
case -EREMOTE:
|
||||
|
@ -140,6 +140,7 @@ tcon_info_alloc(bool dir_leases_enabled)
|
||||
spin_lock_init(&ret_buf->stat_lock);
|
||||
atomic_set(&ret_buf->num_local_opens, 0);
|
||||
atomic_set(&ret_buf->num_remote_opens, 0);
|
||||
ret_buf->stats_from_time = ktime_get_real_seconds();
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
INIT_LIST_HEAD(&ret_buf->dfs_ses_list);
|
||||
#endif
|
||||
|
@ -133,14 +133,14 @@ retry:
|
||||
* Query dir responses don't provide enough
|
||||
* information about reparse points other than
|
||||
* their reparse tags. Save an invalidation by
|
||||
* not clobbering the existing mode, size and
|
||||
* symlink target (if any) when reparse tag and
|
||||
* ctime haven't changed.
|
||||
* not clobbering some existing attributes when
|
||||
* reparse tag and ctime haven't changed.
|
||||
*/
|
||||
rc = 0;
|
||||
if (fattr->cf_cifsattrs & ATTR_REPARSE) {
|
||||
if (likely(reparse_inode_match(inode, fattr))) {
|
||||
fattr->cf_mode = inode->i_mode;
|
||||
fattr->cf_rdev = inode->i_rdev;
|
||||
fattr->cf_eof = CIFS_I(inode)->server_eof;
|
||||
fattr->cf_symlink_target = NULL;
|
||||
} else {
|
||||
@ -645,10 +645,10 @@ static int cifs_entry_is_dot(struct cifs_dirent *de, bool is_unicode)
|
||||
static int is_dir_changed(struct file *file)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
|
||||
struct cifsInodeInfo *cifs_inode_info = CIFS_I(inode);
|
||||
|
||||
if (cifsInfo->time == 0)
|
||||
return 1; /* directory was changed, perhaps due to unlink */
|
||||
if (cifs_inode_info->time == 0)
|
||||
return 1; /* directory was changed, e.g. unlink or new file */
|
||||
else
|
||||
return 0;
|
||||
|
||||
|
@ -56,6 +56,35 @@ static inline __u32 file_create_options(struct dentry *dentry)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parse owner and group from SMB3.1.1 POSIX query info */
|
||||
static int parse_posix_sids(struct cifs_open_info_data *data,
|
||||
struct kvec *rsp_iov)
|
||||
{
|
||||
struct smb2_query_info_rsp *qi = rsp_iov->iov_base;
|
||||
unsigned int out_len = le32_to_cpu(qi->OutputBufferLength);
|
||||
unsigned int qi_len = sizeof(data->posix_fi);
|
||||
int owner_len, group_len;
|
||||
u8 *sidsbuf, *sidsbuf_end;
|
||||
|
||||
if (out_len <= qi_len)
|
||||
return -EINVAL;
|
||||
|
||||
sidsbuf = (u8 *)qi + le16_to_cpu(qi->OutputBufferOffset) + qi_len;
|
||||
sidsbuf_end = sidsbuf + out_len - qi_len;
|
||||
|
||||
owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end);
|
||||
if (owner_len == -1)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(&data->posix_owner, sidsbuf, owner_len);
|
||||
group_len = posix_info_sid_size(sidsbuf + owner_len, sidsbuf_end);
|
||||
if (group_len == -1)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(&data->posix_group, sidsbuf + owner_len, group_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* note: If cfile is passed, the reference to it is dropped here.
|
||||
* So make sure that you do not reuse cfile after return from this func.
|
||||
@ -69,7 +98,6 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
__u32 desired_access, __u32 create_disposition,
|
||||
__u32 create_options, umode_t mode, struct kvec *in_iov,
|
||||
int *cmds, int num_cmds, struct cifsFileInfo *cfile,
|
||||
__u8 **extbuf, size_t *extbuflen,
|
||||
struct kvec *out_iov, int *out_buftype)
|
||||
{
|
||||
|
||||
@ -494,21 +522,9 @@ finished:
|
||||
&rsp_iov[i + 1], sizeof(idata->posix_fi) /* add SIDs */,
|
||||
(char *)&idata->posix_fi);
|
||||
}
|
||||
if (rc == 0) {
|
||||
unsigned int length = le32_to_cpu(qi_rsp->OutputBufferLength);
|
||||
if (rc == 0)
|
||||
rc = parse_posix_sids(idata, &rsp_iov[i + 1]);
|
||||
|
||||
if (length > sizeof(idata->posix_fi)) {
|
||||
char *base = (char *)rsp_iov[i + 1].iov_base +
|
||||
le16_to_cpu(qi_rsp->OutputBufferOffset) +
|
||||
sizeof(idata->posix_fi);
|
||||
*extbuflen = length - sizeof(idata->posix_fi);
|
||||
*extbuf = kmemdup(base, *extbuflen, GFP_KERNEL);
|
||||
if (!*extbuf)
|
||||
rc = -ENOMEM;
|
||||
} else {
|
||||
rc = -EINVAL;
|
||||
}
|
||||
}
|
||||
SMB2_query_info_free(&rqst[num_rqst++]);
|
||||
if (rc)
|
||||
trace_smb3_posix_query_info_compound_err(xid, ses->Suid,
|
||||
@ -662,7 +678,7 @@ int smb2_query_path_info(const unsigned int xid,
|
||||
struct smb2_hdr *hdr;
|
||||
struct kvec in_iov[2], out_iov[3] = {};
|
||||
int out_buftype[3] = {};
|
||||
int cmds[2] = { SMB2_OP_QUERY_INFO, };
|
||||
int cmds[2];
|
||||
bool islink;
|
||||
int i, num_cmds;
|
||||
int rc, rc2;
|
||||
@ -670,20 +686,36 @@ int smb2_query_path_info(const unsigned int xid,
|
||||
data->adjust_tz = false;
|
||||
data->reparse_point = false;
|
||||
|
||||
if (strcmp(full_path, ""))
|
||||
rc = -ENOENT;
|
||||
else
|
||||
rc = open_cached_dir(xid, tcon, full_path, cifs_sb, false, &cfid);
|
||||
/* If it is a root and its handle is cached then use it */
|
||||
if (!rc) {
|
||||
if (cfid->file_all_info_is_valid) {
|
||||
memcpy(&data->fi, &cfid->file_all_info, sizeof(data->fi));
|
||||
/*
|
||||
* BB TODO: Add support for using cached root handle in SMB3.1.1 POSIX.
|
||||
* Create SMB2_query_posix_info worker function to do non-compounded
|
||||
* query when we already have an open file handle for this. For now this
|
||||
* is fast enough (always using the compounded version).
|
||||
*/
|
||||
if (!tcon->posix_extensions) {
|
||||
if (*full_path) {
|
||||
rc = -ENOENT;
|
||||
} else {
|
||||
rc = SMB2_query_info(xid, tcon, cfid->fid.persistent_fid,
|
||||
cfid->fid.volatile_fid, &data->fi);
|
||||
rc = open_cached_dir(xid, tcon, full_path,
|
||||
cifs_sb, false, &cfid);
|
||||
}
|
||||
close_cached_dir(cfid);
|
||||
return rc;
|
||||
/* If it is a root and its handle is cached then use it */
|
||||
if (!rc) {
|
||||
if (cfid->file_all_info_is_valid) {
|
||||
memcpy(&data->fi, &cfid->file_all_info,
|
||||
sizeof(data->fi));
|
||||
} else {
|
||||
rc = SMB2_query_info(xid, tcon,
|
||||
cfid->fid.persistent_fid,
|
||||
cfid->fid.volatile_fid,
|
||||
&data->fi);
|
||||
}
|
||||
close_cached_dir(cfid);
|
||||
return rc;
|
||||
}
|
||||
cmds[0] = SMB2_OP_QUERY_INFO;
|
||||
} else {
|
||||
cmds[0] = SMB2_OP_POSIX_QUERY_INFO;
|
||||
}
|
||||
|
||||
in_iov[0].iov_base = data;
|
||||
@ -693,9 +725,8 @@ int smb2_query_path_info(const unsigned int xid,
|
||||
cifs_get_readable_path(tcon, full_path, &cfile);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||
create_options, ACL_NO_MODE,
|
||||
in_iov, cmds, 1, cfile,
|
||||
NULL, NULL, out_iov, out_buftype);
|
||||
create_options, ACL_NO_MODE, in_iov,
|
||||
cmds, 1, cfile, out_iov, out_buftype);
|
||||
hdr = out_iov[0].iov_base;
|
||||
/*
|
||||
* If first iov is unset, then SMB session was dropped or we've got a
|
||||
@ -707,6 +738,10 @@ int smb2_query_path_info(const unsigned int xid,
|
||||
switch (rc) {
|
||||
case 0:
|
||||
case -EOPNOTSUPP:
|
||||
/*
|
||||
* BB TODO: When support for special files added to Samba
|
||||
* re-verify this path.
|
||||
*/
|
||||
rc = parse_create_response(data, cifs_sb, &out_iov[0]);
|
||||
if (rc || !data->reparse_point)
|
||||
goto out;
|
||||
@ -722,8 +757,8 @@ int smb2_query_path_info(const unsigned int xid,
|
||||
cifs_get_readable_path(tcon, full_path, &cfile);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||
create_options, ACL_NO_MODE, in_iov, cmds,
|
||||
num_cmds, cfile, NULL, NULL, NULL, NULL);
|
||||
create_options, ACL_NO_MODE, in_iov,
|
||||
cmds, num_cmds, cfile, NULL, NULL);
|
||||
break;
|
||||
case -EREMOTE:
|
||||
break;
|
||||
@ -746,101 +781,6 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int smb311_posix_query_path_info(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
struct cifs_open_info_data *data,
|
||||
struct cifs_sid *owner,
|
||||
struct cifs_sid *group)
|
||||
{
|
||||
int rc;
|
||||
__u32 create_options = 0;
|
||||
struct cifsFileInfo *cfile;
|
||||
struct kvec in_iov[2], out_iov[3] = {};
|
||||
int out_buftype[3] = {};
|
||||
__u8 *sidsbuf = NULL;
|
||||
__u8 *sidsbuf_end = NULL;
|
||||
size_t sidsbuflen = 0;
|
||||
size_t owner_len, group_len;
|
||||
int cmds[2] = { SMB2_OP_POSIX_QUERY_INFO, };
|
||||
int i, num_cmds;
|
||||
|
||||
data->adjust_tz = false;
|
||||
data->reparse_point = false;
|
||||
|
||||
/*
|
||||
* BB TODO: Add support for using the cached root handle.
|
||||
* Create SMB2_query_posix_info worker function to do non-compounded query
|
||||
* when we already have an open file handle for this. For now this is fast enough
|
||||
* (always using the compounded version).
|
||||
*/
|
||||
in_iov[0].iov_base = data;
|
||||
in_iov[0].iov_len = sizeof(*data);
|
||||
in_iov[1] = in_iov[0];
|
||||
|
||||
cifs_get_readable_path(tcon, full_path, &cfile);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||
create_options, ACL_NO_MODE, in_iov, cmds, 1,
|
||||
cfile, &sidsbuf, &sidsbuflen, out_iov, out_buftype);
|
||||
/*
|
||||
* If first iov is unset, then SMB session was dropped or we've got a
|
||||
* cached open file (@cfile).
|
||||
*/
|
||||
if (!out_iov[0].iov_base || out_buftype[0] == CIFS_NO_BUFFER)
|
||||
goto out;
|
||||
|
||||
switch (rc) {
|
||||
case 0:
|
||||
case -EOPNOTSUPP:
|
||||
/* BB TODO: When support for special files added to Samba re-verify this path */
|
||||
rc = parse_create_response(data, cifs_sb, &out_iov[0]);
|
||||
if (rc || !data->reparse_point)
|
||||
goto out;
|
||||
|
||||
if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK) {
|
||||
/* symlink already parsed in create response */
|
||||
num_cmds = 1;
|
||||
} else {
|
||||
cmds[1] = SMB2_OP_GET_REPARSE;
|
||||
num_cmds = 2;
|
||||
}
|
||||
create_options |= OPEN_REPARSE_POINT;
|
||||
cifs_get_readable_path(tcon, full_path, &cfile);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||
create_options, ACL_NO_MODE, in_iov, cmds,
|
||||
num_cmds, cfile, &sidsbuf, &sidsbuflen, NULL, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
if (rc == 0) {
|
||||
sidsbuf_end = sidsbuf + sidsbuflen;
|
||||
|
||||
owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end);
|
||||
if (owner_len == -1) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
memcpy(owner, sidsbuf, owner_len);
|
||||
|
||||
group_len = posix_info_sid_size(
|
||||
sidsbuf + owner_len, sidsbuf_end);
|
||||
if (group_len == -1) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
memcpy(group, sidsbuf + owner_len, group_len);
|
||||
}
|
||||
|
||||
kfree(sidsbuf);
|
||||
for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
|
||||
free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
|
||||
struct cifs_tcon *tcon, const char *name,
|
||||
@ -848,9 +788,9 @@ smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
|
||||
{
|
||||
return smb2_compound_op(xid, tcon, cifs_sb, name,
|
||||
FILE_WRITE_ATTRIBUTES, FILE_CREATE,
|
||||
CREATE_NOT_FILE, mode, NULL,
|
||||
&(int){SMB2_OP_MKDIR}, 1,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
CREATE_NOT_FILE, mode,
|
||||
NULL, &(int){SMB2_OP_MKDIR}, 1,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
@ -875,7 +815,7 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name,
|
||||
FILE_WRITE_ATTRIBUTES, FILE_CREATE,
|
||||
CREATE_NOT_FILE, ACL_NO_MODE, &in_iov,
|
||||
&(int){SMB2_OP_SET_INFO}, 1,
|
||||
cfile, NULL, NULL, NULL, NULL);
|
||||
cfile, NULL, NULL);
|
||||
if (tmprc == 0)
|
||||
cifs_i->cifsAttrs = dosattrs;
|
||||
}
|
||||
@ -887,8 +827,9 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
|
||||
drop_cached_dir_by_name(xid, tcon, name, cifs_sb);
|
||||
return smb2_compound_op(xid, tcon, cifs_sb, name,
|
||||
DELETE, FILE_OPEN, CREATE_NOT_FILE,
|
||||
ACL_NO_MODE, NULL, &(int){SMB2_OP_RMDIR}, 1,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
ACL_NO_MODE, NULL,
|
||||
&(int){SMB2_OP_RMDIR}, 1,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
@ -897,8 +838,9 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
|
||||
{
|
||||
return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
|
||||
CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
|
||||
ACL_NO_MODE, NULL, &(int){SMB2_OP_DELETE}, 1,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
ACL_NO_MODE, NULL,
|
||||
&(int){SMB2_OP_DELETE}, 1,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
@ -919,8 +861,8 @@ static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
in_iov.iov_base = smb2_to_name;
|
||||
in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
|
||||
FILE_OPEN, create_options, ACL_NO_MODE, &in_iov,
|
||||
&command, 1, cfile, NULL, NULL, NULL, NULL);
|
||||
FILE_OPEN, create_options, ACL_NO_MODE,
|
||||
&in_iov, &command, 1, cfile, NULL, NULL);
|
||||
smb2_rename_path:
|
||||
kfree(smb2_to_name);
|
||||
return rc;
|
||||
@ -971,7 +913,7 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
FILE_WRITE_DATA, FILE_OPEN,
|
||||
0, ACL_NO_MODE, &in_iov,
|
||||
&(int){SMB2_OP_SET_EOF}, 1,
|
||||
cfile, NULL, NULL, NULL, NULL);
|
||||
cfile, NULL, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
@ -999,8 +941,8 @@ smb2_set_file_info(struct inode *inode, const char *full_path,
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
FILE_WRITE_ATTRIBUTES, FILE_OPEN,
|
||||
0, ACL_NO_MODE, &in_iov,
|
||||
&(int){SMB2_OP_SET_INFO}, 1, cfile,
|
||||
NULL, NULL, NULL, NULL);
|
||||
&(int){SMB2_OP_SET_INFO}, 1,
|
||||
cfile, NULL, NULL);
|
||||
cifs_put_tlink(tlink);
|
||||
return rc;
|
||||
}
|
||||
@ -1035,7 +977,7 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
|
||||
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
da, cd, co, ACL_NO_MODE, in_iov,
|
||||
cmds, 2, cfile, NULL, NULL, NULL, NULL);
|
||||
cmds, 2, cfile, NULL, NULL);
|
||||
if (!rc) {
|
||||
rc = smb311_posix_get_inode_info(&new, full_path,
|
||||
data, sb, xid);
|
||||
@ -1045,7 +987,7 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
|
||||
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
da, cd, co, ACL_NO_MODE, in_iov,
|
||||
cmds, 2, cfile, NULL, NULL, NULL, NULL);
|
||||
cmds, 2, cfile, NULL, NULL);
|
||||
if (!rc) {
|
||||
rc = cifs_get_inode_info(&new, full_path,
|
||||
data, sb, xid, NULL);
|
||||
@ -1072,8 +1014,8 @@ int smb2_query_reparse_point(const unsigned int xid,
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||
OPEN_REPARSE_POINT, ACL_NO_MODE, &in_iov,
|
||||
&(int){SMB2_OP_GET_REPARSE}, 1, cfile,
|
||||
NULL, NULL, NULL, NULL);
|
||||
&(int){SMB2_OP_GET_REPARSE}, 1,
|
||||
cfile, NULL, NULL);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
|
@ -1210,6 +1210,8 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
|
||||
{STATUS_INVALID_TASK_INDEX, -EIO, "STATUS_INVALID_TASK_INDEX"},
|
||||
{STATUS_THREAD_ALREADY_IN_TASK, -EIO, "STATUS_THREAD_ALREADY_IN_TASK"},
|
||||
{STATUS_CALLBACK_BYPASS, -EIO, "STATUS_CALLBACK_BYPASS"},
|
||||
{STATUS_SERVER_UNAVAILABLE, -EAGAIN, "STATUS_SERVER_UNAVAILABLE"},
|
||||
{STATUS_FILE_NOT_AVAILABLE, -EAGAIN, "STATUS_FILE_NOT_AVAILABLE"},
|
||||
{STATUS_PORT_CLOSED, -EIO, "STATUS_PORT_CLOSED"},
|
||||
{STATUS_MESSAGE_LOST, -EIO, "STATUS_MESSAGE_LOST"},
|
||||
{STATUS_INVALID_MESSAGE, -EIO, "STATUS_INVALID_MESSAGE"},
|
||||
|
@ -614,7 +614,8 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
|
||||
"multichannel not available\n"
|
||||
"Empty network interface list returned by server %s\n",
|
||||
ses->server->hostname);
|
||||
rc = -EINVAL;
|
||||
rc = -EOPNOTSUPP;
|
||||
ses->iface_last_update = jiffies;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -712,7 +713,6 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
|
||||
|
||||
ses->iface_count++;
|
||||
spin_unlock(&ses->iface_lock);
|
||||
ses->iface_last_update = jiffies;
|
||||
next_iface:
|
||||
nb_iface++;
|
||||
next = le32_to_cpu(p->Next);
|
||||
@ -734,11 +734,7 @@ next_iface:
|
||||
if ((bytes_left > 8) || p->Next)
|
||||
cifs_dbg(VFS, "%s: incomplete interface info\n", __func__);
|
||||
|
||||
|
||||
if (!ses->iface_count) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
ses->iface_last_update = jiffies;
|
||||
|
||||
out:
|
||||
/*
|
||||
|
@ -156,6 +156,57 @@ out:
|
||||
return;
|
||||
}
|
||||
|
||||
/* helper function for code reuse */
|
||||
static int
|
||||
cifs_chan_skip_or_disable(struct cifs_ses *ses,
|
||||
struct TCP_Server_Info *server,
|
||||
bool from_reconnect)
|
||||
{
|
||||
struct TCP_Server_Info *pserver;
|
||||
unsigned int chan_index;
|
||||
|
||||
if (SERVER_IS_CHAN(server)) {
|
||||
cifs_dbg(VFS,
|
||||
"server %s does not support multichannel anymore. Skip secondary channel\n",
|
||||
ses->server->hostname);
|
||||
|
||||
spin_lock(&ses->chan_lock);
|
||||
chan_index = cifs_ses_get_chan_index(ses, server);
|
||||
if (chan_index == CIFS_INVAL_CHAN_INDEX) {
|
||||
spin_unlock(&ses->chan_lock);
|
||||
goto skip_terminate;
|
||||
}
|
||||
|
||||
ses->chans[chan_index].server = NULL;
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
/*
|
||||
* the above reference of server by channel
|
||||
* needs to be dropped without holding chan_lock
|
||||
* as cifs_put_tcp_session takes a higher lock
|
||||
* i.e. cifs_tcp_ses_lock
|
||||
*/
|
||||
cifs_put_tcp_session(server, from_reconnect);
|
||||
|
||||
server->terminate = true;
|
||||
cifs_signal_cifsd_for_reconnect(server, false);
|
||||
|
||||
/* mark primary server as needing reconnect */
|
||||
pserver = server->primary_server;
|
||||
cifs_signal_cifsd_for_reconnect(pserver, false);
|
||||
skip_terminate:
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
return -EHOSTDOWN;
|
||||
}
|
||||
|
||||
cifs_server_dbg(VFS,
|
||||
"server does not support multichannel anymore. Disable all other channels\n");
|
||||
cifs_disable_secondary_channels(ses);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
|
||||
struct TCP_Server_Info *server, bool from_reconnect)
|
||||
@ -164,8 +215,6 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
|
||||
struct nls_table *nls_codepage = NULL;
|
||||
struct cifs_ses *ses;
|
||||
int xid;
|
||||
struct TCP_Server_Info *pserver;
|
||||
unsigned int chan_index;
|
||||
|
||||
/*
|
||||
* SMB2s NegProt, SessSetup, Logoff do not have tcon yet so
|
||||
@ -310,44 +359,11 @@ again:
|
||||
*/
|
||||
if (ses->chan_count > 1 &&
|
||||
!(server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
|
||||
if (SERVER_IS_CHAN(server)) {
|
||||
cifs_dbg(VFS, "server %s does not support " \
|
||||
"multichannel anymore. skipping secondary channel\n",
|
||||
ses->server->hostname);
|
||||
|
||||
spin_lock(&ses->chan_lock);
|
||||
chan_index = cifs_ses_get_chan_index(ses, server);
|
||||
if (chan_index == CIFS_INVAL_CHAN_INDEX) {
|
||||
spin_unlock(&ses->chan_lock);
|
||||
goto skip_terminate;
|
||||
}
|
||||
|
||||
ses->chans[chan_index].server = NULL;
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
/*
|
||||
* the above reference of server by channel
|
||||
* needs to be dropped without holding chan_lock
|
||||
* as cifs_put_tcp_session takes a higher lock
|
||||
* i.e. cifs_tcp_ses_lock
|
||||
*/
|
||||
cifs_put_tcp_session(server, from_reconnect);
|
||||
|
||||
server->terminate = true;
|
||||
cifs_signal_cifsd_for_reconnect(server, false);
|
||||
|
||||
/* mark primary server as needing reconnect */
|
||||
pserver = server->primary_server;
|
||||
cifs_signal_cifsd_for_reconnect(pserver, false);
|
||||
|
||||
skip_terminate:
|
||||
rc = cifs_chan_skip_or_disable(ses, server,
|
||||
from_reconnect);
|
||||
if (rc) {
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
rc = -EHOSTDOWN;
|
||||
goto out;
|
||||
} else {
|
||||
cifs_server_dbg(VFS, "does not support " \
|
||||
"multichannel anymore. disabling all other channels\n");
|
||||
cifs_disable_secondary_channels(ses);
|
||||
}
|
||||
}
|
||||
|
||||
@ -395,20 +411,35 @@ skip_sess_setup:
|
||||
rc = SMB3_request_interfaces(xid, tcon, false);
|
||||
free_xid(xid);
|
||||
|
||||
if (rc)
|
||||
if (rc == -EOPNOTSUPP) {
|
||||
/*
|
||||
* some servers like Azure SMB server do not advertise
|
||||
* that multichannel has been disabled with server
|
||||
* capabilities, rather return STATUS_NOT_IMPLEMENTED.
|
||||
* treat this as server not supporting multichannel
|
||||
*/
|
||||
|
||||
rc = cifs_chan_skip_or_disable(ses, server,
|
||||
from_reconnect);
|
||||
goto skip_add_channels;
|
||||
} else if (rc)
|
||||
cifs_dbg(FYI, "%s: failed to query server interfaces: %d\n",
|
||||
__func__, rc);
|
||||
|
||||
if (ses->chan_max > ses->chan_count &&
|
||||
ses->iface_count &&
|
||||
!SERVER_IS_CHAN(server)) {
|
||||
if (ses->chan_count == 1)
|
||||
cifs_server_dbg(VFS, "supports multichannel now\n");
|
||||
|
||||
cifs_try_adding_channels(ses);
|
||||
queue_delayed_work(cifsiod_wq, &tcon->query_interfaces,
|
||||
(SMB_INTERFACE_POLL_INTERVAL * HZ));
|
||||
}
|
||||
} else {
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
}
|
||||
skip_add_channels:
|
||||
|
||||
if (smb2_command != SMB2_INTERNAL_CMD)
|
||||
mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
|
||||
@ -1958,10 +1989,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
|
||||
__le16 *unc_path = NULL;
|
||||
int flags = 0;
|
||||
unsigned int total_len;
|
||||
struct TCP_Server_Info *server;
|
||||
|
||||
/* always use master channel */
|
||||
server = ses->server;
|
||||
struct TCP_Server_Info *server = cifs_pick_channel(ses);
|
||||
|
||||
cifs_dbg(FYI, "TCON\n");
|
||||
|
||||
@ -2094,6 +2122,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
|
||||
struct smb2_tree_disconnect_req *req; /* response is trivial */
|
||||
int rc = 0;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct TCP_Server_Info *server = cifs_pick_channel(ses);
|
||||
int flags = 0;
|
||||
unsigned int total_len;
|
||||
struct kvec iov[1];
|
||||
@ -2116,7 +2145,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
|
||||
|
||||
invalidate_all_cached_dirs(tcon);
|
||||
|
||||
rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, ses->server,
|
||||
rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, server,
|
||||
(void **) &req,
|
||||
&total_len);
|
||||
if (rc)
|
||||
@ -2134,7 +2163,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
|
||||
rqst.rq_iov = iov;
|
||||
rqst.rq_nvec = 1;
|
||||
|
||||
rc = cifs_send_recv(xid, ses, ses->server,
|
||||
rc = cifs_send_recv(xid, ses, server,
|
||||
&rqst, &resp_buf_type, flags, &rsp_iov);
|
||||
cifs_small_buf_release(req);
|
||||
if (rc) {
|
||||
@ -2279,7 +2308,7 @@ int smb2_parse_contexts(struct TCP_Server_Info *server,
|
||||
|
||||
noff = le16_to_cpu(cc->NameOffset);
|
||||
nlen = le16_to_cpu(cc->NameLength);
|
||||
if (noff + nlen >= doff)
|
||||
if (noff + nlen > doff)
|
||||
return -EINVAL;
|
||||
|
||||
name = (char *)cc + noff;
|
||||
@ -3918,7 +3947,7 @@ void smb2_reconnect_server(struct work_struct *work)
|
||||
struct cifs_ses *ses, *ses2;
|
||||
struct cifs_tcon *tcon, *tcon2;
|
||||
struct list_head tmp_list, tmp_ses_list;
|
||||
bool tcon_exist = false, ses_exist = false;
|
||||
bool ses_exist = false;
|
||||
bool tcon_selected = false;
|
||||
int rc;
|
||||
bool resched = false;
|
||||
@ -3964,7 +3993,7 @@ void smb2_reconnect_server(struct work_struct *work)
|
||||
if (tcon->need_reconnect || tcon->need_reopen_files) {
|
||||
tcon->tc_count++;
|
||||
list_add_tail(&tcon->rlist, &tmp_list);
|
||||
tcon_selected = tcon_exist = true;
|
||||
tcon_selected = true;
|
||||
}
|
||||
}
|
||||
/*
|
||||
@ -3973,7 +4002,7 @@ void smb2_reconnect_server(struct work_struct *work)
|
||||
*/
|
||||
if (ses->tcon_ipc && ses->tcon_ipc->need_reconnect) {
|
||||
list_add_tail(&ses->tcon_ipc->rlist, &tmp_list);
|
||||
tcon_selected = tcon_exist = true;
|
||||
tcon_selected = true;
|
||||
cifs_smb_ses_inc_refcount(ses);
|
||||
}
|
||||
/*
|
||||
|
@ -299,9 +299,7 @@ int smb311_posix_query_path_info(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
struct cifs_open_info_data *data,
|
||||
struct cifs_sid *owner,
|
||||
struct cifs_sid *group);
|
||||
struct cifs_open_info_data *data);
|
||||
int posix_info_parse(const void *beg, const void *end,
|
||||
struct smb2_posix_info_parsed *out);
|
||||
int posix_info_sid_size(const void *beg, const void *end);
|
||||
|
@ -982,6 +982,8 @@ struct ntstatus {
|
||||
#define STATUS_INVALID_TASK_INDEX cpu_to_le32(0xC0000501)
|
||||
#define STATUS_THREAD_ALREADY_IN_TASK cpu_to_le32(0xC0000502)
|
||||
#define STATUS_CALLBACK_BYPASS cpu_to_le32(0xC0000503)
|
||||
#define STATUS_SERVER_UNAVAILABLE cpu_to_le32(0xC0000466)
|
||||
#define STATUS_FILE_NOT_AVAILABLE cpu_to_le32(0xC0000467)
|
||||
#define STATUS_PORT_CLOSED cpu_to_le32(0xC0000700)
|
||||
#define STATUS_MESSAGE_LOST cpu_to_le32(0xC0000701)
|
||||
#define STATUS_INVALID_MESSAGE cpu_to_le32(0xC0000702)
|
||||
|
Loading…
Reference in New Issue
Block a user