xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs_dump.c (revision cf98b944)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21*cf98b944SMarcel Telka 
22*cf98b944SMarcel Telka /*
23*cf98b944SMarcel Telka  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
24*cf98b944SMarcel Telka  */
25*cf98b944SMarcel Telka 
267c478bd9Sstevel@tonic-gate /*
2709b0d01cSGary Mills  * Copyright 2014 Gary Mills
28d3d50737SRafael Vanoni  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
297c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * Dump memory to NFS swap file after a panic.
347c478bd9Sstevel@tonic-gate  * We have no timeouts, context switches, etc.
357c478bd9Sstevel@tonic-gate  */
36d3d50737SRafael Vanoni 
377c478bd9Sstevel@tonic-gate #include <rpc/types.h>
387c478bd9Sstevel@tonic-gate #include <sys/param.h>
397c478bd9Sstevel@tonic-gate #include <sys/errno.h>
407c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
417c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
427c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
437c478bd9Sstevel@tonic-gate #include <rpc/auth.h>
447c478bd9Sstevel@tonic-gate #include <rpc/xdr.h>
457c478bd9Sstevel@tonic-gate #include <rpc/rpc_msg.h>
467c478bd9Sstevel@tonic-gate #include <rpc/clnt.h>
477c478bd9Sstevel@tonic-gate #include <netinet/in.h>
487c478bd9Sstevel@tonic-gate #include <sys/tiuser.h>
497c478bd9Sstevel@tonic-gate #include <nfs/nfs_clnt.h>
507c478bd9Sstevel@tonic-gate #include <sys/t_kuser.h>
517c478bd9Sstevel@tonic-gate #include <sys/file.h>
527c478bd9Sstevel@tonic-gate #include <sys/netconfig.h>
537c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
547c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
557c478bd9Sstevel@tonic-gate #include <sys/thread.h>
567c478bd9Sstevel@tonic-gate #include <sys/cred.h>
577c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
587c478bd9Sstevel@tonic-gate #include <nfs/rnode.h>
597c478bd9Sstevel@tonic-gate #include <sys/varargs.h>
607c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
617c478bd9Sstevel@tonic-gate #include <sys/systm.h>
627c478bd9Sstevel@tonic-gate #include <sys/dumphdr.h>
637c478bd9Sstevel@tonic-gate #include <sys/debug.h>
647c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate #define	TIMEOUT		(2 * hz)
677c478bd9Sstevel@tonic-gate #define	RETRIES		(5)
687c478bd9Sstevel@tonic-gate #define	HDR_SIZE	(256)
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate static struct knetconfig	nfsdump_cf;
717c478bd9Sstevel@tonic-gate static struct netbuf		nfsdump_addr;
727c478bd9Sstevel@tonic-gate static fhandle_t		nfsdump_fhandle2;
737c478bd9Sstevel@tonic-gate static nfs_fh3			nfsdump_fhandle3;
747c478bd9Sstevel@tonic-gate static int			nfsdump_maxcount;
757c478bd9Sstevel@tonic-gate static rpcvers_t		nfsdump_version;
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate /*
787c478bd9Sstevel@tonic-gate  * nonzero dumplog enables nd_log messages
797c478bd9Sstevel@tonic-gate  */
807c478bd9Sstevel@tonic-gate static int 	dumplog = 0;
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate static int	nd_init(vnode_t *, TIUSER **);
837c478bd9Sstevel@tonic-gate static int	nd_poll(TIUSER *, int, int *);
847c478bd9Sstevel@tonic-gate static int	nd_send_data(TIUSER *, caddr_t, int, XDR *, uint32_t *);
857c478bd9Sstevel@tonic-gate static int	nd_get_reply(TIUSER *, XDR *, uint32_t, int *);
867c478bd9Sstevel@tonic-gate static int	nd_auth_marshall(XDR *);
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate static void nd_log(const char *, ...) __KPRINTFLIKE(1);
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
917c478bd9Sstevel@tonic-gate static void
nd_log(const char * fmt,...)927c478bd9Sstevel@tonic-gate nd_log(const char *fmt, ...)
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate 	if (dumplog) {
957c478bd9Sstevel@tonic-gate 		va_list adx;
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 		va_start(adx, fmt);
987c478bd9Sstevel@tonic-gate 		vprintf(fmt, adx);
997c478bd9Sstevel@tonic-gate 		va_end(adx);
1007c478bd9Sstevel@tonic-gate 	}
1017c478bd9Sstevel@tonic-gate }
1027c478bd9Sstevel@tonic-gate 
103da6c28aaSamw /* ARGSUSED */
1047c478bd9Sstevel@tonic-gate int
nfs_dump(vnode_t * dumpvp,caddr_t addr,offset_t bn,offset_t count,caller_context_t * ct)105d7334e51Srm15945 nfs_dump(vnode_t *dumpvp, caddr_t addr, offset_t bn, offset_t count,
106d7334e51Srm15945     caller_context_t *ct)
1077c478bd9Sstevel@tonic-gate {
1087c478bd9Sstevel@tonic-gate 	static TIUSER	*tiptr;
1097c478bd9Sstevel@tonic-gate 	XDR		xdrs;
1107c478bd9Sstevel@tonic-gate 	int		reply;
1117c478bd9Sstevel@tonic-gate 	int		badmsg;
1127c478bd9Sstevel@tonic-gate 	uint32_t	call_xid;
1137c478bd9Sstevel@tonic-gate 	int		retry = 0;
1147c478bd9Sstevel@tonic-gate 	int		error;
1157c478bd9Sstevel@tonic-gate 	int		i;
1167c478bd9Sstevel@tonic-gate 
117d7334e51Srm15945 	nd_log("nfs_dump: addr=%p bn=%lld count=%lld\n",
118d7334e51Srm15945 	    (void *)addr, bn, count);
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	if (error = nd_init(dumpvp, &tiptr))
1217c478bd9Sstevel@tonic-gate 		return (error);
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i += ptod(1), addr += ptob(1)) {
1247c478bd9Sstevel@tonic-gate 		do {
1257c478bd9Sstevel@tonic-gate 			error = nd_send_data(tiptr, addr, (int)dbtob(bn + i),
1267c478bd9Sstevel@tonic-gate 			    &xdrs, &call_xid);
1277c478bd9Sstevel@tonic-gate 			if (error)
1287c478bd9Sstevel@tonic-gate 				return (error);
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 			do {
1317c478bd9Sstevel@tonic-gate 				if (error = nd_poll(tiptr, retry, &reply))
1327c478bd9Sstevel@tonic-gate 					return (error);
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 				if (!reply) {
1357c478bd9Sstevel@tonic-gate 					retry++;
1367c478bd9Sstevel@tonic-gate 					break;
1377c478bd9Sstevel@tonic-gate 				}
1387c478bd9Sstevel@tonic-gate 				retry = 0;
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 				error = nd_get_reply(tiptr, &xdrs, call_xid,
1417c478bd9Sstevel@tonic-gate 				    &badmsg);
1427c478bd9Sstevel@tonic-gate 				if (error)
1437c478bd9Sstevel@tonic-gate 					return (error);
1447c478bd9Sstevel@tonic-gate 			} while (badmsg);
1457c478bd9Sstevel@tonic-gate 		} while (retry);
1467c478bd9Sstevel@tonic-gate 	}
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	return (0);
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate static int
nd_init(vnode_t * dumpvp,TIUSER ** tiptr)1527c478bd9Sstevel@tonic-gate nd_init(vnode_t *dumpvp, TIUSER **tiptr)
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate 	int 		error;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	if (*tiptr)
1577c478bd9Sstevel@tonic-gate 		return (0);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	/*
1607c478bd9Sstevel@tonic-gate 	 * If dump info hasn't yet been initialized (because dump
1617c478bd9Sstevel@tonic-gate 	 * device was chosen at user-level, rather than at boot time
1627c478bd9Sstevel@tonic-gate 	 * in nfs_swapvp) fill it in now.
1637c478bd9Sstevel@tonic-gate 	 */
1647c478bd9Sstevel@tonic-gate 	if (nfsdump_maxcount == 0) {
1657c478bd9Sstevel@tonic-gate 		nfsdump_version = VTOMI(dumpvp)->mi_vers;
1667c478bd9Sstevel@tonic-gate 		switch (nfsdump_version) {
1677c478bd9Sstevel@tonic-gate 		case NFS_VERSION:
1687c478bd9Sstevel@tonic-gate 			nfsdump_fhandle2 = *VTOFH(dumpvp);
1697c478bd9Sstevel@tonic-gate 			break;
1707c478bd9Sstevel@tonic-gate 		case NFS_V3:
1717c478bd9Sstevel@tonic-gate 			nfsdump_fhandle3 = *VTOFH3(dumpvp);
1727c478bd9Sstevel@tonic-gate 			break;
1737c478bd9Sstevel@tonic-gate 		default:
1747c478bd9Sstevel@tonic-gate 			return (EIO);
1757c478bd9Sstevel@tonic-gate 		}
1767c478bd9Sstevel@tonic-gate 		nfsdump_maxcount = (int)dumpvp_size;
1777c478bd9Sstevel@tonic-gate 		nfsdump_addr = VTOMI(dumpvp)->mi_curr_serv->sv_addr;
1787c478bd9Sstevel@tonic-gate 		nfsdump_cf = *(VTOMI(dumpvp)->mi_curr_serv->sv_knconf);
1797c478bd9Sstevel@tonic-gate 		if (nfsdump_cf.knc_semantics != NC_TPI_CLTS) {
1807c478bd9Sstevel@tonic-gate 			int v6 = 1;
1817c478bd9Sstevel@tonic-gate 			nd_log("nfs_dump: not connectionless!\n");
1827c478bd9Sstevel@tonic-gate 			if ((strcmp(nfsdump_cf.knc_protofmly, NC_INET) == 0) ||
1837c478bd9Sstevel@tonic-gate 			    ((v6 = strcmp(nfsdump_cf.knc_protofmly, NC_INET6))\
1847c478bd9Sstevel@tonic-gate 			    == 0)) {
1857c478bd9Sstevel@tonic-gate 				major_t clone_maj;
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 				nfsdump_cf.knc_proto = NC_UDP;
1887c478bd9Sstevel@tonic-gate 				nfsdump_cf.knc_semantics = NC_TPI_CLTS;
1897c478bd9Sstevel@tonic-gate 				nd_log("nfs_dump: grabbing UDP major number\n");
1907c478bd9Sstevel@tonic-gate 				clone_maj = ddi_name_to_major("clone");
1917c478bd9Sstevel@tonic-gate 				nd_log("nfs_dump: making UDP device\n");
1927c478bd9Sstevel@tonic-gate 				nfsdump_cf.knc_rdev = makedevice(clone_maj,
1937c478bd9Sstevel@tonic-gate 				    ddi_name_to_major(v6?"udp":"udp6"));
1947c478bd9Sstevel@tonic-gate 			} else {
1957c478bd9Sstevel@tonic-gate 				error = EIO;
1967c478bd9Sstevel@tonic-gate 				nfs_perror(error, "\nnfs_dump: cannot dump over"
1977c478bd9Sstevel@tonic-gate 				    " protocol %s: %m\n", nfsdump_cf.knc_proto);
1987c478bd9Sstevel@tonic-gate 				return (error);
1997c478bd9Sstevel@tonic-gate 			}
2007c478bd9Sstevel@tonic-gate 		}
2017c478bd9Sstevel@tonic-gate 	}
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	nd_log("nfs_dump: calling t_kopen\n");
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	if (error = t_kopen(NULL, nfsdump_cf.knc_rdev,
2067c478bd9Sstevel@tonic-gate 	    FREAD|FWRITE|FNDELAY, tiptr, CRED())) {
2077c478bd9Sstevel@tonic-gate 		nfs_perror(error, "\nnfs_dump: t_kopen failed: %m\n");
2087c478bd9Sstevel@tonic-gate 		return (EIO);
2097c478bd9Sstevel@tonic-gate 	}
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	if ((strcmp(nfsdump_cf.knc_protofmly, NC_INET) == 0) ||
2127c478bd9Sstevel@tonic-gate 	    (strcmp(nfsdump_cf.knc_protofmly, NC_INET6) == 0)) {
2137c478bd9Sstevel@tonic-gate 		nd_log("nfs_dump: calling bindresvport\n");
2147c478bd9Sstevel@tonic-gate 		if (error = bindresvport(*tiptr, NULL, NULL, FALSE)) {
2157c478bd9Sstevel@tonic-gate 			nfs_perror(error,
2167c478bd9Sstevel@tonic-gate 			    "\nnfs_dump: bindresvport failed: %m\n");
2177c478bd9Sstevel@tonic-gate 			return (EIO);
2187c478bd9Sstevel@tonic-gate 		}
2197c478bd9Sstevel@tonic-gate 	} else {
2207c478bd9Sstevel@tonic-gate 		nd_log("nfs_dump: calling t_kbind\n");
2217c478bd9Sstevel@tonic-gate 		if ((error = t_kbind(*tiptr, NULL, NULL)) != 0) {
2227c478bd9Sstevel@tonic-gate 			nfs_perror(error, "\nnfs_dump: t_kbind failed: %m\n");
2237c478bd9Sstevel@tonic-gate 			return (EIO);
2247c478bd9Sstevel@tonic-gate 		}
2257c478bd9Sstevel@tonic-gate 	}
2267c478bd9Sstevel@tonic-gate 	return (0);
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate static int
nd_send_data(TIUSER * tiptr,caddr_t addr,int offset,XDR * xdrp,uint32_t * xidp)2307c478bd9Sstevel@tonic-gate nd_send_data(TIUSER *tiptr, caddr_t addr, int offset, XDR *xdrp, uint32_t *xidp)
2317c478bd9Sstevel@tonic-gate {
2327c478bd9Sstevel@tonic-gate 	static struct rpc_msg		call_msg;
2337c478bd9Sstevel@tonic-gate 	static uchar_t			header[HDR_SIZE];
2347c478bd9Sstevel@tonic-gate 	static struct t_kunitdata	sudata;
2357c478bd9Sstevel@tonic-gate 	static uchar_t			*dumpbuf;
2367c478bd9Sstevel@tonic-gate 	int				procnum;
2377c478bd9Sstevel@tonic-gate 	stable_how			stable = FILE_SYNC;
2387c478bd9Sstevel@tonic-gate 	mblk_t				*mblk_p;
2397c478bd9Sstevel@tonic-gate 	int				error;
2407c478bd9Sstevel@tonic-gate 	int				tsize = ptob(1);
2417c478bd9Sstevel@tonic-gate 	uint64				offset3;
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	if (!dumpbuf) {
2447c478bd9Sstevel@tonic-gate 		call_msg.rm_direction = CALL;
2457c478bd9Sstevel@tonic-gate 		call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
2467c478bd9Sstevel@tonic-gate 		call_msg.rm_call.cb_prog = NFS_PROGRAM;
2477c478bd9Sstevel@tonic-gate 		call_msg.rm_call.cb_vers = nfsdump_version;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 		if (!(dumpbuf = kmem_alloc(ptob(1), KM_NOSLEEP))) {
2507c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "\tnfs_dump: cannot allocate dump buffer");
2517c478bd9Sstevel@tonic-gate 			return (ENOMEM);
2527c478bd9Sstevel@tonic-gate 		}
2537c478bd9Sstevel@tonic-gate 	}
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	nd_log("nfs_dump: calling esballoc for header\n");
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	if (!(mblk_p = esballoc(header, HDR_SIZE, BPRI_HI, &frnop))) {
2587c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "\tnfs_dump: out of mblks");
2597c478bd9Sstevel@tonic-gate 		return (ENOBUFS);
2607c478bd9Sstevel@tonic-gate 	}
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	xdrmem_create(xdrp, (caddr_t)header, HDR_SIZE, XDR_ENCODE);
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	call_msg.rm_xid = alloc_xid();
2657c478bd9Sstevel@tonic-gate 	*xidp = call_msg.rm_xid;
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	if (!xdr_callhdr(xdrp, &call_msg)) {
2687c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "\tnfs_dump: cannot serialize header");
2697c478bd9Sstevel@tonic-gate 		return (EIO);
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	if (nfsdump_maxcount) {
2737c478bd9Sstevel@tonic-gate 		/*
2747c478bd9Sstevel@tonic-gate 		 * Do not extend the dump file if it is also
2757c478bd9Sstevel@tonic-gate 		 * the swap file.
2767c478bd9Sstevel@tonic-gate 		 */
2777c478bd9Sstevel@tonic-gate 		if (offset >= nfsdump_maxcount) {
2787c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "\tnfs_dump: end of file");
2797c478bd9Sstevel@tonic-gate 			return (EIO);
2807c478bd9Sstevel@tonic-gate 		}
2817c478bd9Sstevel@tonic-gate 		if (offset + tsize > nfsdump_maxcount)
2827c478bd9Sstevel@tonic-gate 			tsize = nfsdump_maxcount - offset;
2837c478bd9Sstevel@tonic-gate 	}
2847c478bd9Sstevel@tonic-gate 	switch (nfsdump_version) {
2857c478bd9Sstevel@tonic-gate 	case NFS_VERSION:
2867c478bd9Sstevel@tonic-gate 		procnum = RFS_WRITE;
2877c478bd9Sstevel@tonic-gate 		if (!XDR_PUTINT32(xdrp, (int32_t *)&procnum) ||
2887c478bd9Sstevel@tonic-gate 		    !nd_auth_marshall(xdrp) ||
2897c478bd9Sstevel@tonic-gate 		    !xdr_fhandle(xdrp, &nfsdump_fhandle2) ||
2907c478bd9Sstevel@tonic-gate 			/*
2917c478bd9Sstevel@tonic-gate 			 *  Following four values are:
2927c478bd9Sstevel@tonic-gate 			 *	beginoffset
2937c478bd9Sstevel@tonic-gate 			 *	offset
2947c478bd9Sstevel@tonic-gate 			 *	length
2957c478bd9Sstevel@tonic-gate 			 *	bytes array length
2967c478bd9Sstevel@tonic-gate 			 */
2977c478bd9Sstevel@tonic-gate 		    !XDR_PUTINT32(xdrp, (int32_t *)&offset) ||
2987c478bd9Sstevel@tonic-gate 		    !XDR_PUTINT32(xdrp, (int32_t *)&offset) ||
2997c478bd9Sstevel@tonic-gate 		    !XDR_PUTINT32(xdrp, (int32_t *)&tsize) ||
3007c478bd9Sstevel@tonic-gate 		    !XDR_PUTINT32(xdrp, (int32_t *)&tsize)) {
3017c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "\tnfs_dump: serialization failed");
3027c478bd9Sstevel@tonic-gate 			return (EIO);
3037c478bd9Sstevel@tonic-gate 		}
3047c478bd9Sstevel@tonic-gate 		break;
3057c478bd9Sstevel@tonic-gate 	case NFS_V3:
3067c478bd9Sstevel@tonic-gate 		procnum = NFSPROC3_WRITE;
3077c478bd9Sstevel@tonic-gate 		offset3 = offset;
3087c478bd9Sstevel@tonic-gate 		if (!XDR_PUTINT32(xdrp, (int32_t *)&procnum) ||
3097c478bd9Sstevel@tonic-gate 		    !nd_auth_marshall(xdrp) ||
3107c478bd9Sstevel@tonic-gate 		    !xdr_nfs_fh3(xdrp, &nfsdump_fhandle3) ||
3117c478bd9Sstevel@tonic-gate 			/*
3127c478bd9Sstevel@tonic-gate 			 *  Following four values are:
3137c478bd9Sstevel@tonic-gate 			 *	offset
3147c478bd9Sstevel@tonic-gate 			 *	count
3157c478bd9Sstevel@tonic-gate 			 *	stable
3167c478bd9Sstevel@tonic-gate 			 *	bytes array length
3177c478bd9Sstevel@tonic-gate 			 */
3187c478bd9Sstevel@tonic-gate 		    !xdr_u_longlong_t(xdrp, &offset3) ||
3197c478bd9Sstevel@tonic-gate 		    !XDR_PUTINT32(xdrp, (int32_t *)&tsize) ||
3207c478bd9Sstevel@tonic-gate 		    !XDR_PUTINT32(xdrp, (int32_t *)&stable) ||
3217c478bd9Sstevel@tonic-gate 		    !XDR_PUTINT32(xdrp, (int32_t *)&tsize)) {
3227c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "\tnfs_dump: serialization failed");
3237c478bd9Sstevel@tonic-gate 			return (EIO);
3247c478bd9Sstevel@tonic-gate 		}
3257c478bd9Sstevel@tonic-gate 		break;
3267c478bd9Sstevel@tonic-gate 	default:
3277c478bd9Sstevel@tonic-gate 		return (EIO);
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	bcopy(addr, (caddr_t)dumpbuf, tsize);
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	mblk_p->b_wptr += (int)XDR_GETPOS(xdrp);
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	mblk_p->b_cont = esballoc((uchar_t *)dumpbuf, ptob(1), BPRI_HI, &frnop);
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	if (!mblk_p->b_cont) {
3377c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "\tnfs_dump: out of mblks");
3387c478bd9Sstevel@tonic-gate 		return (ENOBUFS);
3397c478bd9Sstevel@tonic-gate 	}
3407c478bd9Sstevel@tonic-gate 	mblk_p->b_cont->b_wptr += ptob(1);
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	sudata.addr = nfsdump_addr;		/* structure copy */
3437c478bd9Sstevel@tonic-gate 	sudata.udata.buf = (char *)NULL;
3447c478bd9Sstevel@tonic-gate 	sudata.udata.maxlen = 0;
3457c478bd9Sstevel@tonic-gate 	sudata.udata.len = 1;			/* needed for t_ksndudata */
3467c478bd9Sstevel@tonic-gate 	sudata.udata.udata_mp = mblk_p;
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	nd_log("nfs_dump: calling t_ksndudata\n");
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	if (error = t_ksndudata(tiptr, &sudata, (frtn_t *)NULL)) {
3517c478bd9Sstevel@tonic-gate 		nfs_perror(error, "\nnfs_dump: t_ksndudata failed: %m\n");
3527c478bd9Sstevel@tonic-gate 		return (error);
3537c478bd9Sstevel@tonic-gate 	}
3547c478bd9Sstevel@tonic-gate 	return (0);
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate static int
nd_get_reply(TIUSER * tiptr,XDR * xdrp,uint32_t call_xid,int * badmsg)3587c478bd9Sstevel@tonic-gate nd_get_reply(TIUSER *tiptr, XDR *xdrp, uint32_t call_xid, int *badmsg)
3597c478bd9Sstevel@tonic-gate {
3607c478bd9Sstevel@tonic-gate 	static struct rpc_msg		reply_msg;
3617c478bd9Sstevel@tonic-gate 	static struct rpc_err		rpc_err;
3627c478bd9Sstevel@tonic-gate 	static struct nfsattrstat	na;
3637c478bd9Sstevel@tonic-gate 	static struct WRITE3res		wres;
3647c478bd9Sstevel@tonic-gate 	static struct t_kunitdata	rudata;
3657c478bd9Sstevel@tonic-gate 	int				uderr;
3667c478bd9Sstevel@tonic-gate 	int				type;
3677c478bd9Sstevel@tonic-gate 	int				error;
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	*badmsg = 0;
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	rudata.addr.maxlen = 0;
3727c478bd9Sstevel@tonic-gate 	rudata.opt.maxlen = 0;
3737c478bd9Sstevel@tonic-gate 	rudata.udata.udata_mp = (mblk_t *)NULL;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	nd_log("nfs_dump: calling t_krcvudata\n");
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	if (error = t_krcvudata(tiptr, &rudata, &type, &uderr)) {
37809b0d01cSGary Mills 		if (error == EBADMSG) {
37909b0d01cSGary Mills 			cmn_err(CE_WARN, "\tnfs_dump:  received EBADMSG");
38009b0d01cSGary Mills 			*badmsg = 1;
38109b0d01cSGary Mills 			return (0);
38209b0d01cSGary Mills 		}
3837c478bd9Sstevel@tonic-gate 		nfs_perror(error, "\nnfs_dump: t_krcvudata failed: %m\n");
3847c478bd9Sstevel@tonic-gate 		return (EIO);
3857c478bd9Sstevel@tonic-gate 	}
3867c478bd9Sstevel@tonic-gate 	if (type != T_DATA) {
3877c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "\tnfs_dump:  received type %d", type);
3887c478bd9Sstevel@tonic-gate 		*badmsg = 1;
3897c478bd9Sstevel@tonic-gate 		return (0);
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate 	if (!rudata.udata.udata_mp) {
3927c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "\tnfs_dump: null receive");
3937c478bd9Sstevel@tonic-gate 		*badmsg = 1;
3947c478bd9Sstevel@tonic-gate 		return (0);
3957c478bd9Sstevel@tonic-gate 	}
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	/*
3987c478bd9Sstevel@tonic-gate 	 * Decode results.
3997c478bd9Sstevel@tonic-gate 	 */
4007c478bd9Sstevel@tonic-gate 	xdrmblk_init(xdrp, rudata.udata.udata_mp, XDR_DECODE, 0);
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	reply_msg.acpted_rply.ar_verf = _null_auth;
4037c478bd9Sstevel@tonic-gate 	switch (nfsdump_version) {
4047c478bd9Sstevel@tonic-gate 	case NFS_VERSION:
4057c478bd9Sstevel@tonic-gate 		reply_msg.acpted_rply.ar_results.where = (caddr_t)&na;
4067c478bd9Sstevel@tonic-gate 		reply_msg.acpted_rply.ar_results.proc = xdr_attrstat;
4077c478bd9Sstevel@tonic-gate 		break;
4087c478bd9Sstevel@tonic-gate 	case NFS_V3:
4097c478bd9Sstevel@tonic-gate 		reply_msg.acpted_rply.ar_results.where = (caddr_t)&wres;
4107c478bd9Sstevel@tonic-gate 		reply_msg.acpted_rply.ar_results.proc = xdr_WRITE3res;
4117c478bd9Sstevel@tonic-gate 		break;
4127c478bd9Sstevel@tonic-gate 	default:
413*cf98b944SMarcel Telka 		XDR_DESTROY(xdrp);
4147c478bd9Sstevel@tonic-gate 		return (EIO);
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	if (!xdr_replymsg(xdrp, &reply_msg)) {
418*cf98b944SMarcel Telka 		XDR_DESTROY(xdrp);
4197c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "\tnfs_dump: xdr_replymsg failed");
4207c478bd9Sstevel@tonic-gate 		return (EIO);
4217c478bd9Sstevel@tonic-gate 	}
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	if (reply_msg.rm_xid != call_xid) {
424*cf98b944SMarcel Telka 		XDR_DESTROY(xdrp);
4257c478bd9Sstevel@tonic-gate 		*badmsg = 1;
4267c478bd9Sstevel@tonic-gate 		return (0);
4277c478bd9Sstevel@tonic-gate 	}
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	_seterr_reply(&reply_msg, &rpc_err);
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	if (rpc_err.re_status != RPC_SUCCESS) {
432*cf98b944SMarcel Telka 		XDR_DESTROY(xdrp);
4337c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "\tnfs_dump: RPC error %d (%s)",
4347c478bd9Sstevel@tonic-gate 		    rpc_err.re_status, clnt_sperrno(rpc_err.re_status));
4357c478bd9Sstevel@tonic-gate 		return (EIO);
4367c478bd9Sstevel@tonic-gate 	}
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	switch (nfsdump_version) {
4397c478bd9Sstevel@tonic-gate 	case NFS_VERSION:
4407c478bd9Sstevel@tonic-gate 		if (na.ns_status) {
441*cf98b944SMarcel Telka 			XDR_DESTROY(xdrp);
4427c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "\tnfs_dump: status %d", na.ns_status);
4437c478bd9Sstevel@tonic-gate 			return (EIO);
4447c478bd9Sstevel@tonic-gate 		}
4457c478bd9Sstevel@tonic-gate 		break;
4467c478bd9Sstevel@tonic-gate 	case NFS_V3:
4477c478bd9Sstevel@tonic-gate 		if (wres.status != NFS3_OK) {
448*cf98b944SMarcel Telka 			XDR_DESTROY(xdrp);
4497c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "\tnfs_dump: status %d", wres.status);
4507c478bd9Sstevel@tonic-gate 			return (EIO);
4517c478bd9Sstevel@tonic-gate 		}
4527c478bd9Sstevel@tonic-gate 		break;
4537c478bd9Sstevel@tonic-gate 	default:
454*cf98b944SMarcel Telka 		XDR_DESTROY(xdrp);
4557c478bd9Sstevel@tonic-gate 		return (EIO);
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
4597c478bd9Sstevel@tonic-gate 		/* free auth handle */
4607c478bd9Sstevel@tonic-gate 		xdrp->x_op = XDR_FREE;
4617c478bd9Sstevel@tonic-gate 		(void) xdr_opaque_auth(xdrp, &(reply_msg.acpted_rply.ar_verf));
4627c478bd9Sstevel@tonic-gate 	}
4637c478bd9Sstevel@tonic-gate 
464*cf98b944SMarcel Telka 	XDR_DESTROY(xdrp);
465*cf98b944SMarcel Telka 
4667c478bd9Sstevel@tonic-gate 	freemsg(rudata.udata.udata_mp);
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	return (0);
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate static int
nd_poll(TIUSER * tiptr,int retry,int * eventp)4727c478bd9Sstevel@tonic-gate nd_poll(TIUSER *tiptr, int retry, int *eventp)
4737c478bd9Sstevel@tonic-gate {
474d3d50737SRafael Vanoni 	clock_t		start_bolt = ddi_get_lbolt();
4757c478bd9Sstevel@tonic-gate 	clock_t		timout = TIMEOUT * (retry + 1);
4767c478bd9Sstevel@tonic-gate 	int		error;
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	nd_log("nfs_dump: calling t_kspoll\n");
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	*eventp = 0;
4817c478bd9Sstevel@tonic-gate 
482d3d50737SRafael Vanoni 	while (!*eventp && ((ddi_get_lbolt() - start_bolt) < timout)) {
4837c478bd9Sstevel@tonic-gate 		/*
4847c478bd9Sstevel@tonic-gate 		 * Briefly enable interrupts before checking for a reply;
4857c478bd9Sstevel@tonic-gate 		 * the network transports do not yet support do_polled_io.
4867c478bd9Sstevel@tonic-gate 		 */
4877c478bd9Sstevel@tonic-gate 		int s = spl0();
4887c478bd9Sstevel@tonic-gate 		splx(s);
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 		if (error = t_kspoll(tiptr, 0, READWAIT, eventp)) {
4917c478bd9Sstevel@tonic-gate 			nfs_perror(error,
4927c478bd9Sstevel@tonic-gate 			    "\nnfs_dump: t_kspoll failed: %m\n");
4937c478bd9Sstevel@tonic-gate 			return (EIO);
4947c478bd9Sstevel@tonic-gate 		}
4957c478bd9Sstevel@tonic-gate 		runqueues();
4967c478bd9Sstevel@tonic-gate 	}
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	if (retry == RETRIES && !*eventp) {
4997c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "\tnfs_dump: server not responding");
5007c478bd9Sstevel@tonic-gate 		return (EIO);
5017c478bd9Sstevel@tonic-gate 	}
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	return (0);
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate static int
nd_auth_marshall(XDR * xdrp)5077c478bd9Sstevel@tonic-gate nd_auth_marshall(XDR *xdrp)
5087c478bd9Sstevel@tonic-gate {
5097c478bd9Sstevel@tonic-gate 	int credsize;
5107c478bd9Sstevel@tonic-gate 	int32_t *ptr;
5117c478bd9Sstevel@tonic-gate 	int hostnamelen;
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	hostnamelen = (int)strlen(utsname.nodename);
5147c478bd9Sstevel@tonic-gate 	credsize = 4 + 4 + roundup(hostnamelen, 4) + 4 + 4 + 4;
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	ptr = XDR_INLINE(xdrp, 4 + 4 + credsize + 4 + 4);
5177c478bd9Sstevel@tonic-gate 	if (!ptr) {
5187c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "\tnfs_dump: auth_marshall failed");
5197c478bd9Sstevel@tonic-gate 		return (0);
5207c478bd9Sstevel@tonic-gate 	}
5217c478bd9Sstevel@tonic-gate 	/*
5227c478bd9Sstevel@tonic-gate 	 * We can do the fast path.
5237c478bd9Sstevel@tonic-gate 	 */
5247c478bd9Sstevel@tonic-gate 	IXDR_PUT_INT32(ptr, AUTH_UNIX);	/* cred flavor */
5257c478bd9Sstevel@tonic-gate 	IXDR_PUT_INT32(ptr, credsize);	/* cred len */
5267c478bd9Sstevel@tonic-gate 	IXDR_PUT_INT32(ptr, gethrestime_sec());
5277c478bd9Sstevel@tonic-gate 	IXDR_PUT_INT32(ptr, hostnamelen);
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	bcopy(utsname.nodename, ptr, hostnamelen);
5307c478bd9Sstevel@tonic-gate 	ptr += roundup(hostnamelen, 4) / 4;
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	IXDR_PUT_INT32(ptr, 0);		/* uid */
5337c478bd9Sstevel@tonic-gate 	IXDR_PUT_INT32(ptr, 0);		/* gid */
5347c478bd9Sstevel@tonic-gate 	IXDR_PUT_INT32(ptr, 0);		/* gid list length (empty) */
5357c478bd9Sstevel@tonic-gate 	IXDR_PUT_INT32(ptr, AUTH_NULL);	/* verf flavor */
5367c478bd9Sstevel@tonic-gate 	IXDR_PUT_INT32(ptr, 0);		/* verf len */
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	return (1);
5397c478bd9Sstevel@tonic-gate }
540