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