2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software donated to Berkeley by
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * @(#)portal_vnops.c 8.14 (Berkeley) 5/21/95
38 * $FreeBSD: src/sys/miscfs/portal/portal_vnops.c,v 1.38 1999/12/21 06:29:00 chris Exp $
39 * $DragonFly: src/sys/vfs/portal/portal_vnops.c,v 1.39 2007/11/20 21:03:50 dillon Exp $
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/sysproto.h>
49 #include <sys/kernel.h>
52 #include <sys/filedesc.h>
53 #include <sys/vnode.h>
54 #include <sys/fcntl.h>
57 #include <sys/mount.h>
58 #include <sys/malloc.h>
59 #include <sys/namei.h>
61 #include <sys/resourcevar.h>
62 #include <sys/socket.h>
63 #include <sys/socketvar.h>
65 #include <sys/unpcb.h>
68 #include <sys/thread2.h>
70 static int portal_fileid
= PORTAL_ROOTFILEID
+1;
72 static int portal_badop (void);
73 static void portal_closefd (struct thread
*td
, int fd
);
74 static int portal_connect (struct socket
*so
, struct socket
*so2
);
75 static int portal_getattr (struct vop_getattr_args
*ap
);
76 static int portal_inactive (struct vop_inactive_args
*ap
);
77 static int portal_lookup (struct vop_old_lookup_args
*ap
);
78 static int portal_open (struct vop_open_args
*ap
);
79 static int portal_print (struct vop_print_args
*ap
);
80 static int portal_readdir (struct vop_readdir_args
*ap
);
81 static int portal_reclaim (struct vop_reclaim_args
*ap
);
82 static int portal_setattr (struct vop_setattr_args
*ap
);
85 portal_closefd(struct thread
*td
, int fd
)
91 error
= sys_close(&ua
);
93 * We should never get an error, and there isn't anything
94 * we could do if we got one, so just print a message.
97 kprintf("portal_closefd: error = %d\n", error
);
101 * vp is the current namei directory
102 * cnp is the name to locate in that directory...
104 * portal_lookup(struct vnode *a_dvp, struct vnode **a_vpp,
105 * struct componentname *a_cnp)
108 portal_lookup(struct vop_old_lookup_args
*ap
)
110 struct componentname
*cnp
= ap
->a_cnp
;
111 struct vnode
**vpp
= ap
->a_vpp
;
112 struct vnode
*dvp
= ap
->a_dvp
;
113 char *pname
= cnp
->cn_nameptr
;
114 struct portalnode
*pt
;
116 struct vnode
*fvp
= 0;
122 if (cnp
->cn_nameiop
== NAMEI_DELETE
|| cnp
->cn_nameiop
== NAMEI_RENAME
)
125 if (cnp
->cn_namelen
== 1 && *pname
== '.') {
132 * Do the MALLOC before the getnewvnode since doing so afterward
133 * might cause a bogus v_data pointer to get dereferenced
134 * elsewhere if MALLOC should block.
136 MALLOC(pt
, struct portalnode
*, sizeof(struct portalnode
),
139 error
= getnewvnode(VT_PORTAL
, dvp
->v_mount
, &fvp
, 0, 0);
148 * Save all of the remaining pathname and
149 * advance the namei next pointer to the end
152 for (size
= 0, path
= pname
; *path
; path
++)
154 cnp
->cn_consume
= size
- cnp
->cn_namelen
;
156 pt
->pt_arg
= kmalloc(size
+1, M_TEMP
, M_WAITOK
);
157 pt
->pt_size
= size
+1;
158 bcopy(pname
, pt
->pt_arg
, pt
->pt_size
);
159 pt
->pt_fileid
= portal_fileid
++;
172 portal_connect(struct socket
*so
, struct socket
*so2
)
174 /* from unp_connect, bypassing the namei stuff... */
180 return (ECONNREFUSED
);
182 if (so
->so_type
!= so2
->so_type
)
185 if ((so2
->so_options
& SO_ACCEPTCONN
) == 0)
186 return (ECONNREFUSED
);
188 if ((so3
= sonewconn(so2
, 0)) == 0)
189 return (ECONNREFUSED
);
194 unp3
->unp_addr
= (struct sockaddr_un
*)
195 dup_sockaddr((struct sockaddr
*)unp2
->unp_addr
);
198 return (unp_connect2(so
, so2
));
202 * portal_open(struct vnode *a_vp, int a_mode, struct ucred *a_cred,
206 portal_open(struct vop_open_args
*ap
)
208 struct socket
*so
= 0;
209 struct portalnode
*pt
;
210 struct thread
*td
= curthread
;
211 struct vnode
*vp
= ap
->a_vp
;
213 struct iovec aiov
[2];
217 struct cmsghdr
*cmsg
;
223 struct portalmount
*fmp
;
225 struct portal_cred pcred
;
228 * Nothing to do when opening the root node.
230 if (vp
->v_flag
& VROOT
)
231 return (vop_stdopen(ap
));
234 * Can't be opened unless the caller is set up
235 * to deal with the side effects. Check for this
236 * by testing whether the p_dupfd has been set.
238 KKASSERT(td
->td_proc
);
239 if (td
->td_lwp
->lwp_dupfd
>= 0)
243 fmp
= VFSTOPORTAL(vp
->v_mount
);
246 * Create a new socket.
248 error
= socreate(AF_UNIX
, &so
, SOCK_STREAM
, 0, td
);
253 * Reserve some buffer space
255 res
= pt
->pt_size
+ sizeof(pcred
) + 512; /* XXX */
256 error
= soreserve(so
, res
, res
, &td
->td_proc
->p_rlimit
[RLIMIT_SBSIZE
]);
261 * Kick off connection
263 error
= portal_connect(so
, (struct socket
*)fmp
->pm_server
->f_data
);
268 * Wait for connection to complete
271 * XXX: Since the mount point is holding a reference on the
272 * underlying server socket, it is not easy to find out whether
273 * the server process is still running. To handle this problem
274 * we loop waiting for the new socket to be connected (something
275 * which will only happen if the server is still running) or for
276 * the reference count on the server socket to drop to 1, which
277 * will happen if the server dies. Sleep for 5 second intervals
278 * and keep polling the reference count. XXX.
281 while ((so
->so_state
& SS_ISCONNECTING
) && so
->so_error
== 0) {
282 if (fmp
->pm_server
->f_count
== 1) {
283 error
= ECONNREFUSED
;
287 (void) tsleep((caddr_t
) &so
->so_timeo
, 0, "portalcon", 5 * hz
);
292 error
= so
->so_error
;
297 * Set miscellaneous flags
299 so
->so_rcv
.ssb_timeo
= 0;
300 so
->so_snd
.ssb_timeo
= 0;
301 so
->so_rcv
.ssb_flags
|= SSB_NOINTR
;
302 so
->so_snd
.ssb_flags
|= SSB_NOINTR
;
305 pcred
.pcr_flag
= ap
->a_mode
;
306 pcred
.pcr_uid
= ap
->a_cred
->cr_uid
;
307 pcred
.pcr_ngroups
= ap
->a_cred
->cr_ngroups
;
308 bcopy(ap
->a_cred
->cr_groups
, pcred
.pcr_groups
, NGROUPS
* sizeof(gid_t
));
309 aiov
[0].iov_base
= (caddr_t
) &pcred
;
310 aiov
[0].iov_len
= sizeof(pcred
);
311 aiov
[1].iov_base
= pt
->pt_arg
;
312 aiov
[1].iov_len
= pt
->pt_size
;
315 auio
.uio_rw
= UIO_WRITE
;
316 auio
.uio_segflg
= UIO_SYSSPACE
;
319 auio
.uio_resid
= aiov
[0].iov_len
+ aiov
[1].iov_len
;
321 error
= sosend(so
, (struct sockaddr
*) 0, &auio
,
322 (struct mbuf
*) 0, (struct mbuf
*) 0, 0, td
);
333 error
= soreceive(so
, NULL
, NULL
, &sio
, &cm
, &flags
);
338 * Grab an error code from the mbuf.
340 if ((m
= sio
.sb_mb
) != NULL
) {
341 m
= m_pullup(m
, sizeof(int)); /* Needed? */
343 error
= *(mtod(m
, int *));
350 error
= ECONNRESET
; /* XXX */
356 } while (cm
== NULL
&& sio
.sb_cc
== 0 && !error
);
361 if (auio
.uio_resid
) {
370 * XXX: Break apart the control message, and retrieve the
371 * received file descriptor. Note that more than one descriptor
372 * may have been received, or that the rights chain may have more
373 * than a single mbuf in it. What to do?
375 cmsg
= mtod(cm
, struct cmsghdr
*);
376 newfds
= (cmsg
->cmsg_len
- sizeof(*cmsg
)) / sizeof (int);
378 error
= ECONNREFUSED
;
382 * At this point the rights message consists of a control message
383 * header, followed by a data region containing a vector of
384 * integer file descriptors. The fds were allocated by the action
385 * of receiving the control message.
387 ip
= (int *) (cmsg
+ 1);
394 kprintf("portal_open: %d extra fds\n", newfds
- 1);
395 for (i
= 1; i
< newfds
; i
++) {
396 portal_closefd(td
, *ip
);
402 * Check that the mode the file is being opened for is a subset
403 * of the mode of the existing descriptor.
405 KKASSERT(td
->td_proc
);
406 fp
= td
->td_proc
->p_fd
->fd_files
[fd
].fp
;
407 if (((ap
->a_mode
& (FREAD
|FWRITE
)) | fp
->f_flag
) != fp
->f_flag
) {
408 portal_closefd(td
, fd
);
414 * Save the dup fd in the proc structure then return the
415 * special error code (ENXIO) which causes magic things to
416 * happen in vn_open. The whole concept is, well, hmmm.
418 td
->td_lwp
->lwp_dupfd
= fd
;
424 * And discard the control message.
431 soshutdown(so
, SHUT_RDWR
);
432 soclose(so
, FNONBLOCK
);
438 * portal_getattr(struct vnode *a_vp, struct vattr *a_vap)
441 portal_getattr(struct vop_getattr_args
*ap
)
443 struct vnode
*vp
= ap
->a_vp
;
444 struct vattr
*vap
= ap
->a_vap
;
446 bzero(vap
, sizeof(*vap
));
450 vap
->va_size
= DEV_BSIZE
;
451 vap
->va_blocksize
= DEV_BSIZE
;
452 nanotime(&vap
->va_atime
);
453 vap
->va_mtime
= vap
->va_atime
;
454 vap
->va_ctime
= vap
->va_mtime
;
457 vap
->va_rmajor
= VNOVAL
;
458 vap
->va_rminor
= VNOVAL
;
459 /* vap->va_qbytes = 0; */
461 /* vap->va_qsize = 0; */
462 if (vp
->v_flag
& VROOT
) {
464 vap
->va_mode
= S_IRUSR
|S_IWUSR
|S_IXUSR
|
465 S_IRGRP
|S_IWGRP
|S_IXGRP
|
466 S_IROTH
|S_IWOTH
|S_IXOTH
;
471 vap
->va_mode
= S_IRUSR
|S_IWUSR
|
475 vap
->va_fileid
= VTOPORTAL(vp
)->pt_fileid
;
481 * portal_setattr(struct vnode *a_vp, struct vattr *a_vap,
482 * struct ucred *a_cred)
485 portal_setattr(struct vop_setattr_args
*ap
)
488 * Can't mess with the root vnode
490 if (ap
->a_vp
->v_flag
& VROOT
)
493 if (ap
->a_vap
->va_flags
!= VNOVAL
)
500 * Fake readdir, just return empty directory.
501 * It is hard to deal with '.' and '..' so don't bother.
503 * portal_readdir(struct vnode *a_vp, struct uio *a_uio,
504 * struct ucred *a_cred, int *a_eofflag,
505 * off_t *a_cookies, int a_ncookies)
508 portal_readdir(struct vop_readdir_args
*ap
)
511 * We don't allow exporting portal mounts, and currently local
512 * requests do not need cookies.
515 panic("portal_readdir: not hungry");
521 * portal_inactive(struct vnode *a_vp)
524 portal_inactive(struct vop_inactive_args
*ap
)
530 * portal_reclaim(struct vnode *a_vp)
533 portal_reclaim(struct vop_reclaim_args
*ap
)
535 struct portalnode
*pt
= VTOPORTAL(ap
->a_vp
);
538 kfree((caddr_t
) pt
->pt_arg
, M_TEMP
);
541 FREE(ap
->a_vp
->v_data
, M_TEMP
);
542 ap
->a_vp
->v_data
= 0;
549 * Print out the contents of a Portal vnode.
551 * portal_print(struct vnode *a_vp)
555 portal_print(struct vop_print_args
*ap
)
557 kprintf("tag VT_PORTAL, portal vnode\n");
563 * Portal "should never get here" operation
569 panic("portal: bad op");
573 struct vop_ops portal_vnode_vops
= {
574 .vop_default
= vop_defaultop
,
575 .vop_access
= (void *)vop_null
,
576 .vop_bmap
= (void *)portal_badop
,
577 .vop_getattr
= portal_getattr
,
578 .vop_inactive
= portal_inactive
,
579 .vop_old_lookup
= portal_lookup
,
580 .vop_open
= portal_open
,
581 .vop_pathconf
= vop_stdpathconf
,
582 .vop_print
= portal_print
,
583 .vop_readdir
= portal_readdir
,
584 .vop_reclaim
= portal_reclaim
,
585 .vop_setattr
= portal_setattr