Commit 7a396820 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 65163d16 78e727e5
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
TODO 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 A Partial List of Missing Features
================================== ==================================
...@@ -12,22 +13,22 @@ for visible, important contributions to this module. Here ...@@ -12,22 +13,22 @@ for visible, important contributions to this module. Here
is a partial list of the known problems and missing features: is a partial list of the known problems and missing features:
a) SMB3 (and SMB3.1.1) missing optional 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 b) Better optimized compounding and error handling for sparse file support,
- directory leases (improved metadata caching). Currently only implemented for root dir perhaps addition of new optional SMB3.1.1 fsctls to make collapse range
- T10 copy offload ie "ODX" (copy chunk, and "Duplicate Extents" ioctl and insert range more atomic
currently the only two server side copy mechanisms supported)
b) improved sparse file support (fiemap and SEEK_HOLE are implemented c) Support for SMB3.1.1 over QUIC (and perhaps other socket based protocols
but additional features would be supportable by the protocol such like SCTP)
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
d) quota support (needs minor kernel change since quota calls otherwise 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. e) Additional use cases can be optimized to use "compounding" (e.g.
open/query/close and open/setinfo/close) to reduce the number of 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 ...@@ -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 v) Additional testing of POSIX Extensions for SMB3.1.1
w) Add support for additional strong encryption types, and additional spnego w) Support for the Mac SMB3.1.1 extensions to improve interop with Apple servers
authentication mechanisms (see MS-SMB2). GCM-256 is now partially implemented.
x) Support for additional authentication options (e.g. IAKERB, peer-to-peer
Kerberos, SCRAM and others supported by existing servers)
x) Finish support for SMB3.1.1 compression y) Improved tracing, more eBPF trace points, better scripts for performance
analysis
Known Bugs Known Bugs
========== ==========
See https://bugzilla.samba.org - search on product "CifsVFS" for See https://bugzilla.samba.org - search on product "CifsVFS" for
current bug list. Also check http://bugzilla.kernel.org (Product = File System, Component = CIFS) current bug list. Also check http://bugzilla.kernel.org (Product = File System, Component = CIFS)
and xfstest results e.g. https://wiki.samba.org/index.php/Xfstest-results-smb3
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
Misc testing to do Misc testing to do
================== ==================
......
...@@ -81,7 +81,7 @@ much older and less secure than the default dialect SMB3 which includes ...@@ -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 many advanced security features such as downgrade attack detection
and encrypted shares and stronger signing and authentication algorithms. and encrypted shares and stronger signing and authentication algorithms.
There are additional mount options that may be helpful for SMB3 to get 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``) ``mfsymlinks`` and either ``cifsacl`` or ``modefromsid`` (usually with ``idsfromsid``)
...@@ -715,6 +715,7 @@ DebugData Displays information about active CIFS sessions and ...@@ -715,6 +715,7 @@ DebugData Displays information about active CIFS sessions and
Stats Lists summary resource usage information as well as per Stats Lists summary resource usage information as well as per
share statistics. share statistics.
open_files List all the open file handles on all active SMB sessions. 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: Configuration pseudo-files:
...@@ -864,6 +865,11 @@ i.e.:: ...@@ -864,6 +865,11 @@ i.e.::
echo "value" > /sys/module/cifs/parameters/<param> 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. 1. enable_oplocks Enable or disable oplocks. Oplocks are enabled by default.
[Y/y/1]. To disable use any of [N/n/0]. [Y/y/1]. To disable use any of [N/n/0].
......
...@@ -5236,7 +5236,7 @@ X: drivers/clk/clkdev.c ...@@ -5236,7 +5236,7 @@ X: drivers/clk/clkdev.c
COMMON INTERNET FILE SYSTEM CLIENT (CIFS and SMB3) COMMON INTERNET FILE SYSTEM CLIENT (CIFS and SMB3)
M: Steve French <sfrench@samba.org> M: Steve French <sfrench@samba.org>
R: Paulo Alcantara <pc@manguebit.com> (DFS, global name space) 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: Shyam Prasad N <sprasad@microsoft.com> (multichannel)
R: Tom Talpey <tom@talpey.com> (RDMA, smbdirect) R: Tom Talpey <tom@talpey.com> (RDMA, smbdirect)
L: linux-cifs@vger.kernel.org L: linux-cifs@vger.kernel.org
......
...@@ -151,7 +151,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, ...@@ -151,7 +151,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
return -EOPNOTSUPP; return -EOPNOTSUPP;
ses = tcon->ses; ses = tcon->ses;
server = ses->server; server = cifs_pick_channel(ses);
cfids = tcon->cfids; cfids = tcon->cfids;
if (!server->ops->new_lease_key) if (!server->ops->new_lease_key)
......
...@@ -659,6 +659,7 @@ static ssize_t cifs_stats_proc_write(struct file *file, ...@@ -659,6 +659,7 @@ static ssize_t cifs_stats_proc_write(struct file *file,
spin_lock(&tcon->stat_lock); spin_lock(&tcon->stat_lock);
tcon->bytes_read = 0; tcon->bytes_read = 0;
tcon->bytes_written = 0; tcon->bytes_written = 0;
tcon->stats_from_time = ktime_get_real_seconds();
spin_unlock(&tcon->stat_lock); spin_unlock(&tcon->stat_lock);
if (server->ops->clear_stats) if (server->ops->clear_stats)
server->ops->clear_stats(tcon); server->ops->clear_stats(tcon);
...@@ -737,8 +738,9 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v) ...@@ -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); seq_printf(m, "\n%d) %s", i, tcon->tree_name);
if (tcon->need_reconnect) if (tcon->need_reconnect)
seq_puts(m, "\tDISCONNECTED "); seq_puts(m, "\tDISCONNECTED ");
seq_printf(m, "\nSMBs: %d", seq_printf(m, "\nSMBs: %d since %ptTs UTC",
atomic_read(&tcon->num_smbs_sent)); atomic_read(&tcon->num_smbs_sent),
&tcon->stats_from_time);
if (server->ops->print_stats) if (server->ops->print_stats)
server->ops->print_stats(m, tcon); server->ops->print_stats(m, tcon);
} }
......
...@@ -681,6 +681,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root) ...@@ -681,6 +681,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
seq_printf(s, ",rasize=%u", cifs_sb->ctx->rasize); seq_printf(s, ",rasize=%u", cifs_sb->ctx->rasize);
if (tcon->ses->server->min_offload) if (tcon->ses->server->min_offload)
seq_printf(s, ",esize=%u", 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", seq_printf(s, ",echo_interval=%lu",
tcon->ses->server->echo_interval / HZ); tcon->ses->server->echo_interval / HZ);
......
...@@ -204,6 +204,8 @@ struct cifs_open_info_data { ...@@ -204,6 +204,8 @@ struct cifs_open_info_data {
}; };
} reparse; } reparse;
char *symlink_target; char *symlink_target;
struct cifs_sid posix_owner;
struct cifs_sid posix_group;
union { union {
struct smb2_file_all_info fi; struct smb2_file_all_info fi;
struct smb311_posix_qinfo posix_fi; struct smb311_posix_qinfo posix_fi;
...@@ -751,6 +753,7 @@ struct TCP_Server_Info { ...@@ -751,6 +753,7 @@ struct TCP_Server_Info {
unsigned int max_read; unsigned int max_read;
unsigned int max_write; unsigned int max_write;
unsigned int min_offload; unsigned int min_offload;
unsigned int retrans;
__le16 compress_algorithm; __le16 compress_algorithm;
__u16 signing_algorithm; __u16 signing_algorithm;
__le16 cipher_type; __le16 cipher_type;
...@@ -1207,6 +1210,7 @@ struct cifs_tcon { ...@@ -1207,6 +1210,7 @@ struct cifs_tcon {
__u64 bytes_read; __u64 bytes_read;
__u64 bytes_written; __u64 bytes_written;
spinlock_t stat_lock; /* protects the two fields above */ spinlock_t stat_lock; /* protects the two fields above */
time64_t stats_from_time;
FILE_SYSTEM_DEVICE_INFO fsDevInfo; FILE_SYSTEM_DEVICE_INFO fsDevInfo;
FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */ FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */
FILE_SYSTEM_UNIX_INFO fsUnixInfo; FILE_SYSTEM_UNIX_INFO fsUnixInfo;
......
...@@ -1574,6 +1574,9 @@ static int match_server(struct TCP_Server_Info *server, ...@@ -1574,6 +1574,9 @@ static int match_server(struct TCP_Server_Info *server,
if (server->min_offload != ctx->min_offload) if (server->min_offload != ctx->min_offload)
return 0; return 0;
if (server->retrans != ctx->retrans)
return 0;
return 1; return 1;
} }
...@@ -1798,6 +1801,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, ...@@ -1798,6 +1801,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
goto out_err_crypto_release; goto out_err_crypto_release;
} }
tcp_ses->min_offload = ctx->min_offload; tcp_ses->min_offload = ctx->min_offload;
tcp_ses->retrans = ctx->retrans;
/* /*
* at this point we are the only ones with the pointer * at this point we are the only ones with the pointer
* to the struct since the kernel thread not created yet * to the struct since the kernel thread not created yet
......
...@@ -139,6 +139,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { ...@@ -139,6 +139,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = {
fsparam_u32("dir_mode", Opt_dirmode), fsparam_u32("dir_mode", Opt_dirmode),
fsparam_u32("port", Opt_port), fsparam_u32("port", Opt_port),
fsparam_u32("min_enc_offload", Opt_min_enc_offload), fsparam_u32("min_enc_offload", Opt_min_enc_offload),
fsparam_u32("retrans", Opt_retrans),
fsparam_u32("esize", Opt_min_enc_offload), fsparam_u32("esize", Opt_min_enc_offload),
fsparam_u32("bsize", Opt_blocksize), fsparam_u32("bsize", Opt_blocksize),
fsparam_u32("rasize", Opt_rasize), fsparam_u32("rasize", Opt_rasize),
...@@ -1064,6 +1065,9 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, ...@@ -1064,6 +1065,9 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
case Opt_min_enc_offload: case Opt_min_enc_offload:
ctx->min_offload = result.uint_32; ctx->min_offload = result.uint_32;
break; break;
case Opt_retrans:
ctx->retrans = result.uint_32;
break;
case Opt_blocksize: case Opt_blocksize:
/* /*
* inode blocksize realistically should never need to be * inode blocksize realistically should never need to be
...@@ -1619,6 +1623,8 @@ int smb3_init_fs_context(struct fs_context *fc) ...@@ -1619,6 +1623,8 @@ int smb3_init_fs_context(struct fs_context *fc)
ctx->backupuid_specified = false; /* no backup intent for a user */ ctx->backupuid_specified = false; /* no backup intent for a user */
ctx->backupgid_specified = false; /* no backup intent for a group */ ctx->backupgid_specified = false; /* no backup intent for a group */
ctx->retrans = 1;
/* /*
* short int override_uid = -1; * short int override_uid = -1;
* short int override_gid = -1; * short int override_gid = -1;
......
...@@ -118,6 +118,7 @@ enum cifs_param { ...@@ -118,6 +118,7 @@ enum cifs_param {
Opt_file_mode, Opt_file_mode,
Opt_dirmode, Opt_dirmode,
Opt_min_enc_offload, Opt_min_enc_offload,
Opt_retrans,
Opt_blocksize, Opt_blocksize,
Opt_rasize, Opt_rasize,
Opt_rsize, Opt_rsize,
...@@ -245,6 +246,7 @@ struct smb3_fs_context { ...@@ -245,6 +246,7 @@ struct smb3_fs_context {
unsigned int rsize; unsigned int rsize;
unsigned int wsize; unsigned int wsize;
unsigned int min_offload; unsigned int min_offload;
unsigned int retrans;
bool sockopt_tcp_nodelay:1; bool sockopt_tcp_nodelay:1;
/* attribute cache timemout for files and directories in jiffies */ /* attribute cache timemout for files and directories in jiffies */
unsigned long acregmax; unsigned long acregmax;
......
...@@ -665,8 +665,6 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, ...@@ -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 */ /* Fill a cifs_fattr struct with info from POSIX info struct */
static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
struct cifs_open_info_data *data, struct cifs_open_info_data *data,
struct cifs_sid *owner,
struct cifs_sid *group,
struct super_block *sb) struct super_block *sb)
{ {
struct smb311_posix_qinfo *info = &data->posix_fi; struct smb311_posix_qinfo *info = &data->posix_fi;
...@@ -722,8 +720,8 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, ...@@ -722,8 +720,8 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
fattr->cf_symlink_target = data->symlink_target; fattr->cf_symlink_target = data->symlink_target;
data->symlink_target = NULL; data->symlink_target = NULL;
} }
sid_to_id(cifs_sb, owner, fattr, SIDOWNER); sid_to_id(cifs_sb, &data->posix_owner, fattr, SIDOWNER);
sid_to_id(cifs_sb, group, fattr, SIDGROUP); 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", cifs_dbg(FYI, "POSIX query info: mode 0x%x uniqueid 0x%llx nlink %d\n",
fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink); 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, ...@@ -1070,9 +1068,7 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
const unsigned int xid, const unsigned int xid,
struct cifs_tcon *tcon, struct cifs_tcon *tcon,
const char *full_path, const char *full_path,
struct cifs_fattr *fattr, struct cifs_fattr *fattr)
struct cifs_sid *owner,
struct cifs_sid *group)
{ {
struct TCP_Server_Info *server = tcon->ses->server; struct TCP_Server_Info *server = tcon->ses->server;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 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, ...@@ -1117,7 +1113,7 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
} }
if (tcon->posix_extensions) if (tcon->posix_extensions)
smb311_posix_info_to_fattr(fattr, data, owner, group, sb); smb311_posix_info_to_fattr(fattr, data, sb);
else else
cifs_open_info_to_fattr(fattr, data, sb); cifs_open_info_to_fattr(fattr, data, sb);
out: out:
...@@ -1171,8 +1167,7 @@ static int cifs_get_fattr(struct cifs_open_info_data *data, ...@@ -1171,8 +1167,7 @@ static int cifs_get_fattr(struct cifs_open_info_data *data,
*/ */
if (cifs_open_data_reparse(data)) { if (cifs_open_data_reparse(data)) {
rc = reparse_info_to_fattr(data, sb, xid, tcon, rc = reparse_info_to_fattr(data, sb, xid, tcon,
full_path, fattr, full_path, fattr);
NULL, NULL);
} else { } else {
cifs_open_info_to_fattr(fattr, data, sb); cifs_open_info_to_fattr(fattr, data, sb);
} }
...@@ -1317,10 +1312,10 @@ static int smb311_posix_get_fattr(struct cifs_open_info_data *data, ...@@ -1317,10 +1312,10 @@ static int smb311_posix_get_fattr(struct cifs_open_info_data *data,
const unsigned int xid) const unsigned int xid)
{ {
struct cifs_open_info_data tmp_data = {}; struct cifs_open_info_data tmp_data = {};
struct TCP_Server_Info *server;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
struct tcon_link *tlink; struct tcon_link *tlink;
struct cifs_sid owner, group;
int tmprc; int tmprc;
int rc = 0; int rc = 0;
...@@ -1328,14 +1323,14 @@ static int smb311_posix_get_fattr(struct cifs_open_info_data *data, ...@@ -1328,14 +1323,14 @@ static int smb311_posix_get_fattr(struct cifs_open_info_data *data,
if (IS_ERR(tlink)) if (IS_ERR(tlink))
return PTR_ERR(tlink); return PTR_ERR(tlink);
tcon = tlink_tcon(tlink); tcon = tlink_tcon(tlink);
server = tcon->ses->server;
/* /*
* 1. Fetch file metadata if not provided (data) * 1. Fetch file metadata if not provided (data)
*/ */
if (!data) { if (!data) {
rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, rc = server->ops->query_path_info(xid, tcon, cifs_sb,
full_path, &tmp_data, full_path, &tmp_data);
&owner, &group);
data = &tmp_data; data = &tmp_data;
} }
...@@ -1347,11 +1342,9 @@ static int smb311_posix_get_fattr(struct cifs_open_info_data *data, ...@@ -1347,11 +1342,9 @@ static int smb311_posix_get_fattr(struct cifs_open_info_data *data,
case 0: case 0:
if (cifs_open_data_reparse(data)) { if (cifs_open_data_reparse(data)) {
rc = reparse_info_to_fattr(data, sb, xid, tcon, rc = reparse_info_to_fattr(data, sb, xid, tcon,
full_path, fattr, full_path, fattr);
&owner, &group);
} else { } else {
smb311_posix_info_to_fattr(fattr, data, smb311_posix_info_to_fattr(fattr, data, sb);
&owner, &group, sb);
} }
break; break;
case -EREMOTE: case -EREMOTE:
......
...@@ -140,6 +140,7 @@ tcon_info_alloc(bool dir_leases_enabled) ...@@ -140,6 +140,7 @@ tcon_info_alloc(bool dir_leases_enabled)
spin_lock_init(&ret_buf->stat_lock); spin_lock_init(&ret_buf->stat_lock);
atomic_set(&ret_buf->num_local_opens, 0); atomic_set(&ret_buf->num_local_opens, 0);
atomic_set(&ret_buf->num_remote_opens, 0); atomic_set(&ret_buf->num_remote_opens, 0);
ret_buf->stats_from_time = ktime_get_real_seconds();
#ifdef CONFIG_CIFS_DFS_UPCALL #ifdef CONFIG_CIFS_DFS_UPCALL
INIT_LIST_HEAD(&ret_buf->dfs_ses_list); INIT_LIST_HEAD(&ret_buf->dfs_ses_list);
#endif #endif
......
...@@ -133,14 +133,14 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, ...@@ -133,14 +133,14 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
* Query dir responses don't provide enough * Query dir responses don't provide enough
* information about reparse points other than * information about reparse points other than
* their reparse tags. Save an invalidation by * their reparse tags. Save an invalidation by
* not clobbering the existing mode, size and * not clobbering some existing attributes when
* symlink target (if any) when reparse tag and * reparse tag and ctime haven't changed.
* ctime haven't changed.
*/ */
rc = 0; rc = 0;
if (fattr->cf_cifsattrs & ATTR_REPARSE) { if (fattr->cf_cifsattrs & ATTR_REPARSE) {
if (likely(reparse_inode_match(inode, fattr))) { if (likely(reparse_inode_match(inode, fattr))) {
fattr->cf_mode = inode->i_mode; fattr->cf_mode = inode->i_mode;
fattr->cf_rdev = inode->i_rdev;
fattr->cf_eof = CIFS_I(inode)->server_eof; fattr->cf_eof = CIFS_I(inode)->server_eof;
fattr->cf_symlink_target = NULL; fattr->cf_symlink_target = NULL;
} else { } else {
...@@ -645,10 +645,10 @@ static int cifs_entry_is_dot(struct cifs_dirent *de, bool is_unicode) ...@@ -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) static int is_dir_changed(struct file *file)
{ {
struct inode *inode = file_inode(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) if (cifs_inode_info->time == 0)
return 1; /* directory was changed, perhaps due to unlink */ return 1; /* directory was changed, e.g. unlink or new file */
else else
return 0; return 0;
......
This diff is collapsed.
...@@ -1210,6 +1210,8 @@ static const struct status_to_posix_error smb2_error_map_table[] = { ...@@ -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_INVALID_TASK_INDEX, -EIO, "STATUS_INVALID_TASK_INDEX"},
{STATUS_THREAD_ALREADY_IN_TASK, -EIO, "STATUS_THREAD_ALREADY_IN_TASK"}, {STATUS_THREAD_ALREADY_IN_TASK, -EIO, "STATUS_THREAD_ALREADY_IN_TASK"},
{STATUS_CALLBACK_BYPASS, -EIO, "STATUS_CALLBACK_BYPASS"}, {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_PORT_CLOSED, -EIO, "STATUS_PORT_CLOSED"},
{STATUS_MESSAGE_LOST, -EIO, "STATUS_MESSAGE_LOST"}, {STATUS_MESSAGE_LOST, -EIO, "STATUS_MESSAGE_LOST"},
{STATUS_INVALID_MESSAGE, -EIO, "STATUS_INVALID_MESSAGE"}, {STATUS_INVALID_MESSAGE, -EIO, "STATUS_INVALID_MESSAGE"},
......
...@@ -614,7 +614,8 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, ...@@ -614,7 +614,8 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
"multichannel not available\n" "multichannel not available\n"
"Empty network interface list returned by server %s\n", "Empty network interface list returned by server %s\n",
ses->server->hostname); ses->server->hostname);
rc = -EINVAL; rc = -EOPNOTSUPP;
ses->iface_last_update = jiffies;
goto out; goto out;
} }
...@@ -712,7 +713,6 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, ...@@ -712,7 +713,6 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
ses->iface_count++; ses->iface_count++;
spin_unlock(&ses->iface_lock); spin_unlock(&ses->iface_lock);
ses->iface_last_update = jiffies;
next_iface: next_iface:
nb_iface++; nb_iface++;
next = le32_to_cpu(p->Next); next = le32_to_cpu(p->Next);
...@@ -734,11 +734,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, ...@@ -734,11 +734,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
if ((bytes_left > 8) || p->Next) if ((bytes_left > 8) || p->Next)
cifs_dbg(VFS, "%s: incomplete interface info\n", __func__); cifs_dbg(VFS, "%s: incomplete interface info\n", __func__);
ses->iface_last_update = jiffies;
if (!ses->iface_count) {
rc = -EINVAL;
goto out;
}
out: out:
/* /*
......
...@@ -156,6 +156,57 @@ smb2_hdr_assemble(struct smb2_hdr *shdr, __le16 smb2_cmd, ...@@ -156,6 +156,57 @@ smb2_hdr_assemble(struct smb2_hdr *shdr, __le16 smb2_cmd,
return; 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 static int
smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
struct TCP_Server_Info *server, bool from_reconnect) struct TCP_Server_Info *server, bool from_reconnect)
...@@ -164,8 +215,6 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, ...@@ -164,8 +215,6 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
struct nls_table *nls_codepage = NULL; struct nls_table *nls_codepage = NULL;
struct cifs_ses *ses; struct cifs_ses *ses;
int xid; int xid;
struct TCP_Server_Info *pserver;
unsigned int chan_index;
/* /*
* SMB2s NegProt, SessSetup, Logoff do not have tcon yet so * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so
...@@ -310,44 +359,11 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, ...@@ -310,44 +359,11 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
*/ */
if (ses->chan_count > 1 && if (ses->chan_count > 1 &&
!(server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) { !(server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
if (SERVER_IS_CHAN(server)) { rc = cifs_chan_skip_or_disable(ses, server,
cifs_dbg(VFS, "server %s does not support " \ from_reconnect);
"multichannel anymore. skipping secondary channel\n", if (rc) {
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); mutex_unlock(&ses->session_mutex);
rc = -EHOSTDOWN;
goto out; 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 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, ...@@ -395,20 +411,35 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
rc = SMB3_request_interfaces(xid, tcon, false); rc = SMB3_request_interfaces(xid, tcon, false);
free_xid(xid); 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", cifs_dbg(FYI, "%s: failed to query server interfaces: %d\n",
__func__, rc); __func__, rc);
if (ses->chan_max > ses->chan_count && if (ses->chan_max > ses->chan_count &&
ses->iface_count &&
!SERVER_IS_CHAN(server)) { !SERVER_IS_CHAN(server)) {
if (ses->chan_count == 1) if (ses->chan_count == 1)
cifs_server_dbg(VFS, "supports multichannel now\n"); cifs_server_dbg(VFS, "supports multichannel now\n");
cifs_try_adding_channels(ses); cifs_try_adding_channels(ses);
queue_delayed_work(cifsiod_wq, &tcon->query_interfaces,
(SMB_INTERFACE_POLL_INTERVAL * HZ));
} }
} else { } else {
mutex_unlock(&ses->session_mutex); mutex_unlock(&ses->session_mutex);
} }
skip_add_channels:
if (smb2_command != SMB2_INTERNAL_CMD) if (smb2_command != SMB2_INTERNAL_CMD)
mod_delayed_work(cifsiod_wq, &server->reconnect, 0); 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, ...@@ -1958,10 +1989,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
__le16 *unc_path = NULL; __le16 *unc_path = NULL;
int flags = 0; int flags = 0;
unsigned int total_len; unsigned int total_len;
struct TCP_Server_Info *server; struct TCP_Server_Info *server = cifs_pick_channel(ses);
/* always use master channel */
server = ses->server;
cifs_dbg(FYI, "TCON\n"); cifs_dbg(FYI, "TCON\n");
...@@ -2094,6 +2122,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon) ...@@ -2094,6 +2122,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
struct smb2_tree_disconnect_req *req; /* response is trivial */ struct smb2_tree_disconnect_req *req; /* response is trivial */
int rc = 0; int rc = 0;
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = cifs_pick_channel(ses);
int flags = 0; int flags = 0;
unsigned int total_len; unsigned int total_len;
struct kvec iov[1]; struct kvec iov[1];
...@@ -2116,7 +2145,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon) ...@@ -2116,7 +2145,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
invalidate_all_cached_dirs(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, (void **) &req,
&total_len); &total_len);
if (rc) if (rc)
...@@ -2134,7 +2163,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon) ...@@ -2134,7 +2163,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
rqst.rq_iov = iov; rqst.rq_iov = iov;
rqst.rq_nvec = 1; 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); &rqst, &resp_buf_type, flags, &rsp_iov);
cifs_small_buf_release(req); cifs_small_buf_release(req);
if (rc) { if (rc) {
...@@ -2279,7 +2308,7 @@ int smb2_parse_contexts(struct TCP_Server_Info *server, ...@@ -2279,7 +2308,7 @@ int smb2_parse_contexts(struct TCP_Server_Info *server,
noff = le16_to_cpu(cc->NameOffset); noff = le16_to_cpu(cc->NameOffset);
nlen = le16_to_cpu(cc->NameLength); nlen = le16_to_cpu(cc->NameLength);
if (noff + nlen >= doff) if (noff + nlen > doff)
return -EINVAL; return -EINVAL;
name = (char *)cc + noff; name = (char *)cc + noff;
...@@ -3918,7 +3947,7 @@ void smb2_reconnect_server(struct work_struct *work) ...@@ -3918,7 +3947,7 @@ void smb2_reconnect_server(struct work_struct *work)
struct cifs_ses *ses, *ses2; struct cifs_ses *ses, *ses2;
struct cifs_tcon *tcon, *tcon2; struct cifs_tcon *tcon, *tcon2;
struct list_head tmp_list, tmp_ses_list; struct list_head tmp_list, tmp_ses_list;
bool tcon_exist = false, ses_exist = false; bool ses_exist = false;
bool tcon_selected = false; bool tcon_selected = false;
int rc; int rc;
bool resched = false; bool resched = false;
...@@ -3964,7 +3993,7 @@ void smb2_reconnect_server(struct work_struct *work) ...@@ -3964,7 +3993,7 @@ void smb2_reconnect_server(struct work_struct *work)
if (tcon->need_reconnect || tcon->need_reopen_files) { if (tcon->need_reconnect || tcon->need_reopen_files) {
tcon->tc_count++; tcon->tc_count++;
list_add_tail(&tcon->rlist, &tmp_list); 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) ...@@ -3973,7 +4002,7 @@ void smb2_reconnect_server(struct work_struct *work)
*/ */
if (ses->tcon_ipc && ses->tcon_ipc->need_reconnect) { if (ses->tcon_ipc && ses->tcon_ipc->need_reconnect) {
list_add_tail(&ses->tcon_ipc->rlist, &tmp_list); list_add_tail(&ses->tcon_ipc->rlist, &tmp_list);
tcon_selected = tcon_exist = true; tcon_selected = true;
cifs_smb_ses_inc_refcount(ses); cifs_smb_ses_inc_refcount(ses);
} }
/* /*
......
...@@ -299,9 +299,7 @@ int smb311_posix_query_path_info(const unsigned int xid, ...@@ -299,9 +299,7 @@ int smb311_posix_query_path_info(const unsigned int xid,
struct cifs_tcon *tcon, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, struct cifs_sb_info *cifs_sb,
const char *full_path, const char *full_path,
struct cifs_open_info_data *data, struct cifs_open_info_data *data);
struct cifs_sid *owner,
struct cifs_sid *group);
int posix_info_parse(const void *beg, const void *end, int posix_info_parse(const void *beg, const void *end,
struct smb2_posix_info_parsed *out); struct smb2_posix_info_parsed *out);
int posix_info_sid_size(const void *beg, const void *end); int posix_info_sid_size(const void *beg, const void *end);
......
...@@ -982,6 +982,8 @@ struct ntstatus { ...@@ -982,6 +982,8 @@ struct ntstatus {
#define STATUS_INVALID_TASK_INDEX cpu_to_le32(0xC0000501) #define STATUS_INVALID_TASK_INDEX cpu_to_le32(0xC0000501)
#define STATUS_THREAD_ALREADY_IN_TASK cpu_to_le32(0xC0000502) #define STATUS_THREAD_ALREADY_IN_TASK cpu_to_le32(0xC0000502)
#define STATUS_CALLBACK_BYPASS cpu_to_le32(0xC0000503) #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_PORT_CLOSED cpu_to_le32(0xC0000700)
#define STATUS_MESSAGE_LOST cpu_to_le32(0xC0000701) #define STATUS_MESSAGE_LOST cpu_to_le32(0xC0000701)
#define STATUS_INVALID_MESSAGE cpu_to_le32(0xC0000702) #define STATUS_INVALID_MESSAGE cpu_to_le32(0xC0000702)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment