cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cifs_swn.c (17349B)


      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}