1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. 26 * All rights reserved. 27 */ 28 29 #include <sys/types.h> 30 #include <rpc/types.h> 31 #include <sys/systm.h> 32 #include <sys/vfs.h> 33 #include <sys/errno.h> 34 #include <sys/cred.h> 35 #include <sys/policy.h> 36 #include <sys/siginfo.h> 37 #include <sys/proc.h> /* for exit() declaration */ 38 #include <sys/kmem.h> 39 #include <nfs/nfs4.h> 40 #include <nfs/nfssys.h> 41 #include <sys/thread.h> 42 #include <rpc/auth.h> 43 #include <rpc/rpcsys.h> 44 #include <rpc/svc.h> 45 #include <rpc/xdr.h> 46 #include <sys/cmn_err.h> 47 #include <sys/sdt.h> 48 #include <nfs/dserv_impl.h> 49 50 /* 51 * This is filled in with an appropriate address for the 52 * function that will traverse the rfs4_client_t table 53 * and mark any matching IP Address as "forced_expire". 54 * 55 * It is the server module load init() function that plops the 56 * function pointer. 57 */ 58 void (*rfs4_client_clrst)(struct nfs4clrst_args *) = NULL; 59 60 /* Temp: used by mdsadm */ 61 int (*mds_recall_lo)(struct mds_reclo_args *, cred_t *) = NULL; 62 int (*mds_notify_device)(struct mds_notifydev_args *, cred_t *) = NULL; 63 64 /* This filled in by nfssrv:_init() */ 65 void (*nfs_srv_quiesce_func)(void) = NULL; 66 67 extern void nfscmd_args(uint_t); 68 69 /* 70 * Time period in seconds for DS_RENEW requests from the heartbeat thread 71 * between DS and MDS 72 */ 73 #define DS_MDS_HEARTBEAT_TIME 5 74 time_t rfs4_ds_mds_hb_time = DS_MDS_HEARTBEAT_TIME; 75 76 /* 77 * These will be reset by klmmod:lm_svc(), when lockd starts NLM service, 78 * based on values read by lockd from /etc/default/nfs. Since nfssrv depends on 79 * klmmod, the declarations need to be here (in nfs, on which both depend) so 80 * that nfssrv can see the klmmod changes. 81 * When the dependency of NFSv4 on NLM/lockd is removed, this will need to 82 * be adjusted. 83 */ 84 #define RFS4_LEASETIME 90 /* seconds */ 85 time_t rfs4_lease_time = RFS4_LEASETIME; 86 time_t rfs4_grace_period = RFS4_LEASETIME; 87 88 /* DSS: distributed stable storage */ 89 size_t nfs4_dss_buflen = 0; 90 91 /* This filled in by nfssrv:_init() */ 92 int (*nfs_srv_dss_func)(char *, size_t) = NULL; 93 94 int 95 nfs_export(void *arg) 96 { 97 STRUCT_DECL(exportfs_args, ea); 98 99 if (!INGLOBALZONE(curproc)) 100 return (set_errno(EPERM)); 101 STRUCT_INIT(ea, get_udatamodel()); 102 if (copyin(arg, STRUCT_BUF(ea), STRUCT_SIZE(ea))) 103 return (set_errno(EFAULT)); 104 105 return (exportfs(STRUCT_BUF(ea), get_udatamodel(), CRED())); 106 } 107 108 int 109 nfssys(enum nfssys_op opcode, void *arg) 110 { 111 /* XXX - jw - need to create this routine. */ 112 #ifdef NotDoneYet 113 extern void rfs4_inst_init(struct nfs_state_init_args *); 114 #endif 115 116 int error = 0; 117 118 if (!(opcode == NFS_REVAUTH || 119 opcode == NFS4_SVC || 120 opcode == NFSSTAT_LAYOUT) && 121 secpolicy_nfs(CRED()) != 0) { 122 return (set_errno(EPERM)); 123 } 124 125 switch (opcode) { 126 /* XXX - jw - need to finish this stuff */ 127 #ifdef NotDoneYet 128 case NFS_INIT_STATESTORE: { 129 struct nfs_state_init_args nsi_args; 130 STRUCT_DECL(nfs_state_init_args, ua); 131 132 if (mds_recall_lo == NULL) { 133 printf(":-P .. NFS server is not loaded\n"); 134 break; 135 } 136 137 if (!INGLOBALZONE(curproc)) 138 return (set_errno(EPERM)); 139 140 STRUCT_INIT(ua, get_udatamodel()); 141 142 nsi_args.inst_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 143 144 error = copyinstr(nsi_args.inst_name, 145 STRUCT_FGETP(ua, inst_name), MAXNAMELEN, NULL); 146 147 if (error != 0) { 148 kmem_free(nsi_args.inst_name, MAXNAMELEN); 149 return (set_errno(EFAULT)); 150 } 151 nsi_args.cap_flags = STRUCT_FGET(ua, cap_flags); 152 153 rfs4_inst_init(&nsi_args); 154 155 break; 156 } 157 158 case NFS_FINI_STATESTORE: { 159 struct nfs_state_init_args nsi_args; 160 STRUCT_DECL(nfs_state_init_args, ua); 161 162 if (mds_recall_lo == NULL) { 163 printf(":-P .. NFS server is not loaded\n"); 164 break; 165 } 166 167 if (!INGLOBALZONE(curproc)) 168 return (set_errno(EPERM)); 169 170 STRUCT_INIT(ua, get_udatamodel()); 171 172 nsi_args.inst_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 173 174 error = copyinstr(nsi_args.inst_name, 175 STRUCT_FGETP(ua, inst_name), MAXNAMELEN, NULL); 176 177 if (error != 0) { 178 kmem_free(nsi_args.inst_name, MAXNAMELEN); 179 return (set_errno(EFAULT)); 180 } 181 rfs4_inst_finit(&nsi_args); 182 183 break; 184 } 185 #endif 186 187 case MDS_RECALL_LAYOUT: { 188 struct mds_reclo_args rargs; 189 int plen = 0; 190 int buf[2] = {0, 0}; 191 XDR xdrs; 192 193 if (mds_recall_lo == NULL) 194 return (set_errno(ENOTSUP)); 195 196 if (copyin(arg, (char *)buf, sizeof (buf))) 197 return (set_errno(EFAULT)); 198 199 xdrmem_create(&xdrs, (char *)buf, sizeof (buf), XDR_DECODE); 200 201 if (! xdr_int(&xdrs, &rargs.lo_type) || 202 ! xdr_int(&xdrs, &plen) || (plen > MAXNAMELEN)) 203 return (set_errno(EINVAL)); 204 205 rargs.lo_fname = kmem_alloc(plen + 1, KM_SLEEP); 206 rargs.lo_fname[plen] = '\0'; 207 error = copyin((char *)arg + BYTES_PER_XDR_UNIT * 2, 208 rargs.lo_fname, plen); 209 210 if (error) { 211 kmem_free(rargs.lo_fname, plen + 1); 212 return (set_errno(EFAULT)); 213 } 214 215 error = mds_recall_lo(&rargs, CRED()); 216 kmem_free(rargs.lo_fname, plen + 1); 217 break; 218 } 219 220 case MDS_NOTIFY_DEVICE: { 221 struct mds_notifydev_args dargs; 222 223 if (mds_notify_device == NULL) 224 return (set_errno(ENOTSUP)); 225 226 if (copyin(arg, (char *)&dargs, sizeof (dargs))) 227 return (set_errno(EFAULT)); 228 229 error = mds_notify_device(&dargs, CRED()); 230 break; 231 } 232 233 case NFS4_CLR_STATE: { /* Clear NFS4 client state */ 234 struct nfs4clrst_args clr; 235 STRUCT_DECL(nfs4clrst_args, u_clr); 236 237 /* 238 * If the server is not loaded then no point in 239 * clearing nothing :-) 240 */ 241 if (rfs4_client_clrst == NULL) { 242 break; 243 } 244 245 if (!INGLOBALZONE(curproc)) 246 return (set_errno(EPERM)); 247 248 STRUCT_INIT(u_clr, get_udatamodel()); 249 250 if (copyin(arg, STRUCT_BUF(u_clr), STRUCT_SIZE(u_clr))) 251 return (set_errno(EFAULT)); 252 253 clr.vers = STRUCT_FGET(u_clr, vers); 254 255 if (clr.vers != NFS4_CLRST_VERSION) 256 return (set_errno(EINVAL)); 257 258 clr.addr_type = STRUCT_FGET(u_clr, addr_type); 259 clr.ap = STRUCT_FGETP(u_clr, ap); 260 rfs4_client_clrst(&clr); 261 break; 262 } 263 264 case SVCPOOL_CREATE: { /* setup an RPC server thread pool */ 265 struct svcpool_args p; 266 267 if (copyin(arg, &p, sizeof (p))) 268 return (set_errno(EFAULT)); 269 270 error = svc_pool_create(&p); 271 272 if (copyout(&p, arg, sizeof (p))) 273 return (set_errno(EFAULT)); 274 break; 275 } 276 277 case SVCPOOL_WAIT: { /* wait in kernel for threads to be needed */ 278 int id; 279 280 if (copyin(arg, &id, sizeof (id))) 281 return (set_errno(EFAULT)); 282 283 error = svc_wait(id); 284 break; 285 } 286 287 case SVCPOOL_RUN: { /* give work to a runnable thread */ 288 int id; 289 290 if (copyin(arg, &id, sizeof (id))) 291 return (set_errno(EFAULT)); 292 293 error = svc_do_run(id); 294 break; 295 } 296 297 case RDMA_SVC_INIT: { 298 struct rdma_svc_args rsa; 299 char netstore[20] = "tcp"; 300 301 if (!INGLOBALZONE(curproc)) 302 return (set_errno(EPERM)); 303 if (get_udatamodel() != DATAMODEL_NATIVE) { 304 STRUCT_DECL(rdma_svc_args, ursa); 305 306 STRUCT_INIT(ursa, get_udatamodel()); 307 if (copyin(arg, STRUCT_BUF(ursa), STRUCT_SIZE(ursa))) 308 return (set_errno(EFAULT)); 309 310 rsa.poolid = STRUCT_FGET(ursa, poolid); 311 rsa.nfs_versmin = STRUCT_FGET(ursa, nfs_versmin); 312 rsa.nfs_versmax = STRUCT_FGET(ursa, nfs_versmax); 313 rsa.delegation = STRUCT_FGET(ursa, delegation); 314 rsa.dfd = STRUCT_FGET(ursa, dfd); 315 } else { 316 if (copyin(arg, &rsa, sizeof (rsa))) 317 return (set_errno(EFAULT)); 318 } 319 rsa.netid = netstore; 320 321 error = rdma_start(&rsa); 322 break; 323 } 324 325 case NFS_SVC: { /* NFS server daemon */ 326 STRUCT_DECL(nfs_svc_args, nsa); 327 328 if (!INGLOBALZONE(curproc)) 329 return (set_errno(EPERM)); 330 STRUCT_INIT(nsa, get_udatamodel()); 331 332 if (copyin(arg, STRUCT_BUF(nsa), STRUCT_SIZE(nsa))) 333 return (set_errno(EFAULT)); 334 335 error = nfs_svc(STRUCT_BUF(nsa), get_udatamodel()); 336 break; 337 } 338 339 case EXPORTFS: { /* export a file system */ 340 error = nfs_export(arg); 341 break; 342 } 343 344 case NFS_GETFH: { /* get a file handle */ 345 STRUCT_DECL(nfs_getfh_args, nga); 346 347 if (!INGLOBALZONE(curproc)) 348 return (set_errno(EPERM)); 349 STRUCT_INIT(nga, get_udatamodel()); 350 if (copyin(arg, STRUCT_BUF(nga), STRUCT_SIZE(nga))) 351 return (set_errno(EFAULT)); 352 353 error = nfs_getfh(STRUCT_BUF(nga), get_udatamodel(), CRED()); 354 break; 355 } 356 357 case NFSSTAT_LAYOUT: { 358 STRUCT_DECL(pnfs_getflo_args, pla); 359 360 STRUCT_INIT(pla, get_udatamodel()); 361 if (copyin(arg, STRUCT_BUF(pla), STRUCT_SIZE(pla))) { 362 error = EFAULT; 363 } else { 364 error = pnfs_collect_layoutstats( 365 STRUCT_BUF(pla), get_udatamodel(), CRED()); 366 } 367 break; 368 } 369 370 371 372 case NFS_REVAUTH: { /* revoke the cached credentials for the uid */ 373 STRUCT_DECL(nfs_revauth_args, nra); 374 375 STRUCT_INIT(nra, get_udatamodel()); 376 if (copyin(arg, STRUCT_BUF(nra), STRUCT_SIZE(nra))) 377 return (set_errno(EFAULT)); 378 379 /* This call performs its own privilege checking */ 380 error = sec_clnt_revoke(STRUCT_FGET(nra, authtype), 381 STRUCT_FGET(nra, uid), CRED(), NULL, get_udatamodel()); 382 break; 383 } 384 385 case LM_SVC: { /* LM server daemon */ 386 struct lm_svc_args lsa; 387 388 if (get_udatamodel() != DATAMODEL_NATIVE) { 389 STRUCT_DECL(lm_svc_args, ulsa); 390 391 STRUCT_INIT(ulsa, get_udatamodel()); 392 if (copyin(arg, STRUCT_BUF(ulsa), STRUCT_SIZE(ulsa))) 393 return (set_errno(EFAULT)); 394 395 lsa.version = STRUCT_FGET(ulsa, version); 396 lsa.fd = STRUCT_FGET(ulsa, fd); 397 lsa.n_fmly = STRUCT_FGET(ulsa, n_fmly); 398 lsa.n_proto = STRUCT_FGET(ulsa, n_proto); 399 lsa.n_rdev = expldev(STRUCT_FGET(ulsa, n_rdev)); 400 lsa.debug = STRUCT_FGET(ulsa, debug); 401 lsa.timout = STRUCT_FGET(ulsa, timout); 402 lsa.grace = STRUCT_FGET(ulsa, grace); 403 lsa.retransmittimeout = STRUCT_FGET(ulsa, 404 retransmittimeout); 405 } else { 406 if (copyin(arg, &lsa, sizeof (lsa))) 407 return (set_errno(EFAULT)); 408 } 409 410 error = lm_svc(&lsa); 411 break; 412 } 413 414 case KILL_LOCKMGR: { 415 error = lm_shutdown(); 416 break; 417 } 418 419 case LOG_FLUSH: { /* Flush log buffer and possibly rename */ 420 STRUCT_DECL(nfsl_flush_args, nfa); 421 422 STRUCT_INIT(nfa, get_udatamodel()); 423 if (copyin(arg, STRUCT_BUF(nfa), STRUCT_SIZE(nfa))) 424 return (set_errno(EFAULT)); 425 426 error = nfsl_flush(STRUCT_BUF(nfa), get_udatamodel()); 427 break; 428 } 429 430 case NFS4_SVC: { /* NFS client callback daemon */ 431 432 STRUCT_DECL(nfs4_svc_args, nsa); 433 434 STRUCT_INIT(nsa, get_udatamodel()); 435 436 if (copyin(arg, STRUCT_BUF(nsa), STRUCT_SIZE(nsa))) 437 return (set_errno(EFAULT)); 438 439 error = nfs4_svc(STRUCT_BUF(nsa), get_udatamodel()); 440 break; 441 } 442 443 /* Request that NFSv4 server quiesce on next shutdown */ 444 case NFS4_SVC_REQUEST_QUIESCE: { 445 int id; 446 447 /* check that nfssrv module is loaded */ 448 if (nfs_srv_quiesce_func == NULL) 449 return (set_errno(ENOTSUP)); 450 451 if (copyin(arg, &id, sizeof (id))) 452 return (set_errno(EFAULT)); 453 454 error = svc_pool_control(id, SVCPSET_SHUTDOWN_PROC, 455 (void *)nfs_srv_quiesce_func); 456 break; 457 } 458 459 case NFS_IDMAP: { 460 struct nfsidmap_args idm; 461 462 if (copyin(arg, &idm, sizeof (idm))) 463 return (set_errno(EFAULT)); 464 465 nfs_idmap_args(&idm); 466 error = 0; 467 break; 468 } 469 470 case NFS_SPE: { 471 nfs41_spe_svc(arg); 472 error = 0; 473 break; 474 } 475 476 case NFS4_DSS_SETPATHS_SIZE: { 477 /* crosses ILP32/LP64 boundary */ 478 uint32_t nfs4_dss_bufsize = 0; 479 480 if (copyin(arg, &nfs4_dss_bufsize, sizeof (nfs4_dss_bufsize))) 481 return (set_errno(EFAULT)); 482 nfs4_dss_buflen = (long)nfs4_dss_bufsize; 483 error = 0; 484 break; 485 } 486 487 case NFS4_DSS_SETPATHS: { 488 char *nfs4_dss_bufp; 489 490 /* check that nfssrv module is loaded */ 491 if (nfs_srv_dss_func == NULL) 492 return (set_errno(ENOTSUP)); 493 494 /* 495 * NFS4_DSS_SETPATHS_SIZE must be called before 496 * NFS4_DSS_SETPATHS, to tell us how big a buffer we need 497 * to allocate. 498 */ 499 if (nfs4_dss_buflen == 0) 500 return (set_errno(EINVAL)); 501 nfs4_dss_bufp = kmem_alloc(nfs4_dss_buflen, KM_SLEEP); 502 if (nfs4_dss_bufp == NULL) 503 return (set_errno(ENOMEM)); 504 505 if (copyin(arg, nfs4_dss_bufp, nfs4_dss_buflen)) { 506 kmem_free(nfs4_dss_bufp, nfs4_dss_buflen); 507 return (set_errno(EFAULT)); 508 } 509 510 /* unpack the buffer and extract the pathnames */ 511 error = nfs_srv_dss_func(nfs4_dss_bufp, nfs4_dss_buflen); 512 kmem_free(nfs4_dss_bufp, nfs4_dss_buflen); 513 514 break; 515 } 516 517 case NFS4_EPHEMERAL_MOUNT_TO: { 518 uint_t mount_to; 519 520 /* 521 * Not a very complicated call. 522 */ 523 if (copyin(arg, &mount_to, sizeof (mount_to))) 524 return (set_errno(EFAULT)); 525 nfs4_ephemeral_set_mount_to(mount_to); 526 error = 0; 527 break; 528 } 529 530 case MOUNTD_ARGS: { 531 uint_t did; 532 533 /* 534 * For now, only passing down the door fd; if we 535 * ever need to pass down more info, we can use 536 * a (properly aligned) struct. 537 */ 538 if (copyin(arg, &did, sizeof (did))) 539 return (set_errno(EFAULT)); 540 mountd_args(did); 541 error = 0; 542 break; 543 } 544 545 case NFSCMD_ARGS: { 546 uint_t did; 547 548 /* 549 * For now, only passing down the door fd; if we 550 * ever need to pass down more info, we can use 551 * a (properly aligned) struct. 552 */ 553 if (copyin(arg, &did, sizeof (did))) 554 return (set_errno(EFAULT)); 555 nfscmd_args(did); 556 error = 0; 557 break; 558 } 559 560 case DSERV_DATASET_INFO: { 561 dserv_dataset_info_t dinfo; 562 563 error = copyin((void *)arg, &dinfo, 564 sizeof (dserv_dataset_info_t)); 565 if (error) 566 return (EFAULT); 567 568 error = dserv_mds_addobjset(dinfo.dataset_name); 569 break; 570 } 571 572 case DSERV_DATASET_PROPS: { 573 dserv_dataset_props_t dprops; 574 575 error = copyin((void *)arg, &dprops, 576 sizeof (dserv_dataset_props_t)); 577 if (error) 578 return (EFAULT); 579 DTRACE_PROBE3(dserv__i__dataset_props, 580 char *, dprops.ddp_name, 581 char *, dprops.ddp_mds_netid, 582 char *, dprops.ddp_mds_uaddr); 583 break; 584 } 585 586 case DSERV_INSTANCE_SHUTDOWN: { 587 error = dserv_mds_instance_teardown(); 588 break; 589 } 590 591 case DSERV_REPORTAVAIL: { 592 error = dserv_mds_reportavail(); 593 break; 594 } 595 596 case DSERV_SVC: { 597 dserv_svc_args_t svcargs; 598 599 error = copyin((void *)arg, &svcargs, 600 sizeof (dserv_svc_args_t)); 601 if (error) 602 return (EFAULT); 603 604 error = dserv_svc(&svcargs); 605 break; 606 } 607 608 case DSERV_SETMDS: { 609 dserv_setmds_args_t smargs; 610 611 error = copyin((void *)arg, &smargs, 612 sizeof (dserv_setmds_args_t)); 613 if (error) 614 return (EFAULT); 615 616 DTRACE_PROBE2(dserv__i__setmds, 617 char *, smargs.dsm_mds_uaddr, char *, smargs.dsm_mds_netid); 618 619 error = dserv_mds_setmds(smargs.dsm_mds_netid, 620 smargs.dsm_mds_uaddr); 621 break; 622 } 623 624 case DSERV_SETPORT: { 625 dserv_setport_args_t spargs; 626 627 error = copyin((void *)arg, &spargs, 628 sizeof (dserv_setport_args_t)); 629 if (error) 630 return (EFAULT); 631 632 DTRACE_PROBE2(dserv__i__setport, char *, spargs.dsa_uaddr, 633 char *, spargs.dsa_proto); 634 635 error = dserv_mds_addport(spargs.dsa_uaddr, spargs.dsa_proto, 636 spargs.dsa_name); 637 break; 638 } 639 640 default: 641 error = EINVAL; 642 break; 643 } 644 645 return ((error != 0) ? set_errno(error) : 0); 646 } 647