Commit e13300bd authored by Linus Torvalds's avatar Linus Torvalds

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

Pull cifs updates from Steve French:
 "The largest part are for support of the newer mount API which has been
  needed for cifs/smb3 mounts for a long time due to the new API's
  better handling of remount, and better error reporting. There are
  three additional small cleanup patches for this being tested, that are
  not included yet.

  This series also includes addition of support for the SMB3 witness
  protocol which can provide important notifications from the server to
  client on server address or export or network changes. This can be
  useful for example in order to be notified before the failure - when a
  server's IP address changes (in the future it will allow us to support
  server notifications of when a share is moved).

  It also includes three patches for stable e.g. some that better handle
  some confusing error messages during session establishment"

* tag '5.11-rc-smb3' of git://git.samba.org/sfrench/cifs-2.6: (55 commits)
  cifs: update internal module version number
  cifs: Fix support for remount when not changing rsize/wsize
  cifs: handle "guest" mount parameter
  cifs: correct four aliased mount parms to allow use of previous names
  cifs: Tracepoints and logs for tracing credit changes.
  cifs: fix use after free in cifs_smb3_do_mount()
  cifs: fix rsize/wsize to be negotiated values
  cifs: Fix some error pointers handling detected by static checker
  smb3: remind users that witness protocol is experimental
  cifs: update super_operations to show_devname
  cifs: fix uninitialized variable in smb3_fs_context_parse_param
  cifs: update mnt_cifs_flags during reconfigure
  cifs: move update of flags into a separate function
  cifs: remove ctx argument from cifs_setup_cifs_sb
  cifs: do not allow changing posix_paths during remount
  cifs: uncomplicate printing the iocharset parameter
  cifs: don't create a temp nls in cifs_setup_ipc
  cifs: simplify handling of cifs_sb/ctx->local_nls
  cifs: we do not allow changing username/password/unc/... during remount
  cifs: add initial reconfigure support
  ...
