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        int i;
 397
 398        switch (state) {
 399        case CIFS_SWN_RESOURCE_STATE_UNAVAILABLE:
 400                cifs_dbg(FYI, "%s: resource name '%s' become unavailable\n", __func__, name);
 401                for (i = 0; i < swnreg->tcon->ses->chan_count; i++) {
 402                        spin_lock(&GlobalMid_Lock);
 403                        if (swnreg->tcon->ses->chans[i].server->tcpStatus != CifsExiting)
 404                                swnreg->tcon->ses->chans[i].server->tcpStatus = CifsNeedReconnect;
 405                        spin_unlock(&GlobalMid_Lock);
 406                }
 407                break;
 408        case CIFS_SWN_RESOURCE_STATE_AVAILABLE:
 409                cifs_dbg(FYI, "%s: resource name '%s' become available\n", __func__, name);
 410                for (i = 0; i < swnreg->tcon->ses->chan_count; i++) {
 411                        spin_lock(&GlobalMid_Lock);
 412                        if (swnreg->tcon->ses->chans[i].server->tcpStatus != CifsExiting)
 413                                swnreg->tcon->ses->chans[i].server->tcpStatus = CifsNeedReconnect;
 414                        spin_unlock(&GlobalMid_Lock);
 415                }
 416                break;
 417        case CIFS_SWN_RESOURCE_STATE_UNKNOWN:
 418                cifs_dbg(FYI, "%s: resource name '%s' changed to unknown state\n", __func__, name);
 419                break;
 420        }
 421        return 0;
 422}
 423
 424static bool cifs_sockaddr_equal(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2)
 425{
 426        if (addr1->ss_family != addr2->ss_family)
 427                return false;
 428
 429        if (addr1->ss_family == AF_INET) {
 430                return (memcmp(&((const struct sockaddr_in *)addr1)->sin_addr,
 431                                &((const struct sockaddr_in *)addr2)->sin_addr,
 432                                sizeof(struct in_addr)) == 0);
 433        }
 434
 435        if (addr1->ss_family == AF_INET6) {
 436                return (memcmp(&((const struct sockaddr_in6 *)addr1)->sin6_addr,
 437                                &((const struct sockaddr_in6 *)addr2)->sin6_addr,
 438                                sizeof(struct in6_addr)) == 0);
 439        }
 440
 441        return false;
 442}
 443
 444static int cifs_swn_store_swn_addr(const struct sockaddr_storage *new,
 445                                   const struct sockaddr_storage *old,
 446                                   struct sockaddr_storage *dst)
 447{
 448        __be16 port = cpu_to_be16(CIFS_PORT);
 449
 450        if (old->ss_family == AF_INET) {
 451                struct sockaddr_in *ipv4 = (struct sockaddr_in *)old;
 452
 453                port = ipv4->sin_port;
 454        } else if (old->ss_family == AF_INET6) {
 455                struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)old;
 456
 457                port = ipv6->sin6_port;
 458        }
 459
 460        if (new->ss_family == AF_INET) {
 461                struct sockaddr_in *ipv4 = (struct sockaddr_in *)new;
 462
 463                ipv4->sin_port = port;
 464        } else if (new->ss_family == AF_INET6) {
 465                struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)new;
 466
 467                ipv6->sin6_port = port;
 468        }
 469
 470        *dst = *new;
 471
 472        return 0;
 473}
 474
 475static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *addr)
 476{
 477        int ret = 0;
 478
 479        /* Store the reconnect address */
 480        mutex_lock(&tcon->ses->server->srv_mutex);
 481        if (cifs_sockaddr_equal(&tcon->ses->server->dstaddr, addr))
 482                goto unlock;
 483
 484        ret = cifs_swn_store_swn_addr(addr, &tcon->ses->server->dstaddr,
 485                                      &tcon->ses->server->swn_dstaddr);
 486        if (ret < 0) {
 487                cifs_dbg(VFS, "%s: failed to store address: %d\n", __func__, ret);
 488                goto unlock;
 489        }
 490        tcon->ses->server->use_swn_dstaddr = true;
 491
 492        /*
 493         * Unregister to stop receiving notifications for the old IP address.
 494         */
 495        ret = cifs_swn_unregister(tcon);
 496        if (ret < 0) {
 497                cifs_dbg(VFS, "%s: Failed to unregister for witness notifications: %d\n",
 498                         __func__, ret);
 499                goto unlock;
 500        }
 501
 502        /*
 503         * And register to receive notifications for the new IP address now that we have
 504         * stored the new address.
 505         */
 506        ret = cifs_swn_register(tcon);
 507        if (ret < 0) {
 508                cifs_dbg(VFS, "%s: Failed to register for witness notifications: %d\n",
 509                         __func__, ret);
 510                goto unlock;
 511        }
 512
 513        spin_lock(&GlobalMid_Lock);
 514        if (tcon->ses->server->tcpStatus != CifsExiting)
 515                tcon->ses->server->tcpStatus = CifsNeedReconnect;
 516        spin_unlock(&GlobalMid_Lock);
 517
 518unlock:
 519        mutex_unlock(&tcon->ses->server->srv_mutex);
 520
 521        return ret;
 522}
 523
 524static int cifs_swn_client_move(struct cifs_swn_reg *swnreg, struct sockaddr_storage *addr)
 525{
 526        struct sockaddr_in *ipv4 = (struct sockaddr_in *)addr;
 527        struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)addr;
 528
 529        if (addr->ss_family == AF_INET)
 530                cifs_dbg(FYI, "%s: move to %pI4\n", __func__, &ipv4->sin_addr);
 531        else if (addr->ss_family == AF_INET6)
 532                cifs_dbg(FYI, "%s: move to %pI6\n", __func__, &ipv6->sin6_addr);
 533
 534        return cifs_swn_reconnect(swnreg->tcon, addr);
 535}
 536
 537int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info)
 538{
 539        struct cifs_swn_reg *swnreg;
 540        char name[256];
 541        int type;
 542
 543        if (info->attrs[CIFS_GENL_ATTR_SWN_REGISTRATION_ID]) {
 544                int swnreg_id;
 545
 546                swnreg_id = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_REGISTRATION_ID]);
 547                mutex_lock(&cifs_swnreg_idr_mutex);
 548                swnreg = idr_find(&cifs_swnreg_idr, swnreg_id);
 549                mutex_unlock(&cifs_swnreg_idr_mutex);
 550                if (swnreg == NULL) {
 551                        cifs_dbg(FYI, "%s: registration id %d not found\n", __func__, swnreg_id);
 552                        return -EINVAL;
 553                }
 554        } else {
 555                cifs_dbg(FYI, "%s: missing registration id attribute\n", __func__);
 556                return -EINVAL;
 557        }
 558
 559        if (info->attrs[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE]) {
 560                type = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE]);
 561        } else {
 562                cifs_dbg(FYI, "%s: missing notification type attribute\n", __func__);
 563                return -EINVAL;
 564        }
 565
 566        switch (type) {
 567        case CIFS_SWN_NOTIFICATION_RESOURCE_CHANGE: {
 568                int state;
 569
 570                if (info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_NAME]) {
 571                        nla_strscpy(name, info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_NAME],
 572                                        sizeof(name));
 573                } else {
 574                        cifs_dbg(FYI, "%s: missing resource name attribute\n", __func__);
 575                        return -EINVAL;
 576                }
 577                if (info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_STATE]) {
 578                        state = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_STATE]);
 579                } else {
 580                        cifs_dbg(FYI, "%s: missing resource state attribute\n", __func__);
 581                        return -EINVAL;
 582                }
 583                return cifs_swn_resource_state_changed(swnreg, name, state);
 584        }
 585        case CIFS_SWN_NOTIFICATION_CLIENT_MOVE: {
 586                struct sockaddr_storage addr;
 587
 588                if (info->attrs[CIFS_GENL_ATTR_SWN_IP]) {
 589                        nla_memcpy(&addr, info->attrs[CIFS_GENL_ATTR_SWN_IP], sizeof(addr));
 590                } else {
 591                        cifs_dbg(FYI, "%s: missing IP address attribute\n", __func__);
 592                        return -EINVAL;
 593                }
 594                return cifs_swn_client_move(swnreg, &addr);
 595        }
 596        default:
 597                cifs_dbg(FYI, "%s: unknown notification type %d\n", __func__, type);
 598                break;
 599        }
 600
 601        return 0;
 602}
 603
 604int cifs_swn_register(struct cifs_tcon *tcon)
 605{
 606        struct cifs_swn_reg *swnreg;
 607        int ret;
 608
 609        swnreg = cifs_get_swn_reg(tcon);
 610        if (IS_ERR(swnreg))
 611                return PTR_ERR(swnreg);
 612
 613        ret = cifs_swn_send_register_message(swnreg);
 614        if (ret < 0) {
 615                cifs_dbg(VFS, "%s: Failed to send swn register message: %d\n", __func__, ret);
 616                /* Do not put the swnreg or return error, the echo task will retry */
 617        }
 618
 619        return 0;
 620}
 621
 622int cifs_swn_unregister(struct cifs_tcon *tcon)
 623{
 624        struct cifs_swn_reg *swnreg;
 625
 626        mutex_lock(&cifs_swnreg_idr_mutex);
 627
 628        swnreg = cifs_find_swn_reg(tcon);
 629        if (IS_ERR(swnreg)) {
 630                mutex_unlock(&cifs_swnreg_idr_mutex);
 631                return PTR_ERR(swnreg);
 632        }
 633
 634        mutex_unlock(&cifs_swnreg_idr_mutex);
 635
 636        cifs_put_swn_reg(swnreg);
 637
 638        return 0;
 639}
 640
 641void cifs_swn_dump(struct seq_file *m)
 642{
 643        struct cifs_swn_reg *swnreg;
 644        struct sockaddr_in *sa;
 645        struct sockaddr_in6 *sa6;
 646        int id;
 647
 648        seq_puts(m, "Witness registrations:");
 649
 650        mutex_lock(&cifs_swnreg_idr_mutex);
 651        idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) {
 652                seq_printf(m, "\nId: %u Refs: %u Network name: '%s'%s Share name: '%s'%s Ip address: ",
 653                                id, kref_read(&swnreg->ref_count),
 654                                swnreg->net_name, swnreg->net_name_notify ? "(y)" : "(n)",
 655                                swnreg->share_name, swnreg->share_name_notify ? "(y)" : "(n)");
 656                switch (swnreg->tcon->ses->server->dstaddr.ss_family) {
 657                case AF_INET:
 658                        sa = (struct sockaddr_in *) &swnreg->tcon->ses->server->dstaddr;
 659                        seq_printf(m, "%pI4", &sa->sin_addr.s_addr);
 660                        break;
 661                case AF_INET6:
 662                        sa6 = (struct sockaddr_in6 *) &swnreg->tcon->ses->server->dstaddr;
 663                        seq_printf(m, "%pI6", &sa6->sin6_addr.s6_addr);
 664                        if (sa6->sin6_scope_id)
 665                                seq_printf(m, "%%%u", sa6->sin6_scope_id);
 666                        break;
 667                default:
 668                        seq_puts(m, "(unknown)");
 669                }
 670                seq_printf(m, "%s", swnreg->ip_notify ? "(y)" : "(n)");
 671        }
 672        mutex_unlock(&cifs_swnreg_idr_mutex);
 673        seq_puts(m, "\n");
 674}
 675
 676void cifs_swn_check(void)
 677{
 678        struct cifs_swn_reg *swnreg;
 679        int id;
 680        int ret;
 681
 682        mutex_lock(&cifs_swnreg_idr_mutex);
 683        idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) {
 684                ret = cifs_swn_send_register_message(swnreg);
 685                if (ret < 0)
 686                        cifs_dbg(FYI, "%s: Failed to send register message: %d\n", __func__, ret);
 687        }
 688        mutex_unlock(&cifs_swnreg_idr_mutex);
 689}
 690