1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * linux/fs/lockd/svc.c 4 * 5 * This is the central lockd service. 6 * 7 * FIXME: Separate the lockd NFS server functionality from the lockd NFS 8 * client functionality. Oh why didn't Sun create two separate 9 * services in the first place? 10 * 11 * Authors: Olaf Kirch (okir@monad.swb.de) 12 * 13 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> 14 */ 15 16 #include <linux/module.h> 17 #include <linux/init.h> 18 #include <linux/sysctl.h> 19 #include <linux/moduleparam.h> 20 21 #include <linux/sched/signal.h> 22 #include <linux/errno.h> 23 #include <linux/in.h> 24 #include <linux/uio.h> 25 #include <linux/smp.h> 26 #include <linux/mutex.h> 27 #include <linux/freezer.h> 28 #include <linux/inetdevice.h> 29 30 #include <linux/sunrpc/types.h> 31 #include <linux/sunrpc/stats.h> 32 #include <linux/sunrpc/clnt.h> 33 #include <linux/sunrpc/svc.h> 34 #include <linux/sunrpc/svcsock.h> 35 #include <linux/sunrpc/svc_xprt.h> 36 #include <net/ip.h> 37 #include <net/addrconf.h> 38 #include <net/ipv6.h> 39 40 #include "lockd.h" 41 #include "netns.h" 42 #include "procfs.h" 43 #include "netlink.h" 44 45 #define NLMDBG_FACILITY NLMDBG_SVC 46 47 static struct svc_program nlmsvc_program; 48 49 const struct nlmsvc_binding __rcu *nlmsvc_ops; 50 EXPORT_SYMBOL_GPL(nlmsvc_ops); 51 52 static DEFINE_MUTEX(nlmsvc_mutex); 53 static unsigned int nlmsvc_users; 54 static struct svc_serv *nlmsvc_serv; 55 56 static void nlmsvc_request_retry(struct timer_list *tl) 57 { 58 svc_wake_up(nlmsvc_serv); 59 } 60 DEFINE_TIMER(nlmsvc_retry, nlmsvc_request_retry); 61 62 unsigned int lockd_net_id; 63 64 /* 65 * These can be set at insmod time (useful for NFS as root filesystem), 66 * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003 67 */ 68 static unsigned long nlm_grace_period; 69 unsigned long nlm_timeout = LOCKD_DFLT_TIMEO; 70 static int nlm_udpport, nlm_tcpport; 71 72 /* 73 * Constants needed for the sysctl interface. 74 */ 75 static const unsigned long nlm_grace_period_min = 0; 76 static const unsigned long nlm_grace_period_max = 240; 77 static const unsigned long nlm_timeout_min = 3; 78 static const unsigned long nlm_timeout_max = 20; 79 80 #ifdef CONFIG_SYSCTL 81 static const int nlm_port_min = 0, nlm_port_max = 65535; 82 static struct ctl_table_header * nlm_sysctl_table; 83 #endif 84 85 static unsigned long get_lockd_grace_period(struct net *net) 86 { 87 struct lockd_net *ln = net_generic(net, lockd_net_id); 88 89 /* Return the net-ns specific grace period, if there is one */ 90 if (ln->gracetime) 91 return ln->gracetime * HZ; 92 93 /* Note: nlm_timeout should always be nonzero */ 94 if (nlm_grace_period) 95 return roundup(nlm_grace_period, nlm_timeout) * HZ; 96 else 97 return nlm_timeout * 5 * HZ; 98 } 99 100 static void grace_ender(struct work_struct *grace) 101 { 102 struct delayed_work *dwork = to_delayed_work(grace); 103 struct lockd_net *ln = container_of(dwork, struct lockd_net, 104 grace_period_end); 105 106 locks_end_grace(&ln->lockd_manager); 107 } 108 109 static void set_grace_period(struct net *net) 110 { 111 unsigned long grace_period = get_lockd_grace_period(net); 112 struct lockd_net *ln = net_generic(net, lockd_net_id); 113 114 locks_start_grace(net, &ln->lockd_manager); 115 cancel_delayed_work_sync(&ln->grace_period_end); 116 schedule_delayed_work(&ln->grace_period_end, grace_period); 117 } 118 119 /* 120 * This is the lockd kernel thread 121 */ 122 static int 123 lockd(void *vrqstp) 124 { 125 struct svc_rqst *rqstp = vrqstp; 126 struct net *net = &init_net; 127 struct lockd_net *ln = net_generic(net, lockd_net_id); 128 129 svc_thread_init_status(rqstp, 0); 130 131 /* try_to_freeze() is called from svc_recv() */ 132 set_freezable(); 133 134 dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); 135 136 /* 137 * The main request loop. We don't terminate until the last 138 * NFS mount or NFS daemon has gone away. 139 */ 140 while (!svc_thread_should_stop(rqstp)) { 141 nlmsvc_retry_blocked(rqstp); 142 svc_recv(rqstp, 0); 143 } 144 if (rcu_access_pointer(nlmsvc_ops)) 145 nlmsvc_invalidate_all(); 146 nlm_shutdown_hosts(); 147 cancel_delayed_work_sync(&ln->grace_period_end); 148 locks_end_grace(&ln->lockd_manager); 149 150 dprintk("lockd_down: service stopped\n"); 151 152 svc_exit_thread(rqstp); 153 return 0; 154 } 155 156 static int create_lockd_listener(struct svc_serv *serv, const char *name, 157 struct net *net, const int family, 158 const unsigned short port, 159 const struct cred *cred) 160 { 161 struct svc_xprt *xprt; 162 163 xprt = svc_find_xprt(serv, name, net, family, 0); 164 if (xprt == NULL) 165 return svc_xprt_create(serv, name, net, family, port, 166 SVC_SOCK_DEFAULTS, cred); 167 svc_xprt_put(xprt); 168 return 0; 169 } 170 171 static int create_lockd_family(struct svc_serv *serv, struct net *net, 172 const int family, const struct cred *cred) 173 { 174 struct lockd_net *ln = net_generic(net, lockd_net_id); 175 int err; 176 177 err = create_lockd_listener(serv, "udp", net, family, 178 ln->udp_port ? ln->udp_port : nlm_udpport, cred); 179 if (err < 0) 180 return err; 181 182 return create_lockd_listener(serv, "tcp", net, family, 183 ln->tcp_port ? ln->tcp_port : nlm_tcpport, cred); 184 } 185 186 /* 187 * Ensure there are active UDP and TCP listeners for lockd. 188 * 189 * Even if we have only TCP NFS mounts and/or TCP NFSDs, some 190 * local services (such as rpc.statd) still require UDP, and 191 * some NFS servers do not yet support NLM over TCP. 192 * 193 * Returns zero if all listeners are available; otherwise a 194 * negative errno value is returned. 195 */ 196 static int make_socks(struct svc_serv *serv, struct net *net, 197 const struct cred *cred) 198 { 199 static int warned; 200 int err; 201 202 err = create_lockd_family(serv, net, PF_INET, cred); 203 if (err < 0) 204 goto out_err; 205 206 err = create_lockd_family(serv, net, PF_INET6, cred); 207 if (err < 0 && err != -EAFNOSUPPORT) 208 goto out_err; 209 210 warned = 0; 211 return 0; 212 213 out_err: 214 if (warned++ == 0) 215 printk(KERN_WARNING 216 "lockd_up: makesock failed, error=%d\n", err); 217 svc_xprt_destroy_all(serv, net, true); 218 return err; 219 } 220 221 static int lockd_up_net(struct svc_serv *serv, struct net *net, 222 const struct cred *cred) 223 { 224 struct lockd_net *ln = net_generic(net, lockd_net_id); 225 int error; 226 227 if (ln->nlmsvc_users++) 228 return 0; 229 230 error = svc_bind(serv, net); 231 if (error) 232 goto err_bind; 233 234 error = make_socks(serv, net, cred); 235 if (error < 0) 236 goto err_bind; 237 set_grace_period(net); 238 dprintk("%s: per-net data created; net=%x\n", __func__, net->ns.inum); 239 return 0; 240 241 err_bind: 242 ln->nlmsvc_users--; 243 return error; 244 } 245 246 static void lockd_down_net(struct svc_serv *serv, struct net *net) 247 { 248 struct lockd_net *ln = net_generic(net, lockd_net_id); 249 250 if (ln->nlmsvc_users) { 251 if (--ln->nlmsvc_users == 0) { 252 nlm_shutdown_hosts_net(net); 253 cancel_delayed_work_sync(&ln->grace_period_end); 254 locks_end_grace(&ln->lockd_manager); 255 svc_xprt_destroy_all(serv, net, true); 256 } 257 } else { 258 pr_err("%s: no users! net=%x\n", 259 __func__, net->ns.inum); 260 BUG(); 261 } 262 } 263 264 static int lockd_inetaddr_event(struct notifier_block *this, 265 unsigned long event, void *ptr) 266 { 267 struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; 268 struct sockaddr_in sin; 269 270 if (event != NETDEV_DOWN) 271 goto out; 272 273 if (nlmsvc_serv) { 274 dprintk("lockd_inetaddr_event: removed %pI4\n", 275 &ifa->ifa_local); 276 sin.sin_family = AF_INET; 277 sin.sin_addr.s_addr = ifa->ifa_local; 278 svc_age_temp_xprts_now(nlmsvc_serv, (struct sockaddr *)&sin); 279 } 280 281 out: 282 return NOTIFY_DONE; 283 } 284 285 static struct notifier_block lockd_inetaddr_notifier = { 286 .notifier_call = lockd_inetaddr_event, 287 }; 288 289 #if IS_ENABLED(CONFIG_IPV6) 290 static int lockd_inet6addr_event(struct notifier_block *this, 291 unsigned long event, void *ptr) 292 { 293 struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr; 294 struct sockaddr_in6 sin6; 295 296 if (event != NETDEV_DOWN) 297 goto out; 298 299 if (nlmsvc_serv) { 300 dprintk("lockd_inet6addr_event: removed %pI6\n", &ifa->addr); 301 sin6.sin6_family = AF_INET6; 302 sin6.sin6_addr = ifa->addr; 303 if (ipv6_addr_type(&sin6.sin6_addr) & IPV6_ADDR_LINKLOCAL) 304 sin6.sin6_scope_id = ifa->idev->dev->ifindex; 305 svc_age_temp_xprts_now(nlmsvc_serv, (struct sockaddr *)&sin6); 306 } 307 308 out: 309 return NOTIFY_DONE; 310 } 311 312 static struct notifier_block lockd_inet6addr_notifier = { 313 .notifier_call = lockd_inet6addr_event, 314 }; 315 #endif 316 317 static int lockd_get(void) 318 { 319 struct svc_serv *serv; 320 unsigned int bufsize; 321 int error; 322 323 if (nlmsvc_serv) { 324 nlmsvc_users++; 325 return 0; 326 } 327 328 /* 329 * Sanity check: if there's no pid, 330 * we should be the first user ... 331 */ 332 if (nlmsvc_users) 333 printk(KERN_WARNING 334 "lockd_up: no pid, %d users??\n", nlmsvc_users); 335 336 #ifdef CONFIG_LOCKD_V4 337 bufsize = 1024 + max3(nlmsvc_version1.vs_xdrsize, 338 nlmsvc_version3.vs_xdrsize, 339 nlmsvc_version4.vs_xdrsize); 340 #else 341 bufsize = 1024 + max(nlmsvc_version1.vs_xdrsize, 342 nlmsvc_version3.vs_xdrsize); 343 #endif 344 serv = svc_create(&nlmsvc_program, bufsize, lockd); 345 if (!serv) { 346 printk(KERN_WARNING "lockd_up: create service failed\n"); 347 return -ENOMEM; 348 } 349 350 error = svc_set_num_threads(serv, 0, 1); 351 if (error < 0) { 352 svc_destroy(&serv); 353 return error; 354 } 355 356 nlmsvc_serv = serv; 357 register_inetaddr_notifier(&lockd_inetaddr_notifier); 358 #if IS_ENABLED(CONFIG_IPV6) 359 register_inet6addr_notifier(&lockd_inet6addr_notifier); 360 #endif 361 dprintk("lockd_up: service created\n"); 362 nlmsvc_users++; 363 return 0; 364 } 365 366 static void lockd_put(void) 367 { 368 if (WARN(nlmsvc_users <= 0, "lockd_down: no users!\n")) 369 return; 370 if (--nlmsvc_users) 371 return; 372 373 unregister_inetaddr_notifier(&lockd_inetaddr_notifier); 374 #if IS_ENABLED(CONFIG_IPV6) 375 unregister_inet6addr_notifier(&lockd_inet6addr_notifier); 376 #endif 377 378 svc_set_num_threads(nlmsvc_serv, 0, 0); 379 timer_delete_sync(&nlmsvc_retry); 380 svc_destroy(&nlmsvc_serv); 381 dprintk("lockd_down: service destroyed\n"); 382 } 383 384 /* 385 * Bring up the lockd process if it's not already up. 386 */ 387 int lockd_up(struct net *net, const struct cred *cred) 388 { 389 int error; 390 391 mutex_lock(&nlmsvc_mutex); 392 393 error = lockd_get(); 394 if (error) 395 goto err; 396 397 error = lockd_up_net(nlmsvc_serv, net, cred); 398 if (error < 0) { 399 lockd_put(); 400 goto err; 401 } 402 403 err: 404 mutex_unlock(&nlmsvc_mutex); 405 return error; 406 } 407 EXPORT_SYMBOL_GPL(lockd_up); 408 409 /* 410 * Decrement the user count and bring down lockd if we're the last. 411 */ 412 void 413 lockd_down(struct net *net) 414 { 415 mutex_lock(&nlmsvc_mutex); 416 lockd_down_net(nlmsvc_serv, net); 417 lockd_put(); 418 mutex_unlock(&nlmsvc_mutex); 419 } 420 EXPORT_SYMBOL_GPL(lockd_down); 421 422 #ifdef CONFIG_SYSCTL 423 424 /* 425 * Sysctl parameters (same as module parameters, different interface). 426 */ 427 428 static const struct ctl_table nlm_sysctls[] = { 429 { 430 .procname = "nlm_grace_period", 431 .data = &nlm_grace_period, 432 .maxlen = sizeof(unsigned long), 433 .mode = 0644, 434 .proc_handler = proc_doulongvec_minmax, 435 .extra1 = (unsigned long *) &nlm_grace_period_min, 436 .extra2 = (unsigned long *) &nlm_grace_period_max, 437 }, 438 { 439 .procname = "nlm_timeout", 440 .data = &nlm_timeout, 441 .maxlen = sizeof(unsigned long), 442 .mode = 0644, 443 .proc_handler = proc_doulongvec_minmax, 444 .extra1 = (unsigned long *) &nlm_timeout_min, 445 .extra2 = (unsigned long *) &nlm_timeout_max, 446 }, 447 { 448 .procname = "nlm_udpport", 449 .data = &nlm_udpport, 450 .maxlen = sizeof(int), 451 .mode = 0644, 452 .proc_handler = proc_dointvec_minmax, 453 .extra1 = (int *) &nlm_port_min, 454 .extra2 = (int *) &nlm_port_max, 455 }, 456 { 457 .procname = "nlm_tcpport", 458 .data = &nlm_tcpport, 459 .maxlen = sizeof(int), 460 .mode = 0644, 461 .proc_handler = proc_dointvec_minmax, 462 .extra1 = (int *) &nlm_port_min, 463 .extra2 = (int *) &nlm_port_max, 464 }, 465 { 466 .procname = "nsm_use_hostnames", 467 .data = &nsm_use_hostnames, 468 .maxlen = sizeof(bool), 469 .mode = 0644, 470 .proc_handler = proc_dobool, 471 }, 472 { 473 .procname = "nsm_local_state", 474 .data = &nsm_local_state, 475 .maxlen = sizeof(nsm_local_state), 476 .mode = 0644, 477 .proc_handler = proc_douintvec, 478 .extra1 = SYSCTL_ZERO, 479 }, 480 }; 481 482 #endif /* CONFIG_SYSCTL */ 483 484 /* 485 * Module (and sysfs) parameters. 486 */ 487 488 #define param_set_min_max(name, type, which_strtol, min, max) \ 489 static int param_set_##name(const char *val, const struct kernel_param *kp) \ 490 { \ 491 char *endp; \ 492 __typeof__(type) num = which_strtol(val, &endp, 0); \ 493 if (endp == val || *endp || num < (min) || num > (max)) \ 494 return -EINVAL; \ 495 *((type *) kp->arg) = num; \ 496 return 0; \ 497 } 498 499 static inline int is_callback(u32 proc) 500 { 501 return proc == NLMPROC_GRANTED 502 || proc == NLMPROC_GRANTED_MSG 503 || proc == NLMPROC_TEST_RES 504 || proc == NLMPROC_LOCK_RES 505 || proc == NLMPROC_CANCEL_RES 506 || proc == NLMPROC_UNLOCK_RES 507 || proc == NLMPROC_NSM_NOTIFY; 508 } 509 510 511 static enum svc_auth_status lockd_authenticate(struct svc_rqst *rqstp) 512 { 513 rqstp->rq_client = NULL; 514 switch (rqstp->rq_authop->flavour) { 515 case RPC_AUTH_NULL: 516 case RPC_AUTH_UNIX: 517 rqstp->rq_auth_stat = rpc_auth_ok; 518 if (rqstp->rq_proc == 0) 519 return SVC_OK; 520 if (is_callback(rqstp->rq_proc)) { 521 /* Leave it to individual procedures to 522 * call nlmsvc_lookup_host(rqstp) 523 */ 524 return SVC_OK; 525 } 526 return svc_set_client(rqstp); 527 } 528 rqstp->rq_auth_stat = rpc_autherr_badcred; 529 return SVC_DENIED; 530 } 531 532 533 param_set_min_max(port, int, simple_strtol, 0, 65535) 534 param_set_min_max(grace_period, unsigned long, simple_strtoul, 535 nlm_grace_period_min, nlm_grace_period_max) 536 param_set_min_max(timeout, unsigned long, simple_strtoul, 537 nlm_timeout_min, nlm_timeout_max) 538 539 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); 540 MODULE_DESCRIPTION("NFS file locking service version " LOCKD_VERSION "."); 541 MODULE_LICENSE("GPL"); 542 543 module_param_call(nlm_grace_period, param_set_grace_period, param_get_ulong, 544 &nlm_grace_period, 0644); 545 module_param_call(nlm_timeout, param_set_timeout, param_get_ulong, 546 &nlm_timeout, 0644); 547 module_param_call(nlm_udpport, param_set_port, param_get_int, 548 &nlm_udpport, 0644); 549 module_param_call(nlm_tcpport, param_set_port, param_get_int, 550 &nlm_tcpport, 0644); 551 module_param(nsm_use_hostnames, bool, 0644); 552 553 static int lockd_init_net(struct net *net) 554 { 555 struct lockd_net *ln = net_generic(net, lockd_net_id); 556 557 INIT_DELAYED_WORK(&ln->grace_period_end, grace_ender); 558 INIT_LIST_HEAD(&ln->lockd_manager.list); 559 ln->lockd_manager.block_opens = false; 560 INIT_LIST_HEAD(&ln->nsm_handles); 561 return 0; 562 } 563 564 static void lockd_exit_net(struct net *net) 565 { 566 struct lockd_net *ln = net_generic(net, lockd_net_id); 567 568 WARN_ONCE(!list_empty(&ln->lockd_manager.list), 569 "net %x %s: lockd_manager.list is not empty\n", 570 net->ns.inum, __func__); 571 WARN_ONCE(!list_empty(&ln->nsm_handles), 572 "net %x %s: nsm_handles list is not empty\n", 573 net->ns.inum, __func__); 574 WARN_ONCE(delayed_work_pending(&ln->grace_period_end), 575 "net %x %s: grace_period_end was not cancelled\n", 576 net->ns.inum, __func__); 577 } 578 579 static struct pernet_operations lockd_net_ops = { 580 .init = lockd_init_net, 581 .exit = lockd_exit_net, 582 .id = &lockd_net_id, 583 .size = sizeof(struct lockd_net), 584 }; 585 586 587 /* 588 * Initialising and terminating the module. 589 */ 590 591 static int __init init_nlm(void) 592 { 593 int err; 594 595 #ifdef CONFIG_SYSCTL 596 err = -ENOMEM; 597 nlm_sysctl_table = register_sysctl("fs/nfs", nlm_sysctls); 598 if (nlm_sysctl_table == NULL) 599 goto err_sysctl; 600 #endif 601 err = register_pernet_subsys(&lockd_net_ops); 602 if (err) 603 goto err_pernet; 604 605 err = genl_register_family(&lockd_nl_family); 606 if (err) 607 goto err_netlink; 608 609 err = lockd_create_procfs(); 610 if (err) 611 goto err_procfs; 612 613 return 0; 614 615 err_procfs: 616 genl_unregister_family(&lockd_nl_family); 617 err_netlink: 618 unregister_pernet_subsys(&lockd_net_ops); 619 err_pernet: 620 #ifdef CONFIG_SYSCTL 621 unregister_sysctl_table(nlm_sysctl_table); 622 err_sysctl: 623 #endif 624 return err; 625 } 626 627 static void __exit exit_nlm(void) 628 { 629 /* FIXME: delete all NLM clients */ 630 nlm_shutdown_hosts(); 631 genl_unregister_family(&lockd_nl_family); 632 lockd_remove_procfs(); 633 unregister_pernet_subsys(&lockd_net_ops); 634 #ifdef CONFIG_SYSCTL 635 unregister_sysctl_table(nlm_sysctl_table); 636 #endif 637 } 638 639 module_init(init_nlm); 640 module_exit(exit_nlm); 641 642 /** 643 * nlmsvc_dispatch - Process an NLM Request 644 * @rqstp: incoming request 645 * 646 * Return values: 647 * %0: Processing complete; do not send a Reply 648 * %1: Processing complete; send Reply in rqstp->rq_res 649 */ 650 int nlmsvc_dispatch(struct svc_rqst *rqstp) 651 { 652 const struct svc_procedure *procp = rqstp->rq_procinfo; 653 __be32 *statp = rqstp->rq_accept_statp; 654 655 if (!procp->pc_decode(rqstp, &rqstp->rq_arg_stream)) 656 goto out_decode_err; 657 658 *statp = procp->pc_func(rqstp); 659 if (*statp == rpc_drop_reply) 660 return 0; 661 if (*statp != rpc_success) 662 return 1; 663 664 if (!procp->pc_encode(rqstp, &rqstp->rq_res_stream)) 665 goto out_encode_err; 666 667 return 1; 668 669 out_decode_err: 670 *statp = rpc_garbage_args; 671 return 1; 672 673 out_encode_err: 674 *statp = rpc_system_err; 675 return 1; 676 } 677 678 /* 679 * Define NLM program and procedures 680 */ 681 static const struct svc_version *nlmsvc_version[] = { 682 [1] = &nlmsvc_version1, 683 [3] = &nlmsvc_version3, 684 #ifdef CONFIG_LOCKD_V4 685 [4] = &nlmsvc_version4, 686 #endif 687 }; 688 689 #define NLM_NRVERS ARRAY_SIZE(nlmsvc_version) 690 static struct svc_program nlmsvc_program = { 691 .pg_prog = NLM_PROGRAM, /* program number */ 692 .pg_nvers = NLM_NRVERS, /* number of entries in nlmsvc_version */ 693 .pg_vers = nlmsvc_version, /* version table */ 694 .pg_name = "lockd", /* service name */ 695 .pg_class = "nfsd", /* share authentication with nfsd */ 696 .pg_authenticate = &lockd_authenticate, /* export authentication */ 697 .pg_init_request = svc_generic_init_request, 698 .pg_rpcbind_set = svc_generic_rpcbind_set, 699 }; 700 701 /** 702 * lockd_nl_server_set_doit - set the lockd server parameters via netlink 703 * @skb: reply buffer 704 * @info: netlink metadata and command arguments 705 * 706 * This updates the per-net values. When updating the values in the init_net 707 * namespace, also update the "legacy" global values. 708 * 709 * Return 0 on success or a negative errno. 710 */ 711 int lockd_nl_server_set_doit(struct sk_buff *skb, struct genl_info *info) 712 { 713 struct net *net = genl_info_net(info); 714 struct lockd_net *ln = net_generic(net, lockd_net_id); 715 const struct nlattr *attr; 716 717 if (GENL_REQ_ATTR_CHECK(info, LOCKD_A_SERVER_GRACETIME)) 718 return -EINVAL; 719 720 if (info->attrs[LOCKD_A_SERVER_GRACETIME] || 721 info->attrs[LOCKD_A_SERVER_TCP_PORT] || 722 info->attrs[LOCKD_A_SERVER_UDP_PORT]) { 723 attr = info->attrs[LOCKD_A_SERVER_GRACETIME]; 724 if (attr) { 725 u32 gracetime = nla_get_u32(attr); 726 727 if (gracetime > nlm_grace_period_max) 728 return -EINVAL; 729 730 ln->gracetime = gracetime; 731 732 if (net == &init_net) 733 nlm_grace_period = gracetime; 734 } 735 736 attr = info->attrs[LOCKD_A_SERVER_TCP_PORT]; 737 if (attr) { 738 ln->tcp_port = nla_get_u16(attr); 739 if (net == &init_net) 740 nlm_tcpport = ln->tcp_port; 741 } 742 743 attr = info->attrs[LOCKD_A_SERVER_UDP_PORT]; 744 if (attr) { 745 ln->udp_port = nla_get_u16(attr); 746 if (net == &init_net) 747 nlm_udpport = ln->udp_port; 748 } 749 } 750 return 0; 751 } 752 753 /** 754 * lockd_nl_server_get_doit - get lockd server parameters via netlink 755 * @skb: reply buffer 756 * @info: netlink metadata and command arguments 757 * 758 * Return 0 on success or a negative errno. 759 */ 760 int lockd_nl_server_get_doit(struct sk_buff *skb, struct genl_info *info) 761 { 762 struct net *net = genl_info_net(info); 763 struct lockd_net *ln = net_generic(net, lockd_net_id); 764 void *hdr; 765 int err; 766 767 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 768 if (!skb) 769 return -ENOMEM; 770 771 hdr = genlmsg_iput(skb, info); 772 if (!hdr) { 773 err = -EMSGSIZE; 774 goto err_free_msg; 775 } 776 777 err = nla_put_u32(skb, LOCKD_A_SERVER_GRACETIME, ln->gracetime) || 778 nla_put_u16(skb, LOCKD_A_SERVER_TCP_PORT, ln->tcp_port) || 779 nla_put_u16(skb, LOCKD_A_SERVER_UDP_PORT, ln->udp_port); 780 if (err) 781 goto err_free_msg; 782 783 genlmsg_end(skb, hdr); 784 785 return genlmsg_reply(skb, info); 786 err_free_msg: 787 nlmsg_free(skb); 788 789 return err; 790 } 791