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 19 static DEFINE_IDR(cifs_swnreg_idr); 20 static DEFINE_MUTEX(cifs_swnreg_idr_mutex); 21 22 struct 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 33 struct cifs_swn_reg_info { 34 int id; 35 unsigned int ref_count; 36 const char *net_name; 37 const char *share_name; 38 bool net_name_notify; 39 bool share_name_notify; 40 bool ip_notify; 41 }; 42 43 static void cifs_swn_snapshot_reg(struct cifs_swn_reg *swnreg, 44 struct cifs_swn_reg_info *info) 45 { 46 info->id = swnreg->id; 47 info->ref_count = kref_read(&swnreg->ref_count); 48 info->net_name = swnreg->net_name; 49 info->share_name = swnreg->share_name; 50 info->net_name_notify = swnreg->net_name_notify; 51 info->share_name_notify = swnreg->share_name_notify; 52 info->ip_notify = swnreg->ip_notify; 53 } 54 55 static int cifs_swn_dup_reg(struct cifs_swn_reg *swnreg, 56 struct cifs_swn_reg_info *info) 57 { 58 cifs_swn_snapshot_reg(swnreg, info); 59 60 info->net_name = kstrdup(swnreg->net_name, GFP_KERNEL); 61 if (!info->net_name) 62 return -ENOMEM; 63 64 info->share_name = kstrdup(swnreg->share_name, GFP_KERNEL); 65 if (!info->share_name) { 66 kfree(info->net_name); 67 return -ENOMEM; 68 } 69 70 return 0; 71 } 72 73 static void cifs_swn_free_reg_info(struct cifs_swn_reg_info *info) 74 { 75 kfree(info->net_name); 76 kfree(info->share_name); 77 } 78 79 static int cifs_swn_auth_info_krb(struct cifs_tcon *tcon, struct sk_buff *skb) 80 { 81 int ret; 82 83 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_KRB_AUTH); 84 if (ret < 0) 85 return ret; 86 87 return 0; 88 } 89 90 static int cifs_swn_auth_info_ntlm(struct cifs_tcon *tcon, struct sk_buff *skb) 91 { 92 int ret; 93 94 if (tcon->ses->user_name != NULL) { 95 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_USER_NAME, tcon->ses->user_name); 96 if (ret < 0) 97 return ret; 98 } 99 100 if (tcon->ses->password != NULL) { 101 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_PASSWORD, tcon->ses->password); 102 if (ret < 0) 103 return ret; 104 } 105 106 if (tcon->ses->domainName != NULL) { 107 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_DOMAIN_NAME, tcon->ses->domainName); 108 if (ret < 0) 109 return ret; 110 } 111 112 return 0; 113 } 114 115 /* 116 * Sends a register message to the userspace daemon based on the registration. 117 * The authentication information to connect to the witness service is bundled 118 * into the message. 119 */ 120 static int cifs_swn_send_register_message(struct cifs_swn_reg_info *swnreg, 121 struct cifs_tcon *tcon) 122 { 123 struct sk_buff *skb; 124 struct genlmsghdr *hdr; 125 enum securityEnum authtype; 126 struct sockaddr_storage *addr; 127 int ret; 128 129 skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 130 if (!skb) 131 return -ENOMEM; 132 133 hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_REGISTER); 134 if (hdr == NULL) { 135 ret = -ENOMEM; 136 goto nlmsg_fail; 137 } 138 139 ret = nla_put_u32(skb, CIFS_GENL_ATTR_SWN_REGISTRATION_ID, swnreg->id); 140 if (ret < 0) 141 goto nlmsg_fail; 142 143 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_NET_NAME, swnreg->net_name); 144 if (ret < 0) 145 goto nlmsg_fail; 146 147 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME, swnreg->share_name); 148 if (ret < 0) 149 goto nlmsg_fail; 150 151 /* 152 * If there is an address stored use it instead of the server address, because we are 153 * in the process of reconnecting to it after a share has been moved or we have been 154 * told to switch to it (client move message). In these cases we unregister from the 155 * server address and register to the new address when we receive the notification. 156 */ 157 if (tcon->ses->server->use_swn_dstaddr) 158 addr = &tcon->ses->server->swn_dstaddr; 159 else 160 addr = &tcon->ses->server->dstaddr; 161 162 ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage), addr); 163 if (ret < 0) 164 goto nlmsg_fail; 165 166 if (swnreg->net_name_notify) { 167 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY); 168 if (ret < 0) 169 goto nlmsg_fail; 170 } 171 172 if (swnreg->share_name_notify) { 173 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY); 174 if (ret < 0) 175 goto nlmsg_fail; 176 } 177 178 if (swnreg->ip_notify) { 179 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_IP_NOTIFY); 180 if (ret < 0) 181 goto nlmsg_fail; 182 } 183 184 authtype = cifs_select_sectype(tcon->ses->server, tcon->ses->sectype); 185 switch (authtype) { 186 case Kerberos: 187 ret = cifs_swn_auth_info_krb(tcon, skb); 188 if (ret < 0) { 189 cifs_dbg(VFS, "%s: Failed to get kerberos auth info: %d\n", __func__, ret); 190 goto nlmsg_fail; 191 } 192 break; 193 case NTLMv2: 194 case RawNTLMSSP: 195 ret = cifs_swn_auth_info_ntlm(tcon, skb); 196 if (ret < 0) { 197 cifs_dbg(VFS, "%s: Failed to get NTLM auth info: %d\n", __func__, ret); 198 goto nlmsg_fail; 199 } 200 break; 201 default: 202 cifs_dbg(VFS, "%s: secType %d not supported!\n", __func__, authtype); 203 ret = -EINVAL; 204 goto nlmsg_fail; 205 } 206 207 genlmsg_end(skb, hdr); 208 genlmsg_multicast(&cifs_genl_family, skb, 0, CIFS_GENL_MCGRP_SWN, GFP_ATOMIC); 209 210 cifs_dbg(FYI, "%s: Message to register for network name %s with id %d sent\n", __func__, 211 swnreg->net_name, swnreg->id); 212 213 return 0; 214 215 nlmsg_fail: 216 genlmsg_cancel(skb, hdr); 217 nlmsg_free(skb); 218 return ret; 219 } 220 221 /* 222 * Sends an uregister message to the userspace daemon based on the registration 223 */ 224 static int cifs_swn_send_unregister_message(struct cifs_swn_reg_info *swnreg, 225 struct cifs_tcon *tcon) 226 { 227 struct sk_buff *skb; 228 struct genlmsghdr *hdr; 229 int ret; 230 231 skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 232 if (skb == NULL) 233 return -ENOMEM; 234 235 hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_UNREGISTER); 236 if (hdr == NULL) { 237 ret = -ENOMEM; 238 goto nlmsg_fail; 239 } 240 241 ret = nla_put_u32(skb, CIFS_GENL_ATTR_SWN_REGISTRATION_ID, swnreg->id); 242 if (ret < 0) 243 goto nlmsg_fail; 244 245 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_NET_NAME, swnreg->net_name); 246 if (ret < 0) 247 goto nlmsg_fail; 248 249 ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME, swnreg->share_name); 250 if (ret < 0) 251 goto nlmsg_fail; 252 253 ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage), 254 &tcon->ses->server->dstaddr); 255 if (ret < 0) 256 goto nlmsg_fail; 257 258 if (swnreg->net_name_notify) { 259 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY); 260 if (ret < 0) 261 goto nlmsg_fail; 262 } 263 264 if (swnreg->share_name_notify) { 265 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY); 266 if (ret < 0) 267 goto nlmsg_fail; 268 } 269 270 if (swnreg->ip_notify) { 271 ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_IP_NOTIFY); 272 if (ret < 0) 273 goto nlmsg_fail; 274 } 275 276 genlmsg_end(skb, hdr); 277 genlmsg_multicast(&cifs_genl_family, skb, 0, CIFS_GENL_MCGRP_SWN, GFP_ATOMIC); 278 279 cifs_dbg(FYI, "%s: Message to unregister for network name %s with id %d sent\n", __func__, 280 swnreg->net_name, swnreg->id); 281 282 return 0; 283 284 nlmsg_fail: 285 genlmsg_cancel(skb, hdr); 286 nlmsg_free(skb); 287 return ret; 288 } 289 290 /* 291 * Allocation-free mirror of extract_hostname() + extract_sharename() from 292 * fs/smb/client/unc.c. Those helpers kmalloc(GFP_KERNEL); this runs under 293 * cifs_tcp_ses_lock and tcon->tc_lock, both spinlocks, so we mirror their 294 * parsing in place against the caller's stable net_name/share_name strings. 295 * Keep in sync with unc.c. 296 */ 297 static bool cifs_swn_tcon_matches(struct cifs_tcon *tcon, 298 const char *net_name, 299 const char *share_name) 300 { 301 const char *unc = tcon->tree_name; 302 const char *host, *share, *delim; 303 size_t host_len, share_len; 304 305 if (!tcon->use_witness) 306 return false; 307 308 /* extract_hostname: require strlen(unc) >= 3 */ 309 if (strnlen(unc, 3) < 3) 310 return false; 311 /* extract_hostname: skip all leading '\' characters */ 312 for (host = unc; *host == '\\'; host++) 313 ; 314 if (!*host) 315 return false; 316 delim = strchr(host, '\\'); 317 if (!delim) 318 return false; 319 host_len = delim - host; 320 if (strlen(net_name) != host_len || 321 strncasecmp(host, net_name, host_len)) 322 return false; 323 324 /* extract_sharename: start at unc + 2, then first '\' onward */ 325 share = unc + 2; 326 delim = strchr(share, '\\'); 327 if (!delim) 328 return false; 329 share = delim + 1; 330 share_len = strlen(share); 331 332 return strlen(share_name) == share_len && 333 !strncasecmp(share, share_name, share_len); 334 } 335 336 /* 337 * One SWN registration id represents one net/share name pair. Multiple 338 * mounted tcons can therefore share the id. Pick a live representative at 339 * use time instead of caching the first tcon pointer in the registration. 340 */ 341 static struct cifs_tcon *cifs_swn_get_tcon(struct cifs_swn_reg_info *swnreg) 342 { 343 struct TCP_Server_Info *server; 344 struct cifs_ses *ses; 345 struct cifs_tcon *tcon; 346 347 spin_lock(&cifs_tcp_ses_lock); 348 list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { 349 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { 350 list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { 351 spin_lock(&tcon->tc_lock); 352 if (tcon->status == TID_EXITING || 353 !cifs_swn_tcon_matches(tcon, swnreg->net_name, 354 swnreg->share_name)) { 355 spin_unlock(&tcon->tc_lock); 356 continue; 357 } 358 ++tcon->tc_count; 359 trace_smb3_tcon_ref(tcon->debug_id, 360 tcon->tc_count, 361 netfs_trace_tcon_ref_get_swn_notify); 362 spin_unlock(&tcon->tc_lock); 363 spin_unlock(&cifs_tcp_ses_lock); 364 return tcon; 365 } 366 } 367 } 368 spin_unlock(&cifs_tcp_ses_lock); 369 return NULL; 370 } 371 372 /* 373 * Try to find a matching registration for the tcon's server name and share name. 374 * Calls to this function must be protected by cifs_swnreg_idr_mutex. 375 * TODO Try to avoid memory allocations 376 */ 377 static struct cifs_swn_reg *cifs_find_swn_reg(struct cifs_tcon *tcon) 378 { 379 struct cifs_swn_reg *swnreg; 380 int id; 381 const char *share_name; 382 const char *net_name; 383 384 net_name = extract_hostname(tcon->tree_name); 385 if (IS_ERR(net_name)) { 386 int ret; 387 388 ret = PTR_ERR(net_name); 389 cifs_dbg(VFS, "%s: failed to extract host name from target '%s': %d\n", 390 __func__, tcon->tree_name, ret); 391 return ERR_PTR(-EINVAL); 392 } 393 394 share_name = extract_sharename(tcon->tree_name); 395 if (IS_ERR(share_name)) { 396 int ret; 397 398 ret = PTR_ERR(share_name); 399 cifs_dbg(VFS, "%s: failed to extract share name from target '%s': %d\n", 400 __func__, tcon->tree_name, ret); 401 kfree(net_name); 402 return ERR_PTR(-EINVAL); 403 } 404 405 idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) { 406 if (strcasecmp(swnreg->net_name, net_name) != 0 407 || strcasecmp(swnreg->share_name, share_name) != 0) { 408 continue; 409 } 410 411 cifs_dbg(FYI, "Existing swn registration for %s:%s found\n", swnreg->net_name, 412 swnreg->share_name); 413 414 kfree(net_name); 415 kfree(share_name); 416 417 return swnreg; 418 } 419 420 kfree(net_name); 421 kfree(share_name); 422 423 return ERR_PTR(-EEXIST); 424 } 425 426 /* 427 * Get a registration for the tcon's server and share name, allocating a new one if it does not 428 * exists 429 */ 430 static struct cifs_swn_reg *cifs_get_swn_reg(struct cifs_tcon *tcon) 431 { 432 struct cifs_swn_reg *reg = NULL; 433 int ret; 434 435 mutex_lock(&cifs_swnreg_idr_mutex); 436 437 /* Check if we are already registered for this network and share names */ 438 reg = cifs_find_swn_reg(tcon); 439 if (!IS_ERR(reg)) { 440 kref_get(®->ref_count); 441 goto unlock; 442 } else if (PTR_ERR(reg) != -EEXIST) { 443 goto unlock; 444 } 445 446 reg = kmalloc_obj(struct cifs_swn_reg, GFP_ATOMIC); 447 if (reg == NULL) { 448 ret = -ENOMEM; 449 goto fail_unlock; 450 } 451 452 kref_init(®->ref_count); 453 454 reg->id = idr_alloc(&cifs_swnreg_idr, reg, 1, 0, GFP_ATOMIC); 455 if (reg->id < 0) { 456 cifs_dbg(FYI, "%s: failed to allocate registration id\n", __func__); 457 ret = reg->id; 458 goto fail; 459 } 460 461 reg->net_name = extract_hostname(tcon->tree_name); 462 if (IS_ERR(reg->net_name)) { 463 ret = PTR_ERR(reg->net_name); 464 cifs_dbg(VFS, "%s: failed to extract host name from target: %d\n", __func__, ret); 465 goto fail_idr; 466 } 467 468 reg->share_name = extract_sharename(tcon->tree_name); 469 if (IS_ERR(reg->share_name)) { 470 ret = PTR_ERR(reg->share_name); 471 cifs_dbg(VFS, "%s: failed to extract share name from target: %d\n", __func__, ret); 472 goto fail_net_name; 473 } 474 475 reg->net_name_notify = true; 476 reg->share_name_notify = true; 477 reg->ip_notify = (tcon->capabilities & SMB2_SHARE_CAP_SCALEOUT); 478 unlock: 479 mutex_unlock(&cifs_swnreg_idr_mutex); 480 481 return reg; 482 483 fail_net_name: 484 kfree(reg->net_name); 485 fail_idr: 486 idr_remove(&cifs_swnreg_idr, reg->id); 487 fail: 488 kfree(reg); 489 fail_unlock: 490 mutex_unlock(&cifs_swnreg_idr_mutex); 491 return ERR_PTR(ret); 492 } 493 494 static void cifs_swn_reg_release(struct kref *ref) 495 { 496 struct cifs_swn_reg *swnreg = container_of(ref, struct cifs_swn_reg, ref_count); 497 498 idr_remove(&cifs_swnreg_idr, swnreg->id); 499 kfree(swnreg->net_name); 500 kfree(swnreg->share_name); 501 kfree(swnreg); 502 } 503 504 static void cifs_put_swn_reg_locked(struct cifs_swn_reg *swnreg, 505 struct cifs_tcon *tcon) 506 { 507 if (kref_read(&swnreg->ref_count) == 1) { 508 struct cifs_swn_reg_info swnreg_info; 509 int ret; 510 511 cifs_swn_snapshot_reg(swnreg, &swnreg_info); 512 ret = cifs_swn_send_unregister_message(&swnreg_info, tcon); 513 if (ret < 0) 514 cifs_dbg(VFS, "%s: Failed to send unregister message: %d\n", 515 __func__, ret); 516 } 517 518 kref_put(&swnreg->ref_count, cifs_swn_reg_release); 519 } 520 521 static int cifs_swn_resource_state_changed(struct cifs_tcon *tcon, const char *name, int state) 522 { 523 switch (state) { 524 case CIFS_SWN_RESOURCE_STATE_UNAVAILABLE: 525 cifs_dbg(FYI, "%s: resource name '%s' become unavailable\n", __func__, name); 526 cifs_signal_cifsd_for_reconnect(tcon->ses->server, true); 527 break; 528 case CIFS_SWN_RESOURCE_STATE_AVAILABLE: 529 cifs_dbg(FYI, "%s: resource name '%s' become available\n", __func__, name); 530 cifs_signal_cifsd_for_reconnect(tcon->ses->server, true); 531 break; 532 case CIFS_SWN_RESOURCE_STATE_UNKNOWN: 533 cifs_dbg(FYI, "%s: resource name '%s' changed to unknown state\n", __func__, name); 534 break; 535 } 536 return 0; 537 } 538 539 static bool cifs_sockaddr_equal(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2) 540 { 541 if (addr1->ss_family != addr2->ss_family) 542 return false; 543 544 if (addr1->ss_family == AF_INET) { 545 return (memcmp(&((const struct sockaddr_in *)addr1)->sin_addr, 546 &((const struct sockaddr_in *)addr2)->sin_addr, 547 sizeof(struct in_addr)) == 0); 548 } 549 550 if (addr1->ss_family == AF_INET6) { 551 return (memcmp(&((const struct sockaddr_in6 *)addr1)->sin6_addr, 552 &((const struct sockaddr_in6 *)addr2)->sin6_addr, 553 sizeof(struct in6_addr)) == 0); 554 } 555 556 return false; 557 } 558 559 static int cifs_swn_store_swn_addr(const struct sockaddr_storage *new, 560 const struct sockaddr_storage *old, 561 struct sockaddr_storage *dst) 562 { 563 __be16 port = cpu_to_be16(CIFS_PORT); 564 565 if (old->ss_family == AF_INET) { 566 struct sockaddr_in *ipv4 = (struct sockaddr_in *)old; 567 568 port = ipv4->sin_port; 569 } else if (old->ss_family == AF_INET6) { 570 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)old; 571 572 port = ipv6->sin6_port; 573 } 574 575 if (new->ss_family == AF_INET) { 576 struct sockaddr_in *ipv4 = (struct sockaddr_in *)new; 577 578 ipv4->sin_port = port; 579 } else if (new->ss_family == AF_INET6) { 580 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)new; 581 582 ipv6->sin6_port = port; 583 } 584 585 *dst = *new; 586 587 return 0; 588 } 589 590 static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *addr) 591 { 592 int ret = 0; 593 594 /* Store the reconnect address */ 595 cifs_server_lock(tcon->ses->server); 596 if (cifs_sockaddr_equal(&tcon->ses->server->dstaddr, addr)) 597 goto unlock; 598 599 ret = cifs_swn_store_swn_addr(addr, &tcon->ses->server->dstaddr, 600 &tcon->ses->server->swn_dstaddr); 601 if (ret < 0) { 602 cifs_dbg(VFS, "%s: failed to store address: %d\n", __func__, ret); 603 goto unlock; 604 } 605 tcon->ses->server->use_swn_dstaddr = true; 606 607 /* 608 * Unregister to stop receiving notifications for the old IP address. 609 */ 610 ret = cifs_swn_unregister(tcon); 611 if (ret < 0) { 612 cifs_dbg(VFS, "%s: Failed to unregister for witness notifications: %d\n", 613 __func__, ret); 614 goto unlock; 615 } 616 617 /* 618 * And register to receive notifications for the new IP address now that we have 619 * stored the new address. 620 */ 621 ret = cifs_swn_register(tcon); 622 if (ret < 0) { 623 cifs_dbg(VFS, "%s: Failed to register for witness notifications: %d\n", 624 __func__, ret); 625 goto unlock; 626 } 627 628 cifs_signal_cifsd_for_reconnect(tcon->ses->server, false); 629 630 unlock: 631 cifs_server_unlock(tcon->ses->server); 632 633 return ret; 634 } 635 636 static int cifs_swn_client_move(struct cifs_tcon *tcon, struct sockaddr_storage *addr) 637 { 638 struct sockaddr_in *ipv4 = (struct sockaddr_in *)addr; 639 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)addr; 640 641 if (addr->ss_family == AF_INET) 642 cifs_dbg(FYI, "%s: move to %pI4\n", __func__, &ipv4->sin_addr); 643 else if (addr->ss_family == AF_INET6) 644 cifs_dbg(FYI, "%s: move to %pI6\n", __func__, &ipv6->sin6_addr); 645 646 return cifs_swn_reconnect(tcon, addr); 647 } 648 649 int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info) 650 { 651 struct cifs_swn_reg *swnreg; 652 struct cifs_swn_reg_info swnreg_info; 653 struct cifs_tcon *tcon; 654 char name[256]; 655 int type; 656 int ret = 0; 657 658 if (info->attrs[CIFS_GENL_ATTR_SWN_REGISTRATION_ID]) { 659 int swnreg_id; 660 661 swnreg_id = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_REGISTRATION_ID]); 662 mutex_lock(&cifs_swnreg_idr_mutex); 663 swnreg = idr_find(&cifs_swnreg_idr, swnreg_id); 664 if (swnreg == NULL) { 665 mutex_unlock(&cifs_swnreg_idr_mutex); 666 cifs_dbg(FYI, "%s: registration id %d not found\n", __func__, swnreg_id); 667 return -EINVAL; 668 } 669 ret = cifs_swn_dup_reg(swnreg, &swnreg_info); 670 mutex_unlock(&cifs_swnreg_idr_mutex); 671 if (ret) 672 return ret; 673 } else { 674 cifs_dbg(FYI, "%s: missing registration id attribute\n", __func__); 675 return -EINVAL; 676 } 677 678 tcon = cifs_swn_get_tcon(&swnreg_info); 679 if (!tcon) { 680 cifs_dbg(FYI, "%s: registration id %d has no live tcon\n", 681 __func__, swnreg_info.id); 682 ret = -ENODEV; 683 goto free_info; 684 } 685 686 if (info->attrs[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE]) { 687 type = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE]); 688 } else { 689 cifs_dbg(FYI, "%s: missing notification type attribute\n", __func__); 690 ret = -EINVAL; 691 goto out; 692 } 693 694 switch (type) { 695 case CIFS_SWN_NOTIFICATION_RESOURCE_CHANGE: { 696 int state; 697 698 if (info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_NAME]) { 699 nla_strscpy(name, info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_NAME], 700 sizeof(name)); 701 } else { 702 cifs_dbg(FYI, "%s: missing resource name attribute\n", __func__); 703 ret = -EINVAL; 704 goto out; 705 } 706 if (info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_STATE]) { 707 state = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_STATE]); 708 } else { 709 cifs_dbg(FYI, "%s: missing resource state attribute\n", __func__); 710 ret = -EINVAL; 711 goto out; 712 } 713 ret = cifs_swn_resource_state_changed(tcon, name, state); 714 break; 715 } 716 case CIFS_SWN_NOTIFICATION_CLIENT_MOVE: { 717 struct sockaddr_storage addr; 718 719 if (info->attrs[CIFS_GENL_ATTR_SWN_IP]) { 720 nla_memcpy(&addr, info->attrs[CIFS_GENL_ATTR_SWN_IP], sizeof(addr)); 721 } else { 722 cifs_dbg(FYI, "%s: missing IP address attribute\n", __func__); 723 ret = -EINVAL; 724 goto out; 725 } 726 ret = cifs_swn_client_move(tcon, &addr); 727 break; 728 } 729 default: 730 cifs_dbg(FYI, "%s: unknown notification type %d\n", __func__, type); 731 break; 732 } 733 734 out: 735 cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_swn_notify); 736 free_info: 737 cifs_swn_free_reg_info(&swnreg_info); 738 return ret; 739 } 740 741 int cifs_swn_register(struct cifs_tcon *tcon) 742 { 743 struct cifs_swn_reg *swnreg; 744 struct cifs_swn_reg_info swnreg_info; 745 int ret; 746 747 swnreg = cifs_get_swn_reg(tcon); 748 if (IS_ERR(swnreg)) 749 return PTR_ERR(swnreg); 750 751 cifs_swn_snapshot_reg(swnreg, &swnreg_info); 752 ret = cifs_swn_send_register_message(&swnreg_info, tcon); 753 if (ret < 0) { 754 cifs_dbg(VFS, "%s: Failed to send swn register message: %d\n", __func__, ret); 755 /* Do not put the swnreg or return error, the echo task will retry */ 756 } 757 758 return 0; 759 } 760 761 int cifs_swn_unregister(struct cifs_tcon *tcon) 762 { 763 struct cifs_swn_reg *swnreg; 764 765 mutex_lock(&cifs_swnreg_idr_mutex); 766 767 swnreg = cifs_find_swn_reg(tcon); 768 if (IS_ERR(swnreg)) { 769 mutex_unlock(&cifs_swnreg_idr_mutex); 770 return PTR_ERR(swnreg); 771 } 772 773 cifs_put_swn_reg_locked(swnreg, tcon); 774 mutex_unlock(&cifs_swnreg_idr_mutex); 775 776 return 0; 777 } 778 779 /* 780 * Snapshot one registration under cifs_swnreg_idr_mutex and return. Callers 781 * intentionally do the per-registration network/genlmsg work without the 782 * mutex held, both to keep the critical section short and to avoid nesting 783 * cifs_swnreg_idr_mutex inside the higher tc_lock when a live tcon is then 784 * pinned for the send. 785 */ 786 static int cifs_swn_get_next_reg_info(int *id, struct cifs_swn_reg_info *info) 787 { 788 struct cifs_swn_reg *swnreg; 789 int ret = 0; 790 791 mutex_lock(&cifs_swnreg_idr_mutex); 792 swnreg = idr_get_next(&cifs_swnreg_idr, id); 793 if (swnreg) { 794 ret = cifs_swn_dup_reg(swnreg, info); 795 if (!ret) { 796 *id = swnreg->id + 1; 797 ret = 1; 798 } 799 } 800 mutex_unlock(&cifs_swnreg_idr_mutex); 801 802 return ret; 803 } 804 805 void cifs_swn_dump(struct seq_file *m) 806 { 807 struct cifs_swn_reg_info swnreg_info; 808 struct cifs_tcon *tcon; 809 struct sockaddr_in *sa; 810 struct sockaddr_in6 *sa6; 811 int id = 0; 812 int ret; 813 814 seq_puts(m, "Witness registrations:"); 815 816 while ((ret = cifs_swn_get_next_reg_info(&id, &swnreg_info)) > 0) { 817 seq_printf(m, "\nId: %u Refs: %u Network name: '%s'%s Share name: '%s'%s Ip address: ", 818 swnreg_info.id, swnreg_info.ref_count, 819 swnreg_info.net_name, swnreg_info.net_name_notify ? "(y)" : "(n)", 820 swnreg_info.share_name, swnreg_info.share_name_notify ? "(y)" : "(n)"); 821 822 tcon = cifs_swn_get_tcon(&swnreg_info); 823 if (!tcon) { 824 seq_puts(m, "(no live tcon)"); 825 goto next; 826 } 827 828 switch (tcon->ses->server->dstaddr.ss_family) { 829 case AF_INET: 830 sa = (struct sockaddr_in *)&tcon->ses->server->dstaddr; 831 seq_printf(m, "%pI4", &sa->sin_addr.s_addr); 832 break; 833 case AF_INET6: 834 sa6 = (struct sockaddr_in6 *)&tcon->ses->server->dstaddr; 835 seq_printf(m, "%pI6", &sa6->sin6_addr.s6_addr); 836 if (sa6->sin6_scope_id) 837 seq_printf(m, "%%%u", sa6->sin6_scope_id); 838 break; 839 default: 840 seq_puts(m, "(unknown)"); 841 } 842 cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_swn_notify); 843 next: 844 seq_printf(m, "%s", swnreg_info.ip_notify ? "(y)" : "(n)"); 845 cifs_swn_free_reg_info(&swnreg_info); 846 } 847 if (ret < 0) 848 seq_printf(m, "\nFailed to snapshot witness registration: %d", ret); 849 seq_puts(m, "\n"); 850 } 851 852 void cifs_swn_check(void) 853 { 854 struct cifs_swn_reg_info swnreg_info; 855 struct cifs_tcon *tcon; 856 int id = 0; 857 int ret; 858 859 while ((ret = cifs_swn_get_next_reg_info(&id, &swnreg_info)) > 0) { 860 tcon = cifs_swn_get_tcon(&swnreg_info); 861 if (!tcon) { 862 cifs_dbg(FYI, "%s: registration id %d has no live tcon\n", 863 __func__, swnreg_info.id); 864 goto free_info; 865 } 866 867 ret = cifs_swn_send_register_message(&swnreg_info, tcon); 868 if (ret < 0) 869 cifs_dbg(FYI, "%s: Failed to send register message: %d\n", __func__, ret); 870 cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_swn_notify); 871 free_info: 872 cifs_swn_free_reg_info(&swnreg_info); 873 } 874 if (ret < 0) 875 cifs_dbg(FYI, "%s: Failed to snapshot registration: %d\n", __func__, ret); 876 } 877