From patchwork Mon Nov 30 18:02:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 11941087 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4DC3DC71155 for ; Mon, 30 Nov 2020 18:04:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 25E43207F7 for ; Mon, 30 Nov 2020 18:04:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387903AbgK3SDw (ORCPT ); Mon, 30 Nov 2020 13:03:52 -0500 Received: from mx2.suse.de ([195.135.220.15]:45300 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728571AbgK3SDw (ORCPT ); Mon, 30 Nov 2020 13:03:52 -0500 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 7031FACF9 for ; Mon, 30 Nov 2020 18:03:10 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH v4 01/11] cifs: Make extract_hostname function public Date: Mon, 30 Nov 2020 19:02:47 +0100 Message-Id: <20201130180257.31787-2-scabrero@suse.de> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201130180257.31787-1-scabrero@suse.de> References: <20201130180257.31787-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 --- 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 28c1459fb0fc..a938371af6ef 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 @@ -1232,39 +1231,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 Mon Nov 30 18:02:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 11941083 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 731F9C71156 for ; Mon, 30 Nov 2020 18:04:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3F7C62087C for ; Mon, 30 Nov 2020 18:04:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387904AbgK3SDw (ORCPT ); Mon, 30 Nov 2020 13:03:52 -0500 Received: from mx2.suse.de ([195.135.220.15]:45310 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728739AbgK3SDw (ORCPT ); Mon, 30 Nov 2020 13:03:52 -0500 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 ADB69AE95 for ; Mon, 30 Nov 2020 18:03:10 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH v4 02/11] cifs: Make extract_sharename function public Date: Mon, 30 Nov 2020 19:02:48 +0100 Message-Id: <20201130180257.31787-3-scabrero@suse.de> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201130180257.31787-1-scabrero@suse.de> References: <20201130180257.31787-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 --- 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 Mon Nov 30 18:02:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 11941089 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8FA12C83013 for ; Mon, 30 Nov 2020 18:04:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 720C520705 for ; Mon, 30 Nov 2020 18:04:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387902AbgK3SDx (ORCPT ); Mon, 30 Nov 2020 13:03:53 -0500 Received: from mx2.suse.de ([195.135.220.15]:45320 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387806AbgK3SDx (ORCPT ); Mon, 30 Nov 2020 13:03:53 -0500 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 EC73EAF10 for ; Mon, 30 Nov 2020 18:03:10 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH v4 03/11] cifs: Register generic netlink family Date: Mon, 30 Nov 2020 19:02:49 +0100 Message-Id: <20201130180257.31787-4-scabrero@suse.de> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201130180257.31787-1-scabrero@suse.de> References: <20201130180257.31787-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 --- fs/cifs/Kconfig | 11 ++++ fs/cifs/Makefile | 2 + fs/cifs/cifsfs.c | 17 ++++++- fs/cifs/netlink.c | 69 ++++++++++++++++++++++++++ fs/cifs/netlink.h | 16 ++++++ include/uapi/linux/cifs/cifs_netlink.h | 31 ++++++++++++ 6 files changed, 145 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..b9154661fa85 --- /dev/null +++ b/fs/cifs/netlink.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Netlink routines for CIFS + * + * Copyright (c) 2020 Samuel Cabrero + */ + +#include +#include + +#include "netlink.h" +#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..cdb1bd78fbc7 --- /dev/null +++ b/include/uapi/linux/cifs/cifs_netlink.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */ +/* + * 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 Mon Nov 30 18:02:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 11941085 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8B906C83011 for ; Mon, 30 Nov 2020 18:04:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5793E206F9 for ; Mon, 30 Nov 2020 18:04:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387905AbgK3SDx (ORCPT ); Mon, 30 Nov 2020 13:03:53 -0500 Received: from mx2.suse.de ([195.135.220.15]:45330 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387902AbgK3SDx (ORCPT ); Mon, 30 Nov 2020 13:03:53 -0500 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 389AAAF1B for ; Mon, 30 Nov 2020 18:03:11 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH v4 04/11] cifs: add witness mount option and data structs Date: Mon, 30 Nov 2020 19:02:50 +0100 Message-Id: <20201130180257.31787-5-scabrero@suse.de> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201130180257.31787-1-scabrero@suse.de> References: <20201130180257.31787-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 484ec2d8c5c9..f45b7c0fbceb 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -619,6 +619,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 */ }; /** @@ -1177,6 +1178,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 a938371af6ef..22d46c8acc7f 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 } }; @@ -1540,6 +1541,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; @@ -3160,6 +3168,8 @@ cifs_put_tcon(struct cifs_tcon *tcon) return; } + /* TODO witness unregister */ + list_del_init(&tcon->tcon_list); spin_unlock(&cifs_tcp_ses_lock); @@ -3321,6 +3331,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) @@ -5072,6 +5102,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 Mon Nov 30 18:02:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 11941099 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8AD2DC71155 for ; Mon, 30 Nov 2020 18:04:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 53DF420705 for ; Mon, 30 Nov 2020 18:04:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387913AbgK3SEe (ORCPT ); Mon, 30 Nov 2020 13:04:34 -0500 Received: from mx2.suse.de ([195.135.220.15]:45750 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729435AbgK3SEd (ORCPT ); Mon, 30 Nov 2020 13:04:33 -0500 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 7A685AF26 for ; Mon, 30 Nov 2020 18:03:11 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH v4 05/11] cifs: Send witness register and unregister commands to userspace daemon Date: Mon, 30 Nov 2020 19:02:51 +0100 Message-Id: <20201130180257.31787-6-scabrero@suse.de> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201130180257.31787-1-scabrero@suse.de> References: <20201130180257.31787-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 | 421 +++++++++++++++++++++++++ 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, 489 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..c0af03955d0c --- /dev/null +++ b/fs/cifs/cifs_swn.c @@ -0,0 +1,421 @@ +// 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_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; + } + + 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 22d46c8acc7f..7fbb201b42c3 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; @@ -3168,7 +3171,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); @@ -3336,8 +3349,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 b9154661fa85..83008a56def5 100644 --- a/fs/cifs/netlink.c +++ b/fs/cifs/netlink.c @@ -13,6 +13,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 cdb1bd78fbc7..5662e2774513 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 Mon Nov 30 18:02:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 11941091 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4A0A7C64E8A for ; Mon, 30 Nov 2020 18:04:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1A0B8207F7 for ; Mon, 30 Nov 2020 18:04:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729527AbgK3SEd (ORCPT ); Mon, 30 Nov 2020 13:04:33 -0500 Received: from mx2.suse.de ([195.135.220.15]:45748 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729436AbgK3SEd (ORCPT ); Mon, 30 Nov 2020 13:04:33 -0500 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 C2CE9AF3E for ; Mon, 30 Nov 2020 18:03:11 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH v4 06/11] cifs: Set witness notification handler for messages from userspace daemon Date: Mon, 30 Nov 2020 19:02:52 +0100 Message-Id: <20201130180257.31787-7-scabrero@suse.de> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201130180257.31787-1-scabrero@suse.de> References: <20201130180257.31787-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 c0af03955d0c..63b0764af5d5 100644 --- a/fs/cifs/cifs_swn.c +++ b/fs/cifs/cifs_swn.c @@ -383,6 +383,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 83008a56def5..5aaabe4cc0a7 100644 --- a/fs/cifs/netlink.c +++ b/fs/cifs/netlink.c @@ -11,6 +11,7 @@ #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 }, @@ -24,9 +25,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 5662e2774513..da3107582f49 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 Mon Nov 30 18:02:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 11941095 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C8491C83013 for ; Mon, 30 Nov 2020 18:04:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9BDFD20705 for ; Mon, 30 Nov 2020 18:04:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729429AbgK3SEe (ORCPT ); Mon, 30 Nov 2020 13:04:34 -0500 Received: from mx2.suse.de ([195.135.220.15]:45774 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729513AbgK3SEe (ORCPT ); Mon, 30 Nov 2020 13:04:34 -0500 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 0D8FFAF44 for ; Mon, 30 Nov 2020 18:03:12 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH v4 07/11] cifs: Add witness information to debug data dump Date: Mon, 30 Nov 2020 19:02:53 +0100 Message-Id: <20201130180257.31787-8-scabrero@suse.de> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201130180257.31787-1-scabrero@suse.de> References: <20201130180257.31787-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 63b0764af5d5..140a53a19aa0 100644 --- a/fs/cifs/cifs_swn.c +++ b/fs/cifs/cifs_swn.c @@ -505,3 +505,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 Mon Nov 30 18:02:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 11941097 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 63CFEC64E7B for ; Mon, 30 Nov 2020 18:04:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 36FC420825 for ; Mon, 30 Nov 2020 18:04:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387912AbgK3SEe (ORCPT ); Mon, 30 Nov 2020 13:04:34 -0500 Received: from mx2.suse.de ([195.135.220.15]:45772 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729396AbgK3SEd (ORCPT ); Mon, 30 Nov 2020 13:04:33 -0500 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 4E202AF40 for ; Mon, 30 Nov 2020 18:03:12 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH v4 08/11] cifs: Send witness register messages to userspace daemon in echo task Date: Mon, 30 Nov 2020 19:02:54 +0100 Message-Id: <20201130180257.31787-9-scabrero@suse.de> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201130180257.31787-1-scabrero@suse.de> References: <20201130180257.31787-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 140a53a19aa0..642c9eedc8ab 100644 --- a/fs/cifs/cifs_swn.c +++ b/fs/cifs/cifs_swn.c @@ -540,3 +540,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 7fbb201b42c3..a298518bebb2 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 Mon Nov 30 18:02:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 11941093 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B47DAC71156 for ; Mon, 30 Nov 2020 18:04:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7EB0121D7A for ; Mon, 30 Nov 2020 18:04:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729396AbgK3SEe (ORCPT ); Mon, 30 Nov 2020 13:04:34 -0500 Received: from mx2.suse.de ([195.135.220.15]:45776 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729524AbgK3SEd (ORCPT ); Mon, 30 Nov 2020 13:04:33 -0500 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 90755AF45 for ; Mon, 30 Nov 2020 18:03:12 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH v4 09/11] cifs: Simplify reconnect code when dfs upcall is enabled Date: Mon, 30 Nov 2020 19:02:55 +0100 Message-Id: <20201130180257.31787-10-scabrero@suse.de> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201130180257.31787-1-scabrero@suse.de> References: <20201130180257.31787-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 a298518bebb2..3af88711643b 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 Mon Nov 30 18:02:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 11941103 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2659EC83014 for ; Mon, 30 Nov 2020 18:04:50 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id EB50B20705 for ; Mon, 30 Nov 2020 18:04:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387914AbgK3SEe (ORCPT ); Mon, 30 Nov 2020 13:04:34 -0500 Received: from mx2.suse.de ([195.135.220.15]:45778 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729515AbgK3SEe (ORCPT ); Mon, 30 Nov 2020 13:04:34 -0500 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 D487CAF48 for ; Mon, 30 Nov 2020 18:03:12 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH v4 10/11] cifs: Handle witness client move notification Date: Mon, 30 Nov 2020 19:02:56 +0100 Message-Id: <20201130180257.31787-11-scabrero@suse.de> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201130180257.31787-1-scabrero@suse.de> References: <20201130180257.31787-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 642c9eedc8ab..a172769c239f 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; @@ -413,6 +424,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; @@ -461,6 +586,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 f45b7c0fbceb..d7f43cec0f13 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -779,6 +779,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 3af88711643b..6bfa232712a5 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 Mon Nov 30 18:02:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Cabrero X-Patchwork-Id: 11941101 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 46A5AC83017 for ; Mon, 30 Nov 2020 18:04:50 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1D1C9208DB for ; Mon, 30 Nov 2020 18:04:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387915AbgK3SEf (ORCPT ); Mon, 30 Nov 2020 13:04:35 -0500 Received: from mx2.suse.de ([195.135.220.15]:45790 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387806AbgK3SEe (ORCPT ); Mon, 30 Nov 2020 13:04:34 -0500 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 2C089AF49 for ; Mon, 30 Nov 2020 18:03:13 +0000 (UTC) From: Samuel Cabrero To: linux-cifs@vger.kernel.org Cc: Samuel Cabrero Subject: [PATCH v4 11/11] cifs: Handle witness share moved notification Date: Mon, 30 Nov 2020 19:02:57 +0100 Message-Id: <20201130180257.31787-12-scabrero@suse.de> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201130180257.31787-1-scabrero@suse.de> References: <20201130180257.31787-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 a172769c239f..c505d35f5b57 100644 --- a/fs/cifs/cifs_swn.c +++ b/fs/cifs/cifs_swn.c @@ -538,6 +538,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; @@ -597,6 +620,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;