linux-cifs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Steve French <smfrench@gmail.com>
To: Samuel Cabrero <scabrero@suse.de>
Cc: CIFS <linux-cifs@vger.kernel.org>, "Aurélien Aptel" <aaptel@suse.com>
Subject: Re: [PATCH v4 05/11] cifs: Send witness register and unregister commands to userspace daemon
Date: Fri, 11 Dec 2020 23:52:34 -0600	[thread overview]
Message-ID: <CAH2r5mtow7suE+Kj-Z9emQ6T64S4xQaov9cPRGL6nte94KvK=Q@mail.gmail.com> (raw)
In-Reply-To: <20201130180257.31787-6-scabrero@suse.de>

[-- Attachment #1: Type: text/plain, Size: 20765 bytes --]

updated version of the patch attached (rebased on current for-next).
Tentatively merged into cifs-2.6.git for-next


On Mon, Nov 30, 2020 at 12:06 PM Samuel Cabrero <scabrero@suse.de> wrote:
>
> + 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 <scabrero@suse.de>
> ---
>  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 <scabrero@suse.de>
> + */
> +
> +#include <linux/kref.h>
> +#include <net/genetlink.h>
> +#include <uapi/linux/cifs/cifs_netlink.h>
> +
> +#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(&reg->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(&reg->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 <scabrero@suse.de>
> + */
> +
> +#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)
> --
> 2.29.2
>


-- 
Thanks,

Steve

[-- Attachment #2: 0008-cifs-Send-witness-register-and-unregister-commands-t.patch --]
[-- Type: text/x-patch, Size: 16370 bytes --]

From d592a0054e8741d60324d1ec067375f5479f3295 Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.de>
Date: Mon, 30 Nov 2020 19:02:51 +0100
Subject: [PATCH 8/8] cifs: Send witness register and unregister commands to
 userspace daemon

+ 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 <scabrero@suse.de>
Signed-off-by: Steve French <stfrench@microsoft.com>
---
 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 9e398d227b0e..5213b20843b5 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 <scabrero@suse.de>
+ */
+
+#include <linux/kref.h>
+#include <net/genetlink.h>
+#include <uapi/linux/cifs/cifs_netlink.h>
+
+#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(&reg->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(&reg->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 <scabrero@suse.de>
+ */
+
+#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 ead1c086b88d..68ef2da7c74b 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;
@@ -1944,7 +1947,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);
@@ -2111,8 +2124,17 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
 	if (ctx->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 {
 				/* TODO: try to extend for non-cluster uses (eg multichannel) */
 				cifs_dbg(VFS, "witness requested on mount but no CLUSTER capability on share\n");
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)
-- 
2.27.0


  reply	other threads:[~2020-12-12  5:54 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-30 18:02 [PATCH v4 00/11] Witness protocol support for transparent failover Samuel Cabrero
2020-11-30 18:02 ` [PATCH v4 01/11] cifs: Make extract_hostname function public Samuel Cabrero
2020-12-12  3:42   ` Steve French
2020-11-30 18:02 ` [PATCH v4 02/11] cifs: Make extract_sharename " Samuel Cabrero
2020-12-12  5:50   ` Steve French
2020-11-30 18:02 ` [PATCH v4 03/11] cifs: Register generic netlink family Samuel Cabrero
2020-12-12  5:51   ` Steve French
2020-11-30 18:02 ` [PATCH v4 04/11] cifs: add witness mount option and data structs Samuel Cabrero
2020-12-12  5:07   ` Steve French
2020-11-30 18:02 ` [PATCH v4 05/11] cifs: Send witness register and unregister commands to userspace daemon Samuel Cabrero
2020-12-12  5:52   ` Steve French [this message]
2020-11-30 18:02 ` [PATCH v4 06/11] cifs: Set witness notification handler for messages from " Samuel Cabrero
2020-12-12  5:55   ` Steve French
2020-11-30 18:02 ` [PATCH v4 07/11] cifs: Add witness information to debug data dump Samuel Cabrero
2020-12-12  5:57   ` Steve French
2020-11-30 18:02 ` [PATCH v4 08/11] cifs: Send witness register messages to userspace daemon in echo task Samuel Cabrero
2020-12-12  6:00   ` Steve French
2020-11-30 18:02 ` [PATCH v4 09/11] cifs: Simplify reconnect code when dfs upcall is enabled Samuel Cabrero
2020-12-12  6:07   ` Steve French
2020-11-30 18:02 ` [PATCH v4 10/11] cifs: Handle witness client move notification Samuel Cabrero
2020-11-30 18:02 ` [PATCH v4 11/11] cifs: Handle witness share moved notification Samuel Cabrero
2020-12-09 12:36 ` [PATCH v4 00/11] Witness protocol support for transparent failover Aurélien Aptel
2020-12-09 15:06   ` Paulo Alcantara

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAH2r5mtow7suE+Kj-Z9emQ6T64S4xQaov9cPRGL6nte94KvK=Q@mail.gmail.com' \
    --to=smfrench@gmail.com \
    --cc=aaptel@suse.com \
    --cc=linux-cifs@vger.kernel.org \
    --cc=scabrero@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).