xref: /illumos-gate/usr/src/uts/common/fs/sockfs/sockcommon_vnops.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/types.h>
28 #include <sys/t_lock.h>
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/bitmap.h>
32 #include <sys/debug.h>
33 #include <sys/errno.h>
34 #include <sys/strsubr.h>
35 #include <sys/cmn_err.h>
36 #include <sys/sysmacros.h>
37 #include <sys/filio.h>
38 #include <sys/flock.h>
39 #include <sys/stat.h>
40 #include <sys/share.h>
41 
42 #include <sys/vfs.h>
43 #include <sys/vfs_opreg.h>
44 
45 #include <sys/sockio.h>
46 #include <sys/socket.h>
47 #include <sys/socketvar.h>
48 #include <sys/strsun.h>
49 
50 #include <fs/sockfs/sockcommon.h>
51 #include <fs/sockfs/socktpi.h>
52 
53 /*
54  * Generic vnode ops
55  */
56 static int	socket_vop_open(struct vnode **, int, struct cred *,
57 		    caller_context_t *);
58 static int	socket_vop_close(struct vnode *, int, int, offset_t,
59 		    struct cred *, caller_context_t *);
60 static int	socket_vop_read(struct vnode *, struct uio *, int,
61 		    struct cred *, caller_context_t *);
62 static int	socket_vop_write(struct vnode *, struct uio *, int,
63 		    struct cred *, caller_context_t *);
64 static int	socket_vop_ioctl(struct vnode *, int, intptr_t, int,
65 		    struct cred *, int32_t *, caller_context_t *);
66 static int	socket_vop_setfl(struct vnode *, int, int, cred_t *,
67 		    caller_context_t *);
68 static int 	socket_vop_getattr(struct vnode *, struct vattr *, int,
69 		    struct cred *, caller_context_t *);
70 static int 	socket_vop_setattr(struct vnode *, struct vattr *, int,
71 		    struct cred *, caller_context_t *);
72 static int 	socket_vop_access(struct vnode *, int, int, struct cred *,
73 		    caller_context_t *);
74 static int 	socket_vop_fsync(struct vnode *, int, struct cred *,
75 		    caller_context_t *);
76 static void	socket_vop_inactive(struct vnode *, struct cred *,
77 		    caller_context_t *);
78 static int 	socket_vop_fid(struct vnode *, struct fid *,
79 		    caller_context_t *);
80 static int 	socket_vop_seek(struct vnode *, offset_t, offset_t *,
81 		    caller_context_t *);
82 static int	socket_vop_poll(struct vnode *, short, int, short *,
83 		    struct pollhead **, caller_context_t *);
84 
85 extern int	socket_close_internal(struct sonode *, int, cred_t *);
86 extern void	socket_destroy_internal(struct sonode *, cred_t *);
87 
88 struct vnodeops *socket_vnodeops;
89 const fs_operation_def_t socket_vnodeops_template[] = {
90 	VOPNAME_OPEN,		{ .vop_open = socket_vop_open },
91 	VOPNAME_CLOSE,		{ .vop_close = socket_vop_close },
92 	VOPNAME_READ,		{ .vop_read = socket_vop_read },
93 	VOPNAME_WRITE,		{ .vop_write = socket_vop_write },
94 	VOPNAME_IOCTL,		{ .vop_ioctl = socket_vop_ioctl },
95 	VOPNAME_SETFL,		{ .vop_setfl = socket_vop_setfl },
96 	VOPNAME_GETATTR,	{ .vop_getattr = socket_vop_getattr },
97 	VOPNAME_SETATTR,	{ .vop_setattr = socket_vop_setattr },
98 	VOPNAME_ACCESS,		{ .vop_access = socket_vop_access },
99 	VOPNAME_FSYNC,		{ .vop_fsync = socket_vop_fsync },
100 	VOPNAME_INACTIVE,	{ .vop_inactive = socket_vop_inactive },
101 	VOPNAME_FID,		{ .vop_fid = socket_vop_fid },
102 	VOPNAME_SEEK,		{ .vop_seek = socket_vop_seek },
103 	VOPNAME_POLL,		{ .vop_poll = socket_vop_poll },
104 	VOPNAME_DISPOSE,	{ .error = fs_error },
105 	NULL,			NULL
106 };
107 
108 
109 /*
110  * generic vnode ops
111  */
112 
113 /*ARGSUSED*/
114 static int
115 socket_vop_open(struct vnode **vpp, int flag, struct cred *cr,
116     caller_context_t *ct)
117 {
118 	struct vnode *vp = *vpp;
119 	struct sonode *so = VTOSO(vp);
120 
121 	flag &= ~FCREAT;		/* paranoia */
122 	mutex_enter(&so->so_lock);
123 	so->so_count++;
124 	mutex_exit(&so->so_lock);
125 
126 	ASSERT(so->so_count != 0);	/* wraparound */
127 	ASSERT(vp->v_type == VSOCK);
128 
129 	return (0);
130 }
131 
132 /*ARGSUSED*/
133 static int
134 socket_vop_close(struct vnode *vp, int flag, int count, offset_t offset,
135     struct cred *cr, caller_context_t *ct)
136 {
137 	struct sonode *so;
138 	int error = 0;
139 
140 	so = VTOSO(vp);
141 	ASSERT(vp->v_type == VSOCK);
142 
143 	cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
144 	cleanshares(vp, ttoproc(curthread)->p_pid);
145 
146 	if (vp->v_stream)
147 		strclean(vp);
148 
149 	if (count > 1) {
150 		dprint(2, ("socket_vop_close: count %d\n", count));
151 		return (0);
152 	}
153 
154 	mutex_enter(&so->so_lock);
155 	if (--so->so_count == 0) {
156 		/*
157 		 * Initiate connection shutdown.
158 		 */
159 		mutex_exit(&so->so_lock);
160 		error = socket_close_internal(so, flag, cr);
161 	} else {
162 		mutex_exit(&so->so_lock);
163 	}
164 
165 	return (error);
166 }
167 
168 /*ARGSUSED2*/
169 static int
170 socket_vop_read(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cr,
171     caller_context_t *ct)
172 {
173 	struct sonode *so = VTOSO(vp);
174 	struct nmsghdr lmsg;
175 
176 	ASSERT(vp->v_type == VSOCK);
177 	bzero((void *)&lmsg, sizeof (lmsg));
178 
179 	return (socket_recvmsg(so, &lmsg, uiop, cr));
180 }
181 
182 /*ARGSUSED2*/
183 static int
184 socket_vop_write(struct vnode *vp, struct uio *uiop, int ioflag,
185     struct cred *cr, caller_context_t *ct)
186 {
187 	struct sonode *so = VTOSO(vp);
188 	struct nmsghdr lmsg;
189 
190 	ASSERT(vp->v_type == VSOCK);
191 	bzero((void *)&lmsg, sizeof (lmsg));
192 
193 	if (!(so->so_mode & SM_BYTESTREAM)) {
194 		/*
195 		 * If the socket is not byte stream set MSG_EOR
196 		 */
197 		lmsg.msg_flags = MSG_EOR;
198 	}
199 
200 	return (socket_sendmsg(so, &lmsg, uiop, cr));
201 }
202 
203 /*ARGSUSED4*/
204 static int
205 socket_vop_ioctl(struct vnode *vp, int cmd, intptr_t arg, int mode,
206     struct cred *cr, int32_t *rvalp, caller_context_t *ct)
207 {
208 	struct sonode *so = VTOSO(vp);
209 
210 	ASSERT(vp->v_type == VSOCK);
211 
212 	return (socket_ioctl(so, cmd, arg, mode, cr, rvalp));
213 }
214 
215 /*
216  * Allow any flags. Record FNDELAY and FNONBLOCK so that they can be inherited
217  * from listener to acceptor.
218  */
219 /* ARGSUSED */
220 static int
221 socket_vop_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr,
222     caller_context_t *ct)
223 {
224 	struct sonode *so = VTOSO(vp);
225 	int error = 0;
226 
227 	ASSERT(vp->v_type == VSOCK);
228 
229 	mutex_enter(&so->so_lock);
230 	if (nflags & FNDELAY)
231 		so->so_state |= SS_NDELAY;
232 	else
233 		so->so_state &= ~SS_NDELAY;
234 	if (nflags & FNONBLOCK)
235 		so->so_state |= SS_NONBLOCK;
236 	else
237 		so->so_state &= ~SS_NONBLOCK;
238 	mutex_exit(&so->so_lock);
239 
240 	if (so->so_state & SS_ASYNC)
241 		oflags |= FASYNC;
242 	/*
243 	 * Sets/clears the SS_ASYNC flag based on the presence/absence
244 	 * of the FASYNC flag passed to fcntl(F_SETFL).
245 	 * This exists solely for BSD fcntl() FASYNC compatibility.
246 	 */
247 	if ((oflags ^ nflags) & FASYNC && so->so_version != SOV_STREAM) {
248 		int async = nflags & FASYNC;
249 		int32_t rv;
250 
251 		/*
252 		 * For non-TPI sockets all we have to do is set/remove the
253 		 * SS_ASYNC bit, but for TPI it is more involved. For that
254 		 * reason we delegate the job to the protocol's ioctl handler.
255 		 */
256 		error = socket_ioctl(so, FIOASYNC, (intptr_t)&async, FKIOCTL,
257 		    cr, &rv);
258 	}
259 	return (error);
260 }
261 
262 
263 /*
264  * Get the made up attributes for the vnode.
265  * 4.3BSD returns the current time for all the timestamps.
266  * 4.4BSD returns 0 for all the timestamps.
267  * Here we use the access and modified times recorded in the sonode.
268  *
269  * Just like in BSD there is not effect on the underlying file system node
270  * bound to an AF_UNIX pathname.
271  *
272  * When sockmod has been popped this will act just like a stream. Since
273  * a socket is always a clone there is no need to inspect the attributes
274  * of the "realvp".
275  */
276 /* ARGSUSED */
277 int
278 socket_vop_getattr(struct vnode *vp, struct vattr *vap, int flags,
279     struct cred *cr, caller_context_t *ct)
280 {
281 	dev_t		fsid;
282 	struct sonode 	*so;
283 	static int	sonode_shift = 0;
284 
285 	/*
286 	 * Calculate the amount of bitshift to a sonode pointer which will
287 	 * still keep it unique.  See below.
288 	 */
289 	if (sonode_shift == 0)
290 		sonode_shift = highbit(sizeof (struct sonode));
291 	ASSERT(sonode_shift > 0);
292 
293 	so = VTOSO(vp);
294 	fsid = sockdev;
295 
296 	if (so->so_version == SOV_STREAM) {
297 		/*
298 		 * The imaginary "sockmod" has been popped - act
299 		 * as a stream
300 		 */
301 		vap->va_type = VCHR;
302 		vap->va_mode = 0;
303 	} else {
304 		vap->va_type = vp->v_type;
305 		vap->va_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|
306 		    S_IROTH|S_IWOTH;
307 	}
308 	vap->va_uid = vap->va_gid = 0;
309 	vap->va_fsid = fsid;
310 	/*
311 	 * If the va_nodeid is > MAX_USHORT, then i386 stats might fail.
312 	 * So we shift down the sonode pointer to try and get the most
313 	 * uniqueness into 16-bits.
314 	 */
315 	vap->va_nodeid = ((ino_t)so >> sonode_shift) & 0xFFFF;
316 	vap->va_nlink = 0;
317 	vap->va_size = 0;
318 
319 	/*
320 	 * We need to zero out the va_rdev to avoid some fstats getting
321 	 * EOVERFLOW.  This also mimics SunOS 4.x and BSD behavior.
322 	 */
323 	vap->va_rdev = (dev_t)0;
324 	vap->va_blksize = MAXBSIZE;
325 	vap->va_nblocks = btod(vap->va_size);
326 
327 	if (!SOCK_IS_NONSTR(so)) {
328 		sotpi_info_t *sti = SOTOTPI(so);
329 
330 		mutex_enter(&so->so_lock);
331 		vap->va_atime.tv_sec = sti->sti_atime;
332 		vap->va_mtime.tv_sec = sti->sti_mtime;
333 		vap->va_ctime.tv_sec = sti->sti_ctime;
334 		mutex_exit(&so->so_lock);
335 	} else {
336 		vap->va_atime.tv_sec = 0;
337 		vap->va_mtime.tv_sec = 0;
338 		vap->va_ctime.tv_sec = 0;
339 	}
340 
341 	vap->va_atime.tv_nsec = 0;
342 	vap->va_mtime.tv_nsec = 0;
343 	vap->va_ctime.tv_nsec = 0;
344 	vap->va_seq = 0;
345 
346 	return (0);
347 }
348 
349 /*
350  * Set attributes.
351  * Just like in BSD there is not effect on the underlying file system node
352  * bound to an AF_UNIX pathname.
353  *
354  * When sockmod has been popped this will act just like a stream. Since
355  * a socket is always a clone there is no need to modify the attributes
356  * of the "realvp".
357  */
358 /* ARGSUSED */
359 int
360 socket_vop_setattr(struct vnode *vp, struct vattr *vap, int flags,
361     struct cred *cr, caller_context_t *ct)
362 {
363 	struct sonode *so = VTOSO(vp);
364 
365 	/*
366 	 * If times were changed, and we have a STREAMS socket, then update
367 	 * the sonode.
368 	 */
369 	if (!SOCK_IS_NONSTR(so)) {
370 		sotpi_info_t *sti = SOTOTPI(so);
371 
372 		mutex_enter(&so->so_lock);
373 		if (vap->va_mask & AT_ATIME)
374 			sti->sti_atime = vap->va_atime.tv_sec;
375 		if (vap->va_mask & AT_MTIME) {
376 			sti->sti_mtime = vap->va_mtime.tv_sec;
377 			sti->sti_ctime = gethrestime_sec();
378 		}
379 		mutex_exit(&so->so_lock);
380 	}
381 
382 	return (0);
383 }
384 
385 /*
386  * Check if user is allowed to access vp. For non-STREAMS based sockets,
387  * there might not be a device attached to the file system. So for those
388  * types of sockets there are no permissions to check.
389  *
390  * XXX Should there be some other mechanism to check access rights?
391  */
392 /*ARGSUSED*/
393 int
394 socket_vop_access(struct vnode *vp, int mode, int flags, struct cred *cr,
395     caller_context_t *ct)
396 {
397 	struct sonode *so = VTOSO(vp);
398 
399 	if (!SOCK_IS_NONSTR(so)) {
400 		ASSERT(so->so_sockparams->sp_sdev_info.sd_vnode != NULL);
401 		return (VOP_ACCESS(so->so_sockparams->sp_sdev_info.sd_vnode,
402 		    mode, flags, cr, NULL));
403 	}
404 	return (0);
405 }
406 
407 /*
408  * 4.3BSD and 4.4BSD fail a fsync on a socket with EINVAL.
409  * This code does the same to be compatible and also to not give an
410  * application the impression that the data has actually been "synced"
411  * to the other end of the connection.
412  */
413 /* ARGSUSED */
414 int
415 socket_vop_fsync(struct vnode *vp, int syncflag, struct cred *cr,
416     caller_context_t *ct)
417 {
418 	return (EINVAL);
419 }
420 
421 /*ARGSUSED*/
422 static void
423 socket_vop_inactive(struct vnode *vp, struct cred *cr, caller_context_t *ct)
424 {
425 	struct sonode *so = VTOSO(vp);
426 
427 	ASSERT(vp->v_type == VSOCK);
428 
429 	mutex_enter(&vp->v_lock);
430 	/*
431 	 * If no one has reclaimed the vnode, remove from the
432 	 * cache now.
433 	 */
434 	if (vp->v_count < 1)
435 		cmn_err(CE_PANIC, "socket_inactive: Bad v_count");
436 
437 	/*
438 	 * Drop the temporary hold by vn_rele now
439 	 */
440 	if (--vp->v_count != 0) {
441 		mutex_exit(&vp->v_lock);
442 		return;
443 	}
444 	mutex_exit(&vp->v_lock);
445 
446 
447 	ASSERT(!vn_has_cached_data(vp));
448 
449 	/* socket specfic clean-up */
450 	socket_destroy_internal(so, cr);
451 }
452 
453 /* ARGSUSED */
454 int
455 socket_vop_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
456 {
457 	return (EINVAL);
458 }
459 
460 /*
461  * Sockets are not seekable.
462  * (and there is a bug to fix STREAMS to make them fail this as well).
463  */
464 /*ARGSUSED*/
465 int
466 socket_vop_seek(struct vnode *vp, offset_t ooff, offset_t *noffp,
467     caller_context_t *ct)
468 {
469 	return (ESPIPE);
470 }
471 
472 /*ARGSUSED*/
473 static int
474 socket_vop_poll(struct vnode *vp, short events, int anyyet, short *reventsp,
475     struct pollhead **phpp, caller_context_t *ct)
476 {
477 	struct sonode *so = VTOSO(vp);
478 
479 	ASSERT(vp->v_type == VSOCK);
480 
481 	return (socket_poll(so, events, anyyet, reventsp, phpp));
482 }
483