Home | History | Annotate | Download | only in infrastructure
      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/CDDL.txt
      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/CDDL.txt.
     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 //
     23 // Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
     24 // Use is subject to license terms.
     25 //
     26 
     27 #pragma ident	"@(#)copy.cc	1.54	08/05/20 SMI"
     28 
     29 //
     30 // This file handles the interface between the kernel's copyin/out and
     31 // the MC copyin/out.
     32 //
     33 
     34 #include <sys/os.h>
     35 #include <orb/infrastructure/orb_conf.h>
     36 #include <orb/infrastructure/orb.h>
     37 #include <orb/infrastructure/copy.h>
     38 #include <h/addrspc.h>
     39 #include <nslib/ns.h>
     40 #include <stdio.h>
     41 #include <sys/cl_comm_support.h>
     42 
     43 #include <sys/thread.h>
     44 #include <sys/copyops.h>
     45 
     46 #include <sys/sol_version.h>
     47 
     48 //
     49 // This file and client/addrspace_impl.cc implement a mechanism to handle
     50 // cross-node ioctls.  The problem is that the device driver can do random
     51 // copyin/outs.  To handle this, we modify the low-level copyin/out/str
     52 // routines to call mc_copyin.  For cross-node operations, we set thread-
     53 // specific data with information on the originating node and pid.
     54 // We assume that the process won't move or exit during the ioctl system
     55 // call, so we can communicate with the home node's addrspace object.
     56 // This object actually does the copyin/out to the originating process.
     57 //
     58 // In the new approach, there is a single addrspace object on each node,
     59 // created when the module is loaded.  This object takes (pid, address,
     60 // length) and does a copyin/copyout/copyinstr.  To support this, instead of
     61 // passing around an addrspace object, ioctls now pass around the nodeid and
     62 // pid.  In addition, if the ioctl is local, the new copyin/out routines are
     63 // bypassed entirely.  The new code speeds up local ioctls by about a factor
     64 // of 4.
     65 //
     66 // There is a special-case scenario to support the HA-ness of ioctls.  The
     67 // problem is that if there is an ioctl that needs to be replayed after a
     68 // failover/switchover (for e.g. the UFS '_FIOLFS' ioctl), then during the
     69 // replay, there is no user thread that makes the call - it is done by the
     70 // appropriate component as part of the failover/switchover, and the arguments
     71 // are already in kernel space.  Hence, when the ioctl handler calls
     72 // copyin/copyout, we need to do a simple bcopy.  To indicate to
     73 // mc_copyin/mc_copyout that the caller of the ioctl is the kernel, we set
     74 // the copy_args of the thread to (orb_conf::node_number, 0) before issuing
     75 // the ioctl.
     76 //
     77 
     78 os::tsd copy::context; // Thread-specific context storage
     79 
     80 //
     81 // We originally had a transport problem with sending too-big packets.
     82 // So, we fairly arbitrarily set a length so the data will fit in a
     83 // 100K packet, and use xfersize to break the transfer into units no
     84 // larger than this.  This may no longer be necessary.
     85 //
     86 
     87 #define	XXX_ARBITRARY_LENGTH (100 * 1024)
     88 
     89 static inline size_t
     90 xfersize(size_t n)
     91 {
     92 	return (MIN(n, XXX_ARBITRARY_LENGTH));
     93 }
     94 
     95 //
     96 // On each node, we have a cache that points to the addrspace objects on
     97 // each of the other nodes.  These entries are loaded from the name server
     98 // on demand.
     99 //
    100 static addrspc::addrspace_var	addrspaceCache_v[NODEID_MAX+1];
    101 static os::mutex_t		addrspace_mutex;
    102 
    103 copy::copy()
    104 {
    105 	for (int i = 0; i <= NODEID_MAX; i++) {
    106 		addrspaceCache_v[i] = addrspc::addrspace::_nil();
    107 	}
    108 }
    109 
    110 //
    111 // getAddrspc does the lookup of an addrspace object in the cache.
    112 // getAddrspc returns nil if it can't find the addrspace object in the
    113 // name server.  This shouldn't happen normally.
    114 //
    115 static addrspc::addrspace_ptr
    116 getAddrspc(sol::nodeid_t nodeid)
    117 {
    118 	addrspc::addrspace_ptr	addrspc_p;
    119 	ASSERT(nodeid <= NODEID_MAX);
    120 
    121 	addrspace_mutex.lock();
    122 	if (CORBA::is_nil(addrspaceCache_v[nodeid])) {
    123 		// get an object reference of the mount name server
    124 		naming::naming_context_var	ctx_v = root_nameserver_funcp();
    125 
    126 		Environment	e;
    127 		char		name[20];
    128 		(void) sprintf(name, "addrspace.%d", nodeid);
    129 		CORBA::Object_var	obj_v = ctx_v->resolve(name, e);
    130 		if (e.exception()) {
    131 			addrspace_mutex.unlock();
    132 #ifdef DEBUG
    133 			e.exception()->print_exception("getAddrspc: Exception "
    134 							"getting\n");
    135 #endif
    136 			return (addrspc::addrspace::_nil());
    137 		}
    138 		addrspaceCache_v[nodeid] = addrspc::addrspace::_narrow(obj_v);
    139 		ASSERT(is_not_nil(addrspaceCache_v[nodeid]));
    140 	}
    141 	addrspc_p = addrspc::addrspace::_duplicate(addrspaceCache_v[nodeid]);
    142 	addrspace_mutex.unlock();
    143 	return (addrspc_p);
    144 }
    145 
    146 //
    147 // checkAddrspc -
    148 // Releases the cached addrspace reference, and gets a new one from the
    149 // name server, caching it again.  Returns the new reference if it differs
    150 // from the reference passed in, otherwise returns nil.  Called by
    151 // mc_xcopyin, mc_xcopyout, and mc_copyinstr when an invocation on the
    152 // addrspace object raises a system exception.  Calling checkAddrspc with
    153 // the old reference used for the invocation will refresh the cache and
    154 // determine if the old reference was stale.  If it was stale (i.e., there
    155 // is a valid new reference that differs from the old one), we want to
    156 // retry the invocation with the new reference; if not, we give up and
    157 // return an error.
    158 //
    159 static addrspc::addrspace_ptr
    160 checkAddrspc(sol::nodeid_t nodeid, addrspc::addrspace_ptr old_obj_p)
    161 {
    162 	// Clear the addrspace object cache entry for the specified node.
    163 	addrspace_mutex.lock();
    164 	addrspaceCache_v[nodeid] = addrspc::addrspace::_nil();
    165 	addrspace_mutex.unlock();
    166 
    167 	// Get new reference from name server and cache it.
    168 	addrspc::addrspace_ptr	new_obj_p = getAddrspc(nodeid);
    169 
    170 	// Compare old and new references.
    171 	if (!CORBA::is_nil(new_obj_p) && new_obj_p->_equiv(old_obj_p)) {
    172 		//
    173 		// Old and new references are the same.
    174 		// Drop new reference and return nil.
    175 		//
    176 		CORBA::release(new_obj_p);
    177 		return (addrspc::addrspace::_nil());
    178 	} else {
    179 		//
    180 		// Either we got a different reference or a nil one.  Return it.
    181 		// getAddrspc has already duplicated it if it's non-nil.
    182 		//
    183 		return (new_obj_p);
    184 	}
    185 }
    186 
    187 static int	mc_copyin(const void *, void *, size_t);
    188 static int	mc_xcopyin(const void *, void *, size_t);
    189 static int	mc_copyout(const void *, void *, size_t);
    190 static int	mc_xcopyout(const void *, void *, size_t);
    191 static int	mc_copyinstr(const char *, char *, size_t, size_t *);
    192 static int	mc_copyoutstr(const char *, char *, size_t, size_t *);
    193 static int	mc_fuword8(const void *, uint8_t *);
    194 static int	mc_fuiword8(const void *, uint8_t *);
    195 static int	mc_fuiword32(const void *, uint32_t *);
    196 static int	mc_suiword8(void *, uint8_t);
    197 static int	mc_suiword32(void *, uint32_t);
    198 static int	mc_fuword16(const void *, uint16_t *);
    199 static int	mc_fuword32(const void *, uint32_t *);
    200 static int	mc_fuword64(const void *, uint64_t *);
    201 static int	mc_suword8(void *, uint8_t);
    202 static int	mc_suword16(void *, uint16_t);
    203 static int	mc_suword32(void *, uint32_t);
    204 static int	mc_suword64(void *, uint64_t);
    205 
    206 static struct copyops mc_copyops = {
    207 	mc_copyin,
    208 	mc_xcopyin,
    209 	mc_copyout,
    210 	mc_xcopyout,
    211 	mc_copyinstr,
    212 	mc_copyoutstr,
    213 	mc_fuword8,
    214 #if SOL_VERSION < __s10
    215 	mc_fuiword8,
    216 #endif
    217 	mc_fuword16,
    218 	mc_fuword32,
    219 #if SOL_VERSION < __s10
    220 	mc_fuiword32,
    221 #endif
    222 	mc_fuword64,
    223 	mc_suword8,
    224 #if SOL_VERSION < __s10
    225 	mc_suiword8,
    226 #endif
    227 	mc_suword16,
    228 	mc_suword32,
    229 #if SOL_VERSION < __s10
    230 	mc_suiword32,
    231 #endif
    232 	mc_suword64,
    233 	default_physio
    234 };
    235 
    236 //
    237 // Copy data in from user address to kernel address.
    238 // 'cn' is the count of the number of bytes to copy.
    239 //
    240 static int
    241 mc_xcopyin(const void *uaddr, void *kaddr, size_t cn)
    242 {
    243 	caddr_t userbuf = (caddr_t)uaddr;
    244 	caddr_t driverbuf = (caddr_t)kaddr;
    245 
    246 	// We have been called by the xcopyin code to perform the
    247 	// network op.
    248 
    249 	copy_args *args = copy::getcontext();
    250 	ASSERT(args != (copy_args *)-1);
    251 	ASSERT(args != (copy_args *)-2);
    252 	ASSERT(args != NULL);
    253 
    254 	if (args->pid == 0) {
    255 		if (args->nodeid == orb_conf::node_number()) {
    256 			//
    257 			// A pid of zero is used to replay ioctls from the
    258 			// local kernel during a switchover/failover.  At this
    259 			// point, the data is already in the kernel and a
    260 			// bcopy is in order.
    261 			//
    262 			bcopy(uaddr, kaddr, cn);
    263 			return (0);
    264 		} else {
    265 			// This path (kernel making an ioctl call on a remote
    266 			// node) has no callers yet, and it is unclear whether
    267 			// we need to implement it.
    268 			// For now, we have a panic in here to catch any
    269 			// callers.
    270 			//
    271 
    272 			//
    273 			// SCMSGS
    274 			// @explanation
    275 			// The system does not support copy operations between
    276 			// the kernel and a user process when the specified
    277 			// node is not the local node.
    278 			// @user_action
    279 			// Contact your authorized Sun service provider to
    280 			// determine whether a workaround or patch is
    281 			// available.
    282 			//
    283 			(void) orb_syslog_msgp->log(SC_SYSLOG_PANIC, MESSAGE,
    284 			    "clcomm: Invalid copyargs: node %d pid %d",
    285 			    args->nodeid, args->pid);
    286 		}
    287 	}
    288 
    289 	addrspc::addrspace_var addrspace_obj = getAddrspc(args->nodeid);
    290 	if (CORBA::is_nil(addrspace_obj)) {
    291 		return (ENODEV);
    292 	}
    293 	Environment e;
    294 
    295 	if (cn == 0) {
    296 		return (0);
    297 	}
    298 	addrspc::ioctldata_t *data_ptr;
    299 	//
    300 	// We invalidate the context to make sure we don't end up
    301 	// in here multiple times somehow.
    302 	//
    303 #ifdef DEBUG
    304 	copy::setcontext((copy_args *)-2);
    305 #endif
    306 	while (cn != 0) {
    307 		sol::error_t err;
    308 
    309 		// Get the data from the remote process into data_ptr.
    310 		err = addrspace_obj->copyin(args->pid,
    311 		    (sol::uintptr_t)(long)userbuf,
    312 		    (sol::size_t)xfersize(cn), data_ptr, e);
    313 		if (e.exception()) {
    314 			//
    315 			// There are no user exceptions defined for
    316 			// this interface, so this is a system
    317 			// exception (e.g., the node is down or has
    318 			// rebooted).  Since we're caching the
    319 			// addrspace reference, we may have a stale
    320 			// reference and need a new one.
    321 			//
    322 			ASSERT(e.sys_exception() != NULL);
    323 			e.clear();
    324 
    325 			// releases old reference in addrspace_obj
    326 			addrspace_obj = checkAddrspc(args->nodeid,
    327 			    addrspace_obj);
    328 			if (CORBA::is_nil(addrspace_obj)) {
    329 				// No new reference.
    330 #ifdef DEBUG
    331 				copy::setcontext(args);
    332 #endif
    333 				return (ENODEV);
    334 			} else {
    335 				//
    336 				// Got a new reference different from
    337 				// the old one.
    338 				//
    339 				continue;
    340 			}
    341 		}
    342 		if (err != 0) {
    343 			delete data_ptr;
    344 #ifdef DEBUG
    345 			copy::setcontext(args);
    346 #endif
    347 			return (EFAULT); // difference xcopy/copy
    348 		}
    349 		ASSERT(data_ptr->length() > 0);
    350 		ASSERT(data_ptr->length() <= cn);
    351 		// Copy the data from data_ptr to the kernel buffer.
    352 		bcopy(data_ptr->buffer(), driverbuf,
    353 				(size_t)data_ptr->length());
    354 		cn -= data_ptr->length();
    355 		driverbuf += data_ptr->length();
    356 		userbuf += data_ptr->length();
    357 		//
    358 		// Copyin created data_ptr; we no longer want it
    359 		// since the data has been copied to driverbuf.
    360 		//
    361 		delete data_ptr;
    362 	}
    363 #ifdef DEBUG
    364 	copy::setcontext(args);
    365 #endif
    366 	return (0);
    367 }
    368 
    369 //
    370 // Copy data out from kernel address to user address.
    371 // 'cn' is the count of the number of bytes to copy.
    372 //
    373 static int
    374 mc_xcopyout(const void *kaddr, void *uaddr, size_t cn)
    375 {
    376 	caddr_t driverbuf = (caddr_t)kaddr;
    377 	caddr_t userbuf = (caddr_t)uaddr;
    378 
    379 	// We have been called by the xcopyout code to perform the
    380 	// network op.
    381 
    382 	copy_args *args = copy::getcontext();
    383 	ASSERT(args != (copy_args *)-1);
    384 	ASSERT(args != (copy_args *)-2);
    385 	ASSERT(args != NULL);
    386 
    387 	if (args->pid == 0) {
    388 		if (args->nodeid == orb_conf::node_number()) {
    389 			//
    390 			// A pid of zero is used to replay ioctls from the
    391 			// local kernel during a switchover/failover.  At this
    392 			// point, the data is already in the kernel and a
    393 			// bcopy is in order.
    394 			//
    395 			bcopy(kaddr, uaddr, cn);
    396 			return (0);
    397 		} else {
    398 			// This path (kernel making an ioctl call on a remote
    399 			// node) has no callers yet, and it is unclear whether
    400 			// we need to implement it.
    401 			// For now, we have a panic in here to catch any
    402 			// callers.
    403 			//
    404 			(void) orb_syslog_msgp->log(SC_SYSLOG_PANIC, MESSAGE,
    405 			    "clcomm: Invalid copyargs: node %d pid %d",
    406 			    args->nodeid, args->pid);
    407 		}
    408 	}
    409 
    410 	if (cn == 0) {
    411 		return (0); // check before we create data object
    412 		//
    413 		// Note, in sun4m Solaris, copyout(..,..,0) fails
    414 		// while copyout(..,..,-1) succeeds, while
    415 		// copyin(bad addr,...,0) gets EFAULT.  This is all
    416 		// basically random behavior based on the details
    417 		// of the assembly code, so let's just succeed.
    418 		// If we want to be bug-for-bug compatible, it
    419 		// will be very messy.
    420 		//
    421 	}
    422 	addrspc::addrspace_var addrspace_obj = getAddrspc(args->nodeid);
    423 	if (CORBA::is_nil(addrspace_obj)) {
    424 		return (ENODEV);
    425 	}
    426 	Environment e;
    427 
    428 	ASSERT(xfersize(cn) <= UINT_MAX);	// for casts below
    429 	addrspc::ioctldata_t *data_ptr = new addrspc::ioctldata_t(
    430 				(uint_t)xfersize(cn), (uint_t)xfersize(cn));
    431 
    432 	while (cn != 0) {
    433 		sol::error_t err;
    434 		size_t xsize = xfersize(cn);
    435 		data_ptr->length((uint_t)xsize);
    436 		// Copy the data into the data_ptr buffer.
    437 		bcopy(driverbuf, data_ptr->buffer(), xsize);
    438 		ASSERT(data_ptr->length() <= data_ptr->maximum());
    439 		// Send the data out to the remote process.
    440 		err = addrspace_obj->copyout(args->pid,
    441 		    (sol::uintptr_t)(long)userbuf,
    442 		    (sol::size_t)xsize, *data_ptr, e);
    443 		if (e.exception()) {
    444 			//
    445 			// There are no user exceptions defined for
    446 			// this interface, so this is a system
    447 			// exception (e.g., the node is down or has
    448 			// rebooted).  Since we're caching the
    449 			// addrspace reference, we may have a stale
    450 			// reference and need a new one.
    451 			//
    452 			ASSERT(e.sys_exception() != NULL);
    453 			e.clear();
    454 
    455 			// Releases old reference in addrspace_obj.
    456 			addrspace_obj = checkAddrspc(args->nodeid,
    457 			    addrspace_obj);
    458 			if (CORBA::is_nil(addrspace_obj)) {
    459 				// No new reference.
    460 				delete data_ptr;
    461 				return (ENODEV);
    462 			} else {
    463 				//
    464 				// Got a new reference different from
    465 				// the old one.
    466 				//
    467 				continue;
    468 			}
    469 		}
    470 		if (err != 0) {
    471 			delete data_ptr;
    472 			return (EFAULT);
    473 		}
    474 		ASSERT(data_ptr->length() > 0);
    475 		ASSERT(data_ptr->length() <= cn);
    476 		cn -= data_ptr->length();
    477 		driverbuf += data_ptr->length();
    478 		userbuf += data_ptr->length();
    479 	}
    480 	// Done with data_ptr.
    481 	delete data_ptr;
    482 	return (0);
    483 }
    484 
    485 //
    486 // mc_copyin is like mc_xcopyin but it return -1 instead of an errno.
    487 //
    488 static int
    489 mc_copyin(const void *uaddr, void *kaddr, size_t cn)
    490 {
    491 	return (mc_xcopyin(uaddr, kaddr, cn) ? -1 : 0);
    492 }
    493 
    494 static int
    495 mc_copyout(const void *kaddr, void *uaddr, size_t cn)
    496 {
    497 	return (mc_xcopyout(kaddr, uaddr, cn) ? -1 : 0);
    498 }
    499 
    500 //
    501 // Copy string in from user address to kernel address driverbuf.  'maxlength'
    502 // is the maximum number of bytes to copy.  'lencopied' returns the number
    503 // of bytes actually copied, including the terminating 0.  If the string
    504 // doesn't fit in maxlength bytes, return ENAMETOOLONG.  If we can't find an
    505 // addrspace object, things are bad, but we'll return ENODEV.
    506 //
    507 static int
    508 mc_copyinstr(const char *uaddr, char *kaddr, size_t maxlength,
    509 	size_t *lencopied)
    510 {
    511 	// We have been called by the copyinstr code to perform the
    512 	// network op.
    513 
    514 	int status;
    515 	copy_args *args = copy::getcontext();
    516 	ASSERT(args != (copy_args *)-1);
    517 	ASSERT(args != (copy_args *)-2);
    518 	ASSERT(args != NULL);
    519 
    520 	Environment e;
    521 	CORBA::Exception *ex;
    522 	if (maxlength == 0) {
    523 		return (EFAULT);
    524 	}
    525 
    526 	if (args->pid == 0) {
    527 		if (args->nodeid == orb_conf::node_number()) {
    528 			//
    529 			// A pid of zero is used to replay ioctls from the
    530 			// local kernel during a switchover/failover.  At this
    531 			// point, the data is already in the kernel and a
    532 			// bcopy is in order.
    533 			//
    534 			size_t len = strlen(uaddr) + 1;
    535 			if (maxlength < len) {
    536 				return (ENAMETOOLONG);
    537 			}
    538 			bcopy(uaddr, kaddr, len);
    539 			return (0);
    540 		} else {
    541 			//
    542 			// This path (kernel making an ioctl call on a remote
    543 			// node) has no callers yet, and it is unclear whether
    544 			// we need to implement it.
    545 			// For now, we have a panic in here to catch any
    546 			// callers.
    547 			//
    548 			(void) orb_syslog_msgp->log(SC_SYSLOG_PANIC, MESSAGE,
    549 			    "clcomm: Invalid copyargs: node %d pid %d",
    550 			    args->nodeid, args->pid);
    551 		}
    552 	}
    553 
    554 	addrspc::addrspace_var addrspace_obj = getAddrspc(args->nodeid);
    555 	if (CORBA::is_nil(addrspace_obj)) {
    556 		return (ENODEV);
    557 	}
    558 	addrspc::ioctldata_t *data_ptr;
    559 	if (maxlength > xfersize(maxlength)) {
    560 		// XXX it should handle long strings.
    561 
    562 		//
    563 		// SCMSGS
    564 		// @explanation
    565 		// The system attempted to copy a string from user space to
    566 		// the kernel. The maximum string length exceeds length limit.
    567 		// @user_action
    568 		// Contact your authorized Sun service provider to determine
    569 		// whether a workaround or patch is available.
    570 		//
    571 		(void) orb_syslog_msgp->log(SC_SYSLOG_PANIC, MESSAGE,
    572 		    "clcomm: copyinstr: max string length %d too long",
    573 		    maxlength);
    574 		// maxlength = xfersize(maxlength);
    575 	}
    576 	do {
    577 		status = addrspace_obj->copyinstr(args->pid,
    578 		    (sol::uintptr_t)(long)uaddr, (sol::size_t)maxlength,
    579 		    data_ptr, e);
    580 		if ((ex = e.exception()) != NULL) {
    581 			//
    582 			// There are no user exceptions defined for
    583 			// this interface, so this is a system
    584 			// exception (e.g., the node is down or has
    585 			// rebooted).  Since we're caching the
    586 			// addrspace reference, we may have a stale
    587 			// reference and need a new one.
    588 			//
    589 			ASSERT(e.sys_exception() != NULL);
    590 			e.clear();
    591 
    592 			// Releases old reference in addrspace_obj.
    593 			addrspace_obj = checkAddrspc(args->nodeid,
    594 			    addrspace_obj);
    595 			if (CORBA::is_nil(addrspace_obj)) {
    596 				// No new reference.
    597 				return (ENODEV);
    598 			}
    599 			//
    600 			// Got a new reference different from
    601 			// the old one.  Fall through and repeat
    602 			// the loop.
    603 			//
    604 		}
    605 	} while (ex != NULL);
    606 
    607 	if (status == EFAULT || status == ENAMETOOLONG) {
    608 		delete data_ptr;
    609 		return (status);
    610 	}
    611 	if (lencopied != NULL) {
    612 		*lencopied = data_ptr->length();
    613 	}
    614 
    615 	bcopy(data_ptr->buffer(), kaddr, (size_t)data_ptr->length());
    616 	delete data_ptr;
    617 	return (status);
    618 }
    619 
    620 static int
    621 mc_copyoutstr(const char *kaddr, char *uaddr,
    622 	size_t maxlength, size_t *lencopied)
    623 {
    624 	// We have been called by the copyoutstr code to perform the
    625 	// network op.
    626 
    627 	int status = 0, status2;
    628 
    629 	if (maxlength == 0) {
    630 		return (EFAULT);
    631 	}
    632 	size_t len;
    633 	for (len = 1; kaddr[len-1] != '\0'; len++) {
    634 		if (len >= maxlength) {
    635 			status = ENAMETOOLONG;
    636 			break;
    637 		}
    638 	}
    639 	//
    640 	// Invariant: len <= maxlength and kaddr[len - 1] == '\0'
    641 	// or len == maxlength, status = ENAMETOOLONG
    642 	// To preserve Solaris semantics, we copy out maxlength
    643 	// bytes even if we have ENAMETOOLONG
    644 	//
    645 	if (lencopied != 0) {
    646 		*lencopied = len;
    647 	}
    648 	status2 = mc_copyout(kaddr, uaddr, len);
    649 	if (status2 != 0) {
    650 		return (EFAULT);
    651 	} else {
    652 		return (status);
    653 	}
    654 }
    655 
    656 static int
    657 mc_fuword8(const void *uaddr, uint8_t *kaddr)
    658 {
    659 	return (mc_xcopyin(uaddr, kaddr, (size_t)1) ? -1 : 0);
    660 }
    661 
    662 static int
    663 mc_fuiword8(const void *uaddr, uint8_t *kaddr)
    664 {
    665 	return (mc_xcopyin(uaddr, kaddr, (size_t)1) ? -1 : 0);
    666 }
    667 
    668 static int
    669 mc_fuword16(const void *uaddr, uint16_t *kaddr)
    670 {
    671 	return (mc_xcopyin(uaddr, kaddr, (size_t)2) ? -1 : 0);
    672 }
    673 
    674 static int
    675 mc_fuword32(const void *uaddr, uint32_t *kaddr)
    676 {
    677 	return (mc_xcopyin(uaddr, kaddr, (size_t)4) ? -1 : 0);
    678 }
    679 
    680 static int
    681 mc_fuiword32(const void *uaddr, uint32_t *kaddr)
    682 {
    683 	return (mc_xcopyin(uaddr, kaddr, (size_t)4) ? -1 : 0);
    684 }
    685 
    686 static int
    687 mc_fuword64(const void *uaddr, uint64_t *kaddr)
    688 {
    689 	return (mc_xcopyin(uaddr, kaddr, (size_t)8) ? -1 : 0);
    690 }
    691 
    692 static int
    693 mc_suword8(void *uaddr, uint8_t val)
    694 {
    695 	return (mc_xcopyout(&val, uaddr, sizeof (val)) ? -1 : 0);
    696 }
    697 
    698 static int
    699 mc_suiword8(void *uaddr, uint8_t val)
    700 {
    701 	return (mc_xcopyout(&val, uaddr, sizeof (val)) ? -1 : 0);
    702 }
    703 
    704 static int
    705 mc_suword16(void *uaddr, uint16_t val)
    706 {
    707 	return (mc_xcopyout(&val, uaddr, sizeof (val)) ? -1 : 0);
    708 }
    709 
    710 static int
    711 mc_suword32(void *uaddr, uint32_t val)
    712 {
    713 	return (mc_xcopyout(&val, uaddr, sizeof (val)) ? -1 : 0);
    714 }
    715 
    716 static int
    717 mc_suiword32(void *uaddr, uint32_t val)
    718 {
    719 	return (mc_xcopyout(&val, uaddr, sizeof (val)) ? -1 : 0);
    720 }
    721 
    722 static int
    723 mc_suword64(void *uaddr, uint64_t val)
    724 {
    725 	return (mc_xcopyout(&val, uaddr, sizeof (val)) ? -1 : 0);
    726 }
    727 
    728 //
    729 // Initialize a transport server thread to use the mc functions for
    730 // copyin/out.
    731 //
    732 extern "C" void
    733 set_server_copyops()
    734 {
    735 	install_copyops(curthread, &mc_copyops);
    736 }
    737