parents d64c6f96 afee4410
......@@ -60,9 +60,9 @@ config CIFS_STATS2
Enabling this option will allow more detailed statistics on SMB
request timing to be displayed in /proc/fs/cifs/DebugData and also
allow optional logging of slow responses to dmesg (depending on the
value of /proc/fs/cifs/cifsFYI, see fs/cifs/README for more details).
These additional statistics may have a minor effect on performance
and memory utilization.
value of /proc/fs/cifs/cifsFYI). See Documentation/admin-guide/cifs/usage.rst
for more details. These additional statistics may have a minor effect
on performance and memory utilization.
Unless you are a developer or are doing network performance analysis
or tuning, say N.
......@@ -102,10 +102,10 @@ config CIFS_WEAK_PW_HASH
is enabled in the kernel build, LANMAN authentication will not be
used automatically. At runtime LANMAN mounts are disabled but
can be set to required (or optional) either in
/proc/fs/cifs (see fs/cifs/README for more detail) or via an
option on the mount command. This support is disabled by
default in order to reduce the possibility of a downgrade
attack.
/proc/fs/cifs (see Documentation/admin-guide/cifs/usage.rst for
more detail) or via an option on the mount command. This support
is disabled by default in order to reduce the possibility of a
downgrade attack.
If unsure, say N.
......@@ -190,6 +190,17 @@ config CIFS_DFS_UPCALL
servers if their addresses change or for implicit mounts of
DFS junction points. If unsure, say Y.
config CIFS_SWN_UPCALL
bool "SWN feature support"
depends on CIFS
help
The Service Witness Protocol (SWN) is used to get notifications
from a highly available server of resource state changes. This
feature enables an upcall mechanism for CIFS which contacts a
userspace daemon to establish the DCE/RPC connection to retrieve
the cluster available interfaces and resource change notifications.
If unsure, say Y.
config CIFS_NFSD_EXPORT
bool "Allow nfsd to export CIFS file system"
depends on CIFS && BROKEN
......
......@@ -8,7 +8,7 @@ obj-$(CONFIG_CIFS) += cifs.o
cifs-y := trace.o cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o \
inode.o link.o misc.o netmisc.o smbencrypt.o transport.o asn1.o \
cifs_unicode.o nterr.o cifsencrypt.o \
readdir.o ioctl.o sess.o export.o smb1ops.o winucase.o \
readdir.o ioctl.o sess.o export.o smb1ops.o unc.o winucase.o \
smb2ops.o smb2maperror.o smb2transport.o \
smb2misc.o smb2pdu.o smb2inode.o smb2file.o cifsacl.o fs_context.o
......@@ -18,6 +18,8 @@ cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o dfs_cache.o
cifs-$(CONFIG_CIFS_SWN_UPCALL) += netlink.o cifs_swn.o
cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o
......
......@@ -53,30 +53,6 @@ const struct fscache_cookie_def cifs_fscache_server_index_def = {
.type = FSCACHE_COOKIE_TYPE_INDEX,
};
char *extract_sharename(const char *treename)
{
const char *src;
char *delim, *dst;
int len;
/* skip double chars at the beginning */
src = treename + 2;
/* share name is always preceded by '\\' now */
delim = strchr(src, '\\');
if (!delim)
return ERR_PTR(-EINVAL);
delim++;
len = strlen(delim);
/* caller has to free the memory */
dst = kstrndup(delim, len, GFP_KERNEL);
if (!dst)
return ERR_PTR(-ENOMEM);
return dst;
}
static enum
fscache_checkaux cifs_fscache_super_check_aux(void *cookie_netfs_data,
const void *data,
......
......@@ -23,6 +23,9 @@
#ifdef CONFIG_CIFS_SMB_DIRECT
#include "smbdirect.h"
#endif
#ifdef CONFIG_CIFS_SWN_UPCALL
#include "cifs_swn.h"
#endif
void
cifs_dump_mem(char *label, void *data, int length)
......@@ -115,6 +118,10 @@ static void cifs_debug_tcon(struct seq_file *m, struct cifs_tcon *tcon)
seq_printf(m, " POSIX Extensions");
if (tcon->ses->server->ops->dump_share_caps)
tcon->ses->server->ops->dump_share_caps(m, tcon);
#ifdef CONFIG_CIFS_SWN_UPCALL
if (tcon->use_witness)
seq_puts(m, " Witness");
#endif
if (tcon->need_reconnect)
seq_puts(m, "\tDISCONNECTED ");
......@@ -262,6 +269,9 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
seq_printf(m, ",XATTR");
#endif
seq_printf(m, ",ACL");
#ifdef CONFIG_CIFS_SWN_UPCALL
seq_puts(m, ",WITNESS");
#endif
seq_putc(m, '\n');
seq_printf(m, "CIFSMaxBufSize: %d\n", CIFSMaxBufSize);
seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid);
......@@ -462,6 +472,9 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
spin_unlock(&cifs_tcp_ses_lock);
seq_putc(m, '\n');
#ifdef CONFIG_CIFS_SWN_UPCALL
cifs_swn_dump(m);
#endif
/* BB add code to dump additional info such as TCP session info now */
return 0;
}
......
......@@ -23,6 +23,7 @@
#include "cifs_debug.h"
#include "cifs_unicode.h"
#include "dfs_cache.h"
#include "fs_context.h"
static LIST_HEAD(cifs_dfs_automount_list);
......@@ -124,7 +125,6 @@ cifs_build_devname(char *nodename, const char *prepath)
* @sb_mountdata: parent/root DFS mount options (template)
* @fullpath: full path in UNC format
* @ref: optional server's referral
* @devname: optional pointer for saving device name
*
* creates mount options for submount based on template options sb_mountdata
* and replacing unc,ip,prefixpath options with ones we've got form ref_unc.
......@@ -134,8 +134,7 @@ cifs_build_devname(char *nodename, const char *prepath)
*/
char *cifs_compose_mount_options(const char *sb_mountdata,
const char *fullpath,
const struct dfs_info3_param *ref,
char **devname)
const struct dfs_info3_param *ref)
{
int rc;
char *name;
......@@ -232,9 +231,6 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
strcat(mountdata, "ip=");
strcat(mountdata, srvIP);
if (devname)
*devname = name;
else
kfree(name);
/*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/
......@@ -258,6 +254,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
* to perform failover in case we failed to connect to the first target in the
* referral.
*
* @mntpt: directory entry for the path we are trying to automount
* @cifs_sb: parent/root superblock
* @fullpath: full path in UNC format
*/
......@@ -275,9 +272,13 @@ static struct vfsmount *cifs_dfs_do_mount(struct dentry *mntpt,
convert_delimiter(devname, '/');
/* TODO: change to call fs_context_for_mount(), fill in context directly, call fc_mount */
/* See afs_mntpt_do_automount in fs/afs/mntpt.c for an example */
/* strip first '\' from fullpath */
mountdata = cifs_compose_mount_options(cifs_sb->mountdata,
fullpath + 1, NULL, NULL);
mountdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options,
fullpath + 1, NULL);
if (IS_ERR(mountdata)) {
kfree(devname);
return (struct vfsmount *)mountdata;
......
......@@ -61,19 +61,9 @@ struct cifs_sb_info {
spinlock_t tlink_tree_lock;
struct tcon_link *master_tlink;
struct nls_table *local_nls;
unsigned int bsize;
unsigned int rsize;
unsigned int wsize;
unsigned long actimeo; /* attribute cache timeout (jiffies) */
struct smb3_fs_context *ctx;
atomic_t active;
kuid_t mnt_uid;
kgid_t mnt_gid;
kuid_t mnt_backupuid;
kgid_t mnt_backupgid;
umode_t mnt_file_mode;
umode_t mnt_dir_mode;
unsigned int mnt_cifs_flags;
char *mountdata; /* options received at mount time or via DFS refs */
struct delayed_work prune_tlinks;
struct rcu_head rcu;
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Witness Service client for CIFS
*
* Copyright (c) 2020 Samuel Cabrero <scabrero@suse.de>
*/
#ifndef _CIFS_SWN_H
#define _CIFS_SWN_H
struct cifs_tcon;
struct sk_buff;
struct genl_info;
extern int cifs_swn_register(struct cifs_tcon *tcon);
extern int cifs_swn_unregister(struct cifs_tcon *tcon);
extern int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info);
extern void cifs_swn_dump(struct seq_file *m);
extern void cifs_swn_check(void);
#endif /* _CIFS_SWN_H */
This diff is collapsed.
......@@ -30,6 +30,10 @@
#define WRITE_BIT 0x2
#define EXEC_BIT 0x1
#define ACL_OWNER_MASK 0700
#define ACL_GROUP_MASK 0770
#define ACL_EVERYONE_MASK 0777
#define UBITSHIFT 6
#define GBITSHIFT 3
......
......@@ -661,6 +661,11 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
unsigned char *tiblob = NULL; /* target info blob */
__le64 rsp_timestamp;
if (nls_cp == NULL) {
cifs_dbg(VFS, "%s called with nls_cp==NULL\n", __func__);
return -EINVAL;
}
if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) {
if (!ses->domainName) {
if (ses->domainAuto) {
......
This diff is collapsed.
......@@ -152,9 +152,13 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
extern void cifs_setsize(struct inode *inode, loff_t offset);
extern int cifs_truncate_page(struct address_space *mapping, loff_t from);
struct smb3_fs_context;
extern struct dentry *cifs_smb3_do_mount(struct file_system_type *fs_type,
int flags, struct smb3_fs_context *ctx);
#ifdef CONFIG_CIFS_NFSD_EXPORT
extern const struct export_operations cifs_export_ops;
#endif /* CONFIG_CIFS_NFSD_EXPORT */
#define CIFS_VERSION "2.29"
#define CIFS_VERSION "2.30"
#endif /* _CIFSFS_H */
......@@ -202,7 +202,7 @@ struct cifs_ses;
struct cifs_tcon;
struct dfs_info3_param;
struct cifs_fattr;
struct smb_vol;
struct smb3_fs_context;
struct cifs_fid;
struct cifs_readdata;
struct cifs_writedata;
......@@ -268,9 +268,9 @@ struct smb_version_operations {
/* negotiate to the server */
int (*negotiate)(const unsigned int, struct cifs_ses *);
/* set negotiated write size */
unsigned int (*negotiate_wsize)(struct cifs_tcon *, struct smb_vol *);
unsigned int (*negotiate_wsize)(struct cifs_tcon *tcon, struct smb3_fs_context *ctx);
/* set negotiated read size */
unsigned int (*negotiate_rsize)(struct cifs_tcon *, struct smb_vol *);
unsigned int (*negotiate_rsize)(struct cifs_tcon *tcon, struct smb3_fs_context *ctx);
/* setup smb sessionn */
int (*sess_setup)(const unsigned int, struct cifs_ses *,
const struct nls_table *);
......@@ -530,97 +530,6 @@ struct smb_version_values {
#define HEADER_SIZE(server) (server->vals->header_size)
#define MAX_HEADER_SIZE(server) (server->vals->max_header_size)
struct smb_vol {
char *username;
char *password;
char *domainname;
char *UNC;
char *iocharset; /* local code page for mapping to and from Unicode */
char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */
char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */
kuid_t cred_uid;
kuid_t linux_uid;
kgid_t linux_gid;
kuid_t backupuid;
kgid_t backupgid;
umode_t file_mode;
umode_t dir_mode;
enum securityEnum sectype; /* sectype requested via mnt opts */
bool sign; /* was signing requested via mnt opts? */
bool ignore_signature:1;
bool retry:1;
bool intr:1;
bool setuids:1;
bool setuidfromacl:1;
bool override_uid:1;
bool override_gid:1;
bool dynperm:1;
bool noperm:1;
bool nodelete:1;
bool mode_ace:1;
bool no_psx_acl:1; /* set if posix acl support should be disabled */
bool cifs_acl:1;
bool backupuid_specified; /* mount option backupuid is specified */
bool backupgid_specified; /* mount option backupgid is specified */
bool no_xattr:1; /* set if xattr (EA) support should be disabled*/
bool server_ino:1; /* use inode numbers from server ie UniqueId */
bool direct_io:1;
bool strict_io:1; /* strict cache behavior */
bool cache_ro:1;
bool cache_rw:1;
bool remap:1; /* set to remap seven reserved chars in filenames */
bool sfu_remap:1; /* remap seven reserved chars ala SFU */
bool posix_paths:1; /* unset to not ask for posix pathnames. */
bool no_linux_ext:1;
bool linux_ext:1;
bool sfu_emul:1;
bool nullauth:1; /* attempt to authenticate with null user */
bool nocase:1; /* request case insensitive filenames */
bool nobrl:1; /* disable sending byte range locks to srv */
bool nohandlecache:1; /* disable caching dir handles if srvr probs */
bool mand_lock:1; /* send mandatory not posix byte range lock reqs */
bool seal:1; /* request transport encryption on share */
bool nodfs:1; /* Do not request DFS, even if available */
bool local_lease:1; /* check leases only on local system, not remote */
bool noblocksnd:1;
bool noautotune:1;
bool nostrictsync:1; /* do not force expensive SMBflush on every sync */
bool no_lease:1; /* disable requesting leases */
bool fsc:1; /* enable fscache */
bool mfsymlinks:1; /* use Minshall+French Symlinks */
bool multiuser:1;
bool rwpidforward:1; /* pid forward for read/write operations */
bool nosharesock:1;
bool persistent:1;
bool nopersistent:1;
bool resilient:1; /* noresilient not required since not fored for CA */
bool domainauto:1;
bool rdma:1;
bool multichannel:1;
bool use_client_guid:1;
/* reuse existing guid for multichannel */
u8 client_guid[SMB2_CLIENT_GUID_SIZE];
unsigned int bsize;
unsigned int rsize;
unsigned int wsize;
unsigned int min_offload;
bool sockopt_tcp_nodelay:1;
unsigned long actimeo; /* attribute cache timeout (jiffies) */
struct smb_version_operations *ops;
struct smb_version_values *vals;
char *prepath;
struct sockaddr_storage dstaddr; /* destination address */
struct sockaddr_storage srcaddr; /* allow binding to a local IP */
struct nls_table *local_nls;
unsigned int echo_interval; /* echo interval in secs */
__u64 snapshot_time; /* needed for timewarp tokens */
__u32 handle_timeout; /* persistent and durable handle timeout in ms */
unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
unsigned int max_channels;
__u16 compression; /* compression algorithm 0xFFFF default 0=disabled */
bool rootfs:1; /* if it's a SMB root file system */
};
/**
* CIFS superblock mount flags (mnt_cifs_flags) to consider when
* trying to reuse existing superblock for a new mount
......@@ -649,7 +558,7 @@ struct smb_vol {
struct cifs_mnt_data {
struct cifs_sb_info *cifs_sb;
struct smb_vol *vol;
struct smb3_fs_context *ctx;
int flags;
};
......@@ -778,6 +687,10 @@ struct TCP_Server_Info {
int nr_targets;
bool noblockcnt; /* use non-blocking connect() */
bool is_channel; /* if a session channel */
#ifdef CONFIG_CIFS_SWN_UPCALL
bool use_swn_dstaddr;
struct sockaddr_storage swn_dstaddr;
#endif
};
struct cifs_credits {
......@@ -1177,6 +1090,9 @@ struct cifs_tcon {
int remap:2;
struct list_head ulist; /* cache update list */
#endif
#ifdef CONFIG_CIFS_SWN_UPCALL
bool use_witness:1; /* use witness protocol */
#endif
};
/*
......
......@@ -262,7 +262,7 @@
| WRITE_OWNER | SYNCHRONIZE)
#define SET_FILE_WRITE_RIGHTS (FILE_WRITE_DATA | FILE_APPEND_DATA \
| FILE_READ_EA | FILE_WRITE_EA \
| FILE_DELETE_CHILD | FILE_READ_ATTRIBUTES \
| FILE_READ_ATTRIBUTES \
| FILE_WRITE_ATTRIBUTES \
| DELETE | READ_CONTROL | WRITE_DAC \
| WRITE_OWNER | SYNCHRONIZE)
......
......@@ -27,8 +27,8 @@
#endif
struct statfs;
struct smb_vol;
struct smb_rqst;
struct smb3_fs_context;
/*
*****************************************************************
......@@ -72,14 +72,13 @@ extern void exit_cifs_spnego(void);
extern char *build_path_from_dentry(struct dentry *);
extern char *build_path_from_dentry_optional_prefix(struct dentry *direntry,
bool prefix);
extern char *cifs_build_path_to_root(struct smb_vol *vol,
extern char *cifs_build_path_to_root(struct smb3_fs_context *ctx,
struct cifs_sb_info *cifs_sb,
struct cifs_tcon *tcon,
int add_treename);
extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
extern char *cifs_compose_mount_options(const char *sb_mountdata,
const char *fullpath, const struct dfs_info3_param *ref,
char **devname);
const char *fullpath, const struct dfs_info3_param *ref);
/* extern void renew_parental_timestamps(struct dentry *direntry);*/
extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
struct TCP_Server_Info *server);
......@@ -89,6 +88,7 @@ extern void cifs_mid_q_entry_release(struct mid_q_entry *midEntry);
extern void cifs_wake_up_task(struct mid_q_entry *mid);
extern int cifs_handle_standard(struct TCP_Server_Info *server,
struct mid_q_entry *mid);
extern int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx);
extern bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs);
extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
extern int cifs_call_async(struct TCP_Server_Info *server,
......@@ -215,8 +215,8 @@ extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
struct cifs_fattr *fattr, struct inode *inode,
bool get_mode_from_special_sid,
const char *path, const struct cifs_fid *pfid);
extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64,
kuid_t, kgid_t);
extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
kuid_t uid, kgid_t gid);
extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
const char *, u32 *);
extern struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *,
......@@ -234,13 +234,9 @@ extern int cifs_read_page_from_socket(struct TCP_Server_Info *server,
struct page *page,
unsigned int page_offset,
unsigned int to_read);
extern int cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
struct cifs_sb_info *cifs_sb);
extern int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb);
extern int cifs_match_super(struct super_block *, void *);
extern void cifs_cleanup_volume_info(struct smb_vol *pvolume_info);
extern struct smb_vol *cifs_get_volume_info(char *mount_data,
const char *devname, bool is_smb3);
extern int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol);
extern int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx);
extern void cifs_umount(struct cifs_sb_info *);
extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon);
extern void cifs_reopen_persistent_handles(struct cifs_tcon *tcon);
......@@ -256,7 +252,7 @@ extern void cifs_add_pending_open_locked(struct cifs_fid *fid,
struct tcon_link *tlink,
struct cifs_pending_open *open);
extern void cifs_del_pending_open(struct cifs_pending_open *open);
extern struct TCP_Server_Info *cifs_get_tcp_session(struct smb_vol *vol);
extern struct TCP_Server_Info *cifs_get_tcp_session(struct smb3_fs_context *ctx);
extern void cifs_put_tcp_session(struct TCP_Server_Info *server,
int from_reconnect);
extern void cifs_put_tcon(struct cifs_tcon *tcon);
......@@ -332,7 +328,7 @@ extern int parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
const char *searchName, bool is_unicode);
extern void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
struct smb_vol *vol);
struct smb3_fs_context *ctx);
extern int CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
struct kstatfs *FSData);
extern int SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
......@@ -553,18 +549,15 @@ extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
unsigned char *p24);
extern int
cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data,
const char *devname, bool is_smb3);
extern void
cifs_cleanup_volume_info_contents(struct smb_vol *volume_info);
cifs_setup_volume_info(struct smb3_fs_context *ctx);
extern struct TCP_Server_Info *
cifs_find_tcp_session(struct smb_vol *vol);
cifs_find_tcp_session(struct smb3_fs_context *ctx);
extern void cifs_put_smb_ses(struct cifs_ses *ses);
extern struct cifs_ses *
cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info);
cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx);
void cifs_readdata_release(struct kref *refcount);
int cifs_async_readv(struct cifs_readdata *rdata);
......@@ -604,9 +597,7 @@ extern void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page,
unsigned int *len, unsigned int *offset);
struct cifs_chan *
cifs_ses_find_chan(struct cifs_ses *ses, struct TCP_Server_Info *server);
int cifs_try_adding_channels(struct cifs_ses *ses);
int cifs_ses_add_channel(struct cifs_ses *ses,
struct cifs_server_iface *iface);
int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses);
bool is_server_using_iface(struct TCP_Server_Info *server,
struct cifs_server_iface *iface);
bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface);
......@@ -620,6 +611,8 @@ int smb2_parse_query_directory(struct cifs_tcon *tcon, struct kvec *rsp_iov,
struct super_block *cifs_get_tcp_super(struct TCP_Server_Info *server);
void cifs_put_tcp_super(struct super_block *sb);
int update_super_prepath(struct cifs_tcon *tcon, char *prefix);
char *extract_hostname(const char *unc);
char *extract_sharename(const char *unc);
#ifdef CONFIG_CIFS_DFS_UPCALL
static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
......
This diff is collapsed.
......@@ -18,6 +18,7 @@
#include "cifs_debug.h"
#include "cifs_unicode.h"
#include "smb2glob.h"
#include "fs_context.h"
#include "dfs_cache.h"
......@@ -48,8 +49,8 @@ struct cache_entry {
struct vol_info {
char *fullpath;
spinlock_t smb_vol_lock;
struct smb_vol smb_vol;
spinlock_t ctx_lock;
struct smb3_fs_context ctx;
char *mntdata;
struct list_head list;
struct list_head rlist;
......@@ -586,7 +587,7 @@ static void __vol_release(struct vol_info *vi)
{
kfree(vi->fullpath);
kfree(vi->mntdata);
cifs_cleanup_volume_info_contents(&vi->smb_vol);
smb3_cleanup_fs_context_contents(&vi->ctx);
kfree(vi);
}
......@@ -1140,80 +1141,22 @@ int dfs_cache_get_tgt_referral(const char *path,
return rc;
}
static int dup_vol(struct smb_vol *vol, struct smb_vol *new)
{
memcpy(new, vol, sizeof(*new));
if (vol->username) {
new->username = kstrndup(vol->username, strlen(vol->username),
GFP_KERNEL);
if (!new->username)
return -ENOMEM;
}
if (vol->password) {
new->password = kstrndup(vol->password, strlen(vol->password),
GFP_KERNEL);
if (!new->password)
goto err_free_username;
}
if (vol->UNC) {
cifs_dbg(FYI, "%s: vol->UNC: %s\n", __func__, vol->UNC);
new->UNC = kstrndup(vol->UNC, strlen(vol->UNC), GFP_KERNEL);
if (!new->UNC)
goto err_free_password;
}
if (vol->domainname) {
new->domainname = kstrndup(vol->domainname,
strlen(vol->domainname), GFP_KERNEL);
if (!new->domainname)
goto err_free_unc;
}
if (vol->iocharset) {
new->iocharset = kstrndup(vol->iocharset,
strlen(vol->iocharset), GFP_KERNEL);
if (!new->iocharset)
goto err_free_domainname;
}
if (vol->prepath) {
cifs_dbg(FYI, "%s: vol->prepath: %s\n", __func__, vol->prepath);
new->prepath = kstrndup(vol->prepath, strlen(vol->prepath),
GFP_KERNEL);
if (!new->prepath)
goto err_free_iocharset;
}
return 0;
err_free_iocharset:
kfree(new->iocharset);
err_free_domainname:
kfree(new->domainname);
err_free_unc:
kfree(new->UNC);
err_free_password:
kfree_sensitive(new->password);
err_free_username:
kfree(new->username);
kfree(new);
return -ENOMEM;
}
/**
* dfs_cache_add_vol - add a cifs volume during mount() that will be handled by
* dfs_cache_add_vol - add a cifs context during mount() that will be handled by
* DFS cache refresh worker.
*
* @mntdata: mount data.
* @vol: cifs volume.
* @ctx: cifs context.
* @fullpath: origin full path.
*
* Return zero if volume was set up correctly, otherwise non-zero.
* Return zero if context was set up correctly, otherwise non-zero.
*/
int dfs_cache_add_vol(char *mntdata, struct smb_vol *vol, const char *fullpath)
int dfs_cache_add_vol(char *mntdata, struct smb3_fs_context *ctx, const char *fullpath)
{
int rc;
struct vol_info *vi;
if (!vol || !fullpath || !mntdata)
if (!ctx || !fullpath || !mntdata)
return -EINVAL;
cifs_dbg(FYI, "%s: fullpath: %s\n", __func__, fullpath);
......@@ -1228,12 +1171,12 @@ int dfs_cache_add_vol(char *mntdata, struct smb_vol *vol, const char *fullpath)
goto err_free_vi;
}
rc = dup_vol(vol, &vi->smb_vol);
rc = smb3_fs_context_dup(&vi->ctx, ctx);
if (rc)
goto err_free_fullpath;
vi->mntdata = mntdata;
spin_lock_init(&vi->smb_vol_lock);
spin_lock_init(&vi->ctx_lock);
kref_init(&vi->refcnt);
spin_lock(&vol_list_lock);
......@@ -1289,10 +1232,10 @@ int dfs_cache_update_vol(const char *fullpath, struct TCP_Server_Info *server)
spin_unlock(&vol_list_lock);
cifs_dbg(FYI, "%s: updating volume info\n", __func__);
spin_lock(&vi->smb_vol_lock);
memcpy(&vi->smb_vol.dstaddr, &server->dstaddr,
sizeof(vi->smb_vol.dstaddr));
spin_unlock(&vi->smb_vol_lock);
spin_lock(&vi->ctx_lock);
memcpy(&vi->ctx.dstaddr, &server->dstaddr,
sizeof(vi->ctx.dstaddr));
spin_unlock(&vi->ctx_lock);
kref_put(&vi->refcnt, vol_release);
......@@ -1445,11 +1388,11 @@ static inline void put_tcp_server(struct TCP_Server_Info *server)
cifs_put_tcp_session(server, 0);
}
static struct TCP_Server_Info *get_tcp_server(struct smb_vol *vol)
static struct TCP_Server_Info *get_tcp_server(struct smb3_fs_context *ctx)
{
struct TCP_Server_Info *server;
server = cifs_find_tcp_session(vol);
server = cifs_find_tcp_session(ctx);
if (IS_ERR_OR_NULL(server))
return NULL;
......@@ -1473,10 +1416,10 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi,
int rc;
struct cache_entry *ce;
struct dfs_info3_param ref = {0};
char *mdata = NULL, *devname = NULL;
char *mdata = NULL;
struct TCP_Server_Info *server;
struct cifs_ses *ses;
struct smb_vol vol = {NULL};
struct smb3_fs_context ctx = {NULL};
rpath = get_dfs_root(path);
if (IS_ERR(rpath))
......@@ -1500,8 +1443,7 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi,
up_read(&htable_rw_lock);
mdata = cifs_compose_mount_options(vi->mntdata, rpath, &ref,
&devname);
mdata = cifs_compose_mount_options(vi->mntdata, rpath, &ref);
free_dfs_info_param(&ref);
if (IS_ERR(mdata)) {
......@@ -1510,24 +1452,23 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi,
goto out;
}
rc = cifs_setup_volume_info(&vol, mdata, devname, false);
kfree(devname);
rc = cifs_setup_volume_info(&ctx);
if (rc) {
ses = ERR_PTR(rc);
goto out;
}
server = get_tcp_server(&vol);
server = get_tcp_server(&ctx);
if (!server) {
ses = ERR_PTR(-EHOSTDOWN);
goto out;
}
ses = cifs_get_smb_ses(server, &vol);
ses = cifs_get_smb_ses(server, &ctx);
out:
cifs_cleanup_volume_info_contents(&vol);
smb3_cleanup_fs_context_contents(&ctx);
kfree(mdata);
kfree(rpath);
......@@ -1619,7 +1560,7 @@ static void refresh_cache_worker(struct work_struct *work)
*/
spin_lock(&vol_list_lock);
list_for_each_entry(vi, &vol_list, list) {
server = get_tcp_server(&vi->smb_vol);
server = get_tcp_server(&vi->ctx);
if (!server)
continue;
......@@ -1631,9 +1572,9 @@ static void refresh_cache_worker(struct work_struct *work)
/* Walk through all TCONs and refresh any expired cache entry */
list_for_each_entry_safe(vi, nvi, &vols, rlist) {
spin_lock(&vi->smb_vol_lock);
server = get_tcp_server(&vi->smb_vol);
spin_unlock(&vi->smb_vol_lock);
spin_lock(&vi->ctx_lock);
server = get_tcp_server(&vi->ctx);
spin_unlock(&vi->ctx_lock);
if (!server)
goto next_vol;
......
......@@ -44,7 +44,7 @@ dfs_cache_noreq_update_tgthint(const char *path,
extern int dfs_cache_get_tgt_referral(const char *path,
const struct dfs_cache_tgt_iterator *it,
struct dfs_info3_param *ref);
extern int dfs_cache_add_vol(char *mntdata, struct smb_vol *vol,
extern int dfs_cache_add_vol(char *mntdata, struct smb3_fs_context *ctx,
const char *fullpath);
extern int dfs_cache_update_vol(const char *fullpath,
struct TCP_Server_Info *server);
......
......@@ -33,6 +33,7 @@
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
#include "cifs_unicode.h"
#include "fs_context.h"
static void
renew_parental_timestamps(struct dentry *direntry)
......@@ -46,10 +47,10 @@ renew_parental_timestamps(struct dentry *direntry)
}
char *
cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
cifs_build_path_to_root(struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_sb,
struct cifs_tcon *tcon, int add_treename)
{
int pplen = vol->prepath ? strlen(vol->prepath) + 1 : 0;
int pplen = ctx->prepath ? strlen(ctx->prepath) + 1 : 0;
int dfsplen;
char *full_path = NULL;
......@@ -71,7 +72,7 @@ cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
if (dfsplen)
memcpy(full_path, tcon->treeName, dfsplen);
full_path[dfsplen] = CIFS_DIR_SEP(cifs_sb);
memcpy(full_path + dfsplen + 1, vol->prepath, pplen);
memcpy(full_path + dfsplen + 1, ctx->prepath, pplen);
convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb));
return full_path;
}
......
......@@ -44,6 +44,7 @@
#include "cifs_fs_sb.h"
#include "fscache.h"
#include "smbdirect.h"
#include "fs_context.h"
static inline int cifs_convert_flags(unsigned int flags)
{
......@@ -416,6 +417,8 @@ static void cifsFileInfo_put_work(struct work_struct *work)
* cifsFileInfo_put - release a reference of file priv data
*
* Always potentially wait for oplock handler. See _cifsFileInfo_put().
*
* @cifs_file: cifs/smb3 specific info (eg refcounts) for an open file
*/
void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
{
......@@ -431,8 +434,11 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
*
* If @wait_for_oplock_handler is true and we are releasing the last
* reference, wait for any running oplock break handler of the file
* and cancel any pending one. If calling this function from the
* oplock break handler, you need to pass false.
* and cancel any pending one.
*
* @cifs_file: cifs/smb3 specific info (eg refcounts) for an open file
* @wait_oplock_handler: must be false if called from oplock_break_handler
* @offload: not offloaded on close and oplock breaks
*
*/
void _cifsFileInfo_put(struct cifsFileInfo *cifs_file,
......@@ -566,7 +572,7 @@ int cifs_open(struct inode *inode, struct file *file)
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
/* can not refresh inode info since size could be stale */
rc = cifs_posix_open(full_path, &inode, inode->i_sb,
cifs_sb->mnt_file_mode /* ignored */,
cifs_sb->ctx->file_mode /* ignored */,
file->f_flags, &oplock, &fid.netfid, xid);
if (rc == 0) {
cifs_dbg(FYI, "posix open succeeded\n");
......@@ -735,7 +741,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
~(O_CREAT | O_EXCL | O_TRUNC);
rc = cifs_posix_open(full_path, NULL, inode->i_sb,
cifs_sb->mnt_file_mode /* ignored */,
cifs_sb->ctx->file_mode /* ignored */,
oflags, &oplock, &cfile->fid.netfid, xid);
if (rc == 0) {
cifs_dbg(FYI, "posix reopen succeeded\n");
......@@ -2330,7 +2336,7 @@ static int cifs_writepages(struct address_space *mapping,
* If wsize is smaller than the page cache size, default to writing
* one page at a time via cifs_writepage
*/
if (cifs_sb->wsize < PAGE_SIZE)
if (cifs_sb->ctx->wsize < PAGE_SIZE)
return generic_writepages(mapping, wbc);
xid = get_xid();
......@@ -2363,7 +2369,7 @@ static int cifs_writepages(struct address_space *mapping,
if (rc)
get_file_rc = rc;
rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize,
rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->wsize,
&wsize, credits);
if (rc != 0) {
done = true;
......@@ -2905,7 +2911,7 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
break;
}
rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize,
rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->wsize,
&wsize, credits);
if (rc)
break;
......@@ -3636,7 +3642,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
break;
}
rc = server->ops->wait_mtu_credits(server, cifs_sb->rsize,
rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->rsize,
&rsize, credits);
if (rc)
break;
......@@ -4022,7 +4028,7 @@ cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset)
cifs_sb = CIFS_FILE_SB(file);
/* FIXME: set up handlers for larger reads and/or convert to async */
rsize = min_t(unsigned int, cifs_sb->rsize, CIFSMaxBufSize);
rsize = min_t(unsigned int, cifs_sb->ctx->rsize, CIFSMaxBufSize);
if (file->private_data == NULL) {
rc = -EBADF;
......@@ -4407,7 +4413,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
break;
}
rc = server->ops->wait_mtu_credits(server, cifs_sb->rsize,
rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->rsize,
&rsize, credits);
if (rc)
break;
......
This diff is collapsed.
......@@ -9,8 +9,11 @@
#ifndef _FS_CONTEXT_H
#define _FS_CONTEXT_H
#include <linux/parser.h>
#include "cifsglob.h"
#include <linux/parser.h>
#include <linux/fs_parser.h>
#define cifs_invalf(fc, fmt, ...) invalf(fc, fmt, ## __VA_ARGS__)
enum smb_version {
Smb_1 = 1,
......@@ -24,8 +27,6 @@ enum smb_version {
Smb_version_err
};
int cifs_parse_smb_version(char *value, struct smb_vol *vol, bool is_smb3);
enum {
Opt_cache_loose,
Opt_cache_strict,
......@@ -35,8 +36,6 @@ enum {
Opt_cache_err
};
int cifs_parse_cache_flavor(char *value, struct smb_vol *vol);
enum cifs_sec_param {
Opt_sec_krb5,
Opt_sec_krb5i,
......@@ -53,6 +52,220 @@ enum cifs_sec_param {
Opt_sec_err
};
int cifs_parse_security_flavors(char *value, struct smb_vol *vol);
enum cifs_param {
/* Mount options that take no arguments */
Opt_user_xattr,
Opt_forceuid,
Opt_forcegid,
Opt_noblocksend,
Opt_noautotune,
Opt_nolease,
Opt_hard,
Opt_soft,
Opt_perm,
Opt_nodelete,
Opt_mapposix,
Opt_mapchars,
Opt_nomapchars,
Opt_sfu,
Opt_nodfs,
Opt_posixpaths,
Opt_unix,
Opt_nocase,
Opt_brl,
Opt_handlecache,
Opt_forcemandatorylock,
Opt_setuidfromacl,
Opt_setuids,
Opt_dynperm,
Opt_intr,
Opt_strictsync,
Opt_serverino,
Opt_rwpidforward,
Opt_cifsacl,
Opt_acl,
Opt_locallease,
Opt_sign,
Opt_ignore_signature,
Opt_seal,
Opt_noac,
Opt_fsc,
Opt_mfsymlinks,
Opt_multiuser,
Opt_sloppy,
Opt_nosharesock,
Opt_persistent,
Opt_resilient,
Opt_domainauto,
Opt_rdma,
Opt_modesid,
Opt_rootfs,
Opt_multichannel,
Opt_compress,
Opt_witness,
/* Mount options which take numeric value */
Opt_backupuid,
Opt_backupgid,
Opt_uid,
Opt_cruid,
Opt_gid,
Opt_port,
Opt_file_mode,
Opt_dirmode,
Opt_min_enc_offload,
Opt_blocksize,
Opt_rsize,
Opt_wsize,
Opt_actimeo,
Opt_echo_interval,
Opt_max_credits,
Opt_snapshot,
Opt_max_channels,
Opt_handletimeout,
/* Mount options which take string value */
Opt_source,
Opt_user,
Opt_pass,
Opt_ip,
Opt_domain,
Opt_srcaddr,
Opt_iocharset,
Opt_netbiosname,
Opt_servern,
Opt_ver,
Opt_vers,
Opt_sec,
Opt_cache,
/* Mount options to be ignored */
Opt_ignore,
Opt_err
};
struct smb3_fs_context {
bool uid_specified;
bool gid_specified;
bool sloppy;
bool got_ip;
bool got_version;
bool got_rsize;
bool got_wsize;
bool got_bsize;
unsigned short port;
char *username;
char *password;
char *domainname;
char *UNC;
char *nodename;
char *iocharset; /* local code page for mapping to and from Unicode */
char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */
char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */
kuid_t cred_uid;
kuid_t linux_uid;
kgid_t linux_gid;
kuid_t backupuid;
kgid_t backupgid;
umode_t file_mode;
umode_t dir_mode;
enum securityEnum sectype; /* sectype requested via mnt opts */
bool sign; /* was signing requested via mnt opts? */
bool ignore_signature:1;
bool retry:1;
bool intr:1;
bool setuids:1;
bool setuidfromacl:1;
bool override_uid:1;
bool override_gid:1;
bool dynperm:1;
bool noperm:1;
bool nodelete:1;
bool mode_ace:1;
bool no_psx_acl:1; /* set if posix acl support should be disabled */
bool cifs_acl:1;
bool backupuid_specified; /* mount option backupuid is specified */
bool backupgid_specified; /* mount option backupgid is specified */
bool no_xattr:1; /* set if xattr (EA) support should be disabled*/
bool server_ino:1; /* use inode numbers from server ie UniqueId */
bool direct_io:1;
bool strict_io:1; /* strict cache behavior */
bool cache_ro:1;
bool cache_rw:1;
bool remap:1; /* set to remap seven reserved chars in filenames */
bool sfu_remap:1; /* remap seven reserved chars ala SFU */
bool posix_paths:1; /* unset to not ask for posix pathnames. */
bool no_linux_ext:1;
bool linux_ext:1;
bool sfu_emul:1;
bool nullauth:1; /* attempt to authenticate with null user */
bool nocase:1; /* request case insensitive filenames */
bool nobrl:1; /* disable sending byte range locks to srv */
bool nohandlecache:1; /* disable caching dir handles if srvr probs */
bool mand_lock:1; /* send mandatory not posix byte range lock reqs */
bool seal:1; /* request transport encryption on share */
bool nodfs:1; /* Do not request DFS, even if available */
bool local_lease:1; /* check leases only on local system, not remote */
bool noblocksnd:1;
bool noautotune:1;
bool nostrictsync:1; /* do not force expensive SMBflush on every sync */
bool no_lease:1; /* disable requesting leases */
bool fsc:1; /* enable fscache */
bool mfsymlinks:1; /* use Minshall+French Symlinks */
bool multiuser:1;
bool rwpidforward:1; /* pid forward for read/write operations */
bool nosharesock:1;
bool persistent:1;
bool nopersistent:1;
bool resilient:1; /* noresilient not required since not fored for CA */
bool domainauto:1;
bool rdma:1;
bool multichannel:1;
bool use_client_guid:1;
/* reuse existing guid for multichannel */
u8 client_guid[SMB2_CLIENT_GUID_SIZE];
unsigned int bsize;
unsigned int rsize;
unsigned int wsize;
unsigned int min_offload;
bool sockopt_tcp_nodelay:1;
unsigned long actimeo; /* attribute cache timeout (jiffies) */
struct smb_version_operations *ops;
struct smb_version_values *vals;
char *prepath;
struct sockaddr_storage dstaddr; /* destination address */
struct sockaddr_storage srcaddr; /* allow binding to a local IP */
struct nls_table *local_nls; /* This is a copy of the pointer in cifs_sb */
unsigned int echo_interval; /* echo interval in secs */
__u64 snapshot_time; /* needed for timewarp tokens */
__u32 handle_timeout; /* persistent and durable handle timeout in ms */
unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
unsigned int max_channels;
__u16 compression; /* compression algorithm 0xFFFF default 0=disabled */
bool rootfs:1; /* if it's a SMB root file system */
bool witness:1; /* use witness protocol */
char *mount_options;
};
extern const struct fs_parameter_spec smb3_fs_parameters[];
extern int cifs_parse_cache_flavor(char *value,
struct smb3_fs_context *ctx);
extern int cifs_parse_security_flavors(char *value,
struct smb3_fs_context *ctx);
extern int smb3_init_fs_context(struct fs_context *fc);
extern void smb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx);
extern void smb3_cleanup_fs_context(struct smb3_fs_context *ctx);
static inline struct smb3_fs_context *smb3_fc2context(const struct fs_context *fc)
{
return fc->fs_private;
}
extern int smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx);
extern void smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb);
#endif
......@@ -22,6 +22,7 @@
#include "cifsglob.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
#include "cifsproto.h"
/*
* Key layout of CIFS server cache index object
......
......@@ -57,7 +57,6 @@ extern const struct fscache_cookie_def cifs_fscache_inode_object_def;
extern int cifs_fscache_register(void);
extern void cifs_fscache_unregister(void);
extern char *extract_sharename(const char *);
/*
* fscache.c
......
......@@ -37,6 +37,7 @@
#include "cifs_fs_sb.h"
#include "cifs_unicode.h"
#include "fscache.h"
#include "fs_context.h"
static void cifs_set_ops(struct inode *inode)
......@@ -294,7 +295,7 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
break;
}
fattr->cf_uid = cifs_sb->mnt_uid;
fattr->cf_uid = cifs_sb->ctx->linux_uid;
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) {
u64 id = le64_to_cpu(info->Uid);
if (id < ((uid_t)-1)) {
......@@ -304,7 +305,7 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
}
}
fattr->cf_gid = cifs_sb->mnt_gid;
fattr->cf_gid = cifs_sb->ctx->linux_gid;
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) {
u64 id = le64_to_cpu(info->Gid);
if (id < ((gid_t)-1)) {
......@@ -333,8 +334,8 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
memset(fattr, 0, sizeof(*fattr));
fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU;
fattr->cf_uid = cifs_sb->mnt_uid;
fattr->cf_gid = cifs_sb->mnt_gid;
fattr->cf_uid = cifs_sb->ctx->linux_uid;
fattr->cf_gid = cifs_sb->ctx->linux_gid;
ktime_get_coarse_real_ts64(&fattr->cf_mtime);
fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime;
fattr->cf_nlink = 2;
......@@ -644,8 +645,8 @@ smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct smb311_posix_qinfo *
}
/* else if reparse point ... TODO: add support for FIFO and blk dev; special file types */
fattr->cf_uid = cifs_sb->mnt_uid; /* TODO: map uid and gid from SID */
fattr->cf_gid = cifs_sb->mnt_gid;
fattr->cf_uid = cifs_sb->ctx->linux_uid; /* TODO: map uid and gid from SID */
fattr->cf_gid = cifs_sb->ctx->linux_gid;
cifs_dbg(FYI, "POSIX query info: mode 0x%x uniqueid 0x%llx nlink %d\n",
fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink);
......@@ -685,25 +686,25 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
if (reparse_tag == IO_REPARSE_TAG_LX_SYMLINK) {
fattr->cf_mode |= S_IFLNK | cifs_sb->mnt_file_mode;
fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode;
fattr->cf_dtype = DT_LNK;
} else if (reparse_tag == IO_REPARSE_TAG_LX_FIFO) {
fattr->cf_mode |= S_IFIFO | cifs_sb->mnt_file_mode;
fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode;
fattr->cf_dtype = DT_FIFO;
} else if (reparse_tag == IO_REPARSE_TAG_AF_UNIX) {
fattr->cf_mode |= S_IFSOCK | cifs_sb->mnt_file_mode;
fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode;
fattr->cf_dtype = DT_SOCK;
} else if (reparse_tag == IO_REPARSE_TAG_LX_CHR) {
fattr->cf_mode |= S_IFCHR | cifs_sb->mnt_file_mode;
fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode;
fattr->cf_dtype = DT_CHR;
} else if (reparse_tag == IO_REPARSE_TAG_LX_BLK) {
fattr->cf_mode |= S_IFBLK | cifs_sb->mnt_file_mode;
fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode;
fattr->cf_dtype = DT_BLK;
} else if (symlink) { /* TODO add more reparse tag checks */
fattr->cf_mode = S_IFLNK;
fattr->cf_dtype = DT_LNK;
} else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode;
fattr->cf_dtype = DT_DIR;
/*
* Server can return wrong NumberOfLinks value for directories
......@@ -712,7 +713,7 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
if (!tcon->unix_ext)
fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
} else {
fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
fattr->cf_mode = S_IFREG | cifs_sb->ctx->file_mode;
fattr->cf_dtype = DT_REG;
/* clear write bits if ATTR_READONLY is set */
......@@ -731,8 +732,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
}
}
fattr->cf_uid = cifs_sb->mnt_uid;
fattr->cf_gid = cifs_sb->mnt_gid;
fattr->cf_uid = cifs_sb->ctx->linux_uid;
fattr->cf_gid = cifs_sb->ctx->linux_gid;
}
static int
......@@ -771,6 +772,7 @@ cifs_get_file_info(struct file *filp)
*/
rc = 0;
CIFS_I(inode)->time = 0;
goto cgfi_exit;
default:
goto cgfi_exit;
}
......@@ -803,11 +805,15 @@ static __u64 simple_hashstr(const char *str)
* cifs_backup_query_path_info - SMB1 fallback code to get ino
*
* Fallback code to get file metadata when we don't have access to
* @full_path (EACCES) and have backup creds.
* full_path (EACCES) and have backup creds.
*
* @data will be set to search info result buffer
* @resp_buf will be set to cifs resp buf and needs to be freed with
* cifs_buf_release() when done with @data.
* @xid: transaction id used to identify original request in logs
* @tcon: information about the server share we have mounted
* @sb: the superblock stores info such as disk space available
* @full_path: name of the file we are getting the metadata for
* @resp_buf: will be set to cifs resp buf and needs to be freed with
* cifs_buf_release() when done with @data
* @data: will be set to search info result buffer
*/
static int
cifs_backup_query_path_info(int xid,
......@@ -1386,8 +1392,8 @@ struct inode *cifs_root_iget(struct super_block *sb)
set_nlink(inode, 2);
inode->i_op = &cifs_ipc_inode_ops;
inode->i_fop = &simple_dir_operations;
inode->i_uid = cifs_sb->mnt_uid;
inode->i_gid = cifs_sb->mnt_gid;
inode->i_uid = cifs_sb->ctx->linux_uid;
inode->i_gid = cifs_sb->ctx->linux_gid;
spin_unlock(&inode->i_lock);
} else if (rc) {
iget_failed(inode);
......@@ -2192,11 +2198,11 @@ cifs_inode_needs_reval(struct inode *inode)
if (!lookupCacheEnabled)
return true;
if (!cifs_sb->actimeo)
if (!cifs_sb->ctx->actimeo)
return true;
if (!time_in_range(jiffies, cifs_i->time,
cifs_i->time + cifs_sb->actimeo))
cifs_i->time + cifs_sb->ctx->actimeo))
return true;
/* hardlinked files w/ noserverino get "special" treatment */
......@@ -2228,7 +2234,9 @@ cifs_invalidate_mapping(struct inode *inode)
/**
* cifs_wait_bit_killable - helper for functions that are sleeping on bit locks
* @word: long word containing the bit lock
*
* @key: currently unused
* @mode: the task state to sleep in
*/
static int
cifs_wait_bit_killable(struct wait_bit_key *key, int mode)
......@@ -2401,7 +2409,7 @@ int cifs_getattr(const struct path *path, struct kstat *stat,
}
generic_fillattr(inode, stat);
stat->blksize = cifs_sb->bsize;
stat->blksize = cifs_sb->ctx->bsize;
stat->ino = CIFS_I(inode)->uniqueid;
/* old CIFS Unix Extensions doesn't return create time */
......@@ -2812,7 +2820,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) {
if (uid_valid(uid) || gid_valid(gid)) {
rc = id_mode_to_cifs_acl(inode, full_path, NO_CHANGE_64,
mode = NO_CHANGE_64;
rc = id_mode_to_cifs_acl(inode, full_path, &mode,
uid, gid);
if (rc) {
cifs_dbg(FYI, "%s: Setting id failed with error: %d\n",
......@@ -2833,13 +2842,20 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
rc = 0;
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) {
rc = id_mode_to_cifs_acl(inode, full_path, mode,
rc = id_mode_to_cifs_acl(inode, full_path, &mode,
INVALID_UID, INVALID_GID);
if (rc) {
cifs_dbg(FYI, "%s: Setting ACL failed with error: %d\n",
__func__, rc);
goto cifs_setattr_exit;
}
/*
* In case of CIFS_MOUNT_CIFS_ACL, we cannot support all modes.
* Pick up the actual mode bits that were set.
*/
if (mode != attrs->ia_mode)
attrs->ia_mode = mode;
} else
if (((mode & S_IWUGO) == 0) &&
(cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
......@@ -2862,10 +2878,10 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
attrs->ia_mode &= ~(S_IALLUGO);
if (S_ISDIR(inode->i_mode))
attrs->ia_mode |=
cifs_sb->mnt_dir_mode;
cifs_sb->ctx->dir_mode;
else
attrs->ia_mode |=
cifs_sb->mnt_file_mode;
cifs_sb->ctx->file_mode;
}
} else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
/* ignore mode change - ATTR_READONLY hasn't changed */
......
......@@ -35,6 +35,7 @@
#ifdef CONFIG_CIFS_DFS_UPCALL
#include "dns_resolve.h"
#endif
#include "fs_context.h"
extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp;
......@@ -632,11 +633,11 @@ bool
backup_cred(struct cifs_sb_info *cifs_sb)
{
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) {
if (uid_eq(cifs_sb->mnt_backupuid, current_fsuid()))
if (uid_eq(cifs_sb->ctx->backupuid, current_fsuid()))
return true;
}
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID) {
if (in_group_p(cifs_sb->mnt_backupgid))
if (in_group_p(cifs_sb->ctx->backupgid))
return true;
}
......
// SPDX-License-Identifier: GPL-2.0
/*
* Netlink routines for CIFS
*
* Copyright (c) 2020 Samuel Cabrero <scabrero@suse.de>
*/
#include <net/genetlink.h>
#include <uapi/linux/cifs/cifs_netlink.h>
#include "netlink.h"
#include "cifsglob.h"
#include "cifs_debug.h"
#include "cifs_swn.h"
static const struct nla_policy cifs_genl_policy[CIFS_GENL_ATTR_MAX + 1] = {
[CIFS_GENL_ATTR_SWN_REGISTRATION_ID] = { .type = NLA_U32 },
[CIFS_GENL_ATTR_SWN_NET_NAME] = { .type = NLA_STRING },
[CIFS_GENL_ATTR_SWN_SHARE_NAME] = { .type = NLA_STRING },
[CIFS_GENL_ATTR_SWN_IP] = { .len = sizeof(struct sockaddr_storage) },
[CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY] = { .type = NLA_FLAG },
[CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY] = { .type = NLA_FLAG },
[CIFS_GENL_ATTR_SWN_IP_NOTIFY] = { .type = NLA_FLAG },
[CIFS_GENL_ATTR_SWN_KRB_AUTH] = { .type = NLA_FLAG },
[CIFS_GENL_ATTR_SWN_USER_NAME] = { .type = NLA_STRING },
[CIFS_GENL_ATTR_SWN_PASSWORD] = { .type = NLA_STRING },
[CIFS_GENL_ATTR_SWN_DOMAIN_NAME] = { .type = NLA_STRING },
[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE] = { .type = NLA_U32 },
[CIFS_GENL_ATTR_SWN_RESOURCE_STATE] = { .type = NLA_U32 },
[CIFS_GENL_ATTR_SWN_RESOURCE_NAME] = { .type = NLA_STRING},
};
static struct genl_ops cifs_genl_ops[] = {
{
.cmd = CIFS_GENL_CMD_SWN_NOTIFY,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = cifs_swn_notify,
},
};
static const struct genl_multicast_group cifs_genl_mcgrps[] = {
[CIFS_GENL_MCGRP_SWN] = { .name = CIFS_GENL_MCGRP_SWN_NAME },
};
struct genl_family cifs_genl_family = {
.name = CIFS_GENL_NAME,
.version = CIFS_GENL_VERSION,
.hdrsize = 0,
.maxattr = CIFS_GENL_ATTR_MAX,
.module = THIS_MODULE,
.policy = cifs_genl_policy,
.ops = cifs_genl_ops,
.n_ops = ARRAY_SIZE(cifs_genl_ops),
.mcgrps = cifs_genl_mcgrps,
.n_mcgrps = ARRAY_SIZE(cifs_genl_mcgrps),
};
/**
* cifs_genl_init - Register generic netlink family
*
* Return zero if initialized successfully, otherwise non-zero.
*/
int cifs_genl_init(void)
{
int ret;
ret = genl_register_family(&cifs_genl_family);
if (ret < 0) {
cifs_dbg(VFS, "%s: failed to register netlink family\n",
__func__);
return ret;
}
return 0;
}
/**
* cifs_genl_exit - Unregister generic netlink family
*/
void cifs_genl_exit(void)
{
int ret;
ret = genl_unregister_family(&cifs_genl_family);
if (ret < 0) {
cifs_dbg(VFS, "%s: failed to unregister netlink family\n",
__func__);
}
}
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Netlink routines for CIFS
*
* Copyright (c) 2020 Samuel Cabrero <scabrero@suse.de>
*/
#ifndef _CIFS_NETLINK_H
#define _CIFS_NETLINK_H
extern struct genl_family cifs_genl_family;
extern int cifs_genl_init(void);
extern void cifs_genl_exit(void);
#endif /* _CIFS_NETLINK_H */
......@@ -33,6 +33,7 @@
#include "cifs_fs_sb.h"
#include "cifsfs.h"
#include "smb2proto.h"
#include "fs_context.h"
/*
* To be safe - for UCS to UTF-8 with strings loaded with the rare long
......@@ -165,8 +166,8 @@ static bool reparse_file_needs_reval(const struct cifs_fattr *fattr)
static void
cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
{
fattr->cf_uid = cifs_sb->mnt_uid;
fattr->cf_gid = cifs_sb->mnt_gid;
fattr->cf_uid = cifs_sb->ctx->linux_uid;
fattr->cf_gid = cifs_sb->ctx->linux_gid;
/*
* The IO_REPARSE_TAG_LX_ tags originally were used by WSL but they
......@@ -177,25 +178,25 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
* reasonably map some of them to directories vs. files vs. symlinks
*/
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode;
fattr->cf_dtype = DT_DIR;
} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_SYMLINK) {
fattr->cf_mode |= S_IFLNK | cifs_sb->mnt_file_mode;
fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode;
fattr->cf_dtype = DT_LNK;
} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_FIFO) {
fattr->cf_mode |= S_IFIFO | cifs_sb->mnt_file_mode;
fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode;
fattr->cf_dtype = DT_FIFO;
} else if (fattr->cf_cifstag == IO_REPARSE_TAG_AF_UNIX) {
fattr->cf_mode |= S_IFSOCK | cifs_sb->mnt_file_mode;
fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode;
fattr->cf_dtype = DT_SOCK;
} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_CHR) {
fattr->cf_mode |= S_IFCHR | cifs_sb->mnt_file_mode;
fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode;
fattr->cf_dtype = DT_CHR;
} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_BLK) {
fattr->cf_mode |= S_IFBLK | cifs_sb->mnt_file_mode;
fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode;
fattr->cf_dtype = DT_BLK;
} else { /* TODO: should we mark some other reparse points (like DFSR) as directories? */
fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
fattr->cf_mode = S_IFREG | cifs_sb->ctx->file_mode;
fattr->cf_dtype = DT_REG;
}
......
......@@ -32,6 +32,11 @@
#include <linux/slab.h>
#include "cifs_spnego.h"
#include "smb2proto.h"
#include "fs_context.h"
static int
cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
struct cifs_server_iface *iface);
bool
is_server_using_iface(struct TCP_Server_Info *server,
......@@ -70,7 +75,7 @@ bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface)
}
/* returns number of channels added */
int cifs_try_adding_channels(struct cifs_ses *ses)
int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
{
int old_chan_count = ses->chan_count;
int left = ses->chan_max - ses->chan_count;
......@@ -133,7 +138,7 @@ int cifs_try_adding_channels(struct cifs_ses *ses)
continue;
}
rc = cifs_ses_add_channel(ses, iface);
rc = cifs_ses_add_channel(cifs_sb, ses, iface);
if (rc) {
cifs_dbg(FYI, "failed to open extra channel on iface#%d rc=%d\n",
i, rc);
......@@ -166,11 +171,12 @@ cifs_ses_find_chan(struct cifs_ses *ses, struct TCP_Server_Info *server)
return NULL;
}
int
cifs_ses_add_channel(struct cifs_ses *ses, struct cifs_server_iface *iface)
static int
cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
struct cifs_server_iface *iface)
{
struct cifs_chan *chan;
struct smb_vol vol = {NULL};
struct smb3_fs_context ctx = {NULL};
static const char unc_fmt[] = "\\%s\\foo";
char unc[sizeof(unc_fmt)+SERVER_NAME_LEN_WITH_NULL] = {0};
struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr;
......@@ -188,67 +194,62 @@ cifs_ses_add_channel(struct cifs_ses *ses, struct cifs_server_iface *iface)
&ipv6->sin6_addr);
/*
* Setup a smb_vol with mostly the same info as the existing
* Setup a ctx with mostly the same info as the existing
* session and overwrite it with the requested iface data.
*
* We need to setup at least the fields used for negprot and
* sesssetup.
*
* We only need the volume here, so we can reuse memory from
* We only need the ctx here, so we can reuse memory from
* the session and server without caring about memory
* management.
*/
/* Always make new connection for now (TODO?) */
vol.nosharesock = true;
ctx.nosharesock = true;
/* Auth */
vol.domainauto = ses->domainAuto;
vol.domainname = ses->domainName;
vol.username = ses->user_name;
vol.password = ses->password;
vol.sectype = ses->sectype;
vol.sign = ses->sign;
ctx.domainauto = ses->domainAuto;
ctx.domainname = ses->domainName;
ctx.username = ses->user_name;
ctx.password = ses->password;
ctx.sectype = ses->sectype;
ctx.sign = ses->sign;
/* UNC and paths */
/* XXX: Use ses->server->hostname? */
sprintf(unc, unc_fmt, ses->serverName);
vol.UNC = unc;
vol.prepath = "";
ctx.UNC = unc;
ctx.prepath = "";
/* Reuse same version as master connection */
vol.vals = ses->server->vals;
vol.ops = ses->server->ops;
ctx.vals = ses->server->vals;
ctx.ops = ses->server->ops;
vol.noblocksnd = ses->server->noblocksnd;
vol.noautotune = ses->server->noautotune;
vol.sockopt_tcp_nodelay = ses->server->tcp_nodelay;
vol.echo_interval = ses->server->echo_interval / HZ;
ctx.noblocksnd = ses->server->noblocksnd;
ctx.noautotune = ses->server->noautotune;
ctx.sockopt_tcp_nodelay = ses->server->tcp_nodelay;
ctx.echo_interval = ses->server->echo_interval / HZ;
/*
* This will be used for encoding/decoding user/domain/pw
* during sess setup auth.
*
* XXX: We use the default for simplicity but the proper way
* would be to use the one that ses used, which is not
* stored. This might break when dealing with non-ascii
* strings.
*/
vol.local_nls = load_nls_default();
ctx.local_nls = cifs_sb->local_nls;
/* Use RDMA if possible */
vol.rdma = iface->rdma_capable;
memcpy(&vol.dstaddr, &iface->sockaddr, sizeof(struct sockaddr_storage));
ctx.rdma = iface->rdma_capable;
memcpy(&ctx.dstaddr, &iface->sockaddr, sizeof(struct sockaddr_storage));
/* reuse master con client guid */
memcpy(&vol.client_guid, ses->server->client_guid,
memcpy(&ctx.client_guid, ses->server->client_guid,
SMB2_CLIENT_GUID_SIZE);
vol.use_client_guid = true;
ctx.use_client_guid = true;
mutex_lock(&ses->session_mutex);
chan = ses->binding_chan = &ses->chans[ses->chan_count];
chan->server = cifs_get_tcp_session(&vol);
chan->server = cifs_get_tcp_session(&ctx);
if (IS_ERR(chan->server)) {
rc = PTR_ERR(chan->server);
chan->server = NULL;
......@@ -274,7 +275,7 @@ cifs_ses_add_channel(struct cifs_ses *ses, struct cifs_server_iface *iface)
if (rc)
goto out;
rc = cifs_setup_session(xid, ses, vol.local_nls);
rc = cifs_setup_session(xid, ses, cifs_sb->local_nls);
if (rc)
goto out;
......@@ -297,7 +298,6 @@ cifs_ses_add_channel(struct cifs_ses *ses, struct cifs_server_iface *iface)
if (rc && chan->server)
cifs_put_tcp_session(chan->server, 0);
unload_nls(vol.local_nls);
return rc;
}
......@@ -812,6 +812,7 @@ cifs_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
return NTLMv2;
if (global_secflags & CIFSSEC_MAY_NTLM)
return NTLM;
break;
default:
break;
}
......
......@@ -12,6 +12,7 @@
#include "cifs_debug.h"
#include "cifspdu.h"
#include "cifs_unicode.h"
#include "fs_context.h"
/*
* An NT cancel request header looks just like the original request except:
......@@ -428,15 +429,15 @@ cifs_negotiate(const unsigned int xid, struct cifs_ses *ses)
}
static unsigned int
cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
{
__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
struct TCP_Server_Info *server = tcon->ses->server;
unsigned int wsize;
/* start with specified wsize, or default */
if (volume_info->wsize)
wsize = volume_info->wsize;
if (ctx->wsize)
wsize = ctx->wsize;
else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
wsize = CIFS_DEFAULT_IOSIZE;
else
......@@ -463,7 +464,7 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
}
static unsigned int
cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
{
__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
struct TCP_Server_Info *server = tcon->ses->server;
......@@ -488,7 +489,7 @@ cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
else
defsize = server->maxBuf - sizeof(READ_RSP);
rsize = volume_info->rsize ? volume_info->rsize : defsize;
rsize = ctx->rsize ? ctx->rsize : defsize;
/*
* no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to
......@@ -1005,7 +1006,7 @@ cifs_is_read_op(__u32 oplock)
static unsigned int
cifs_wp_retry_size(struct inode *inode)
{
return CIFS_SB(inode->i_sb)->wsize;
return CIFS_SB(inode->i_sb)->ctx->wsize;
}
static bool
......
......@@ -94,6 +94,8 @@ static const __le16 smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = {
/* SMB2_OPLOCK_BREAK */ cpu_to_le16(24)
};
#define SMB311_NEGPROT_BASE_SIZE (sizeof(struct smb2_sync_hdr) + sizeof(struct smb2_negotiate_rsp))
static __u32 get_neg_ctxt_len(struct smb2_sync_hdr *hdr, __u32 len,
__u32 non_ctxlen)
{
......@@ -107,12 +109,27 @@ static __u32 get_neg_ctxt_len(struct smb2_sync_hdr *hdr, __u32 len,
(pneg_rsp->DialectRevision != cpu_to_le16(SMB311_PROT_ID)))
return 0;
/* Make sure that negotiate contexts start after gss security blob */
/*
* if SPNEGO blob present (ie the RFC2478 GSS info which indicates
* which security mechanisms the server supports) make sure that
* the negotiate contexts start after it
*/
nc_offset = le32_to_cpu(pneg_rsp->NegotiateContextOffset);
if (nc_offset < non_ctxlen) {
pr_warn_once("Invalid negotiate context offset\n");
/*
* non_ctxlen is at least shdr->StructureSize + pdu->StructureSize2
* and the latter is 1 byte bigger than the fix-sized area of the
* NEGOTIATE response
*/
if (nc_offset + 1 < non_ctxlen) {
pr_warn_once("Invalid negotiate context offset %d\n", nc_offset);
return 0;
}
} else if (nc_offset + 1 == non_ctxlen) {
cifs_dbg(FYI, "no SPNEGO security blob in negprot rsp\n");
size_of_pad_before_neg_ctxts = 0;
} else if (non_ctxlen == SMB311_NEGPROT_BASE_SIZE)
/* has padding, but no SPNEGO blob */
size_of_pad_before_neg_ctxts = nc_offset - non_ctxlen + 1;
else
size_of_pad_before_neg_ctxts = nc_offset - non_ctxlen;
/* Verify that at least minimal negotiate contexts fit within frame */
......@@ -859,6 +876,10 @@ smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server)
*
* Assumes @iov does not contain the rfc1002 length and iov[0] has the
* SMB2 header.
*
* @ses: server session structure
* @iov: array containing the SMB request we will send to the server
* @nvec: number of array entries for the iov
*/
int
smb311_update_preauth_hash(struct cifs_ses *ses, struct kvec *iov, int nvec)
......
......@@ -24,6 +24,7 @@
#include "smb2glob.h"
#include "cifs_ioctl.h"
#include "smbdirect.h"
#include "fs_context.h"
/* Change credits for different ops and return the total number of credits */
static int
......@@ -99,9 +100,10 @@ smb2_add_credits(struct TCP_Server_Info *server,
spin_unlock(&server->req_lock);
wake_up(&server->request_q);
if (reconnect_detected)
if (reconnect_detected) {
cifs_dbg(FYI, "trying to put %d credits from the old server instance %d\n",
add, instance);
}
if (server->tcpStatus == CifsNeedReconnect
|| server->tcpStatus == CifsExiting)
......@@ -123,7 +125,7 @@ smb2_add_credits(struct TCP_Server_Info *server,
default:
trace_smb3_add_credits(server->CurrentMid,
server->hostname, rc, add);
cifs_dbg(FYI, "add %u credits total=%d\n", add, rc);
cifs_dbg(FYI, "%s: added %u credits total=%d\n", __func__, add, rc);
}
}
......@@ -135,6 +137,11 @@ smb2_set_credits(struct TCP_Server_Info *server, const int val)
if (val == 1)
server->reconnect_instance++;
spin_unlock(&server->req_lock);
trace_smb3_set_credits(server->CurrentMid,
server->hostname, val, val);
cifs_dbg(FYI, "%s: set %u credits\n", __func__, val);
/* don't log while holding the lock */
if (val == 1)
cifs_dbg(FYI, "set credits to 1 due to smb2 reconnect\n");
......@@ -201,6 +208,7 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE);
credits->instance = server->reconnect_instance;
server->credits -= credits->value;
scredits = server->credits;
server->in_flight++;
if (server->in_flight > server->max_in_flight)
server->max_in_flight = server->in_flight;
......@@ -208,6 +216,12 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
}
}
spin_unlock(&server->req_lock);
trace_smb3_add_credits(server->CurrentMid,
server->hostname, scredits, -(credits->value));
cifs_dbg(FYI, "%s: removed %u credits total=%d\n",
__func__, credits->value, scredits);
return rc;
}
......@@ -217,13 +231,17 @@ smb2_adjust_credits(struct TCP_Server_Info *server,
const unsigned int payload_size)
{
int new_val = DIV_ROUND_UP(payload_size, SMB2_MAX_BUFFER_SIZE);
int scredits;
if (!credits->value || credits->value == new_val)
return 0;
if (credits->value < new_val) {
WARN_ONCE(1, "request has less credits (%d) than required (%d)",
trace_smb3_too_many_credits(server->CurrentMid,
server->hostname, 0, credits->value - new_val);
cifs_server_dbg(VFS, "request has less credits (%d) than required (%d)",
credits->value, new_val);
return -ENOTSUPP;
}
......@@ -231,15 +249,24 @@ smb2_adjust_credits(struct TCP_Server_Info *server,
if (server->reconnect_instance != credits->instance) {
spin_unlock(&server->req_lock);
trace_smb3_reconnect_detected(server->CurrentMid,
server->hostname, 0, 0);
cifs_server_dbg(VFS, "trying to return %d credits to old session\n",
credits->value - new_val);
return -EAGAIN;
}
server->credits += credits->value - new_val;
scredits = server->credits;
spin_unlock(&server->req_lock);
wake_up(&server->request_q);
credits->value = new_val;
trace_smb3_add_credits(server->CurrentMid,
server->hostname, scredits, credits->value - new_val);
cifs_dbg(FYI, "%s: adjust added %u credits total=%d\n",
__func__, credits->value - new_val, scredits);
return 0;
}
......@@ -339,13 +366,13 @@ smb2_negotiate(const unsigned int xid, struct cifs_ses *ses)
}
static unsigned int
smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
{
struct TCP_Server_Info *server = tcon->ses->server;
unsigned int wsize;
/* start with specified wsize, or default */
wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE;
wsize = ctx->wsize ? ctx->wsize : CIFS_DEFAULT_IOSIZE;
wsize = min_t(unsigned int, wsize, server->max_write);
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE);
......@@ -354,13 +381,13 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
}
static unsigned int
smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
{
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 = ctx->wsize ? ctx->wsize : SMB3_DEFAULT_IOSIZE;
wsize = min_t(unsigned int, wsize, server->max_write);
#ifdef CONFIG_CIFS_SMB_DIRECT
if (server->rdma) {
......@@ -386,13 +413,13 @@ smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
}
static unsigned int
smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
{
struct TCP_Server_Info *server = tcon->ses->server;
unsigned int rsize;
/* start with specified rsize, or default */
rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE;
rsize = ctx->rsize ? ctx->rsize : CIFS_DEFAULT_IOSIZE;
rsize = min_t(unsigned int, rsize, server->max_read);
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
......@@ -402,13 +429,13 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
}
static unsigned int
smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
{
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 = ctx->rsize ? ctx->rsize : SMB3_DEFAULT_IOSIZE;
rsize = min_t(unsigned int, rsize, server->max_read);
#ifdef CONFIG_CIFS_SMB_DIRECT
if (server->rdma) {
......@@ -477,7 +504,8 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
goto out;
}
if (bytes_left || p->Next)
/* Azure rounds the buffer size up 8, to a 16 byte boundary */
if ((bytes_left > 8) || p->Next)
cifs_dbg(VFS, "%s: incomplete interface info\n", __func__);
......@@ -2341,6 +2369,7 @@ static bool
smb2_is_status_pending(char *buf, struct TCP_Server_Info *server)
{
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
int scredits;
if (shdr->Status != STATUS_PENDING)
return false;
......@@ -2348,8 +2377,14 @@ smb2_is_status_pending(char *buf, struct TCP_Server_Info *server)
if (shdr->CreditRequest) {
spin_lock(&server->req_lock);
server->credits += le16_to_cpu(shdr->CreditRequest);
scredits = server->credits;
spin_unlock(&server->req_lock);
wake_up(&server->request_q);
trace_smb3_add_credits(server->CurrentMid,
server->hostname, scredits, le16_to_cpu(shdr->CreditRequest));
cifs_dbg(FYI, "%s: status pending add %u credits total=%d\n",
__func__, le16_to_cpu(shdr->CreditRequest), scredits);
}
return true;
......@@ -3949,7 +3984,7 @@ smb3_parse_lease_buf(void *buf, unsigned int *epoch, char *lease_key)
static unsigned int
smb2_wp_retry_size(struct inode *inode)
{
return min_t(unsigned int, CIFS_SB(inode->i_sb)->wsize,
return min_t(unsigned int, CIFS_SB(inode->i_sb)->ctx->wsize,
SMB2_MAX_BUFFER_SIZE);
}
......
......@@ -427,8 +427,8 @@ build_preauth_ctxt(struct smb2_preauth_neg_context *pneg_ctxt)
pneg_ctxt->ContextType = SMB2_PREAUTH_INTEGRITY_CAPABILITIES;
pneg_ctxt->DataLength = cpu_to_le16(38);
pneg_ctxt->HashAlgorithmCount = cpu_to_le16(1);
pneg_ctxt->SaltLength = cpu_to_le16(SMB311_SALT_SIZE);
get_random_bytes(pneg_ctxt->Salt, SMB311_SALT_SIZE);
pneg_ctxt->SaltLength = cpu_to_le16(SMB311_LINUX_CLIENT_SALT_SIZE);
get_random_bytes(pneg_ctxt->Salt, SMB311_LINUX_CLIENT_SALT_SIZE);
pneg_ctxt->HashAlgorithms = SMB2_PREAUTH_INTEGRITY_SHA512;
}
......@@ -566,6 +566,9 @@ static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt)
if (len < MIN_PREAUTH_CTXT_DATA_LEN) {
pr_warn_once("server sent bad preauth context\n");
return;
} else if (len < MIN_PREAUTH_CTXT_DATA_LEN + le16_to_cpu(ctxt->SaltLength)) {
pr_warn_once("server sent invalid SaltLength\n");
return;
}
if (le16_to_cpu(ctxt->HashAlgorithmCount) != 1)
pr_warn_once("Invalid SMB3 hash algorithm count\n");
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment