fs: rename AT_* to VATTR_*
[unleashed/lotheac.git] / kernel / fs / sockfs / sockcommon_vnops.c
blobfd4c635ebd06a5a6a4472b811b8d4cd2b1eecc11
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 * Copyright (c) 2017 by Delphix. All rights reserved.
30 #include <sys/types.h>
31 #include <sys/t_lock.h>
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/bitmap.h>
35 #include <sys/debug.h>
36 #include <sys/errno.h>
37 #include <sys/strsubr.h>
38 #include <sys/cmn_err.h>
39 #include <sys/sysmacros.h>
40 #include <sys/filio.h>
41 #include <sys/flock.h>
42 #include <sys/stat.h>
43 #include <sys/share.h>
44 #include <sys/fs_subr.h>
46 #include <sys/vfs.h>
48 #include <sys/sockio.h>
49 #include <sys/socket.h>
50 #include <sys/socketvar.h>
51 #include <sys/strsun.h>
53 #include "sockcommon.h"
54 #include "socktpi.h"
57 * Generic vnode ops
59 static int socket_vop_open(struct vnode **, int, struct cred *,
60 caller_context_t *);
61 static int socket_vop_close(struct vnode *, int, int, offset_t,
62 struct cred *, caller_context_t *);
63 static int socket_vop_read(struct vnode *, struct uio *, int,
64 struct cred *, caller_context_t *);
65 static int socket_vop_write(struct vnode *, struct uio *, int,
66 struct cred *, caller_context_t *);
67 static int socket_vop_ioctl(struct vnode *, int, intptr_t, int,
68 struct cred *, int32_t *, caller_context_t *);
69 static int socket_vop_setfl(struct vnode *, int, int, cred_t *,
70 caller_context_t *);
71 static int socket_vop_getattr(struct vnode *, struct vattr *, int,
72 struct cred *, caller_context_t *);
73 static int socket_vop_setattr(struct vnode *, struct vattr *, int,
74 struct cred *, caller_context_t *);
75 static int socket_vop_access(struct vnode *, int, int, struct cred *,
76 caller_context_t *);
77 static int socket_vop_fsync(struct vnode *, int, struct cred *,
78 caller_context_t *);
79 static void socket_vop_inactive(struct vnode *, struct cred *,
80 caller_context_t *);
81 static int socket_vop_fid(struct vnode *, struct fid *,
82 caller_context_t *);
83 static int socket_vop_seek(struct vnode *, offset_t, offset_t *,
84 caller_context_t *);
85 static int socket_vop_poll(struct vnode *, short, int, short *,
86 struct pollhead **, caller_context_t *);
88 extern int socket_close_internal(struct sonode *, int, cred_t *);
89 extern void socket_destroy_internal(struct sonode *, cred_t *);
91 const struct vnodeops socket_vnodeops = {
92 .vnop_name = "sockfs",
93 .vop_open = socket_vop_open,
94 .vop_close = socket_vop_close,
95 .vop_read = socket_vop_read,
96 .vop_write = socket_vop_write,
97 .vop_ioctl = socket_vop_ioctl,
98 .vop_setfl = socket_vop_setfl,
99 .vop_getattr = socket_vop_getattr,
100 .vop_setattr = socket_vop_setattr,
101 .vop_access = socket_vop_access,
102 .vop_fsync = socket_vop_fsync,
103 .vop_inactive = socket_vop_inactive,
104 .vop_fid = socket_vop_fid,
105 .vop_seek = socket_vop_seek,
106 .vop_poll = socket_vop_poll,
107 .vop_dispose = fs_nodispose,
112 * generic vnode ops
115 /*ARGSUSED*/
116 static int
117 socket_vop_open(struct vnode **vpp, int flag, struct cred *cr,
118 caller_context_t *ct)
120 struct vnode *vp = *vpp;
121 struct sonode *so = VTOSO(vp);
123 flag &= ~FCREAT; /* paranoia */
124 mutex_enter(&so->so_lock);
125 so->so_count++;
126 mutex_exit(&so->so_lock);
128 ASSERT(so->so_count != 0); /* wraparound */
129 ASSERT(vp->v_type == VSOCK);
131 return (0);
134 /*ARGSUSED*/
135 static int
136 socket_vop_close(struct vnode *vp, int flag, int count, offset_t offset,
137 struct cred *cr, caller_context_t *ct)
139 struct sonode *so;
140 int error = 0;
142 so = VTOSO(vp);
143 ASSERT(vp->v_type == VSOCK);
145 cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
146 cleanshares(vp, ttoproc(curthread)->p_pid);
148 if (vp->v_stream)
149 strclean(vp);
151 if (count > 1) {
152 dprint(2, ("socket_vop_close: count %d\n", count));
153 return (0);
156 mutex_enter(&so->so_lock);
157 if (--so->so_count == 0) {
159 * Initiate connection shutdown.
161 mutex_exit(&so->so_lock);
162 error = socket_close_internal(so, flag, cr);
163 } else {
164 mutex_exit(&so->so_lock);
167 return (error);
170 /*ARGSUSED2*/
171 static int
172 socket_vop_read(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cr,
173 caller_context_t *ct)
175 struct sonode *so = VTOSO(vp);
176 struct msghdr lmsg;
178 ASSERT(vp->v_type == VSOCK);
179 bzero((void *)&lmsg, sizeof (lmsg));
181 return (socket_recvmsg(so, &lmsg, uiop, cr));
184 /*ARGSUSED2*/
185 static int
186 socket_vop_write(struct vnode *vp, struct uio *uiop, int ioflag,
187 struct cred *cr, caller_context_t *ct)
189 struct sonode *so = VTOSO(vp);
190 struct msghdr lmsg;
192 ASSERT(vp->v_type == VSOCK);
193 bzero((void *)&lmsg, sizeof (lmsg));
195 if (!(so->so_mode & SM_BYTESTREAM)) {
197 * If the socket is not byte stream set MSG_EOR
199 lmsg.msg_flags = MSG_EOR;
202 return (socket_sendmsg(so, &lmsg, uiop, cr));
205 /*ARGSUSED4*/
206 static int
207 socket_vop_ioctl(struct vnode *vp, int cmd, intptr_t arg, int mode,
208 struct cred *cr, int32_t *rvalp, caller_context_t *ct)
210 struct sonode *so = VTOSO(vp);
212 ASSERT(vp->v_type == VSOCK);
214 return (socket_ioctl(so, cmd, arg, mode, cr, rvalp));
218 * Allow any flags. Record FNDELAY and FNONBLOCK so that they can be inherited
219 * from listener to acceptor.
221 /* ARGSUSED */
222 static int
223 socket_vop_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr,
224 caller_context_t *ct)
226 struct sonode *so = VTOSO(vp);
227 int error = 0;
229 ASSERT(vp->v_type == VSOCK);
231 mutex_enter(&so->so_lock);
232 if (nflags & FNDELAY)
233 so->so_state |= SS_NDELAY;
234 else
235 so->so_state &= ~SS_NDELAY;
236 if (nflags & FNONBLOCK)
237 so->so_state |= SS_NONBLOCK;
238 else
239 so->so_state &= ~SS_NONBLOCK;
240 mutex_exit(&so->so_lock);
242 if (so->so_state & SS_ASYNC)
243 oflags |= FASYNC;
245 * Sets/clears the SS_ASYNC flag based on the presence/absence
246 * of the FASYNC flag passed to fcntl(F_SETFL).
247 * This exists solely for BSD fcntl() FASYNC compatibility.
249 if ((oflags ^ nflags) & FASYNC && !so->so_is_stream) {
250 int async = nflags & FASYNC;
251 int32_t rv;
254 * For non-TPI sockets all we have to do is set/remove the
255 * SS_ASYNC bit, but for TPI it is more involved. For that
256 * reason we delegate the job to the protocol's ioctl handler.
258 error = socket_ioctl(so, FIOASYNC, (intptr_t)&async, FKIOCTL,
259 cr, &rv);
261 return (error);
266 * Get the made up attributes for the vnode.
267 * 4.3BSD returns the current time for all the timestamps.
268 * 4.4BSD returns 0 for all the timestamps.
269 * Here we use the access and modified times recorded in the sonode.
271 * Just like in BSD there is not effect on the underlying file system node
272 * bound to an AF_UNIX pathname.
274 * When sockmod has been popped this will act just like a stream. Since
275 * a socket is always a clone there is no need to inspect the attributes
276 * of the "realvp".
278 /* ARGSUSED */
280 socket_vop_getattr(struct vnode *vp, struct vattr *vap, int flags,
281 struct cred *cr, caller_context_t *ct)
283 dev_t fsid;
284 struct sonode *so;
285 static int sonode_shift = 0;
288 * Calculate the amount of bitshift to a sonode pointer which will
289 * still keep it unique. See below.
291 if (sonode_shift == 0)
292 sonode_shift = highbit(sizeof (struct sonode));
293 ASSERT(sonode_shift > 0);
295 so = VTOSO(vp);
296 fsid = sockdev;
298 if (so->so_is_stream) {
300 * The imaginary "sockmod" has been popped - act
301 * as a stream
303 vap->va_type = VCHR;
304 vap->va_mode = 0;
305 } else {
306 vap->va_type = vp->v_type;
307 vap->va_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|
308 S_IROTH|S_IWOTH;
310 vap->va_uid = vap->va_gid = 0;
311 vap->va_fsid = fsid;
313 * If the va_nodeid is > MAX_USHORT, then i386 stats might fail.
314 * So we shift down the sonode pointer to try and get the most
315 * uniqueness into 16-bits.
317 vap->va_nodeid = ((ino_t)so >> sonode_shift) & 0xFFFF;
318 vap->va_nlink = 0;
319 vap->va_size = 0;
322 * We need to zero out the va_rdev to avoid some fstats getting
323 * EOVERFLOW. This also mimics SunOS 4.x and BSD behavior.
325 vap->va_rdev = (dev_t)0;
326 vap->va_blksize = MAXBSIZE;
327 vap->va_nblocks = btod(vap->va_size);
329 if (!SOCK_IS_NONSTR(so)) {
330 sotpi_info_t *sti = SOTOTPI(so);
332 mutex_enter(&so->so_lock);
333 vap->va_atime.tv_sec = sti->sti_atime;
334 vap->va_mtime.tv_sec = sti->sti_mtime;
335 vap->va_ctime.tv_sec = sti->sti_ctime;
336 mutex_exit(&so->so_lock);
337 } else {
338 vap->va_atime.tv_sec = 0;
339 vap->va_mtime.tv_sec = 0;
340 vap->va_ctime.tv_sec = 0;
343 vap->va_atime.tv_nsec = 0;
344 vap->va_mtime.tv_nsec = 0;
345 vap->va_ctime.tv_nsec = 0;
346 vap->va_seq = 0;
348 return (0);
352 * Set attributes.
353 * Just like in BSD there is not effect on the underlying file system node
354 * bound to an AF_UNIX pathname.
356 * When sockmod has been popped this will act just like a stream. Since
357 * a socket is always a clone there is no need to modify the attributes
358 * of the "realvp".
360 /* ARGSUSED */
362 socket_vop_setattr(struct vnode *vp, struct vattr *vap, int flags,
363 struct cred *cr, caller_context_t *ct)
365 struct sonode *so = VTOSO(vp);
368 * If times were changed, and we have a STREAMS socket, then update
369 * the sonode.
371 if (!SOCK_IS_NONSTR(so)) {
372 sotpi_info_t *sti = SOTOTPI(so);
374 mutex_enter(&so->so_lock);
375 if (vap->va_mask & VATTR_ATIME)
376 sti->sti_atime = vap->va_atime.tv_sec;
377 if (vap->va_mask & VATTR_MTIME) {
378 sti->sti_mtime = vap->va_mtime.tv_sec;
379 sti->sti_ctime = gethrestime_sec();
381 mutex_exit(&so->so_lock);
384 return (0);
388 * Check if user is allowed to access vp. For non-STREAMS based sockets,
389 * there might not be a device attached to the file system. So for those
390 * types of sockets there are no permissions to check.
392 * XXX Should there be some other mechanism to check access rights?
394 /*ARGSUSED*/
396 socket_vop_access(struct vnode *vp, int mode, int flags, struct cred *cr,
397 caller_context_t *ct)
399 struct sonode *so = VTOSO(vp);
401 if (!SOCK_IS_NONSTR(so)) {
402 ASSERT(so->so_sockparams->sp_sdev_info.sd_vnode != NULL);
403 return (fop_access(so->so_sockparams->sp_sdev_info.sd_vnode,
404 mode, flags, cr, NULL));
406 return (0);
410 * 4.3BSD and 4.4BSD fail a fsync on a socket with EINVAL.
411 * This code does the same to be compatible and also to not give an
412 * application the impression that the data has actually been "synced"
413 * to the other end of the connection.
415 /* ARGSUSED */
417 socket_vop_fsync(struct vnode *vp, int syncflag, struct cred *cr,
418 caller_context_t *ct)
420 return (EINVAL);
423 /*ARGSUSED*/
424 static void
425 socket_vop_inactive(struct vnode *vp, struct cred *cr, caller_context_t *ct)
427 struct sonode *so = VTOSO(vp);
429 ASSERT(vp->v_type == VSOCK);
431 mutex_enter(&vp->v_lock);
433 * If no one has reclaimed the vnode, remove from the
434 * cache now.
436 if (vp->v_count < 1)
437 cmn_err(CE_PANIC, "socket_inactive: Bad v_count");
439 VN_RELE_LOCKED(vp);
440 if (vp->v_count != 0) {
441 mutex_exit(&vp->v_lock);
442 return;
444 mutex_exit(&vp->v_lock);
447 ASSERT(!vn_has_cached_data(vp));
449 /* socket specfic clean-up */
450 socket_destroy_internal(so, cr);
453 /* ARGSUSED */
455 socket_vop_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
457 return (EINVAL);
461 * Sockets are not seekable.
462 * (and there is a bug to fix STREAMS to make them fail this as well).
464 /*ARGSUSED*/
466 socket_vop_seek(struct vnode *vp, offset_t ooff, offset_t *noffp,
467 caller_context_t *ct)
469 return (ESPIPE);
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)
477 struct sonode *so = VTOSO(vp);
479 ASSERT(vp->v_type == VSOCK);
481 return (socket_poll(so, events, anyyet, reventsp, phpp));