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