Home | History | Annotate | Download | only in nfs
      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