From patchwork Thu Oct 22 18:13:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 1386372 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4CHFqN5LMWz9sTK for ; Fri, 23 Oct 2020 05:13:52 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2898174AbgJVSNu (ORCPT ); Thu, 22 Oct 2020 14:13:50 -0400 Received: from mx2.suse.de ([195.135.220.15]:58736 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2506218AbgJVSNt (ORCPT ); Thu, 22 Oct 2020 14:13:49 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 909DAADF8 for ; Thu, 22 Oct 2020 18:13:48 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH 01/11] cifs: Make extract_hostname function public Date: Thu, 22 Oct 2020 20:13:29 +0200 Message-Id: <20201022181339.30771-2-scabrero@suse.de> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201022181339.30771-1-scabrero@suse.de> References: <20201022181339.30771-1-scabrero@suse.de> Reply-To: scabrero@suse.de MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Move the function to misc.c and give it a public header. Signed-off-by: Samuel Cabrero Reviewed-by: Aurelien Aptel --- fs/cifs/cifsproto.h | 1 + fs/cifs/connect.c | 34 ---------------------------------- fs/cifs/misc.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 24c6f36177ba..d716e81d86fa 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -620,6 +620,7 @@ 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); #ifdef CONFIG_CIFS_DFS_UPCALL static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses, diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c38156f324dd..5aadc4632097 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -284,7 +284,6 @@ static int ip_connect(struct TCP_Server_Info *server); static int generic_ip_connect(struct TCP_Server_Info *server); static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); static void cifs_prune_tlinks(struct work_struct *work); -static char *extract_hostname(const char *unc); /* * Resolve hostname and set ip addr in tcp ses. Useful for hostnames that may @@ -1230,39 +1229,6 @@ cifs_demultiplex_thread(void *p) module_put_and_exit(0); } -/* extract the host portion of the UNC string */ -static char * -extract_hostname(const char *unc) -{ - const char *src; - char *dst, *delim; - unsigned int len; - - /* skip double chars at beginning of string */ - /* BB: check validity of these bytes? */ - if (strlen(unc) < 3) - return ERR_PTR(-EINVAL); - for (src = unc; *src && *src == '\\'; src++) - ; - if (!*src) - return ERR_PTR(-EINVAL); - - /* delimiter between hostname and sharename is always '\\' now */ - delim = strchr(src, '\\'); - if (!delim) - return ERR_PTR(-EINVAL); - - len = delim - src; - dst = kmalloc((len + 1), GFP_KERNEL); - if (dst == NULL) - return ERR_PTR(-ENOMEM); - - memcpy(dst, src, len); - dst[len] = '\0'; - - return dst; -} - static int get_option_ul(substring_t args[], unsigned long *option) { int rc; diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 1c14cf01dbef..3d5cc25c167f 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -1195,3 +1195,35 @@ int update_super_prepath(struct cifs_tcon *tcon, char *prefix) cifs_put_tcon_super(sb); return rc; } + +/* extract the host portion of the UNC string */ +char *extract_hostname(const char *unc) +{ + const char *src; + char *dst, *delim; + unsigned int len; + + /* skip double chars at beginning of string */ + /* BB: check validity of these bytes? */ + if (strlen(unc) < 3) + return ERR_PTR(-EINVAL); + for (src = unc; *src && *src == '\\'; src++) + ; + if (!*src) + return ERR_PTR(-EINVAL); + + /* delimiter between hostname and sharename is always '\\' now */ + delim = strchr(src, '\\'); + if (!delim) + return ERR_PTR(-EINVAL); + + len = delim - src; + dst = kmalloc((len + 1), GFP_KERNEL); + if (dst == NULL) + return ERR_PTR(-ENOMEM); + + memcpy(dst, src, len); + dst[len] = '\0'; + + return dst; +} From patchwork Thu Oct 22 18:13:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 1386373 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4CHFqQ2PYvz9sSW for ; Fri, 23 Oct 2020 05:13:54 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2901735AbgJVSNu (ORCPT ); Thu, 22 Oct 2020 14:13:50 -0400 Received: from mx2.suse.de ([195.135.220.15]:58760 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2898343AbgJVSNu (ORCPT ); Thu, 22 Oct 2020 14:13:50 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id D899BAE3A for ; Thu, 22 Oct 2020 18:13:48 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH 02/11] cifs: Make extract_sharename function public Date: Thu, 22 Oct 2020 20:13:30 +0200 Message-Id: <20201022181339.30771-3-scabrero@suse.de> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201022181339.30771-1-scabrero@suse.de> References: <20201022181339.30771-1-scabrero@suse.de> Reply-To: scabrero@suse.de MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Move the function to misc.c Signed-off-by: Samuel Cabrero Reviewed-by: Aurelien Aptel --- fs/cifs/cache.c | 24 ------------------------ fs/cifs/cifsproto.h | 1 + fs/cifs/fscache.c | 1 + fs/cifs/fscache.h | 1 - fs/cifs/misc.c | 24 ++++++++++++++++++++++++ 5 files changed, 26 insertions(+), 25 deletions(-) diff --git a/fs/cifs/cache.c b/fs/cifs/cache.c index 0f2adecb94f2..488fe0ffc1ef 100644 --- a/fs/cifs/cache.c +++ b/fs/cifs/cache.c @@ -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, diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index d716e81d86fa..5f997a01fb45 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -621,6 +621,7 @@ 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, diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c index da688185403c..20d24af33ee2 100644 --- a/fs/cifs/fscache.c +++ b/fs/cifs/fscache.c @@ -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 diff --git a/fs/cifs/fscache.h b/fs/cifs/fscache.h index 1091633d2adb..e811f2dd7619 100644 --- a/fs/cifs/fscache.h +++ b/fs/cifs/fscache.h @@ -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 diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 3d5cc25c167f..f0a1c24751b2 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -1227,3 +1227,27 @@ char *extract_hostname(const char *unc) return dst; } + +char *extract_sharename(const char *unc) +{ + const char *src; + char *delim, *dst; + int len; + + /* skip double chars at the beginning */ + src = unc + 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; +} From patchwork Thu Oct 22 18:13:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 1386375 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4CHFqR2j4sz9sTK for ; Fri, 23 Oct 2020 05:13:55 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2506218AbgJVSNv (ORCPT ); Thu, 22 Oct 2020 14:13:51 -0400 Received: from mx2.suse.de ([195.135.220.15]:58774 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2505941AbgJVSNv (ORCPT ); Thu, 22 Oct 2020 14:13:51 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 3088BB305 for ; Thu, 22 Oct 2020 18:13:49 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH 03/11] cifs: Register generic netlink family Date: Thu, 22 Oct 2020 20:13:31 +0200 Message-Id: <20201022181339.30771-4-scabrero@suse.de> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201022181339.30771-1-scabrero@suse.de> References: <20201022181339.30771-1-scabrero@suse.de> Reply-To: scabrero@suse.de MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Register a new generic netlink family to talk to the witness service userspace daemon. Signed-off-by: Samuel Cabrero Reported-by: kernel test robot Reported-by: kernel test robot --- fs/cifs/Kconfig | 11 +++++ fs/cifs/Makefile | 2 + fs/cifs/cifsfs.c | 17 ++++++- fs/cifs/netlink.c | 68 ++++++++++++++++++++++++++ fs/cifs/netlink.h | 16 ++++++ include/uapi/linux/cifs/cifs_netlink.h | 31 ++++++++++++ 6 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 fs/cifs/netlink.c create mode 100644 fs/cifs/netlink.h create mode 100644 include/uapi/linux/cifs/cifs_netlink.h diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 604f65f4b6c5..664ac5c63d39 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -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 an + 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 diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index cd17d0e50f2a..b88fd46ac597 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile @@ -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-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 472cb7777e3e..8111d0109a2e 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -55,6 +55,9 @@ #ifdef CONFIG_CIFS_DFS_UPCALL #include "dfs_cache.h" #endif +#ifdef CONFIG_CIFS_SWN_UPCALL +#include "netlink.h" +#endif /* * DOS dates from 1980/1/1 through 2107/12/31 @@ -1617,10 +1620,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 +1644,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 +1685,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 diff --git a/fs/cifs/netlink.c b/fs/cifs/netlink.c new file mode 100644 index 000000000000..5cd5dfee1132 --- /dev/null +++ b/fs/cifs/netlink.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Netlink routines for CIFS + * + * Copyright (c) 2020 Samuel Cabrero + */ + +#include +#include + +#include "cifsglob.h" +#include "cifs_debug.h" + +static const struct nla_policy cifs_genl_policy[CIFS_GENL_ATTR_MAX + 1] = { +}; + +static struct genl_ops cifs_genl_ops[] = { +}; + +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__); + } +} diff --git a/fs/cifs/netlink.h b/fs/cifs/netlink.h new file mode 100644 index 000000000000..e2fa8ed24c54 --- /dev/null +++ b/fs/cifs/netlink.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Netlink routines for CIFS + * + * Copyright (c) 2020 Samuel Cabrero + */ + +#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 */ diff --git a/include/uapi/linux/cifs/cifs_netlink.h b/include/uapi/linux/cifs/cifs_netlink.h new file mode 100644 index 000000000000..2332a3c3f268 --- /dev/null +++ b/include/uapi/linux/cifs/cifs_netlink.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Netlink routines for CIFS + * + * Copyright (c) 2020 Samuel Cabrero + */ + + +#ifndef _UAPILINUX_CIFS_NETLINK_H +#define _UAPILINUX_CIFS_NETLINK_H + +#define CIFS_GENL_NAME "cifs" +#define CIFS_GENL_VERSION 0x1 + +#define CIFS_GENL_MCGRP_SWN_NAME "cifs_mcgrp_swn" + +enum cifs_genl_multicast_groups { + CIFS_GENL_MCGRP_SWN, +}; + +enum cifs_genl_attributes { + __CIFS_GENL_ATTR_MAX, +}; +#define CIFS_GENL_ATTR_MAX (__CIFS_GENL_ATTR_MAX - 1) + +enum cifs_genl_commands { + __CIFS_GENL_CMD_MAX +}; +#define CIFS_GENL_CMD_MAX (__CIFS_GENL_CMD_MAX - 1) + +#endif /* _UAPILINUX_CIFS_NETLINK_H */ From patchwork Thu Oct 22 18:13:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 1386374 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4CHFqQ6Mlyz9sTD for ; Fri, 23 Oct 2020 05:13:54 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2901746AbgJVSNv (ORCPT ); Thu, 22 Oct 2020 14:13:51 -0400 Received: from mx2.suse.de ([195.135.220.15]:58806 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2506218AbgJVSNv (ORCPT ); Thu, 22 Oct 2020 14:13:51 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 7BB89ADDF for ; Thu, 22 Oct 2020 18:13:49 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH 04/11] cifs: add witness mount option and data structs Date: Thu, 22 Oct 2020 20:13:32 +0200 Message-Id: <20201022181339.30771-5-scabrero@suse.de> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201022181339.30771-1-scabrero@suse.de> References: <20201022181339.30771-1-scabrero@suse.de> Reply-To: scabrero@suse.de MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Add 'witness' mount option to register for witness notifications. Signed-off-by: Samuel Cabrero --- fs/cifs/cifsfs.c | 5 +++++ fs/cifs/cifsglob.h | 4 ++++ fs/cifs/connect.c | 35 ++++++++++++++++++++++++++++++++++- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8111d0109a2e..c2bbc444b463 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -637,6 +637,11 @@ cifs_show_options(struct seq_file *s, struct dentry *root) 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; } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index b6925aeeb621..5ca3a5568ac5 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -615,6 +615,7 @@ struct smb_vol { 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 */ }; /** @@ -1173,6 +1174,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 }; /* diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 5aadc4632097..ed749e978ad8 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -102,7 +102,7 @@ enum { Opt_resilient, Opt_noresilient, Opt_domainauto, Opt_rdma, Opt_modesid, Opt_rootfs, Opt_multichannel, Opt_nomultichannel, - Opt_compress, + Opt_compress, Opt_witness, /* Mount options which take numeric value */ Opt_backupuid, Opt_backupgid, Opt_uid, @@ -276,6 +276,7 @@ static const match_table_t cifs_mount_option_tokens = { { Opt_ignore, "relatime" }, { Opt_ignore, "_netdev" }, { Opt_rootfs, "rootfs" }, + { Opt_witness, "witness" }, { Opt_err, NULL } }; @@ -1538,6 +1539,13 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, vol->rootfs = true; #endif break; + case Opt_witness: +#ifndef CONFIG_CIFS_SWN_UPCALL + cifs_dbg(VFS, "Witness support needs CONFIG_CIFS_SWN_UPCALL kernel config option set\n"); + goto cifs_parse_mount_err; +#endif + vol->witness = true; + break; case Opt_posixpaths: vol->posix_paths = 1; break; @@ -3158,6 +3166,8 @@ cifs_put_tcon(struct cifs_tcon *tcon) return; } + /* TODO witness unregister */ + list_del_init(&tcon->tcon_list); spin_unlock(&cifs_tcp_ses_lock); @@ -3319,6 +3329,26 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) tcon->use_resilient = true; } +#ifdef CONFIG_CIFS_SWN_UPCALL + tcon->use_witness = false; + if (volume_info->witness) { + if (ses->server->vals->protocol_id >= SMB30_PROT_ID) { + if (tcon->capabilities & SMB2_SHARE_CAP_CLUSTER) { + /* TODO witness register */ + tcon->use_witness = true; + } else { + cifs_dbg(VFS, "witness requested on mount but no CLUSTER capability on share\n"); + rc = -EOPNOTSUPP; + goto out_fail; + } + } else { + cifs_dbg(VFS, "SMB3 or later required for witness option\n"); + rc = -EOPNOTSUPP; + goto out_fail; + } + } +#endif + /* If the user really knows what they are doing they can override */ if (tcon->share_flags & SMB2_SHAREFLAG_NO_CACHING) { if (volume_info->cache_ro) @@ -5070,6 +5100,9 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) vol_info->sectype = master_tcon->ses->sectype; vol_info->sign = master_tcon->ses->sign; vol_info->seal = master_tcon->seal; +#ifdef CONFIG_CIFS_SWN_UPCALL + vol_info->witness = master_tcon->use_witness; +#endif rc = cifs_set_vol_auth(vol_info, master_tcon->ses); if (rc) { From patchwork Thu Oct 22 18:13:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 1386379 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4CHFqT5CGbz9sSW for ; Fri, 23 Oct 2020 05:13:57 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2898343AbgJVSNw (ORCPT ); Thu, 22 Oct 2020 14:13:52 -0400 Received: from mx2.suse.de ([195.135.220.15]:58826 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2897861AbgJVSNw (ORCPT ); Thu, 22 Oct 2020 14:13:52 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id CF5C1B814 for ; Thu, 22 Oct 2020 18:13:49 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH 05/11] cifs: Send witness register and unregister commands to userspace daemon Date: Thu, 22 Oct 2020 20:13:33 +0200 Message-Id: <20201022181339.30771-6-scabrero@suse.de> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201022181339.30771-1-scabrero@suse.de> References: <20201022181339.30771-1-scabrero@suse.de> Reply-To: scabrero@suse.de MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org + Define the generic netlink family commands and message attributes to communicate with the userspace daemon + The register and unregister commands are sent when connecting or disconnecting a tree. The witness registration keeps a pointer to the tcon and has the same lifetime. + Each registration has an id allocated by an IDR. This id is sent to the userspace daemon in the register command, and will be included in the notification messages from the userspace daemon to retrieve from the IDR the matching registration. + The authentication information is bundled in the register message. If kerberos is used the message just carries a flag. Signed-off-by: Samuel Cabrero --- fs/cifs/Makefile | 2 +- fs/cifs/cifs_swn.c | 417 +++++++++++++++++++++++++ fs/cifs/cifs_swn.h | 17 + fs/cifs/connect.c | 26 +- fs/cifs/netlink.c | 11 + include/uapi/linux/cifs/cifs_netlink.h | 15 + 6 files changed, 485 insertions(+), 3 deletions(-) create mode 100644 fs/cifs/cifs_swn.c create mode 100644 fs/cifs/cifs_swn.h diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index b88fd46ac597..abb2fbc0f904 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile @@ -18,7 +18,7 @@ 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-$(CONFIG_CIFS_SWN_UPCALL) += netlink.o cifs_swn.o cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o diff --git a/fs/cifs/cifs_swn.c b/fs/cifs/cifs_swn.c new file mode 100644 index 000000000000..c7d70e28341e --- /dev/null +++ b/fs/cifs/cifs_swn.c @@ -0,0 +1,417 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Witness Service client for CIFS + * + * Copyright (c) 2020 Samuel Cabrero + */ + +#include +#include +#include + +#include "cifs_swn.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "fscache.h" +#include "cifs_debug.h" +#include "netlink.h" + +static DEFINE_IDR(cifs_swnreg_idr); +static DEFINE_MUTEX(cifs_swnreg_idr_mutex); + +struct cifs_swn_reg { + int id; + struct kref ref_count; + + const char *net_name; + const char *share_name; + bool net_name_notify; + bool share_name_notify; + bool ip_notify; + + struct cifs_tcon *tcon; +}; + +static int cifs_swn_auth_info_krb(struct cifs_tcon *tcon, struct sk_buff *skb) +{ + int ret; + + ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_KRB_AUTH); + if (ret < 0) + return ret; + + return 0; +} + +static int cifs_swn_auth_info_ntlm(struct cifs_tcon *tcon, struct sk_buff *skb) +{ + int ret; + + if (tcon->ses->user_name != NULL) { + ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_USER_NAME, tcon->ses->user_name); + if (ret < 0) + return ret; + } + + if (tcon->ses->password != NULL) { + ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_PASSWORD, tcon->ses->password); + if (ret < 0) + return ret; + } + + if (tcon->ses->domainName != NULL) { + ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_DOMAIN_NAME, tcon->ses->domainName); + if (ret < 0) + return ret; + } + + return 0; +} + +/* + * Sends a register message to the userspace daemon based on the registration. + * The authentication information to connect to the witness service is bundled + * into the message. + */ +static int cifs_swn_send_register_message(struct cifs_swn_reg *swnreg) +{ + struct sk_buff *skb; + struct genlmsghdr *hdr; + enum securityEnum authtype; + int ret; + + skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (skb == NULL) { + ret = -ENOMEM; + goto fail; + } + + hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_REGISTER); + if (hdr == NULL) { + ret = -ENOMEM; + goto nlmsg_fail; + } + + ret = nla_put_u32(skb, CIFS_GENL_ATTR_SWN_REGISTRATION_ID, swnreg->id); + if (ret < 0) + goto nlmsg_fail; + + ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_NET_NAME, swnreg->net_name); + if (ret < 0) + goto nlmsg_fail; + + ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME, swnreg->share_name); + if (ret < 0) + goto nlmsg_fail; + + ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage), + &swnreg->tcon->ses->server->dstaddr); + if (ret < 0) + goto nlmsg_fail; + + if (swnreg->net_name_notify) { + ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY); + if (ret < 0) + goto nlmsg_fail; + } + + if (swnreg->share_name_notify) { + ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY); + if (ret < 0) + goto nlmsg_fail; + } + + if (swnreg->ip_notify) { + ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_IP_NOTIFY); + if (ret < 0) + goto nlmsg_fail; + } + + authtype = cifs_select_sectype(swnreg->tcon->ses->server, swnreg->tcon->ses->sectype); + switch (authtype) { + case Kerberos: + ret = cifs_swn_auth_info_krb(swnreg->tcon, skb); + if (ret < 0) { + cifs_dbg(VFS, "%s: Failed to get kerberos auth info: %d\n", __func__, ret); + goto nlmsg_fail; + } + break; + case LANMAN: + case NTLM: + case NTLMv2: + case RawNTLMSSP: + ret = cifs_swn_auth_info_ntlm(swnreg->tcon, skb); + if (ret < 0) { + cifs_dbg(VFS, "%s: Failed to get NTLM auth info: %d\n", __func__, ret); + goto nlmsg_fail; + } + break; + default: + cifs_dbg(VFS, "%s: secType %d not supported!\n", __func__, authtype); + ret = -EINVAL; + goto nlmsg_fail; + } + + genlmsg_end(skb, hdr); + genlmsg_multicast(&cifs_genl_family, skb, 0, CIFS_GENL_MCGRP_SWN, GFP_ATOMIC); + + cifs_dbg(FYI, "%s: Message to register for network name %s with id %d sent\n", __func__, + swnreg->net_name, swnreg->id); + + return 0; + +nlmsg_fail: + genlmsg_cancel(skb, hdr); + nlmsg_free(skb); +fail: + return ret; +} + +/* + * Sends an uregister message to the userspace daemon based on the registration + */ +static int cifs_swn_send_unregister_message(struct cifs_swn_reg *swnreg) +{ + struct sk_buff *skb; + struct genlmsghdr *hdr; + int ret; + + skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (skb == NULL) + return -ENOMEM; + + hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_UNREGISTER); + if (hdr == NULL) { + ret = -ENOMEM; + goto nlmsg_fail; + } + + ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_NET_NAME, swnreg->net_name); + if (ret < 0) + goto nlmsg_fail; + + ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME, swnreg->share_name); + if (ret < 0) + goto nlmsg_fail; + + ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage), + &swnreg->tcon->ses->server->dstaddr); + if (ret < 0) + goto nlmsg_fail; + + if (swnreg->net_name_notify) { + ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY); + if (ret < 0) + goto nlmsg_fail; + } + + if (swnreg->share_name_notify) { + ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY); + if (ret < 0) + goto nlmsg_fail; + } + + if (swnreg->ip_notify) { + ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_IP_NOTIFY); + if (ret < 0) + goto nlmsg_fail; + } + + genlmsg_end(skb, hdr); + genlmsg_multicast(&cifs_genl_family, skb, 0, CIFS_GENL_MCGRP_SWN, GFP_ATOMIC); + + cifs_dbg(FYI, "%s: Message to unregister for network name %s with id %d sent\n", __func__, + swnreg->net_name, swnreg->id); + + return 0; + +nlmsg_fail: + genlmsg_cancel(skb, hdr); + nlmsg_free(skb); + return ret; +} + +/* + * Try to find a matching registration for the tcon's server name and share name. + * Calls to this funciton must be protected by cifs_swnreg_idr_mutex. + * TODO Try to avoid memory allocations + */ +static struct cifs_swn_reg *cifs_find_swn_reg(struct cifs_tcon *tcon) +{ + struct cifs_swn_reg *swnreg; + int id; + const char *share_name; + const char *net_name; + + net_name = extract_hostname(tcon->treeName); + if (IS_ERR_OR_NULL(net_name)) { + int ret; + + ret = PTR_ERR(net_name); + cifs_dbg(VFS, "%s: failed to extract host name from target '%s': %d\n", + __func__, tcon->treeName, ret); + return NULL; + } + + share_name = extract_sharename(tcon->treeName); + if (IS_ERR_OR_NULL(share_name)) { + int ret; + + ret = PTR_ERR(net_name); + cifs_dbg(VFS, "%s: failed to extract share name from target '%s': %d\n", + __func__, tcon->treeName, ret); + kfree(net_name); + return NULL; + } + + idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) { + if (strcasecmp(swnreg->net_name, net_name) != 0 + || strcasecmp(swnreg->share_name, share_name) != 0) { + continue; + } + + mutex_unlock(&cifs_swnreg_idr_mutex); + + cifs_dbg(FYI, "Existing swn registration for %s:%s found\n", swnreg->net_name, + swnreg->share_name); + + kfree(net_name); + kfree(share_name); + + return swnreg; + } + + kfree(net_name); + kfree(share_name); + + return NULL; +} + +/* + * Get a registration for the tcon's server and share name, allocating a new one if it does not + * exists + */ +static struct cifs_swn_reg *cifs_get_swn_reg(struct cifs_tcon *tcon) +{ + struct cifs_swn_reg *reg = NULL; + int ret; + + mutex_lock(&cifs_swnreg_idr_mutex); + + /* Check if we are already registered for this network and share names */ + reg = cifs_find_swn_reg(tcon); + if (IS_ERR(reg)) { + return reg; + } else if (reg != NULL) { + kref_get(®->ref_count); + mutex_unlock(&cifs_swnreg_idr_mutex); + return reg; + } + + reg = kmalloc(sizeof(struct cifs_swn_reg), GFP_ATOMIC); + if (reg == NULL) { + mutex_unlock(&cifs_swnreg_idr_mutex); + return ERR_PTR(-ENOMEM); + } + + kref_init(®->ref_count); + + reg->id = idr_alloc(&cifs_swnreg_idr, reg, 1, 0, GFP_ATOMIC); + if (reg->id < 0) { + cifs_dbg(FYI, "%s: failed to allocate registration id\n", __func__); + ret = reg->id; + goto fail; + } + + reg->net_name = extract_hostname(tcon->treeName); + if (IS_ERR(reg->net_name)) { + ret = PTR_ERR(reg->net_name); + cifs_dbg(VFS, "%s: failed to extract host name from target: %d\n", __func__, ret); + goto fail_idr; + } + + reg->share_name = extract_sharename(tcon->treeName); + if (IS_ERR(reg->share_name)) { + ret = PTR_ERR(reg->share_name); + cifs_dbg(VFS, "%s: failed to extract share name from target: %d\n", __func__, ret); + goto fail_net_name; + } + + reg->net_name_notify = true; + reg->share_name_notify = true; + reg->ip_notify = (tcon->capabilities & SMB2_SHARE_CAP_SCALEOUT); + + reg->tcon = tcon; + + mutex_unlock(&cifs_swnreg_idr_mutex); + + return reg; + +fail_net_name: + kfree(reg->net_name); +fail_idr: + idr_remove(&cifs_swnreg_idr, reg->id); +fail: + kfree(reg); + mutex_unlock(&cifs_swnreg_idr_mutex); + return ERR_PTR(ret); +} + +static void cifs_swn_reg_release(struct kref *ref) +{ + struct cifs_swn_reg *swnreg = container_of(ref, struct cifs_swn_reg, ref_count); + int ret; + + ret = cifs_swn_send_unregister_message(swnreg); + if (ret < 0) + cifs_dbg(VFS, "%s: Failed to send unregister message: %d\n", __func__, ret); + + idr_remove(&cifs_swnreg_idr, swnreg->id); + kfree(swnreg->net_name); + kfree(swnreg->share_name); + kfree(swnreg); +} + +static void cifs_put_swn_reg(struct cifs_swn_reg *swnreg) +{ + mutex_lock(&cifs_swnreg_idr_mutex); + kref_put(&swnreg->ref_count, cifs_swn_reg_release); + mutex_unlock(&cifs_swnreg_idr_mutex); +} + +int cifs_swn_register(struct cifs_tcon *tcon) +{ + struct cifs_swn_reg *swnreg; + int ret; + + swnreg = cifs_get_swn_reg(tcon); + if (IS_ERR(swnreg)) + return PTR_ERR(swnreg); + + ret = cifs_swn_send_register_message(swnreg); + if (ret < 0) { + cifs_dbg(VFS, "%s: Failed to send swn register message: %d\n", __func__, ret); + /* Do not put the swnreg or return error, the echo task will retry */ + } + + return 0; +} + +int cifs_swn_unregister(struct cifs_tcon *tcon) +{ + struct cifs_swn_reg *swnreg; + + mutex_lock(&cifs_swnreg_idr_mutex); + + swnreg = cifs_find_swn_reg(tcon); + if (swnreg == NULL) { + mutex_unlock(&cifs_swnreg_idr_mutex); + return -EEXIST; + } + + mutex_unlock(&cifs_swnreg_idr_mutex); + + cifs_put_swn_reg(swnreg); + + return 0; +} diff --git a/fs/cifs/cifs_swn.h b/fs/cifs/cifs_swn.h new file mode 100644 index 000000000000..69c7bd1035da --- /dev/null +++ b/fs/cifs/cifs_swn.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Witness Service client for CIFS + * + * Copyright (c) 2020 Samuel Cabrero + */ + +#ifndef _CIFS_SWN_H +#define _CIFS_SWN_H + +struct cifs_tcon; + +extern int cifs_swn_register(struct cifs_tcon *tcon); + +extern int cifs_swn_unregister(struct cifs_tcon *tcon); + +#endif /* _CIFS_SWN_H */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index ed749e978ad8..0e3a88932560 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -62,6 +62,9 @@ #include "dfs_cache.h" #endif #include "fs_context.h" +#ifdef CONFIG_CIFS_SWN_UPCALL +#include "cifs_swn.h" +#endif extern mempool_t *cifs_req_poolp; extern bool disable_legacy_dialects; @@ -3166,7 +3169,17 @@ cifs_put_tcon(struct cifs_tcon *tcon) return; } - /* TODO witness unregister */ +#ifdef CONFIG_CIFS_SWN_UPCALL + if (tcon->use_witness) { + int rc; + + rc = cifs_swn_unregister(tcon); + if (rc < 0) { + cifs_dbg(VFS, "%s: Failed to unregister for witness notifications: %d\n", + __func__, rc); + } + } +#endif list_del_init(&tcon->tcon_list); spin_unlock(&cifs_tcp_ses_lock); @@ -3334,8 +3347,17 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) if (volume_info->witness) { if (ses->server->vals->protocol_id >= SMB30_PROT_ID) { if (tcon->capabilities & SMB2_SHARE_CAP_CLUSTER) { - /* TODO witness register */ + /* + * Set witness in use flag in first place + * to retry registration in the echo task + */ tcon->use_witness = true; + /* And try to register immediately */ + rc = cifs_swn_register(tcon); + if (rc < 0) { + cifs_dbg(VFS, "Failed to register for witness notifications: %d\n", rc); + goto out_fail; + } } else { cifs_dbg(VFS, "witness requested on mount but no CLUSTER capability on share\n"); rc = -EOPNOTSUPP; diff --git a/fs/cifs/netlink.c b/fs/cifs/netlink.c index 5cd5dfee1132..169ac4aacdbb 100644 --- a/fs/cifs/netlink.c +++ b/fs/cifs/netlink.c @@ -12,6 +12,17 @@ #include "cifs_debug.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 }, }; static struct genl_ops cifs_genl_ops[] = { diff --git a/include/uapi/linux/cifs/cifs_netlink.h b/include/uapi/linux/cifs/cifs_netlink.h index 2332a3c3f268..4a2a41de1496 100644 --- a/include/uapi/linux/cifs/cifs_netlink.h +++ b/include/uapi/linux/cifs/cifs_netlink.h @@ -19,11 +19,26 @@ enum cifs_genl_multicast_groups { }; enum cifs_genl_attributes { + CIFS_GENL_ATTR_UNSPEC, + CIFS_GENL_ATTR_SWN_REGISTRATION_ID, + CIFS_GENL_ATTR_SWN_NET_NAME, + CIFS_GENL_ATTR_SWN_SHARE_NAME, + CIFS_GENL_ATTR_SWN_IP, + CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY, + CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY, + CIFS_GENL_ATTR_SWN_IP_NOTIFY, + CIFS_GENL_ATTR_SWN_KRB_AUTH, + CIFS_GENL_ATTR_SWN_USER_NAME, + CIFS_GENL_ATTR_SWN_PASSWORD, + CIFS_GENL_ATTR_SWN_DOMAIN_NAME, __CIFS_GENL_ATTR_MAX, }; #define CIFS_GENL_ATTR_MAX (__CIFS_GENL_ATTR_MAX - 1) enum cifs_genl_commands { + CIFS_GENL_CMD_UNSPEC, + CIFS_GENL_CMD_SWN_REGISTER, + CIFS_GENL_CMD_SWN_UNREGISTER, __CIFS_GENL_CMD_MAX }; #define CIFS_GENL_CMD_MAX (__CIFS_GENL_CMD_MAX - 1) From patchwork Thu Oct 22 18:13:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 1386377 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4CHFqS3q5yz9sTD for ; Fri, 23 Oct 2020 05:13:56 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2901742AbgJVSNw (ORCPT ); Thu, 22 Oct 2020 14:13:52 -0400 Received: from mx2.suse.de ([195.135.220.15]:58850 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2901668AbgJVSNv (ORCPT ); Thu, 22 Oct 2020 14:13:51 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 211D0B815 for ; Thu, 22 Oct 2020 18:13:50 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH 06/11] cifs: Set witness notification handler for messages from userspace daemon Date: Thu, 22 Oct 2020 20:13:34 +0200 Message-Id: <20201022181339.30771-7-scabrero@suse.de> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201022181339.30771-1-scabrero@suse.de> References: <20201022181339.30771-1-scabrero@suse.de> Reply-To: scabrero@suse.de MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org + Set a handler for the witness notification messages received from the userspace daemon. + Handle the resource state change notification. When the resource becomes unavailable or available set the tcp status to CifsNeedReconnect for all channels. Signed-off-by: Samuel Cabrero --- fs/cifs/cifs_swn.c | 86 ++++++++++++++++++++++++++ fs/cifs/cifs_swn.h | 4 ++ fs/cifs/netlink.c | 9 +++ include/uapi/linux/cifs/cifs_netlink.h | 17 +++++ 4 files changed, 116 insertions(+) diff --git a/fs/cifs/cifs_swn.c b/fs/cifs/cifs_swn.c index c7d70e28341e..501d84893262 100644 --- a/fs/cifs/cifs_swn.c +++ b/fs/cifs/cifs_swn.c @@ -379,6 +379,92 @@ static void cifs_put_swn_reg(struct cifs_swn_reg *swnreg) mutex_unlock(&cifs_swnreg_idr_mutex); } +static int cifs_swn_resource_state_changed(struct cifs_swn_reg *swnreg, const char *name, int state) +{ + int i; + + switch (state) { + case CIFS_SWN_RESOURCE_STATE_UNAVAILABLE: + cifs_dbg(FYI, "%s: resource name '%s' become unavailable\n", __func__, name); + for (i = 0; i < swnreg->tcon->ses->chan_count; i++) { + spin_lock(&GlobalMid_Lock); + if (swnreg->tcon->ses->chans[i].server->tcpStatus != CifsExiting) + swnreg->tcon->ses->chans[i].server->tcpStatus = CifsNeedReconnect; + spin_unlock(&GlobalMid_Lock); + } + break; + case CIFS_SWN_RESOURCE_STATE_AVAILABLE: + cifs_dbg(FYI, "%s: resource name '%s' become available\n", __func__, name); + for (i = 0; i < swnreg->tcon->ses->chan_count; i++) { + spin_lock(&GlobalMid_Lock); + if (swnreg->tcon->ses->chans[i].server->tcpStatus != CifsExiting) + swnreg->tcon->ses->chans[i].server->tcpStatus = CifsNeedReconnect; + spin_unlock(&GlobalMid_Lock); + } + break; + case CIFS_SWN_RESOURCE_STATE_UNKNOWN: + cifs_dbg(FYI, "%s: resource name '%s' changed to unknown state\n", __func__, name); + break; + } + return 0; +} + +int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info) +{ + struct cifs_swn_reg *swnreg; + char name[256]; + int type; + + if (info->attrs[CIFS_GENL_ATTR_SWN_REGISTRATION_ID]) { + int swnreg_id; + + swnreg_id = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_REGISTRATION_ID]); + mutex_lock(&cifs_swnreg_idr_mutex); + swnreg = idr_find(&cifs_swnreg_idr, swnreg_id); + mutex_unlock(&cifs_swnreg_idr_mutex); + if (swnreg == NULL) { + cifs_dbg(FYI, "%s: registration id %d not found\n", __func__, swnreg_id); + return -EINVAL; + } + } else { + cifs_dbg(FYI, "%s: missing registration id attribute\n", __func__); + return -EINVAL; + } + + if (info->attrs[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE]) { + type = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE]); + } else { + cifs_dbg(FYI, "%s: missing notification type attribute\n", __func__); + return -EINVAL; + } + + switch (type) { + case CIFS_SWN_NOTIFICATION_RESOURCE_CHANGE: { + int state; + + if (info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_NAME]) { + nla_strlcpy(name, info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_NAME], + sizeof(name)); + } else { + cifs_dbg(FYI, "%s: missing resource name attribute\n", __func__); + return -EINVAL; + } + if (info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_STATE]) { + state = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_STATE]); + } else { + cifs_dbg(FYI, "%s: missing resource state attribute\n", __func__); + return -EINVAL; + } + return cifs_swn_resource_state_changed(swnreg, name, state); + } + default: + cifs_dbg(FYI, "%s: unknown notification type %d\n", __func__, type); + break; + } + + return 0; +} + int cifs_swn_register(struct cifs_tcon *tcon) { struct cifs_swn_reg *swnreg; diff --git a/fs/cifs/cifs_swn.h b/fs/cifs/cifs_swn.h index 69c7bd1035da..7ef9ecedbd05 100644 --- a/fs/cifs/cifs_swn.h +++ b/fs/cifs/cifs_swn.h @@ -9,9 +9,13 @@ #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); + #endif /* _CIFS_SWN_H */ diff --git a/fs/cifs/netlink.c b/fs/cifs/netlink.c index 169ac4aacdbb..1b0862ac345b 100644 --- a/fs/cifs/netlink.c +++ b/fs/cifs/netlink.c @@ -10,6 +10,7 @@ #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 }, @@ -23,9 +24,17 @@ static const struct nla_policy cifs_genl_policy[CIFS_GENL_ATTR_MAX + 1] = { [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[] = { diff --git a/include/uapi/linux/cifs/cifs_netlink.h b/include/uapi/linux/cifs/cifs_netlink.h index 4a2a41de1496..22107fc39926 100644 --- a/include/uapi/linux/cifs/cifs_netlink.h +++ b/include/uapi/linux/cifs/cifs_netlink.h @@ -31,6 +31,9 @@ enum cifs_genl_attributes { CIFS_GENL_ATTR_SWN_USER_NAME, CIFS_GENL_ATTR_SWN_PASSWORD, CIFS_GENL_ATTR_SWN_DOMAIN_NAME, + CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE, + CIFS_GENL_ATTR_SWN_RESOURCE_STATE, + CIFS_GENL_ATTR_SWN_RESOURCE_NAME, __CIFS_GENL_ATTR_MAX, }; #define CIFS_GENL_ATTR_MAX (__CIFS_GENL_ATTR_MAX - 1) @@ -39,8 +42,22 @@ enum cifs_genl_commands { CIFS_GENL_CMD_UNSPEC, CIFS_GENL_CMD_SWN_REGISTER, CIFS_GENL_CMD_SWN_UNREGISTER, + CIFS_GENL_CMD_SWN_NOTIFY, __CIFS_GENL_CMD_MAX }; #define CIFS_GENL_CMD_MAX (__CIFS_GENL_CMD_MAX - 1) +enum cifs_swn_notification_type { + CIFS_SWN_NOTIFICATION_RESOURCE_CHANGE = 0x01, + CIFS_SWN_NOTIFICATION_CLIENT_MOVE = 0x02, + CIFS_SWN_NOTIFICATION_SHARE_MOVE = 0x03, + CIFS_SWN_NOTIFICATION_IP_CHANGE = 0x04, +}; + +enum cifs_swn_resource_state { + CIFS_SWN_RESOURCE_STATE_UNKNOWN = 0x00, + CIFS_SWN_RESOURCE_STATE_AVAILABLE = 0x01, + CIFS_SWN_RESOURCE_STATE_UNAVAILABLE = 0xFF +}; + #endif /* _UAPILINUX_CIFS_NETLINK_H */ From patchwork Thu Oct 22 18:13:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 1386378 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4CHFqT1lzpz9sSG for ; Fri, 23 Oct 2020 05:13:57 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2901668AbgJVSNw (ORCPT ); Thu, 22 Oct 2020 14:13:52 -0400 Received: from mx2.suse.de ([195.135.220.15]:58860 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2898343AbgJVSNw (ORCPT ); Thu, 22 Oct 2020 14:13:52 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 6C3C0B818 for ; Thu, 22 Oct 2020 18:13:50 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH 07/11] cifs: Add witness information to debug data dump Date: Thu, 22 Oct 2020 20:13:35 +0200 Message-Id: <20201022181339.30771-8-scabrero@suse.de> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201022181339.30771-1-scabrero@suse.de> References: <20201022181339.30771-1-scabrero@suse.de> Reply-To: scabrero@suse.de MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org + Indicate if witness feature is supported + Indicate if witness is used when dumping tcons + Dumps witness registrations. Example: Witness registrations: Id: 1 Refs: 1 Network name: 'fs.fover.ad'(y) Share name: 'share1'(y) \ Ip address: 192.168.103.200(n) Signed-off-by: Samuel Cabrero --- fs/cifs/cifs_debug.c | 13 +++++++++++++ fs/cifs/cifs_swn.c | 35 +++++++++++++++++++++++++++++++++++ fs/cifs/cifs_swn.h | 2 ++ 3 files changed, 50 insertions(+) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 53588d7517b4..b231dcf1d1f9 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -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; } diff --git a/fs/cifs/cifs_swn.c b/fs/cifs/cifs_swn.c index 501d84893262..4396e21ef228 100644 --- a/fs/cifs/cifs_swn.c +++ b/fs/cifs/cifs_swn.c @@ -501,3 +501,38 @@ int cifs_swn_unregister(struct cifs_tcon *tcon) return 0; } + +void cifs_swn_dump(struct seq_file *m) +{ + struct cifs_swn_reg *swnreg; + struct sockaddr_in *sa; + struct sockaddr_in6 *sa6; + int id; + + seq_puts(m, "Witness registrations:"); + + mutex_lock(&cifs_swnreg_idr_mutex); + idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) { + seq_printf(m, "\nId: %u Refs: %u Network name: '%s'%s Share name: '%s'%s Ip address: ", + id, kref_read(&swnreg->ref_count), + swnreg->net_name, swnreg->net_name_notify ? "(y)" : "(n)", + swnreg->share_name, swnreg->share_name_notify ? "(y)" : "(n)"); + switch (swnreg->tcon->ses->server->dstaddr.ss_family) { + case AF_INET: + sa = (struct sockaddr_in *) &swnreg->tcon->ses->server->dstaddr; + seq_printf(m, "%pI4", &sa->sin_addr.s_addr); + break; + case AF_INET6: + sa6 = (struct sockaddr_in6 *) &swnreg->tcon->ses->server->dstaddr; + seq_printf(m, "%pI6", &sa6->sin6_addr.s6_addr); + if (sa6->sin6_scope_id) + seq_printf(m, "%%%u", sa6->sin6_scope_id); + break; + default: + seq_puts(m, "(unknown)"); + } + seq_printf(m, "%s", swnreg->ip_notify ? "(y)" : "(n)"); + } + mutex_unlock(&cifs_swnreg_idr_mutex); + seq_puts(m, "\n"); +} diff --git a/fs/cifs/cifs_swn.h b/fs/cifs/cifs_swn.h index 7ef9ecedbd05..13b25cdc9295 100644 --- a/fs/cifs/cifs_swn.h +++ b/fs/cifs/cifs_swn.h @@ -18,4 +18,6 @@ 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); + #endif /* _CIFS_SWN_H */ From patchwork Thu Oct 22 18:13:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 1386376 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4CHFqR6y95z9sSW for ; Fri, 23 Oct 2020 05:13:55 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2901781AbgJVSNw (ORCPT ); Thu, 22 Oct 2020 14:13:52 -0400 Received: from mx2.suse.de ([195.135.220.15]:58878 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2901742AbgJVSNv (ORCPT ); Thu, 22 Oct 2020 14:13:51 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id B452FAE3A for ; Thu, 22 Oct 2020 18:13:50 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH 08/11] cifs: Send witness register messages to userspace daemon in echo task Date: Thu, 22 Oct 2020 20:13:36 +0200 Message-Id: <20201022181339.30771-9-scabrero@suse.de> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201022181339.30771-1-scabrero@suse.de> References: <20201022181339.30771-1-scabrero@suse.de> Reply-To: scabrero@suse.de MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org If the daemon starts after mounting a share, or if it crashes, this provides a mechanism to register again. Signed-off-by: Samuel Cabrero --- fs/cifs/cifs_swn.c | 15 +++++++++++++++ fs/cifs/cifs_swn.h | 2 ++ fs/cifs/connect.c | 5 +++++ 3 files changed, 22 insertions(+) diff --git a/fs/cifs/cifs_swn.c b/fs/cifs/cifs_swn.c index 4396e21ef228..93e31e4a9d99 100644 --- a/fs/cifs/cifs_swn.c +++ b/fs/cifs/cifs_swn.c @@ -536,3 +536,18 @@ void cifs_swn_dump(struct seq_file *m) mutex_unlock(&cifs_swnreg_idr_mutex); seq_puts(m, "\n"); } + +void cifs_swn_check(void) +{ + struct cifs_swn_reg *swnreg; + int id; + int ret; + + mutex_lock(&cifs_swnreg_idr_mutex); + idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) { + ret = cifs_swn_send_register_message(swnreg); + if (ret < 0) + cifs_dbg(FYI, "%s: Failed to send register message: %d\n", __func__, ret); + } + mutex_unlock(&cifs_swnreg_idr_mutex); +} diff --git a/fs/cifs/cifs_swn.h b/fs/cifs/cifs_swn.h index 13b25cdc9295..236ecd4959d5 100644 --- a/fs/cifs/cifs_swn.h +++ b/fs/cifs/cifs_swn.h @@ -20,4 +20,6 @@ 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 */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 0e3a88932560..cb9ca4238ae9 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -613,6 +613,11 @@ cifs_echo_request(struct work_struct *work) cifs_dbg(FYI, "Unable to send echo request to server: %s\n", server->hostname); +#ifdef CONFIG_CIFS_SWN_UPCALL + /* Check witness registrations */ + cifs_swn_check(); +#endif + requeue_echo: queue_delayed_work(cifsiod_wq, &server->echo, server->echo_interval); } From patchwork Thu Oct 22 18:13:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 1386381 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4CHFqW0Qqgz9sTD for ; Fri, 23 Oct 2020 05:13:59 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2505941AbgJVSNx (ORCPT ); Thu, 22 Oct 2020 14:13:53 -0400 Received: from mx2.suse.de ([195.135.220.15]:58892 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2901776AbgJVSNx (ORCPT ); Thu, 22 Oct 2020 14:13:53 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 084FEB81E for ; Thu, 22 Oct 2020 18:13:51 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH 09/11] cifs: Simplify reconnect code when dfs upcall is enabled Date: Thu, 22 Oct 2020 20:13:37 +0200 Message-Id: <20201022181339.30771-10-scabrero@suse.de> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201022181339.30771-1-scabrero@suse.de> References: <20201022181339.30771-1-scabrero@suse.de> Reply-To: scabrero@suse.de MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Some witness notifications, like client move, tell the client to reconnect to a specific IP address. In this situation the DFS failover code path has to be skipped so clean up as much as possible the cifs_reconnect() code. Signed-off-by: Samuel Cabrero --- fs/cifs/connect.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index cb9ca4238ae9..14bbec0aeccf 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -296,7 +296,7 @@ static void cifs_prune_tlinks(struct work_struct *work); * This should be called with server->srv_mutex held. */ #ifdef CONFIG_CIFS_DFS_UPCALL -static int reconn_set_ipaddr(struct TCP_Server_Info *server) +static int reconn_set_ipaddr_from_hostname(struct TCP_Server_Info *server) { int rc; int len; @@ -331,14 +331,7 @@ static int reconn_set_ipaddr(struct TCP_Server_Info *server) return !rc ? -1 : 0; } -#else -static inline int reconn_set_ipaddr(struct TCP_Server_Info *server) -{ - return 0; -} -#endif -#ifdef CONFIG_CIFS_DFS_UPCALL /* These functions must be called with server->srv_mutex held */ static void reconn_set_next_dfs_target(struct TCP_Server_Info *server, struct cifs_sb_info *cifs_sb, @@ -346,6 +339,7 @@ static void reconn_set_next_dfs_target(struct TCP_Server_Info *server, struct dfs_cache_tgt_iterator **tgt_it) { const char *name; + int rc; if (!cifs_sb || !cifs_sb->origin_fullpath) return; @@ -370,6 +364,12 @@ static void reconn_set_next_dfs_target(struct TCP_Server_Info *server, "%s: failed to extract hostname from target: %ld\n", __func__, PTR_ERR(server->hostname)); } + + rc = reconn_set_ipaddr_from_hostname(server); + if (rc) { + cifs_dbg(FYI, "%s: failed to resolve hostname: %d\n", + __func__, rc); + } } static inline int reconn_setup_dfs_targets(struct cifs_sb_info *cifs_sb, @@ -528,11 +528,6 @@ cifs_reconnect(struct TCP_Server_Info *server) */ reconn_set_next_dfs_target(server, cifs_sb, &tgt_list, &tgt_it); #endif - rc = reconn_set_ipaddr(server); - if (rc) { - cifs_dbg(FYI, "%s: failed to resolve hostname: %d\n", - __func__, rc); - } if (cifs_rdma_enabled(server)) rc = smbd_reconnect(server); From patchwork Thu Oct 22 18:13:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 1386380 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4CHFqV45K3z9sSG for ; Fri, 23 Oct 2020 05:13:58 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2897861AbgJVSNx (ORCPT ); Thu, 22 Oct 2020 14:13:53 -0400 Received: from mx2.suse.de ([195.135.220.15]:58806 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2505941AbgJVSNx (ORCPT ); Thu, 22 Oct 2020 14:13:53 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 5070FB90F for ; Thu, 22 Oct 2020 18:13:51 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH 10/11] cifs: Handle witness client move notification Date: Thu, 22 Oct 2020 20:13:38 +0200 Message-Id: <20201022181339.30771-11-scabrero@suse.de> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201022181339.30771-1-scabrero@suse.de> References: <20201022181339.30771-1-scabrero@suse.de> Reply-To: scabrero@suse.de MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org This message is sent to tell a client to close its current connection and connect to the specified address. Signed-off-by: Samuel Cabrero --- fs/cifs/cifs_swn.c | 140 ++++++++++++++++++++++++++++++++++++++++++++- fs/cifs/cifsglob.h | 4 ++ fs/cifs/connect.c | 26 +++++++-- 3 files changed, 162 insertions(+), 8 deletions(-) diff --git a/fs/cifs/cifs_swn.c b/fs/cifs/cifs_swn.c index 93e31e4a9d99..b71b05638b1c 100644 --- a/fs/cifs/cifs_swn.c +++ b/fs/cifs/cifs_swn.c @@ -78,6 +78,7 @@ static int cifs_swn_send_register_message(struct cifs_swn_reg *swnreg) struct sk_buff *skb; struct genlmsghdr *hdr; enum securityEnum authtype; + struct sockaddr_storage *addr; int ret; skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); @@ -104,8 +105,18 @@ static int cifs_swn_send_register_message(struct cifs_swn_reg *swnreg) if (ret < 0) goto nlmsg_fail; - ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage), - &swnreg->tcon->ses->server->dstaddr); + /* + * If there is an address stored use it instead of the server address, because we are + * in the process of reconnecting to it after a share has been moved or we have been + * told to switch to it (client move message). In these cases we unregister from the + * server address and register to the new address when we receive the notification. + */ + if (swnreg->tcon->ses->server->use_swn_dstaddr) + addr = &swnreg->tcon->ses->server->swn_dstaddr; + else + addr = &swnreg->tcon->ses->server->dstaddr; + + ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage), addr); if (ret < 0) goto nlmsg_fail; @@ -409,6 +420,120 @@ static int cifs_swn_resource_state_changed(struct cifs_swn_reg *swnreg, const ch return 0; } +static bool cifs_sockaddr_equal(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2) +{ + if (addr1->ss_family != addr2->ss_family) + return false; + + if (addr1->ss_family == AF_INET) { + return (memcmp(&((const struct sockaddr_in *)addr1)->sin_addr, + &((const struct sockaddr_in *)addr2)->sin_addr, + sizeof(struct in_addr)) == 0); + } + + if (addr1->ss_family == AF_INET6) { + return (memcmp(&((const struct sockaddr_in6 *)addr1)->sin6_addr, + &((const struct sockaddr_in6 *)addr2)->sin6_addr, + sizeof(struct in6_addr)) == 0); + } + + return false; +} + +static int cifs_swn_store_swn_addr(const struct sockaddr_storage *new, + const struct sockaddr_storage *old, + struct sockaddr_storage *dst) +{ + __be16 port; + + if (old->ss_family == AF_INET) { + struct sockaddr_in *ipv4 = (struct sockaddr_in *)old; + + port = ipv4->sin_port; + } + + if (old->ss_family == AF_INET6) { + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)old; + + port = ipv6->sin6_port; + } + + if (new->ss_family == AF_INET) { + struct sockaddr_in *ipv4 = (struct sockaddr_in *)new; + + ipv4->sin_port = port; + } + + if (new->ss_family == AF_INET6) { + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)new; + + ipv6->sin6_port = port; + } + + *dst = *new; + + return 0; +} + +static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *addr) +{ + /* Store the reconnect address */ + mutex_lock(&tcon->ses->server->srv_mutex); + if (!cifs_sockaddr_equal(&tcon->ses->server->dstaddr, addr)) { + int ret; + + ret = cifs_swn_store_swn_addr(addr, &tcon->ses->server->dstaddr, + &tcon->ses->server->swn_dstaddr); + if (ret < 0) { + cifs_dbg(VFS, "%s: failed to store address: %d\n", __func__, ret); + return ret; + } + tcon->ses->server->use_swn_dstaddr = true; + + /* + * Unregister to stop receiving notifications for the old IP address. + */ + ret = cifs_swn_unregister(tcon); + if (ret < 0) { + cifs_dbg(VFS, "%s: Failed to unregister for witness notifications: %d\n", + __func__, ret); + return ret; + } + + /* + * And register to receive notifications for the new IP address now that we have + * stored the new address. + */ + ret = cifs_swn_register(tcon); + if (ret < 0) { + cifs_dbg(VFS, "%s: Failed to register for witness notifications: %d\n", + __func__, ret); + return ret; + } + + spin_lock(&GlobalMid_Lock); + if (tcon->ses->server->tcpStatus != CifsExiting) + tcon->ses->server->tcpStatus = CifsNeedReconnect; + spin_unlock(&GlobalMid_Lock); + } + mutex_unlock(&tcon->ses->server->srv_mutex); + + return 0; +} + +static int cifs_swn_client_move(struct cifs_swn_reg *swnreg, struct sockaddr_storage *addr) +{ + struct sockaddr_in *ipv4 = (struct sockaddr_in *)addr; + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)addr; + + if (addr->ss_family == AF_INET) + cifs_dbg(FYI, "%s: move to %pI4\n", __func__, &ipv4->sin_addr); + else if (addr->ss_family == AF_INET6) + cifs_dbg(FYI, "%s: move to %pI6\n", __func__, &ipv6->sin6_addr); + + return cifs_swn_reconnect(swnreg->tcon, addr); +} + int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info) { struct cifs_swn_reg *swnreg; @@ -457,6 +582,17 @@ int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info) } return cifs_swn_resource_state_changed(swnreg, name, state); } + case CIFS_SWN_NOTIFICATION_CLIENT_MOVE: { + struct sockaddr_storage addr; + + if (info->attrs[CIFS_GENL_ATTR_SWN_IP]) { + nla_memcpy(&addr, info->attrs[CIFS_GENL_ATTR_SWN_IP], sizeof(addr)); + } else { + cifs_dbg(FYI, "%s: missing IP address attribute\n", __func__); + return -EINVAL; + } + return cifs_swn_client_move(swnreg, &addr); + } default: cifs_dbg(FYI, "%s: unknown notification type %d\n", __func__, type); break; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 5ca3a5568ac5..4a9089f9948c 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -775,6 +775,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 { diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 14bbec0aeccf..0da10d199f47 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -520,13 +520,24 @@ cifs_reconnect(struct TCP_Server_Info *server) try_to_freeze(); mutex_lock(&server->srv_mutex); + +#ifdef CONFIG_CIFS_SWN_UPCALL + if (server->use_swn_dstaddr) { + server->dstaddr = server->swn_dstaddr; + } else { +#endif + #ifdef CONFIG_CIFS_DFS_UPCALL - /* - * Set up next DFS target server (if any) for reconnect. If DFS - * feature is disabled, then we will retry last server we - * connected to before. - */ - reconn_set_next_dfs_target(server, cifs_sb, &tgt_list, &tgt_it); + /* + * Set up next DFS target server (if any) for reconnect. If DFS + * feature is disabled, then we will retry last server we + * connected to before. + */ + reconn_set_next_dfs_target(server, cifs_sb, &tgt_list, &tgt_it); +#endif + +#ifdef CONFIG_CIFS_SWN_UPCALL + } #endif if (cifs_rdma_enabled(server)) @@ -544,6 +555,9 @@ cifs_reconnect(struct TCP_Server_Info *server) if (server->tcpStatus != CifsExiting) server->tcpStatus = CifsNeedNegotiate; spin_unlock(&GlobalMid_Lock); +#ifdef CONFIG_CIFS_SWN_UPCALL + server->use_swn_dstaddr = false; +#endif mutex_unlock(&server->srv_mutex); } } while (server->tcpStatus == CifsNeedReconnect); From patchwork Thu Oct 22 18:13:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 1386382 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4CHFqW49bHz9sSG for ; Fri, 23 Oct 2020 05:13:59 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2898038AbgJVSNy (ORCPT ); Thu, 22 Oct 2020 14:13:54 -0400 Received: from mx2.suse.de ([195.135.220.15]:58916 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2901782AbgJVSNx (ORCPT ); Thu, 22 Oct 2020 14:13:53 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 97C58B305 for ; Thu, 22 Oct 2020 18:13:51 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH 11/11] cifs: Handle witness share moved notification Date: Thu, 22 Oct 2020 20:13:39 +0200 Message-Id: <20201022181339.30771-12-scabrero@suse.de> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201022181339.30771-1-scabrero@suse.de> References: <20201022181339.30771-1-scabrero@suse.de> Reply-To: scabrero@suse.de MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Just log a message as it is not clear enough what this notification means. It is received for example when a node belonging to a scale-out file server dies, but it is also received as soon as a client registers for notifications (w2k12r2) when the server is scale-out. Signed-off-by: Samuel Cabrero --- fs/cifs/cifs_swn.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/fs/cifs/cifs_swn.c b/fs/cifs/cifs_swn.c index b71b05638b1c..ab079533dc24 100644 --- a/fs/cifs/cifs_swn.c +++ b/fs/cifs/cifs_swn.c @@ -534,6 +534,29 @@ static int cifs_swn_client_move(struct cifs_swn_reg *swnreg, struct sockaddr_sto return cifs_swn_reconnect(swnreg->tcon, addr); } +static int cifs_swn_share_moved(struct cifs_swn_reg *swnreg, struct sockaddr_storage *addr) +{ + struct sockaddr_in *ipv4 = (struct sockaddr_in *)addr; + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)addr; + + if (addr->ss_family == AF_INET) + cifs_dbg(FYI, "%s: share '%s' from '%s' moved to %pI4\n", + __func__, swnreg->share_name, swnreg->net_name, + &ipv4->sin_addr); + else if (addr->ss_family == AF_INET6) + cifs_dbg(FYI, "%s: share '%s' from '%s' moved to %pI6\n", + __func__, swnreg->share_name, swnreg->net_name, + &ipv6->sin6_addr); + + /* + * FIXME It is not clear enough how to handle this notification and what does it mean. + * It is received for example when a node belonging to a scale-out file server dies, but + * it is also received as soon as a client registers for notifications (w2k12r2) when the + * share is scale-out and all nodes are working fine. Just log for now. + */ + return 0; +} + int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info) { struct cifs_swn_reg *swnreg; @@ -593,6 +616,17 @@ int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info) } return cifs_swn_client_move(swnreg, &addr); } + case CIFS_SWN_NOTIFICATION_SHARE_MOVE: { + struct sockaddr_storage addr; + + if (info->attrs[CIFS_GENL_ATTR_SWN_IP]) { + nla_memcpy(&addr, info->attrs[CIFS_GENL_ATTR_SWN_IP], sizeof(addr)); + } else { + cifs_dbg(FYI, "%s: missing IP address attribute\n", __func__); + return -EINVAL; + } + return cifs_swn_share_moved(swnreg, &addr); + } default: cifs_dbg(FYI, "%s: unknown notification type %d\n", __func__, type); break;