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 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * @(#)portal_vnops.c 8.14 (Berkeley) 5/21/95
34 * $FreeBSD: src/sys/miscfs/portal/portal_vnops.c,v 1.38 1999/12/21 06:29:00 chris Exp $
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/sysproto.h>
44 #include <sys/kernel.h>
47 #include <sys/filedesc.h>
48 #include <sys/vnode.h>
49 #include <sys/fcntl.h>
52 #include <sys/mount.h>
53 #include <sys/malloc.h>
54 #include <sys/namei.h>
56 #include <sys/resourcevar.h>
57 #include <sys/socket.h>
58 #include <sys/socketvar.h>
60 #include <sys/unpcb.h>
63 #include <sys/thread2.h>
65 static int portal_fileid
= PORTAL_ROOTFILEID
+1;
67 static int portal_badop (void);
68 static void portal_closefd (struct thread
*td
, int fd
);
69 static int portal_connect (struct socket
*so
, struct socket
*so2
);
70 static int portal_getattr (struct vop_getattr_args
*ap
);
71 static int portal_inactive (struct vop_inactive_args
*ap
);
72 static int portal_lookup (struct vop_old_lookup_args
*ap
);
73 static int portal_open (struct vop_open_args
*ap
);
74 static int portal_print (struct vop_print_args
*ap
);
75 static int portal_readdir (struct vop_readdir_args
*ap
);
76 static int portal_reclaim (struct vop_reclaim_args
*ap
);
77 static int portal_setattr (struct vop_setattr_args
*ap
);
80 portal_closefd(struct thread
*td
, int fd
)
86 error
= sys_close(&ua
);
88 * We should never get an error, and there isn't anything
89 * we could do if we got one, so just print a message.
92 kprintf("portal_closefd: error = %d\n", error
);
96 * vp is the current namei directory
97 * cnp is the name to locate in that directory...
99 * portal_lookup(struct vnode *a_dvp, struct vnode **a_vpp,
100 * struct componentname *a_cnp)
103 portal_lookup(struct vop_old_lookup_args
*ap
)
105 struct componentname
*cnp
= ap
->a_cnp
;
106 struct vnode
**vpp
= ap
->a_vpp
;
107 struct vnode
*dvp
= ap
->a_dvp
;
108 char *pname
= cnp
->cn_nameptr
;
109 struct portalnode
*pt
;
111 struct vnode
*fvp
= NULL
;
117 if (cnp
->cn_nameiop
== NAMEI_DELETE
|| cnp
->cn_nameiop
== NAMEI_RENAME
)
120 if (cnp
->cn_namelen
== 1 && *pname
== '.') {
127 * Do the MALLOC before the getnewvnode since doing so afterward
128 * might cause a bogus v_data pointer to get dereferenced
129 * elsewhere if MALLOC should block.
131 pt
= kmalloc(sizeof(struct portalnode
), M_TEMP
, M_WAITOK
);
133 error
= getnewvnode(VT_PORTAL
, dvp
->v_mount
, &fvp
, 0, 0);
142 * Save all of the remaining pathname and
143 * advance the namei next pointer to the end
146 for (size
= 0, path
= pname
; *path
; path
++)
148 cnp
->cn_consume
= size
- cnp
->cn_namelen
;
150 pt
->pt_arg
= kmalloc(size
+1, M_TEMP
, M_WAITOK
);
151 pt
->pt_size
= size
+1;
152 bcopy(pname
, pt
->pt_arg
, pt
->pt_size
);
153 pt
->pt_fileid
= portal_fileid
++;
166 portal_connect(struct socket
*so
, struct socket
*so2
)
168 /* from unp_connect, bypassing the namei stuff... */
174 return (ECONNREFUSED
);
176 if (so
->so_type
!= so2
->so_type
)
179 if ((so2
->so_options
& SO_ACCEPTCONN
) == 0)
180 return (ECONNREFUSED
);
182 if ((so3
= sonewconn(so2
, 0)) == NULL
)
183 return (ECONNREFUSED
);
188 unp3
->unp_addr
= (struct sockaddr_un
*)
189 dup_sockaddr((struct sockaddr
*)unp2
->unp_addr
);
192 return (unp_connect2(so
, so2
));
196 * portal_open(struct vnode *a_vp, int a_mode, struct ucred *a_cred,
200 portal_open(struct vop_open_args
*ap
)
202 struct socket
*so
= NULL
;
203 struct portalnode
*pt
;
204 struct thread
*td
= curthread
;
205 struct vnode
*vp
= ap
->a_vp
;
207 struct iovec aiov
[2];
210 struct mbuf
*cm
= NULL
;
211 struct cmsghdr
*cmsg
;
217 struct portalmount
*fmp
;
219 struct portal_cred pcred
;
222 * Nothing to do when opening the root node.
224 if (vp
->v_flag
& VROOT
)
225 return (vop_stdopen(ap
));
228 * Can't be opened unless the caller is set up
229 * to deal with the side effects. Check for this
230 * by testing whether the p_dupfd has been set.
232 KKASSERT(td
->td_proc
);
233 if (td
->td_lwp
->lwp_dupfd
>= 0)
237 fmp
= VFSTOPORTAL(vp
->v_mount
);
240 * Create a new socket.
242 error
= socreate(AF_UNIX
, &so
, SOCK_STREAM
, 0, td
);
247 * Reserve some buffer space
249 res
= pt
->pt_size
+ sizeof(pcred
) + 512; /* XXX */
250 error
= soreserve(so
, res
, res
, &td
->td_proc
->p_rlimit
[RLIMIT_SBSIZE
]);
255 * Kick off connection
257 error
= portal_connect(so
, (struct socket
*)fmp
->pm_server
->f_data
);
262 * Wait for connection to complete
265 * XXX: Since the mount point is holding a reference on the
266 * underlying server socket, it is not easy to find out whether
267 * the server process is still running. To handle this problem
268 * we loop waiting for the new socket to be connected (something
269 * which will only happen if the server is still running) or for
270 * the reference count on the server socket to drop to 1, which
271 * will happen if the server dies. Sleep for 5 second intervals
272 * and keep polling the reference count. XXX.
275 while ((so
->so_state
& SS_ISCONNECTING
) && so
->so_error
== 0) {
276 if (fmp
->pm_server
->f_count
== 1) {
277 error
= ECONNREFUSED
;
281 (void) tsleep((caddr_t
) &so
->so_timeo
, 0, "portalcon", 5 * hz
);
286 error
= so
->so_error
;
291 * Set miscellaneous flags
293 so
->so_rcv
.ssb_timeo
= 0;
294 so
->so_snd
.ssb_timeo
= 0;
295 atomic_set_int(&so
->so_rcv
.ssb_flags
, SSB_NOINTR
);
296 atomic_set_int(&so
->so_snd
.ssb_flags
, SSB_NOINTR
);
299 pcred
.pcr_flag
= ap
->a_mode
;
300 pcred
.pcr_uid
= ap
->a_cred
->cr_uid
;
301 pcred
.pcr_ngroups
= ap
->a_cred
->cr_ngroups
;
302 bcopy(ap
->a_cred
->cr_groups
, pcred
.pcr_groups
, NGROUPS
* sizeof(gid_t
));
303 aiov
[0].iov_base
= (caddr_t
) &pcred
;
304 aiov
[0].iov_len
= sizeof(pcred
);
305 aiov
[1].iov_base
= pt
->pt_arg
;
306 aiov
[1].iov_len
= pt
->pt_size
;
309 auio
.uio_rw
= UIO_WRITE
;
310 auio
.uio_segflg
= UIO_SYSSPACE
;
313 auio
.uio_resid
= aiov
[0].iov_len
+ aiov
[1].iov_len
;
315 error
= sosend(so
, NULL
, &auio
, NULL
, NULL
, 0, td
);
326 error
= soreceive(so
, NULL
, NULL
, &sio
, &cm
, &flags
);
331 * Grab an error code from the mbuf.
333 if ((m
= sio
.sb_mb
) != NULL
) {
334 m
= m_pullup(m
, sizeof(int)); /* Needed? */
336 error
= *(mtod(m
, int *));
343 error
= ECONNRESET
; /* XXX */
349 } while (cm
== NULL
&& sio
.sb_cc
== 0 && !error
);
354 if (auio
.uio_resid
) {
363 * XXX: Break apart the control message, and retrieve the
364 * received file descriptor. Note that more than one descriptor
365 * may have been received, or that the rights chain may have more
366 * than a single mbuf in it. What to do?
368 cmsg
= mtod(cm
, struct cmsghdr
*);
369 newfds
= (cmsg
->cmsg_len
- sizeof(*cmsg
)) / sizeof (int);
371 error
= ECONNREFUSED
;
375 * At this point the rights message consists of a control message
376 * header, followed by a data region containing a vector of
377 * integer file descriptors. The fds were allocated by the action
378 * of receiving the control message.
380 ip
= (int *) (cmsg
+ 1);
387 kprintf("portal_open: %d extra fds\n", newfds
- 1);
388 for (i
= 1; i
< newfds
; i
++) {
389 portal_closefd(td
, *ip
);
395 * Check that the mode the file is being opened for is a subset
396 * of the mode of the existing descriptor.
398 KKASSERT(td
->td_proc
);
399 fp
= td
->td_proc
->p_fd
->fd_files
[fd
].fp
;
400 if (((ap
->a_mode
& (FREAD
|FWRITE
)) | fp
->f_flag
) != fp
->f_flag
) {
401 portal_closefd(td
, fd
);
407 * Save the dup fd in the proc structure then return the
408 * special error code (ENXIO) which causes magic things to
409 * happen in vn_open. The whole concept is, well, hmmm.
411 td
->td_lwp
->lwp_dupfd
= fd
;
417 * And discard the control message.
424 soshutdown(so
, SHUT_RDWR
);
425 soclose(so
, FNONBLOCK
);
431 * portal_getattr(struct vnode *a_vp, struct vattr *a_vap)
434 portal_getattr(struct vop_getattr_args
*ap
)
436 struct vnode
*vp
= ap
->a_vp
;
437 struct vattr
*vap
= ap
->a_vap
;
439 bzero(vap
, sizeof(*vap
));
443 vap
->va_size
= DEV_BSIZE
;
444 vap
->va_blocksize
= DEV_BSIZE
;
445 nanotime(&vap
->va_atime
);
446 vap
->va_mtime
= vap
->va_atime
;
447 vap
->va_ctime
= vap
->va_mtime
;
450 vap
->va_rmajor
= VNOVAL
;
451 vap
->va_rminor
= VNOVAL
;
452 /* vap->va_qbytes = 0; */
454 /* vap->va_qsize = 0; */
455 if (vp
->v_flag
& VROOT
) {
457 vap
->va_mode
= S_IRUSR
|S_IWUSR
|S_IXUSR
|
458 S_IRGRP
|S_IWGRP
|S_IXGRP
|
459 S_IROTH
|S_IWOTH
|S_IXOTH
;
464 vap
->va_mode
= S_IRUSR
|S_IWUSR
|
468 vap
->va_fileid
= VTOPORTAL(vp
)->pt_fileid
;
474 * portal_setattr(struct vnode *a_vp, struct vattr *a_vap,
475 * struct ucred *a_cred)
478 portal_setattr(struct vop_setattr_args
*ap
)
481 * Can't mess with the root vnode
483 if (ap
->a_vp
->v_flag
& VROOT
)
486 if (ap
->a_vap
->va_flags
!= VNOVAL
)
493 * Fake readdir, just return empty directory.
494 * It is hard to deal with '.' and '..' so don't bother.
496 * portal_readdir(struct vnode *a_vp, struct uio *a_uio,
497 * struct ucred *a_cred, int *a_eofflag,
498 * off_t *a_cookies, int a_ncookies)
501 portal_readdir(struct vop_readdir_args
*ap
)
504 * We don't allow exporting portal mounts, and currently local
505 * requests do not need cookies.
508 panic("portal_readdir: not hungry");
514 * portal_inactive(struct vnode *a_vp)
517 portal_inactive(struct vop_inactive_args
*ap
)
523 * portal_reclaim(struct vnode *a_vp)
526 portal_reclaim(struct vop_reclaim_args
*ap
)
528 struct portalnode
*pt
= VTOPORTAL(ap
->a_vp
);
531 kfree((caddr_t
) pt
->pt_arg
, M_TEMP
);
534 kfree(ap
->a_vp
->v_data
, M_TEMP
);
535 ap
->a_vp
->v_data
= 0;
542 * Print out the contents of a Portal vnode.
544 * portal_print(struct vnode *a_vp)
548 portal_print(struct vop_print_args
*ap
)
550 kprintf("tag VT_PORTAL, portal vnode\n");
556 * Portal "should never get here" operation
562 panic("portal: bad op");
566 struct vop_ops portal_vnode_vops
= {
567 .vop_default
= vop_defaultop
,
568 .vop_access
= (void *)vop_null
,
569 .vop_bmap
= (void *)portal_badop
,
570 .vop_getattr
= portal_getattr
,
571 .vop_inactive
= portal_inactive
,
572 .vop_old_lookup
= portal_lookup
,
573 .vop_open
= portal_open
,
574 .vop_pathconf
= vop_stdpathconf
,
575 .vop_print
= portal_print
,
576 .vop_readdir
= portal_readdir
,
577 .vop_reclaim
= portal_reclaim
,
578 .vop_setattr
= portal_setattr