10f1702c5SYu Xiangning /*
20f1702c5SYu Xiangning  * CDDL HEADER START
30f1702c5SYu Xiangning  *
40f1702c5SYu Xiangning  * The contents of this file are subject to the terms of the
50f1702c5SYu Xiangning  * Common Development and Distribution License (the "License").
60f1702c5SYu Xiangning  * You may not use this file except in compliance with the License.
70f1702c5SYu Xiangning  *
80f1702c5SYu Xiangning  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90f1702c5SYu Xiangning  * or http://www.opensolaris.org/os/licensing.
100f1702c5SYu Xiangning  * See the License for the specific language governing permissions
110f1702c5SYu Xiangning  * and limitations under the License.
120f1702c5SYu Xiangning  *
130f1702c5SYu Xiangning  * When distributing Covered Code, include this CDDL HEADER in each
140f1702c5SYu Xiangning  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150f1702c5SYu Xiangning  * If applicable, add the following below this CDDL HEADER, with the
160f1702c5SYu Xiangning  * fields enclosed by brackets "[]" replaced with your own identifying
170f1702c5SYu Xiangning  * information: Portions Copyright [yyyy] [name of copyright owner]
180f1702c5SYu Xiangning  *
190f1702c5SYu Xiangning  * CDDL HEADER END
200f1702c5SYu Xiangning  */
210f1702c5SYu Xiangning 
220f1702c5SYu Xiangning /*
230f1702c5SYu Xiangning  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240f1702c5SYu Xiangning  * Use is subject to license terms.
250f1702c5SYu Xiangning  */
26ade42b55SSebastien Roy /*
27ade42b55SSebastien Roy  * Copyright (c) 2017 by Delphix. All rights reserved.
28*e7434800SJason King  * Copyright 2021 Racktop Systems, Inc.
29ade42b55SSebastien Roy  */
300f1702c5SYu Xiangning 
310f1702c5SYu Xiangning #include <sys/types.h>
320f1702c5SYu Xiangning #include <sys/t_lock.h>
330f1702c5SYu Xiangning #include <sys/param.h>
340f1702c5SYu Xiangning #include <sys/systm.h>
350f1702c5SYu Xiangning #include <sys/bitmap.h>
360f1702c5SYu Xiangning #include <sys/debug.h>
370f1702c5SYu Xiangning #include <sys/errno.h>
380f1702c5SYu Xiangning #include <sys/strsubr.h>
390f1702c5SYu Xiangning #include <sys/cmn_err.h>
400f1702c5SYu Xiangning #include <sys/sysmacros.h>
410f1702c5SYu Xiangning #include <sys/filio.h>
420f1702c5SYu Xiangning #include <sys/flock.h>
430f1702c5SYu Xiangning #include <sys/stat.h>
440f1702c5SYu Xiangning #include <sys/share.h>
450f1702c5SYu Xiangning 
460f1702c5SYu Xiangning #include <sys/vfs.h>
470f1702c5SYu Xiangning #include <sys/vfs_opreg.h>
480f1702c5SYu Xiangning 
490f1702c5SYu Xiangning #include <sys/sockio.h>
500f1702c5SYu Xiangning #include <sys/socket.h>
510f1702c5SYu Xiangning #include <sys/socketvar.h>
520f1702c5SYu Xiangning #include <sys/strsun.h>
530f1702c5SYu Xiangning 
540f1702c5SYu Xiangning #include <fs/sockfs/sockcommon.h>
550f1702c5SYu Xiangning #include <fs/sockfs/socktpi.h>
560f1702c5SYu Xiangning 
570f1702c5SYu Xiangning /*
580f1702c5SYu Xiangning  * Generic vnode ops
590f1702c5SYu Xiangning  */
600f1702c5SYu Xiangning static int	socket_vop_open(struct vnode **, int, struct cred *,
610f1702c5SYu Xiangning 		    caller_context_t *);
620f1702c5SYu Xiangning static int	socket_vop_close(struct vnode *, int, int, offset_t,
630f1702c5SYu Xiangning 		    struct cred *, caller_context_t *);
640f1702c5SYu Xiangning static int	socket_vop_read(struct vnode *, struct uio *, int,
650f1702c5SYu Xiangning 		    struct cred *, caller_context_t *);
660f1702c5SYu Xiangning static int	socket_vop_write(struct vnode *, struct uio *, int,
670f1702c5SYu Xiangning 		    struct cred *, caller_context_t *);
680f1702c5SYu Xiangning static int	socket_vop_ioctl(struct vnode *, int, intptr_t, int,
690f1702c5SYu Xiangning 		    struct cred *, int32_t *, caller_context_t *);
700f1702c5SYu Xiangning static int	socket_vop_setfl(struct vnode *, int, int, cred_t *,
710f1702c5SYu Xiangning 		    caller_context_t *);
72*e7434800SJason King static int	socket_vop_getattr(struct vnode *, struct vattr *, int,
730f1702c5SYu Xiangning 		    struct cred *, caller_context_t *);
74*e7434800SJason King static int	socket_vop_setattr(struct vnode *, struct vattr *, int,
750f1702c5SYu Xiangning 		    struct cred *, caller_context_t *);
76*e7434800SJason King static int	socket_vop_access(struct vnode *, int, int, struct cred *,
770f1702c5SYu Xiangning 		    caller_context_t *);
78*e7434800SJason King static int	socket_vop_fsync(struct vnode *, int, struct cred *,
790f1702c5SYu Xiangning 		    caller_context_t *);
800f1702c5SYu Xiangning static void	socket_vop_inactive(struct vnode *, struct cred *,
810f1702c5SYu Xiangning 		    caller_context_t *);
82*e7434800SJason King static int	socket_vop_fid(struct vnode *, struct fid *,
830f1702c5SYu Xiangning 		    caller_context_t *);
84*e7434800SJason King static int	socket_vop_seek(struct vnode *, offset_t, offset_t *,
850f1702c5SYu Xiangning 		    caller_context_t *);
860f1702c5SYu Xiangning static int	socket_vop_poll(struct vnode *, short, int, short *,
870f1702c5SYu Xiangning 		    struct pollhead **, caller_context_t *);
880f1702c5SYu Xiangning 
890f1702c5SYu Xiangning extern int	socket_close_internal(struct sonode *, int, cred_t *);
900f1702c5SYu Xiangning extern void	socket_destroy_internal(struct sonode *, cred_t *);
910f1702c5SYu Xiangning 
920f1702c5SYu Xiangning struct vnodeops *socket_vnodeops;
930f1702c5SYu Xiangning const fs_operation_def_t socket_vnodeops_template[] = {
940f1702c5SYu Xiangning 	VOPNAME_OPEN,		{ .vop_open = socket_vop_open },
950f1702c5SYu Xiangning 	VOPNAME_CLOSE,		{ .vop_close = socket_vop_close },
960f1702c5SYu Xiangning 	VOPNAME_READ,		{ .vop_read = socket_vop_read },
970f1702c5SYu Xiangning 	VOPNAME_WRITE,		{ .vop_write = socket_vop_write },
980f1702c5SYu Xiangning 	VOPNAME_IOCTL,		{ .vop_ioctl = socket_vop_ioctl },
990f1702c5SYu Xiangning 	VOPNAME_SETFL,		{ .vop_setfl = socket_vop_setfl },
1000f1702c5SYu Xiangning 	VOPNAME_GETATTR,	{ .vop_getattr = socket_vop_getattr },
1010f1702c5SYu Xiangning 	VOPNAME_SETATTR,	{ .vop_setattr = socket_vop_setattr },
1020f1702c5SYu Xiangning 	VOPNAME_ACCESS,		{ .vop_access = socket_vop_access },
1030f1702c5SYu Xiangning 	VOPNAME_FSYNC,		{ .vop_fsync = socket_vop_fsync },
1040f1702c5SYu Xiangning 	VOPNAME_INACTIVE,	{ .vop_inactive = socket_vop_inactive },
1050f1702c5SYu Xiangning 	VOPNAME_FID,		{ .vop_fid = socket_vop_fid },
1060f1702c5SYu Xiangning 	VOPNAME_SEEK,		{ .vop_seek = socket_vop_seek },
1070f1702c5SYu Xiangning 	VOPNAME_POLL,		{ .vop_poll = socket_vop_poll },
1080f1702c5SYu Xiangning 	VOPNAME_DISPOSE,	{ .error = fs_error },
1090f1702c5SYu Xiangning 	NULL,			NULL
1100f1702c5SYu Xiangning };
1110f1702c5SYu Xiangning 
1120f1702c5SYu Xiangning 
1130f1702c5SYu Xiangning /*
1140f1702c5SYu Xiangning  * generic vnode ops
1150f1702c5SYu Xiangning  */
1160f1702c5SYu Xiangning 
1170f1702c5SYu Xiangning /*ARGSUSED*/
1180f1702c5SYu Xiangning static int
socket_vop_open(struct vnode ** vpp,int flag,struct cred * cr,caller_context_t * ct)1190f1702c5SYu Xiangning socket_vop_open(struct vnode **vpp, int flag, struct cred *cr,
1200f1702c5SYu Xiangning     caller_context_t *ct)
1210f1702c5SYu Xiangning {
1220f1702c5SYu Xiangning 	struct vnode *vp = *vpp;
1230f1702c5SYu Xiangning 	struct sonode *so = VTOSO(vp);
1240f1702c5SYu Xiangning 
1250f1702c5SYu Xiangning 	flag &= ~FCREAT;		/* paranoia */
1260f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
1270f1702c5SYu Xiangning 	so->so_count++;
1280f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
1290f1702c5SYu Xiangning 
1300f1702c5SYu Xiangning 	ASSERT(so->so_count != 0);	/* wraparound */
1310f1702c5SYu Xiangning 	ASSERT(vp->v_type == VSOCK);
1320f1702c5SYu Xiangning 
1330f1702c5SYu Xiangning 	return (0);
1340f1702c5SYu Xiangning }
1350f1702c5SYu Xiangning 
1360f1702c5SYu Xiangning /*ARGSUSED*/
1370f1702c5SYu Xiangning static int
socket_vop_close(struct vnode * vp,int flag,int count,offset_t offset,struct cred * cr,caller_context_t * ct)1380f1702c5SYu Xiangning socket_vop_close(struct vnode *vp, int flag, int count, offset_t offset,
1390f1702c5SYu Xiangning     struct cred *cr, caller_context_t *ct)
1400f1702c5SYu Xiangning {
1410f1702c5SYu Xiangning 	struct sonode *so;
1420f1702c5SYu Xiangning 	int error = 0;
1430f1702c5SYu Xiangning 
1440f1702c5SYu Xiangning 	so = VTOSO(vp);
1450f1702c5SYu Xiangning 	ASSERT(vp->v_type == VSOCK);
1460f1702c5SYu Xiangning 
1470f1702c5SYu Xiangning 	cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
1480f1702c5SYu Xiangning 	cleanshares(vp, ttoproc(curthread)->p_pid);
1490f1702c5SYu Xiangning 
1500f1702c5SYu Xiangning 	if (vp->v_stream)
1510f1702c5SYu Xiangning 		strclean(vp);
1520f1702c5SYu Xiangning 
1530f1702c5SYu Xiangning 	if (count > 1) {
1540f1702c5SYu Xiangning 		dprint(2, ("socket_vop_close: count %d\n", count));
1550f1702c5SYu Xiangning 		return (0);
1560f1702c5SYu Xiangning 	}
1570f1702c5SYu Xiangning 
1580f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
1590f1702c5SYu Xiangning 	if (--so->so_count == 0) {
1600f1702c5SYu Xiangning 		/*
1610f1702c5SYu Xiangning 		 * Initiate connection shutdown.
1620f1702c5SYu Xiangning 		 */
1630f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
1640f1702c5SYu Xiangning 		error = socket_close_internal(so, flag, cr);
1650f1702c5SYu Xiangning 	} else {
1660f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
1670f1702c5SYu Xiangning 	}
1680f1702c5SYu Xiangning 
1690f1702c5SYu Xiangning 	return (error);
1700f1702c5SYu Xiangning }
1710f1702c5SYu Xiangning 
1720f1702c5SYu Xiangning /*ARGSUSED2*/
1730f1702c5SYu Xiangning static int
socket_vop_read(struct vnode * vp,struct uio * uiop,int ioflag,struct cred * cr,caller_context_t * ct)1740f1702c5SYu Xiangning socket_vop_read(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cr,
1750f1702c5SYu Xiangning     caller_context_t *ct)
1760f1702c5SYu Xiangning {
1770f1702c5SYu Xiangning 	struct sonode *so = VTOSO(vp);
1780f1702c5SYu Xiangning 	struct nmsghdr lmsg;
1790f1702c5SYu Xiangning 
1800f1702c5SYu Xiangning 	ASSERT(vp->v_type == VSOCK);
1810f1702c5SYu Xiangning 	bzero((void *)&lmsg, sizeof (lmsg));
1820f1702c5SYu Xiangning 
1830f1702c5SYu Xiangning 	return (socket_recvmsg(so, &lmsg, uiop, cr));
1840f1702c5SYu Xiangning }
1850f1702c5SYu Xiangning 
1860f1702c5SYu Xiangning /*ARGSUSED2*/
1870f1702c5SYu Xiangning static int
socket_vop_write(struct vnode * vp,struct uio * uiop,int ioflag,struct cred * cr,caller_context_t * ct)1880f1702c5SYu Xiangning socket_vop_write(struct vnode *vp, struct uio *uiop, int ioflag,
1890f1702c5SYu Xiangning     struct cred *cr, caller_context_t *ct)
1900f1702c5SYu Xiangning {
1910f1702c5SYu Xiangning 	struct sonode *so = VTOSO(vp);
1920f1702c5SYu Xiangning 	struct nmsghdr lmsg;
1930f1702c5SYu Xiangning 
1940f1702c5SYu Xiangning 	ASSERT(vp->v_type == VSOCK);
1950f1702c5SYu Xiangning 	bzero((void *)&lmsg, sizeof (lmsg));
1960f1702c5SYu Xiangning 
1970f1702c5SYu Xiangning 	if (!(so->so_mode & SM_BYTESTREAM)) {
1980f1702c5SYu Xiangning 		/*
1990f1702c5SYu Xiangning 		 * If the socket is not byte stream set MSG_EOR
2000f1702c5SYu Xiangning 		 */
2010f1702c5SYu Xiangning 		lmsg.msg_flags = MSG_EOR;
2020f1702c5SYu Xiangning 	}
2030f1702c5SYu Xiangning 
2040f1702c5SYu Xiangning 	return (socket_sendmsg(so, &lmsg, uiop, cr));
2050f1702c5SYu Xiangning }
2060f1702c5SYu Xiangning 
2070f1702c5SYu Xiangning /*ARGSUSED4*/
2080f1702c5SYu Xiangning static int
socket_vop_ioctl(struct vnode * vp,int cmd,intptr_t arg,int mode,struct cred * cr,int32_t * rvalp,caller_context_t * ct)2090f1702c5SYu Xiangning socket_vop_ioctl(struct vnode *vp, int cmd, intptr_t arg, int mode,
2100f1702c5SYu Xiangning     struct cred *cr, int32_t *rvalp, caller_context_t *ct)
2110f1702c5SYu Xiangning {
2120f1702c5SYu Xiangning 	struct sonode *so = VTOSO(vp);
2130f1702c5SYu Xiangning 
2140f1702c5SYu Xiangning 	ASSERT(vp->v_type == VSOCK);
2150f1702c5SYu Xiangning 
2160f1702c5SYu Xiangning 	return (socket_ioctl(so, cmd, arg, mode, cr, rvalp));
2170f1702c5SYu Xiangning }
2180f1702c5SYu Xiangning 
2190f1702c5SYu Xiangning /*
2200f1702c5SYu Xiangning  * Allow any flags. Record FNDELAY and FNONBLOCK so that they can be inherited
2210f1702c5SYu Xiangning  * from listener to acceptor.
2220f1702c5SYu Xiangning  */
2230f1702c5SYu Xiangning /* ARGSUSED */
2240f1702c5SYu Xiangning static int
socket_vop_setfl(vnode_t * vp,int oflags,int nflags,cred_t * cr,caller_context_t * ct)2250f1702c5SYu Xiangning socket_vop_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr,
2260f1702c5SYu Xiangning     caller_context_t *ct)
2270f1702c5SYu Xiangning {
2280f1702c5SYu Xiangning 	struct sonode *so = VTOSO(vp);
2290f1702c5SYu Xiangning 	int error = 0;
2300f1702c5SYu Xiangning 
2310f1702c5SYu Xiangning 	ASSERT(vp->v_type == VSOCK);
2320f1702c5SYu Xiangning 
2330f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
2340f1702c5SYu Xiangning 	if (nflags & FNDELAY)
2350f1702c5SYu Xiangning 		so->so_state |= SS_NDELAY;
2360f1702c5SYu Xiangning 	else
2370f1702c5SYu Xiangning 		so->so_state &= ~SS_NDELAY;
2380f1702c5SYu Xiangning 	if (nflags & FNONBLOCK)
2390f1702c5SYu Xiangning 		so->so_state |= SS_NONBLOCK;
2400f1702c5SYu Xiangning 	else
2410f1702c5SYu Xiangning 		so->so_state &= ~SS_NONBLOCK;
2420f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
2430f1702c5SYu Xiangning 
2440f1702c5SYu Xiangning 	if (so->so_state & SS_ASYNC)
2450f1702c5SYu Xiangning 		oflags |= FASYNC;
2460f1702c5SYu Xiangning 	/*
2470f1702c5SYu Xiangning 	 * Sets/clears the SS_ASYNC flag based on the presence/absence
2480f1702c5SYu Xiangning 	 * of the FASYNC flag passed to fcntl(F_SETFL).
2490f1702c5SYu Xiangning 	 * This exists solely for BSD fcntl() FASYNC compatibility.
2500f1702c5SYu Xiangning 	 */
2510f1702c5SYu Xiangning 	if ((oflags ^ nflags) & FASYNC && so->so_version != SOV_STREAM) {
2520f1702c5SYu Xiangning 		int async = nflags & FASYNC;
2530f1702c5SYu Xiangning 		int32_t rv;
2540f1702c5SYu Xiangning 
2550f1702c5SYu Xiangning 		/*
2560f1702c5SYu Xiangning 		 * For non-TPI sockets all we have to do is set/remove the
2570f1702c5SYu Xiangning 		 * SS_ASYNC bit, but for TPI it is more involved. For that
2580f1702c5SYu Xiangning 		 * reason we delegate the job to the protocol's ioctl handler.
2590f1702c5SYu Xiangning 		 */
2600f1702c5SYu Xiangning 		error = socket_ioctl(so, FIOASYNC, (intptr_t)&async, FKIOCTL,
2610f1702c5SYu Xiangning 		    cr, &rv);
2620f1702c5SYu Xiangning 	}
2630f1702c5SYu Xiangning 	return (error);
2640f1702c5SYu Xiangning }
2650f1702c5SYu Xiangning 
2660f1702c5SYu Xiangning 
2670f1702c5SYu Xiangning /*
2680f1702c5SYu Xiangning  * Get the made up attributes for the vnode.
2690f1702c5SYu Xiangning  * 4.3BSD returns the current time for all the timestamps.
2700f1702c5SYu Xiangning  * 4.4BSD returns 0 for all the timestamps.
2710f1702c5SYu Xiangning  * Here we use the access and modified times recorded in the sonode.
2720f1702c5SYu Xiangning  *
2730f1702c5SYu Xiangning  * Just like in BSD there is not effect on the underlying file system node
2740f1702c5SYu Xiangning  * bound to an AF_UNIX pathname.
2750f1702c5SYu Xiangning  *
2760f1702c5SYu Xiangning  * When sockmod has been popped this will act just like a stream. Since
2770f1702c5SYu Xiangning  * a socket is always a clone there is no need to inspect the attributes
2780f1702c5SYu Xiangning  * of the "realvp".
2790f1702c5SYu Xiangning  */
2800f1702c5SYu Xiangning /* ARGSUSED */
2810f1702c5SYu Xiangning int
socket_vop_getattr(struct vnode * vp,struct vattr * vap,int flags,struct cred * cr,caller_context_t * ct)2820f1702c5SYu Xiangning socket_vop_getattr(struct vnode *vp, struct vattr *vap, int flags,
2830f1702c5SYu Xiangning     struct cred *cr, caller_context_t *ct)
2840f1702c5SYu Xiangning {
2850f1702c5SYu Xiangning 	dev_t		fsid;
286*e7434800SJason King 	struct sonode	*so;
2870f1702c5SYu Xiangning 	static int	sonode_shift = 0;
2880f1702c5SYu Xiangning 
2890f1702c5SYu Xiangning 	/*
2900f1702c5SYu Xiangning 	 * Calculate the amount of bitshift to a sonode pointer which will
291*e7434800SJason King 	 * still keep it unique.  See below. Note that highbit() uses
292*e7434800SJason King 	 * 1-based indexing for the highest bit set (and 0 for 'no bits set').
293*e7434800SJason King 	 * To use the result of highbit() as a shift value, we must subtract 1
294*e7434800SJason King 	 * from the result.
2950f1702c5SYu Xiangning 	 */
296*e7434800SJason King 	if (sonode_shift == 0) {
297*e7434800SJason King 		int bit = highbit(sizeof (struct sonode));
298*e7434800SJason King 
299*e7434800SJason King 		/* Sanity check */
300*e7434800SJason King 		VERIFY3S(bit, >, 0);
301*e7434800SJason King 		sonode_shift = bit - 1;
302*e7434800SJason King 	}
3030f1702c5SYu Xiangning 
3040f1702c5SYu Xiangning 	so = VTOSO(vp);
3050f1702c5SYu Xiangning 	fsid = sockdev;
3060f1702c5SYu Xiangning 
3070f1702c5SYu Xiangning 	if (so->so_version == SOV_STREAM) {
3080f1702c5SYu Xiangning 		/*
3090f1702c5SYu Xiangning 		 * The imaginary "sockmod" has been popped - act
3100f1702c5SYu Xiangning 		 * as a stream
3110f1702c5SYu Xiangning 		 */
3120f1702c5SYu Xiangning 		vap->va_type = VCHR;
3130f1702c5SYu Xiangning 		vap->va_mode = 0;
3140f1702c5SYu Xiangning 	} else {
3150f1702c5SYu Xiangning 		vap->va_type = vp->v_type;
3160f1702c5SYu Xiangning 		vap->va_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|
3170f1702c5SYu Xiangning 		    S_IROTH|S_IWOTH;
3180f1702c5SYu Xiangning 	}
3190f1702c5SYu Xiangning 	vap->va_uid = vap->va_gid = 0;
3200f1702c5SYu Xiangning 	vap->va_fsid = fsid;
3210f1702c5SYu Xiangning 	/*
322*e7434800SJason King 	 * If the va_nodeid is > UINT32_MAX, then stat(2) might fail in
323*e7434800SJason King 	 * unexpected ways inside non-largefile aware 32-bit processes --
324*e7434800SJason King 	 * historically, socket inode values (va_nodeid values) were capped at
325*e7434800SJason King 	 * UINT16_MAX (for even more ancient reasons long since unnecessary).
326*e7434800SJason King 	 * To avoid the potential of surprise failures, we shift down
327*e7434800SJason King 	 * the sonode pointer address to try and get the most
328*e7434800SJason King 	 * uniqueness into 32-bits. In practice, this represents the unique
329*e7434800SJason King 	 * portion of the kernel address space, so the chance of duplicate
330*e7434800SJason King 	 * socket inode values is minimized.
3310f1702c5SYu Xiangning 	 */
332*e7434800SJason King 	vap->va_nodeid = ((ino_t)so >> sonode_shift) & 0xFFFFFFFF;
3330f1702c5SYu Xiangning 	vap->va_nlink = 0;
3340f1702c5SYu Xiangning 	vap->va_size = 0;
3350f1702c5SYu Xiangning 
3360f1702c5SYu Xiangning 	/*
3370f1702c5SYu Xiangning 	 * We need to zero out the va_rdev to avoid some fstats getting
3380f1702c5SYu Xiangning 	 * EOVERFLOW.  This also mimics SunOS 4.x and BSD behavior.
3390f1702c5SYu Xiangning 	 */
3400f1702c5SYu Xiangning 	vap->va_rdev = (dev_t)0;
3410f1702c5SYu Xiangning 	vap->va_blksize = MAXBSIZE;
3420f1702c5SYu Xiangning 	vap->va_nblocks = btod(vap->va_size);
3430f1702c5SYu Xiangning 
3440f1702c5SYu Xiangning 	if (!SOCK_IS_NONSTR(so)) {
3450f1702c5SYu Xiangning 		sotpi_info_t *sti = SOTOTPI(so);
3460f1702c5SYu Xiangning 
3470f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
3480f1702c5SYu Xiangning 		vap->va_atime.tv_sec = sti->sti_atime;
3490f1702c5SYu Xiangning 		vap->va_mtime.tv_sec = sti->sti_mtime;
3500f1702c5SYu Xiangning 		vap->va_ctime.tv_sec = sti->sti_ctime;
3510f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
3520f1702c5SYu Xiangning 	} else {
3530f1702c5SYu Xiangning 		vap->va_atime.tv_sec = 0;
3540f1702c5SYu Xiangning 		vap->va_mtime.tv_sec = 0;
3550f1702c5SYu Xiangning 		vap->va_ctime.tv_sec = 0;
3560f1702c5SYu Xiangning 	}
3570f1702c5SYu Xiangning 
3580f1702c5SYu Xiangning 	vap->va_atime.tv_nsec = 0;
3590f1702c5SYu Xiangning 	vap->va_mtime.tv_nsec = 0;
3600f1702c5SYu Xiangning 	vap->va_ctime.tv_nsec = 0;
3610f1702c5SYu Xiangning 	vap->va_seq = 0;
3620f1702c5SYu Xiangning 
3630f1702c5SYu Xiangning 	return (0);
3640f1702c5SYu Xiangning }
3650f1702c5SYu Xiangning 
3660f1702c5SYu Xiangning /*
3670f1702c5SYu Xiangning  * Set attributes.
3680f1702c5SYu Xiangning  * Just like in BSD there is not effect on the underlying file system node
3690f1702c5SYu Xiangning  * bound to an AF_UNIX pathname.
3700f1702c5SYu Xiangning  *
3710f1702c5SYu Xiangning  * When sockmod has been popped this will act just like a stream. Since
3720f1702c5SYu Xiangning  * a socket is always a clone there is no need to modify the attributes
3730f1702c5SYu Xiangning  * of the "realvp".
3740f1702c5SYu Xiangning  */
3750f1702c5SYu Xiangning /* ARGSUSED */
3760f1702c5SYu Xiangning int
socket_vop_setattr(struct vnode * vp,struct vattr * vap,int flags,struct cred * cr,caller_context_t * ct)3770f1702c5SYu Xiangning socket_vop_setattr(struct vnode *vp, struct vattr *vap, int flags,
3780f1702c5SYu Xiangning     struct cred *cr, caller_context_t *ct)
3790f1702c5SYu Xiangning {
3800f1702c5SYu Xiangning 	struct sonode *so = VTOSO(vp);
3810f1702c5SYu Xiangning 
3820f1702c5SYu Xiangning 	/*
3830f1702c5SYu Xiangning 	 * If times were changed, and we have a STREAMS socket, then update
3840f1702c5SYu Xiangning 	 * the sonode.
3850f1702c5SYu Xiangning 	 */
3860f1702c5SYu Xiangning 	if (!SOCK_IS_NONSTR(so)) {
3870f1702c5SYu Xiangning 		sotpi_info_t *sti = SOTOTPI(so);
3880f1702c5SYu Xiangning 
3890f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
3900f1702c5SYu Xiangning 		if (vap->va_mask & AT_ATIME)
3910f1702c5SYu Xiangning 			sti->sti_atime = vap->va_atime.tv_sec;
3920f1702c5SYu Xiangning 		if (vap->va_mask & AT_MTIME) {
3930f1702c5SYu Xiangning 			sti->sti_mtime = vap->va_mtime.tv_sec;
3940f1702c5SYu Xiangning 			sti->sti_ctime = gethrestime_sec();
3950f1702c5SYu Xiangning 		}
3960f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
3970f1702c5SYu Xiangning 	}
3980f1702c5SYu Xiangning 
3990f1702c5SYu Xiangning 	return (0);
4000f1702c5SYu Xiangning }
4010f1702c5SYu Xiangning 
4020f1702c5SYu Xiangning /*
4030f1702c5SYu Xiangning  * Check if user is allowed to access vp. For non-STREAMS based sockets,
4040f1702c5SYu Xiangning  * there might not be a device attached to the file system. So for those
4050f1702c5SYu Xiangning  * types of sockets there are no permissions to check.
4060f1702c5SYu Xiangning  *
4070f1702c5SYu Xiangning  * XXX Should there be some other mechanism to check access rights?
4080f1702c5SYu Xiangning  */
4090f1702c5SYu Xiangning /*ARGSUSED*/
4100f1702c5SYu Xiangning int
socket_vop_access(struct vnode * vp,int mode,int flags,struct cred * cr,caller_context_t * ct)4110f1702c5SYu Xiangning socket_vop_access(struct vnode *vp, int mode, int flags, struct cred *cr,
4120f1702c5SYu Xiangning     caller_context_t *ct)
4130f1702c5SYu Xiangning {
4140f1702c5SYu Xiangning 	struct sonode *so = VTOSO(vp);
4150f1702c5SYu Xiangning 
4160f1702c5SYu Xiangning 	if (!SOCK_IS_NONSTR(so)) {
4170f1702c5SYu Xiangning 		ASSERT(so->so_sockparams->sp_sdev_info.sd_vnode != NULL);
4180f1702c5SYu Xiangning 		return (VOP_ACCESS(so->so_sockparams->sp_sdev_info.sd_vnode,
4190f1702c5SYu Xiangning 		    mode, flags, cr, NULL));
4200f1702c5SYu Xiangning 	}
4210f1702c5SYu Xiangning 	return (0);
4220f1702c5SYu Xiangning }
4230f1702c5SYu Xiangning 
4240f1702c5SYu Xiangning /*
4250f1702c5SYu Xiangning  * 4.3BSD and 4.4BSD fail a fsync on a socket with EINVAL.
4260f1702c5SYu Xiangning  * This code does the same to be compatible and also to not give an
4270f1702c5SYu Xiangning  * application the impression that the data has actually been "synced"
4280f1702c5SYu Xiangning  * to the other end of the connection.
4290f1702c5SYu Xiangning  */
4300f1702c5SYu Xiangning /* ARGSUSED */
4310f1702c5SYu Xiangning int
socket_vop_fsync(struct vnode * vp,int syncflag,struct cred * cr,caller_context_t * ct)4320f1702c5SYu Xiangning socket_vop_fsync(struct vnode *vp, int syncflag, struct cred *cr,
4330f1702c5SYu Xiangning     caller_context_t *ct)
4340f1702c5SYu Xiangning {
4350f1702c5SYu Xiangning 	return (EINVAL);
4360f1702c5SYu Xiangning }
4370f1702c5SYu Xiangning 
4380f1702c5SYu Xiangning /*ARGSUSED*/
4390f1702c5SYu Xiangning static void
socket_vop_inactive(struct vnode * vp,struct cred * cr,caller_context_t * ct)4400f1702c5SYu Xiangning socket_vop_inactive(struct vnode *vp, struct cred *cr, caller_context_t *ct)
4410f1702c5SYu Xiangning {
4420f1702c5SYu Xiangning 	struct sonode *so = VTOSO(vp);
4430f1702c5SYu Xiangning 
4440f1702c5SYu Xiangning 	ASSERT(vp->v_type == VSOCK);
4450f1702c5SYu Xiangning 
4460f1702c5SYu Xiangning 	mutex_enter(&vp->v_lock);
4470f1702c5SYu Xiangning 	/*
4480f1702c5SYu Xiangning 	 * If no one has reclaimed the vnode, remove from the
4490f1702c5SYu Xiangning 	 * cache now.
4500f1702c5SYu Xiangning 	 */
4510f1702c5SYu Xiangning 	if (vp->v_count < 1)
4520f1702c5SYu Xiangning 		cmn_err(CE_PANIC, "socket_inactive: Bad v_count");
4530f1702c5SYu Xiangning 
454ade42b55SSebastien Roy 	VN_RELE_LOCKED(vp);
455ade42b55SSebastien Roy 	if (vp->v_count != 0) {
4560f1702c5SYu Xiangning 		mutex_exit(&vp->v_lock);
4570f1702c5SYu Xiangning 		return;
4580f1702c5SYu Xiangning 	}
4590f1702c5SYu Xiangning 	mutex_exit(&vp->v_lock);
4600f1702c5SYu Xiangning 
4610f1702c5SYu Xiangning 
4620f1702c5SYu Xiangning 	ASSERT(!vn_has_cached_data(vp));
4630f1702c5SYu Xiangning 
4640f1702c5SYu Xiangning 	/* socket specfic clean-up */
4650f1702c5SYu Xiangning 	socket_destroy_internal(so, cr);
4660f1702c5SYu Xiangning }
4670f1702c5SYu Xiangning 
4680f1702c5SYu Xiangning /* ARGSUSED */
4690f1702c5SYu Xiangning int
socket_vop_fid(struct vnode * vp,struct fid * fidp,caller_context_t * ct)4700f1702c5SYu Xiangning socket_vop_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
4710f1702c5SYu Xiangning {
4720f1702c5SYu Xiangning 	return (EINVAL);
4730f1702c5SYu Xiangning }
4740f1702c5SYu Xiangning 
4750f1702c5SYu Xiangning /*
4760f1702c5SYu Xiangning  * Sockets are not seekable.
4770f1702c5SYu Xiangning  * (and there is a bug to fix STREAMS to make them fail this as well).
4780f1702c5SYu Xiangning  */
4790f1702c5SYu Xiangning /*ARGSUSED*/
4800f1702c5SYu Xiangning int
socket_vop_seek(struct vnode * vp,offset_t ooff,offset_t * noffp,caller_context_t * ct)4810f1702c5SYu Xiangning socket_vop_seek(struct vnode *vp, offset_t ooff, offset_t *noffp,
4820f1702c5SYu Xiangning     caller_context_t *ct)
4830f1702c5SYu Xiangning {
4840f1702c5SYu Xiangning 	return (ESPIPE);
4850f1702c5SYu Xiangning }
4860f1702c5SYu Xiangning 
4870f1702c5SYu Xiangning /*ARGSUSED*/
4880f1702c5SYu Xiangning static int
socket_vop_poll(struct vnode * vp,short events,int anyyet,short * reventsp,struct pollhead ** phpp,caller_context_t * ct)4890f1702c5SYu Xiangning socket_vop_poll(struct vnode *vp, short events, int anyyet, short *reventsp,
4900f1702c5SYu Xiangning     struct pollhead **phpp, caller_context_t *ct)
4910f1702c5SYu Xiangning {
4920f1702c5SYu Xiangning 	struct sonode *so = VTOSO(vp);
4930f1702c5SYu Xiangning 
4940f1702c5SYu Xiangning 	ASSERT(vp->v_type == VSOCK);
4950f1702c5SYu Xiangning 
4960f1702c5SYu Xiangning 	return (socket_poll(so, events, anyyet, reventsp, phpp));
4970f1702c5SYu Xiangning }
498