summaryrefslogtreecommitdiff
path: root/fs/cifs/cifsfs.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-12-17 17:41:37 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2020-12-17 17:41:37 -0800
commite13300bdaa68f5487000e66baed1ff69bcb510bf (patch)
tree6eb13723d607e46416e10dfc077acc22a8b12419 /fs/cifs/cifsfs.c
parentd64c6f96ba86bd8b97ed8d6762a8c8cc1770d214 (diff)
parentafee4410bc6c50e1422c5a45d633ad0e478ea960 (diff)
downloadlinux-e13300bdaa68f5487000e66baed1ff69bcb510bf.tar.gz
linux-e13300bdaa68f5487000e66baed1ff69bcb510bf.tar.bz2
linux-e13300bdaa68f5487000e66baed1ff69bcb510bf.zip
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 ...
Diffstat (limited to 'fs/cifs/cifsfs.c')
-rw-r--r--fs/cifs/cifsfs.c174
1 files changed, 94 insertions, 80 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 472cb7777e3e..ce0d0037fd0a 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -55,6 +55,10 @@
#ifdef CONFIG_CIFS_DFS_UPCALL
#include "dfs_cache.h"
#endif
+#ifdef CONFIG_CIFS_SWN_UPCALL
+#include "netlink.h"
+#endif
+#include "fs_context.h"
/*
* DOS dates from 1980/1/1 through 2107/12/31
@@ -214,7 +218,7 @@ cifs_read_super(struct super_block *sb)
if (rc)
goto out_no_root;
/* tune readahead according to rsize */
- sb->s_bdi->ra_pages = cifs_sb->rsize / PAGE_SIZE;
+ sb->s_bdi->ra_pages = cifs_sb->ctx->rsize / PAGE_SIZE;
sb->s_blocksize = CIFS_MAX_MSGSIZE;
sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */
@@ -458,16 +462,23 @@ cifs_show_cache_flavor(struct seq_file *s, struct cifs_sb_info *cifs_sb)
seq_puts(s, "loose");
}
-static void
-cifs_show_nls(struct seq_file *s, struct nls_table *cur)
+/*
+ * cifs_show_devname() is used so we show the mount device name with correct
+ * format (e.g. forward slashes vs. back slashes) in /proc/mounts
+ */
+static int cifs_show_devname(struct seq_file *m, struct dentry *root)
{
- struct nls_table *def;
-
- /* Display iocharset= option if it's not default charset */
- def = load_nls_default();
- if (def != cur)
- seq_printf(s, ",iocharset=%s", cur->charset);
- unload_nls(def);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(root->d_sb);
+ char *devname = kstrdup(cifs_sb->ctx->UNC, GFP_KERNEL);
+
+ if (devname == NULL)
+ seq_puts(m, "none");
+ else {
+ convert_delimiter(devname, '/');
+ seq_puts(m, devname);
+ kfree(devname);
+ }
+ return 0;
}
/*
@@ -489,7 +500,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
if (tcon->no_lease)
seq_puts(s, ",nolease");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)
+ if (cifs_sb->ctx->multiuser)
seq_puts(s, ",multiuser");
else if (tcon->ses->user_name)
seq_show_option(s, "username", tcon->ses->user_name);
@@ -514,14 +525,14 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
}
seq_printf(s, ",uid=%u",
- from_kuid_munged(&init_user_ns, cifs_sb->mnt_uid));
+ from_kuid_munged(&init_user_ns, cifs_sb->ctx->linux_uid));
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
seq_puts(s, ",forceuid");
else
seq_puts(s, ",noforceuid");
seq_printf(s, ",gid=%u",
- from_kgid_munged(&init_user_ns, cifs_sb->mnt_gid));
+ from_kgid_munged(&init_user_ns, cifs_sb->ctx->linux_gid));
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
seq_puts(s, ",forcegid");
else
@@ -531,11 +542,10 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
if (!tcon->unix_ext)
seq_printf(s, ",file_mode=0%ho,dir_mode=0%ho",
- cifs_sb->mnt_file_mode,
- cifs_sb->mnt_dir_mode);
-
- cifs_show_nls(s, cifs_sb->local_nls);
-
+ cifs_sb->ctx->file_mode,
+ cifs_sb->ctx->dir_mode);
+ if (cifs_sb->ctx->iocharset)
+ seq_printf(s, ",iocharset=%s", cifs_sb->ctx->iocharset);
if (tcon->seal)
seq_puts(s, ",seal");
else if (tcon->ses->server->ignore_signature)
@@ -605,15 +615,15 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID)
seq_printf(s, ",backupuid=%u",
from_kuid_munged(&init_user_ns,
- cifs_sb->mnt_backupuid));
+ cifs_sb->ctx->backupuid));
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID)
seq_printf(s, ",backupgid=%u",
from_kgid_munged(&init_user_ns,
- cifs_sb->mnt_backupgid));
+ cifs_sb->ctx->backupgid));
- seq_printf(s, ",rsize=%u", cifs_sb->rsize);
- seq_printf(s, ",wsize=%u", cifs_sb->wsize);
- seq_printf(s, ",bsize=%u", cifs_sb->bsize);
+ seq_printf(s, ",rsize=%u", cifs_sb->ctx->rsize);
+ seq_printf(s, ",wsize=%u", cifs_sb->ctx->wsize);
+ seq_printf(s, ",bsize=%u", cifs_sb->ctx->bsize);
if (tcon->ses->server->min_offload)
seq_printf(s, ",esize=%u", tcon->ses->server->min_offload);
seq_printf(s, ",echo_interval=%lu",
@@ -628,12 +638,17 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
if (tcon->handle_timeout)
seq_printf(s, ",handletimeout=%u", tcon->handle_timeout);
/* convert actimeo and display it in seconds */
- seq_printf(s, ",actimeo=%lu", cifs_sb->actimeo / HZ);
+ seq_printf(s, ",actimeo=%lu", cifs_sb->ctx->actimeo / HZ);
if (tcon->ses->chan_max > 1)
seq_printf(s, ",multichannel,max_channels=%zu",
tcon->ses->chan_max);
+#ifdef CONFIG_CIFS_SWN_UPCALL
+ if (tcon->use_witness)
+ seq_puts(s, ",witness");
+#endif
+
return 0;
}
@@ -681,13 +696,6 @@ static int cifs_show_stats(struct seq_file *s, struct dentry *root)
}
#endif
-static int cifs_remount(struct super_block *sb, int *flags, char *data)
-{
- sync_filesystem(sb);
- *flags |= SB_NODIRATIME;
- return 0;
-}
-
static int cifs_drop_inode(struct inode *inode)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
@@ -703,13 +711,14 @@ static const struct super_operations cifs_super_ops = {
.free_inode = cifs_free_inode,
.drop_inode = cifs_drop_inode,
.evict_inode = cifs_evict_inode,
+/* .show_path = cifs_show_path, */ /* Would we ever need show path? */
+ .show_devname = cifs_show_devname,
/* .delete_inode = cifs_delete_inode, */ /* Do not need above
function unless later we add lazy close of inodes or unless the
kernel forgets to call us with the same number of releases (closes)
as opens */
.show_options = cifs_show_options,
.umount_begin = cifs_umount_begin,
- .remount_fs = cifs_remount,
#ifdef CONFIG_CIFS_STATS2
.show_stats = cifs_show_stats,
#endif
@@ -720,7 +729,7 @@ static const struct super_operations cifs_super_ops = {
* Return dentry with refcount + 1 on success and NULL otherwise.
*/
static struct dentry *
-cifs_get_root(struct smb_vol *vol, struct super_block *sb)
+cifs_get_root(struct smb3_fs_context *ctx, struct super_block *sb)
{
struct dentry *dentry;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
@@ -731,7 +740,7 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
return dget(sb->s_root);
- full_path = cifs_build_path_to_root(vol, cifs_sb,
+ full_path = cifs_build_path_to_root(ctx, cifs_sb,
cifs_sb_master_tcon(cifs_sb), 0);
if (full_path == NULL)
return ERR_PTR(-ENOMEM);
@@ -777,14 +786,13 @@ static int cifs_set_super(struct super_block *sb, void *data)
return set_anon_super(sb, NULL);
}
-static struct dentry *
+struct dentry *
cifs_smb3_do_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data, bool is_smb3)
+ int flags, struct smb3_fs_context *old_ctx)
{
int rc;
struct super_block *sb;
- struct cifs_sb_info *cifs_sb;
- struct smb_vol *volume_info;
+ struct cifs_sb_info *cifs_sb = NULL;
struct cifs_mnt_data mnt_data;
struct dentry *root;
@@ -793,42 +801,49 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
* If CIFS_DEBUG && cifs_FYI
*/
if (cifsFYI)
- cifs_dbg(FYI, "Devname: %s flags: %d\n", dev_name, flags);
+ cifs_dbg(FYI, "Devname: %s flags: %d\n", old_ctx->UNC, flags);
else
- cifs_info("Attempting to mount %s\n", dev_name);
-
- volume_info = cifs_get_volume_info((char *)data, dev_name, is_smb3);
- if (IS_ERR(volume_info))
- return ERR_CAST(volume_info);
+ cifs_info("Attempting to mount %s\n", old_ctx->UNC);
cifs_sb = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL);
if (cifs_sb == NULL) {
root = ERR_PTR(-ENOMEM);
- goto out_nls;
+ goto out;
}
- cifs_sb->mountdata = kstrndup(data, PAGE_SIZE, GFP_KERNEL);
- if (cifs_sb->mountdata == NULL) {
+ cifs_sb->ctx = kzalloc(sizeof(struct smb3_fs_context), GFP_KERNEL);
+ if (!cifs_sb->ctx) {
root = ERR_PTR(-ENOMEM);
- goto out_free;
+ goto out;
+ }
+ rc = smb3_fs_context_dup(cifs_sb->ctx, old_ctx);
+ if (rc) {
+ root = ERR_PTR(rc);
+ goto out;
+ }
+
+ rc = cifs_setup_volume_info(cifs_sb->ctx);
+ if (rc) {
+ root = ERR_PTR(rc);
+ goto out;
}
- rc = cifs_setup_cifs_sb(volume_info, cifs_sb);
+ rc = cifs_setup_cifs_sb(cifs_sb);
if (rc) {
root = ERR_PTR(rc);
- goto out_free;
+ goto out;
}
- rc = cifs_mount(cifs_sb, volume_info);
+ rc = cifs_mount(cifs_sb, cifs_sb->ctx);
if (rc) {
if (!(flags & SB_SILENT))
cifs_dbg(VFS, "cifs_mount failed w/return code = %d\n",
rc);
root = ERR_PTR(rc);
- goto out_free;
+ goto out;
}
- mnt_data.vol = volume_info;
+ mnt_data.ctx = cifs_sb->ctx;
mnt_data.cifs_sb = cifs_sb;
mnt_data.flags = flags;
@@ -839,12 +854,14 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
if (IS_ERR(sb)) {
root = ERR_CAST(sb);
cifs_umount(cifs_sb);
+ cifs_sb = NULL;
goto out;
}
if (sb->s_root) {
cifs_dbg(FYI, "Use existing superblock\n");
cifs_umount(cifs_sb);
+ cifs_sb = NULL;
} else {
rc = cifs_read_super(sb);
if (rc) {
@@ -855,41 +872,24 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
sb->s_flags |= SB_ACTIVE;
}
- root = cifs_get_root(volume_info, sb);
+ root = cifs_get_root(cifs_sb ? cifs_sb->ctx : old_ctx, sb);
if (IS_ERR(root))
goto out_super;
cifs_dbg(FYI, "dentry root is: %p\n", root);
- goto out;
+ return root;
out_super:
deactivate_locked_super(sb);
out:
- cifs_cleanup_volume_info(volume_info);
+ if (cifs_sb) {
+ kfree(cifs_sb->prepath);
+ smb3_cleanup_fs_context(cifs_sb->ctx);
+ kfree(cifs_sb);
+ }
return root;
-
-out_free:
- kfree(cifs_sb->prepath);
- kfree(cifs_sb->mountdata);
- kfree(cifs_sb);
-out_nls:
- unload_nls(volume_info->local_nls);
- goto out;
}
-static struct dentry *
-smb3_do_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
-{
- return cifs_smb3_do_mount(fs_type, flags, dev_name, data, true);
-}
-
-static struct dentry *
-cifs_do_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
-{
- return cifs_smb3_do_mount(fs_type, flags, dev_name, data, false);
-}
static ssize_t
cifs_loose_read_iter(struct kiocb *iocb, struct iov_iter *iter)
@@ -1026,7 +1026,8 @@ cifs_setlease(struct file *file, long arg, struct file_lock **lease, void **priv
struct file_system_type cifs_fs_type = {
.owner = THIS_MODULE,
.name = "cifs",
- .mount = cifs_do_mount,
+ .init_fs_context = smb3_init_fs_context,
+ .parameters = smb3_fs_parameters,
.kill_sb = cifs_kill_sb,
.fs_flags = FS_RENAME_DOES_D_MOVE,
};
@@ -1035,7 +1036,8 @@ MODULE_ALIAS_FS("cifs");
static struct file_system_type smb3_fs_type = {
.owner = THIS_MODULE,
.name = "smb3",
- .mount = smb3_do_mount,
+ .init_fs_context = smb3_init_fs_context,
+ .parameters = smb3_fs_parameters,
.kill_sb = cifs_kill_sb,
.fs_flags = FS_RENAME_DOES_D_MOVE,
};
@@ -1617,10 +1619,15 @@ init_cifs(void)
if (rc)
goto out_destroy_dfs_cache;
#endif /* CONFIG_CIFS_UPCALL */
+#ifdef CONFIG_CIFS_SWN_UPCALL
+ rc = cifs_genl_init();
+ if (rc)
+ goto out_register_key_type;
+#endif /* CONFIG_CIFS_SWN_UPCALL */
rc = init_cifs_idmap();
if (rc)
- goto out_register_key_type;
+ goto out_cifs_swn_init;
rc = register_filesystem(&cifs_fs_type);
if (rc)
@@ -1636,7 +1643,11 @@ init_cifs(void)
out_init_cifs_idmap:
exit_cifs_idmap();
+out_cifs_swn_init:
+#ifdef CONFIG_CIFS_SWN_UPCALL
+ cifs_genl_exit();
out_register_key_type:
+#endif
#ifdef CONFIG_CIFS_UPCALL
exit_cifs_spnego();
out_destroy_dfs_cache:
@@ -1673,6 +1684,9 @@ exit_cifs(void)
unregister_filesystem(&smb3_fs_type);
cifs_dfs_release_automount_timer();
exit_cifs_idmap();
+#ifdef CONFIG_CIFS_SWN_UPCALL
+ cifs_genl_exit();
+#endif
#ifdef CONFIG_CIFS_UPCALL
exit_cifs_spnego();
#endif