linux/fs/cifs/cifs_swn.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Witness Service client for CIFS
   4 *
   5 * Copyright (c) 2020 Samuel Cabrero <scabrero@suse.de>
   6 */
   7
   8#include <linux/kref.h>
   9#include <net/genetlink.h>
  10#include <uapi/linux/cifs/cifs_netlink.h>
  11
  12#include "cifs_swn.h"
  13#include "cifsglob.h"
  14#include "cifsproto.h"
  15#include "fscache.h"
  16#include "cifs_debug.h"
  17#include "netlink.h"
  18
  19static DEFINE_IDR(cifs_swnreg_idr);
  20static DEFINE_MUTEX(cifs_swnreg_idr_mutex);
  21
  22struct cifs_swn_reg {
  23        int id;
  24        struct kref ref_count;
  25
  26        const char *net_name;
  27        const char *share_name;
  28        bool net_name_notify;
  29        bool share_name_notify;
  30        bool ip_notify;
  31
  32        struct cifs_tcon *tcon;
  33};
  34
  35static int cifs_swn_auth_info_krb(struct cifs_tcon *tcon, struct sk_buff *skb)
  36{
  37        int ret;
  38
  39        ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_KRB_AUTH);
  40        if (ret < 0)
  41                return ret;
  42
  43        return 0;
  44}
  45
  46static int cifs_swn_auth_info_ntlm(struct cifs_tcon *tcon, struct sk_buff *skb)
  47{
  48        int ret;
  49
  50        if (tcon->ses->user_name != NULL) {
  51                ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_USER_NAME, tcon->ses->user_name);
  52                if (ret < 0)
  53                        return ret;
  54        }
  55
  56        if (tcon->ses->password != NULL) {
  57                ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_PASSWORD, tcon->ses->password);
  58                if (ret < 0)
  59                        return ret;
  60        }
  61
  62        if (tcon->ses->domainName != NULL) {
  63                ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_DOMAIN_NAME, tcon->ses->domainName);
  64                if (ret < 0)
  65                        return ret;
  66        }
  67
  68        return 0;
  69}
  70
  71/*
  72 * Sends a register message to the userspace daemon based on the registration.
  73 * The authentication information to connect to the witness service is bundled
  74 * into the message.
  75 */
  76static int cifs_swn_send_register_message(struct cifs_swn_reg *swnreg)
  77{
  78        struct sk_buff *skb;
  79        struct genlmsghdr *hdr;
  80        enum securityEnum authtype;
  81        struct sockaddr_storage *addr;
  82        int ret;
  83
  84        skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  85        if (skb == NULL) {
  86                ret = -ENOMEM;
  87                goto fail;
  88        }
  89
  90        hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_REGISTER);
  91        if (hdr == NULL) {
  92                ret = -ENOMEM;
  93                goto nlmsg_fail;
  94        }
  95
  96        ret = nla_put_u32(skb, CIFS_GENL_ATTR_SWN_REGISTRATION_ID, swnreg->id);
  97        if (ret < 0)
  98                goto nlmsg_fail;
  99
 100        ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_NET_NAME, swnreg->net_name);
 101        if (ret < 0)
 102                goto nlmsg_fail;
 103
 104        ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME, swnreg->share_name);
 105        if (ret < 0)
 106                goto nlmsg_fail;
 107
 108        /*
 109         * If there is an address stored use it instead of the server address, because we are
 110         * in the process of reconnecting to it after a share has been moved or we have been
 111         * told to switch to it (client move message). In these cases we unregister from the
 112         * server address and register to the new address when we receive the notification.
 113         */
 114        if (swnreg->tcon->ses->server->use_swn_dstaddr)
 115                addr = &swnreg->tcon->ses->server->swn_dstaddr;
 116        else
 117                addr = &swnreg->tcon->ses->server->dstaddr;
 118
 119        ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage), addr);
 120        if (ret < 0)
 121                goto nlmsg_fail;
 122
 123        if (swnreg->net_name_notify) {
 124                ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY);
 125                if (ret < 0)
 126                        goto nlmsg_fail;
 127        }
 128
 129        if (swnreg->share_name_notify) {
 130                ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY);
 131                if (ret < 0)
 132                        goto nlmsg_fail;
 133        }
 134
 135        if (swnreg->ip_notify) {
 136                ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_IP_NOTIFY);
 137                if (ret < 0)
 138                        goto nlmsg_fail;
 139        }
 140
 141        authtype = cifs_select_sectype(swnreg->tcon->ses->server, swnreg->tcon->ses->sectype);
 142        switch (authtype) {
 143        case Kerberos:
 144                ret = cifs_swn_auth_info_krb(swnreg->tcon, skb);
 145                if (ret < 0) {
 146                        cifs_dbg(VFS, "%s: Failed to get kerberos auth info: %d\n", __func__, ret);
 147                        goto nlmsg_fail;
 148                }
 149                break;
 150        case NTLMv2:
 151        case RawNTLMSSP:
 152                ret = cifs_swn_auth_info_ntlm(swnreg->tcon, skb);
 153                if (ret < 0) {
 154                        cifs_dbg(VFS, "%s: Failed to get NTLM auth info: %d\n", __func__, ret);
 155                        goto nlmsg_fail;
 156                }
 157                break;
 158        default:
 159                cifs_dbg(VFS, "%s: secType %d not supported!\n", __func__, authtype);
 160                ret = -EINVAL;
 161                goto nlmsg_fail;
 162        }
 163
 164        genlmsg_end(skb, hdr);
 165        genlmsg_multicast(&cifs_genl_family, skb, 0, CIFS_GENL_MCGRP_SWN, GFP_ATOMIC);
 166
 167        cifs_dbg(FYI, "%s: Message to register for network name %s with id %d sent\n", __func__,
 168                        swnreg->net_name, swnreg->id);
 169
 170        return 0;
 171
 172nlmsg_fail:
 173        genlmsg_cancel(skb, hdr);
 174        nlmsg_free(skb);
 175fail:
 176        return ret;
 177}
 178
 179/*
 180 * Sends an uregister message to the userspace daemon based on the registration
 181 */
 182static int cifs_swn_send_unregister_message(struct cifs_swn_reg *swnreg)
 183{
 184        struct sk_buff *skb;
 185        struct genlmsghdr *hdr;
 186        int ret;
 187
 188        skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 189        if (skb == NULL)
 190                return -ENOMEM;
 191
 192        hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_UNREGISTER);
 193        if (hdr == NULL) {
 194                ret = -ENOMEM;
 195                goto nlmsg_fail;
 196        }
 197
 198        ret = nla_put_u32(skb, CIFS_GENL_ATTR_SWN_REGISTRATION_ID, swnreg->id);
 199        if (ret < 0)
 200                goto nlmsg_fail;
 201
 202        ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_NET_NAME, swnreg->net_name);
 203        if (ret < 0)
 204                goto nlmsg_fail;
 205
 206        ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME, swnreg->share_name);
 207        if (ret < 0)
 208                goto nlmsg_fail;
 209
 210        ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage),
 211                        &swnreg->tcon->ses->server->dstaddr);
 212        if (ret < 0)
 213                goto nlmsg_fail;
 214
 215        if (swnreg->net_name_notify) {
 216                ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY);
 217                if (ret < 0)
 218                        goto nlmsg_fail;
 219        }
 220
 221        if (swnreg->share_name_notify) {
 222                ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY);
 223                if (ret < 0)
 224                        goto nlmsg_fail;
 225        }
 226
 227        if (swnreg->ip_notify) {
 228                ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_IP_NOTIFY);
 229                if (ret < 0)
 230                        goto nlmsg_fail;
 231        }
 232
 233        genlmsg_end(skb, hdr);
 234        genlmsg_multicast(&cifs_genl_family, skb, 0, CIFS_GENL_MCGRP_SWN, GFP_ATOMIC);
 235
 236        cifs_dbg(FYI, "%s: Message to unregister for network name %s with id %d sent\n", __func__,
 237                        swnreg->net_name, swnreg->id);
 238
 239        return 0;
 240
 241nlmsg_fail:
 242        genlmsg_cancel(skb, hdr);
 243        nlmsg_free(skb);
 244        return ret;
 245}
 246
 247/*
 248 * Try to find a matching registration for the tcon's server name and share name.
 249 * Calls to this function must be protected by cifs_swnreg_idr_mutex.
 250 * TODO Try to avoid memory allocations
 251 */
 252static struct cifs_swn_reg *cifs_find_swn_reg(struct cifs_tcon *tcon)
 253{
 254        struct cifs_swn_reg *swnreg;
 255        int id;
 256        const char *share_name;
 257        const char *net_name;
 258
 259        net_name = extract_hostname(tcon->treeName);
 260        if (IS_ERR(net_name)) {
 261                int ret;
 262
 263                ret = PTR_ERR(net_name);
 264                cifs_dbg(VFS, "%s: failed to extract host name from target '%s': %d\n",
 265                                __func__, tcon->treeName, ret);
 266                return ERR_PTR(-EINVAL);
 267        }
 268
 269        share_name = extract_sharename(tcon->treeName);
 270        if (IS_ERR(share_name)) {
 271                int ret;
 272
 273                ret = PTR_ERR(share_name);
 274                cifs_dbg(VFS, "%s: failed to extract share name from target '%s': %d\n",
 275                                __func__, tcon->treeName, ret);
 276                kfree(net_name);
 277                return ERR_PTR(-EINVAL);
 278        }
 279
 280        idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) {
 281                if (strcasecmp(swnreg->net_name, net_name) != 0
 282                    || strcasecmp(swnreg->share_name, share_name) != 0) {
 283                        continue;
 284                }
 285
 286                cifs_dbg(FYI, "Existing swn registration for %s:%s found\n", swnreg->net_name,
 287                                swnreg->share_name);
 288
 289                kfree(net_name);
 290                kfree(share_name);
 291
 292                return swnreg;
 293        }
 294
 295        kfree(net_name);
 296        kfree(share_name);
 297
 298        return ERR_PTR(-EEXIST);
 299}
 300
 301/*
 302 * Get a registration for the tcon's server and share name, allocating a new one if it does not
 303 * exists
 304 */
 305static struct cifs_swn_reg *cifs_get_swn_reg(struct cifs_tcon *tcon)
 306{
 307        struct cifs_swn_reg *reg = NULL;
 308        int ret;
 309
 310        mutex_lock(&cifs_swnreg_idr_mutex);
 311
 312        /* Check if we are already registered for this network and share names */
 313        reg = cifs_find_swn_reg(tcon);
 314        if (!IS_ERR(reg)) {
 315                kref_get(&reg->ref_count);
 316                mutex_unlock(&cifs_swnreg_idr_mutex);
 317                return reg;
 318        } else if (PTR_ERR(reg) != -EEXIST) {
 319                mutex_unlock(&cifs_swnreg_idr_mutex);
 320                return reg;
 321        }
 322
 323        reg = kmalloc(sizeof(struct cifs_swn_reg), GFP_ATOMIC);
 324        if (reg == NULL) {
 325                mutex_unlock(&cifs_swnreg_idr_mutex);
 326                return ERR_PTR(-ENOMEM);
 327        }
 328
 329        kref_init(&reg->ref_count);
 330
 331        reg->id = idr_alloc(&cifs_swnreg_idr, reg, 1, 0, GFP_ATOMIC);
 332        if (reg->id < 0) {
 333                cifs_dbg(FYI, "%s: failed to allocate registration id\n", __func__);
 334                ret = reg->id;
 335                goto fail;
 336        }
 337
 338        reg->net_name = extract_hostname(tcon->treeName);
 339        if (IS_ERR(reg->net_name)) {
 340                ret = PTR_ERR(reg->net_name);
 341                cifs_dbg(VFS, "%s: failed to extract host name from target: %d\n", __func__, ret);
 342                goto fail_idr;
 343        }
 344
 345        reg->share_name = extract_sharename(tcon->treeName);
 346        if (IS_ERR(reg->share_name)) {
 347                ret = PTR_ERR(reg->share_name);
 348                cifs_dbg(VFS, "%s: failed to extract share name from target: %d\n", __func__, ret);
 349                goto fail_net_name;
 350        }
 351
 352        reg->net_name_notify = true;
 353        reg->share_name_notify = true;
 354        reg->ip_notify = (tcon->capabilities & SMB2_SHARE_CAP_SCALEOUT);
 355
 356        reg->tcon = tcon;
 357
 358        mutex_unlock(&cifs_swnreg_idr_mutex);
 359
 360        return reg;
 361
 362fail_net_name:
 363        kfree(reg->net_name);
 364fail_idr:
 365        idr_remove(&cifs_swnreg_idr, reg->id);
 366fail:
 367        kfree(reg);
 368        mutex_unlock(&cifs_swnreg_idr_mutex);
 369        return ERR_PTR(ret);
 370}
 371
 372static void cifs_swn_reg_release(struct kref *ref)
 373{
 374        struct cifs_swn_reg *swnreg = container_of(ref, struct cifs_swn_reg, ref_count);
 375        int ret;
 376
 377        ret = cifs_swn_send_unregister_message(swnreg);
 378        if (ret < 0)
 379                cifs_dbg(VFS, "%s: Failed to send unregister message: %d\n", __func__, ret);
 380
 381        idr_remove(&cifs_swnreg_idr, swnreg->id);
 382        kfree(swnreg->net_name);
 383        kfree(swnreg->share_name);
 384        kfree(swnreg);
 385}
 386
 387static void cifs_put_swn_reg(struct cifs_swn_reg *swnreg)
 388{
 389        mutex_lock(&cifs_swnreg_idr_mutex);
 390        kref_put(&swnreg->ref_count, cifs_swn_reg_release);
 391        mutex_unlock(&cifs_swnreg_idr_mutex);
 392}
 393
 394static int cifs_swn_resource_state_changed(struct cifs_swn_reg *swnreg, const char *name, int state)
 395{
 396        switch (state) {
 397        case CIFS_SWN_RESOURCE_STATE_UNAVAILABLE:
 398                cifs_dbg(FYI, "%s: resource name '%s' become unavailable\n", __func__, name);
 399                cifs_signal_cifsd_for_reconnect(swnreg->tcon->ses->server, true);
 400                break;
 401        case CIFS_SWN_RESOURCE_STATE_AVAILABLE:
 402                cifs_dbg(FYI, "%s: resource name '%s' become available\n", __func__, name);
 403                cifs_signal_cifsd_for_reconnect(swnreg->tcon->ses->server, true);
 404                break;
 405        case CIFS_SWN_RESOURCE_STATE_UNKNOWN:
 406                cifs_dbg(FYI, "%s: resource name '%s' changed to unknown state\n", __func__, name);
 407                break;
 408        }
 409        return 0;
 410}
 411
 412static bool cifs_sockaddr_equal(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2)
 413{
 414        if (addr1->ss_family != addr2->ss_family)
 415                return false;
 416
 417        if (addr1->ss_family == AF_INET) {
 418                return (memcmp(&((const struct sockaddr_in *)addr1)->sin_addr,
 419                                &((const struct sockaddr_in *)addr2)->sin_addr,
 420                                sizeof(struct in_addr)) == 0);
 421        }
 422
 423        if (addr1->ss_family == AF_INET6) {
 424                return (memcmp(&((const struct sockaddr_in6 *)addr1)->sin6_addr,
 425                                &((const struct sockaddr_in6 *)addr2)->sin6_addr,
 426                                sizeof(struct in6_addr)) == 0);
 427        }
 428
 429        return false;
 430}
 431
 432static int cifs_swn_store_swn_addr(const struct sockaddr_storage *new,
 433                                   const struct sockaddr_storage *old,
 434                                   struct sockaddr_storage *dst)
 435{
 436        __be16 port = cpu_to_be16(CIFS_PORT);
 437
 438        if (old->ss_family == AF_INET) {
 439                struct sockaddr_in *ipv4 = (struct sockaddr_in *)old;
 440
 441                port = ipv4->sin_port;
 442        } else if (old->ss_family == AF_INET6) {
 443                struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)old;
 444
 445                port = ipv6->sin6_port;
 446        }
 447
 448        if (new->ss_family == AF_INET) {
 449                struct sockaddr_in *ipv4 = (struct sockaddr_in *)new;
 450
 451                ipv4->sin_port = port;
 452        } else if (new->ss_family == AF_INET6) {
 453                struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)new;
 454
 455                ipv6->sin6_port = port;
 456        }
 457
 458        *dst = *new;
 459
 460        return 0;
 461}
 462
 463static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *addr)
 464{
 465        int ret = 0;
 466
 467        /* Store the reconnect address */
 468        cifs_server_lock(tcon->ses->server);
 469        if (cifs_sockaddr_equal(&tcon->ses->server->dstaddr, addr))
 470                goto unlock;
 471
 472        ret = cifs_swn_store_swn_addr(addr, &tcon->ses->server->dstaddr,
 473                                      &tcon->ses->server->swn_dstaddr);
 474        if (ret < 0) {
 475                cifs_dbg(VFS, "%s: failed to store address: %d\n", __func__, ret);
 476                goto unlock;
 477        }
 478        tcon->ses->server->use_swn_dstaddr = true;
 479
 480        /*
 481         * Unregister to stop receiving notifications for the old IP address.
 482         */
 483        ret = cifs_swn_unregister(tcon);
 484        if (ret < 0) {
 485                cifs_dbg(VFS, "%s: Failed to unregister for witness notifications: %d\n",
 486                         __func__, ret);
 487                goto unlock;
 488        }
 489
 490        /*
 491         * And register to receive notifications for the new IP address now that we have
 492         * stored the new address.
 493         */
 494        ret = cifs_swn_register(tcon);
 495        if (ret < 0) {
 496                cifs_dbg(VFS, "%s: Failed to register for witness notifications: %d\n",
 497                         __func__, ret);
 498                goto unlock;
 499        }
 500
 501        cifs_signal_cifsd_for_reconnect(tcon->ses->server, false);
 502
 503unlock:
 504        cifs_server_unlock(tcon->ses->server);
 505
 506        return ret;
 507}
 508
 509static int cifs_swn_client_move(struct cifs_swn_reg *swnreg, struct sockaddr_storage *addr)
 510{
 511        struct sockaddr_in *ipv4 = (struct sockaddr_in *)addr;
 512        struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)addr;
 513
 514        if (addr->ss_family == AF_INET)
 515                cifs_dbg(FYI, "%s: move to %pI4\n", __func__, &ipv4->sin_addr);
 516        else if (addr->ss_family == AF_INET6)
 517                cifs_dbg(FYI, "%s: move to %pI6\n", __func__, &ipv6->sin6_addr);
 518
 519        return cifs_swn_reconnect(swnreg->tcon, addr);
 520}
 521
 522int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info)
 523{
 524        struct cifs_swn_reg *swnreg;
 525        char name[256];
 526        int type;
 527
 528        if (info->attrs[CIFS_GENL_ATTR_SWN_REGISTRATION_ID]) {
 529                int swnreg_id;
 530
 531                swnreg_id = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_REGISTRATION_ID]);
 532                mutex_lock(&cifs_swnreg_idr_mutex);
 533                swnreg = idr_find(&cifs_swnreg_idr, swnreg_id);
 534                mutex_unlock(&cifs_swnreg_idr_mutex);
 535                if (swnreg == NULL) {
 536                        cifs_dbg(FYI, "%s: registration id %d not found\n", __func__, swnreg_id);
 537                        return -EINVAL;
 538                }
 539        } else {
 540                cifs_dbg(FYI, "%s: missing registration id attribute\n", __func__);
 541                return -EINVAL;
 542        }
 543
 544        if (info->attrs[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE]) {
 545                type = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE]);
 546        } else {
 547                cifs_dbg(FYI, "%s: missing notification type attribute\n", __func__);
 548                return -EINVAL;
 549        }
 550
 551        switch (type) {
 552        case CIFS_SWN_NOTIFICATION_RESOURCE_CHANGE: {
 553                int state;
 554
 555                if (info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_NAME]) {
 556                        nla_strscpy(name, info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_NAME],
 557                                        sizeof(name));
 558                } else {
 559                        cifs_dbg(FYI, "%s: missing resource name attribute\n", __func__);
 560                        return -EINVAL;
 561                }
 562                if (info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_STATE]) {
 563                        state = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_STATE]);
 564                } else {
 565                        cifs_dbg(FYI, "%s: missing resource state attribute\n", __func__);
 566                        return -EINVAL;
 567                }
 568                return cifs_swn_resource_state_changed(swnreg, name, state);
 569        }
 570        case CIFS_SWN_NOTIFICATION_CLIENT_MOVE: {
 571                struct sockaddr_storage addr;
 572
 573                if (info->attrs[CIFS_GENL_ATTR_SWN_IP]) {
 574                        nla_memcpy(&addr, info->attrs[CIFS_GENL_ATTR_SWN_IP], sizeof(addr));
 575                } else {
 576                        cifs_dbg(FYI, "%s: missing IP address attribute\n", __func__);
 577                        return -EINVAL;
 578                }
 579                return cifs_swn_client_move(swnreg, &addr);
 580        }
 581        default:
 582                cifs_dbg(FYI, "%s: unknown notification type %d\n", __func__, type);
 583                break;
 584        }
 585
 586        return 0;
 587}
 588
 589int cifs_swn_register(struct cifs_tcon *tcon)
 590{
 591        struct cifs_swn_reg *swnreg;
 592        int ret;
 593
 594        swnreg = cifs_get_swn_reg(tcon);
 595        if (IS_ERR(swnreg))
 596                return PTR_ERR(swnreg);
 597
 598        ret = cifs_swn_send_register_message(swnreg);
 599        if (ret < 0) {
 600                cifs_dbg(VFS, "%s: Failed to send swn register message: %d\n", __func__, ret);
 601                /* Do not put the swnreg or return error, the echo task will retry */
 602        }
 603
 604        return 0;
 605}
 606
 607int cifs_swn_unregister(struct cifs_tcon *tcon)
 608{
 609        struct cifs_swn_reg *swnreg;
 610
 611        mutex_lock(&cifs_swnreg_idr_mutex);
 612
 613        swnreg = cifs_find_swn_reg(tcon);
 614        if (IS_ERR(swnreg)) {
 615                mutex_unlock(&cifs_swnreg_idr_mutex);
 616                return PTR_ERR(swnreg);
 617        }
 618
 619        mutex_unlock(&cifs_swnreg_idr_mutex);
 620
 621        cifs_put_swn_reg(swnreg);
 622
 623        return 0;
 624}
 625
 626void cifs_swn_dump(struct seq_file *m)
 627{
 628        struct cifs_swn_reg *swnreg;
 629        struct sockaddr_in *sa;
 630        struct sockaddr_in6 *sa6;
 631        int id;
 632
 633        seq_puts(m, "Witness registrations:");
 634
 635        mutex_lock(&cifs_swnreg_idr_mutex);
 636        idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) {
 637                seq_printf(m, "\nId: %u Refs: %u Network name: '%s'%s Share name: '%s'%s Ip address: ",
 638                                id, kref_read(&swnreg->ref_count),
 639                                swnreg->net_name, swnreg->net_name_notify ? "(y)" : "(n)",
 640                                swnreg->share_name, swnreg->share_name_notify ? "(y)" : "(n)");
 641                switch (swnreg->tcon->ses->server->dstaddr.ss_family) {
 642                case AF_INET:
 643                        sa = (struct sockaddr_in *) &swnreg->tcon->ses->server->dstaddr;
 644                        seq_printf(m, "%pI4", &sa->sin_addr.s_addr);
 645                        break;
 646                case AF_INET6:
 647                        sa6 = (struct sockaddr_in6 *) &swnreg->tcon->ses->server->dstaddr;
 648                        seq_printf(m, "%pI6", &sa6->sin6_addr.s6_addr);
 649                        if (sa6->sin6_scope_id)
 650                                seq_printf(m, "%%%u", sa6->sin6_scope_id);
 651                        break;
 652                default:
 653                        seq_puts(m, "(unknown)");
 654                }
 655                seq_printf(m, "%s", swnreg->ip_notify ? "(y)" : "(n)");
 656        }
 657        mutex_unlock(&cifs_swnreg_idr_mutex);
 658        seq_puts(m, "\n");
 659}
 660
 661void cifs_swn_check(void)
 662{
 663        struct cifs_swn_reg *swnreg;
 664        int id;
 665        int ret;
 666
 667        mutex_lock(&cifs_swnreg_idr_mutex);
 668        idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) {
 669                ret = cifs_swn_send_register_message(swnreg);
 670                if (ret < 0)
 671                        cifs_dbg(FYI, "%s: Failed to send register message: %d\n", __func__, ret);
 672        }
 673        mutex_unlock(&cifs_swnreg_idr_mutex);
 674}
 675