xref: /freebsd/sys/fs/pseudofs/pseudofs_vnops.c (revision e738085b94631f90e21a49852538ac95974baf44)
19733a808SDag-Erling Smørgrav /*-
2d63027b6SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
3d63027b6SPedro F. Giffuni  *
4*e738085bSDag-Erling Smørgrav  * Copyright (c) 2001 Dag-Erling Smørgrav
59733a808SDag-Erling Smørgrav  * All rights reserved.
69733a808SDag-Erling Smørgrav  *
79733a808SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
89733a808SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
99733a808SDag-Erling Smørgrav  * are met:
109733a808SDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
119733a808SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer
129733a808SDag-Erling Smørgrav  *    in this position and unchanged.
139733a808SDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
149733a808SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
159733a808SDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
169733a808SDag-Erling Smørgrav  * 3. The name of the author may not be used to endorse or promote products
179733a808SDag-Erling Smørgrav  *    derived from this software without specific prior written permission.
189733a808SDag-Erling Smørgrav  *
199733a808SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
209733a808SDag-Erling Smørgrav  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
219733a808SDag-Erling Smørgrav  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
229733a808SDag-Erling Smørgrav  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
239733a808SDag-Erling Smørgrav  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
249733a808SDag-Erling Smørgrav  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
259733a808SDag-Erling Smørgrav  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
269733a808SDag-Erling Smørgrav  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
279733a808SDag-Erling Smørgrav  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
289733a808SDag-Erling Smørgrav  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
299733a808SDag-Erling Smørgrav  */
309733a808SDag-Erling Smørgrav 
31de52d21aSDag-Erling Smørgrav #include <sys/cdefs.h>
32de52d21aSDag-Erling Smørgrav #include "opt_pseudofs.h"
33de52d21aSDag-Erling Smørgrav 
349733a808SDag-Erling Smørgrav #include <sys/param.h>
359733a808SDag-Erling Smørgrav #include <sys/kernel.h>
369733a808SDag-Erling Smørgrav #include <sys/systm.h>
379733a808SDag-Erling Smørgrav #include <sys/ctype.h>
389733a808SDag-Erling Smørgrav #include <sys/dirent.h>
397d8f809fSDag-Erling Smørgrav #include <sys/fcntl.h>
408b7358caSJacques Vidrine #include <sys/limits.h>
4121ceb6efSDag-Erling Smørgrav #include <sys/lock.h>
42bc593ccdSDag-Erling Smørgrav #include <sys/malloc.h>
439733a808SDag-Erling Smørgrav #include <sys/mount.h>
441e4ebf4eSDag-Erling Smørgrav #include <sys/mutex.h>
459733a808SDag-Erling Smørgrav #include <sys/namei.h>
469733a808SDag-Erling Smørgrav #include <sys/proc.h>
479733a808SDag-Erling Smørgrav #include <sys/sbuf.h>
489733a808SDag-Erling Smørgrav #include <sys/sx.h>
499733a808SDag-Erling Smørgrav #include <sys/sysctl.h>
509733a808SDag-Erling Smørgrav #include <sys/vnode.h>
519733a808SDag-Erling Smørgrav 
529733a808SDag-Erling Smørgrav #include <fs/pseudofs/pseudofs.h>
539733a808SDag-Erling Smørgrav #include <fs/pseudofs/pseudofs_internal.h>
549733a808SDag-Erling Smørgrav 
5559fc1b06SDag-Erling Smørgrav #define KASSERT_PN_IS_DIR(pn)						\
5659fc1b06SDag-Erling Smørgrav 	KASSERT((pn)->pn_type == pfstype_root ||			\
5759fc1b06SDag-Erling Smørgrav 	    (pn)->pn_type == pfstype_dir ||				\
5859fc1b06SDag-Erling Smørgrav 	    (pn)->pn_type == pfstype_procdir,				\
5959fc1b06SDag-Erling Smørgrav 	    ("%s(): VDIR vnode refers to non-directory pfs_node", __func__))
6059fc1b06SDag-Erling Smørgrav 
6159fc1b06SDag-Erling Smørgrav #define KASSERT_PN_IS_FILE(pn)						\
6259fc1b06SDag-Erling Smørgrav 	KASSERT((pn)->pn_type == pfstype_file,				\
6359fc1b06SDag-Erling Smørgrav 	    ("%s(): VREG vnode refers to non-file pfs_node", __func__))
6459fc1b06SDag-Erling Smørgrav 
6559fc1b06SDag-Erling Smørgrav #define KASSERT_PN_IS_LINK(pn)						\
6659fc1b06SDag-Erling Smørgrav 	KASSERT((pn)->pn_type == pfstype_symlink,			\
6759fc1b06SDag-Erling Smørgrav 	    ("%s(): VLNK vnode refers to non-link pfs_node", __func__))
6859fc1b06SDag-Erling Smørgrav 
69ce764cbdSEdward Tomasz Napierala #define	PFS_MAXBUFSIZ		1024 * 1024
70ce764cbdSEdward Tomasz Napierala 
719733a808SDag-Erling Smørgrav /*
72388596dfSDag-Erling Smørgrav  * Returns the fileno, adjusted for target pid
73f61bc4eaSDag-Erling Smørgrav  */
74f61bc4eaSDag-Erling Smørgrav static uint32_t
pn_fileno(struct pfs_node * pn,pid_t pid)75388596dfSDag-Erling Smørgrav pn_fileno(struct pfs_node *pn, pid_t pid)
76f61bc4eaSDag-Erling Smørgrav {
77388596dfSDag-Erling Smørgrav 
78388596dfSDag-Erling Smørgrav 	KASSERT(pn->pn_fileno > 0,
79388596dfSDag-Erling Smørgrav 	    ("%s(): no fileno allocated", __func__));
80f61bc4eaSDag-Erling Smørgrav 	if (pid != NO_PID)
81f61bc4eaSDag-Erling Smørgrav 		return (pn->pn_fileno * NO_PID + pid);
82f61bc4eaSDag-Erling Smørgrav 	return (pn->pn_fileno);
83f61bc4eaSDag-Erling Smørgrav }
84f61bc4eaSDag-Erling Smørgrav 
85f61bc4eaSDag-Erling Smørgrav /*
86388596dfSDag-Erling Smørgrav  * Returns non-zero if given file is visible to given thread.
87198bc14bSDag-Erling Smørgrav  */
88198bc14bSDag-Erling Smørgrav static int
pfs_visible_proc(struct thread * td,struct pfs_node * pn,struct proc * proc)89388596dfSDag-Erling Smørgrav pfs_visible_proc(struct thread *td, struct pfs_node *pn, struct proc *proc)
90388596dfSDag-Erling Smørgrav {
91388596dfSDag-Erling Smørgrav 
92388596dfSDag-Erling Smørgrav 	if (proc == NULL)
93388596dfSDag-Erling Smørgrav 		return (0);
94388596dfSDag-Erling Smørgrav 
95388596dfSDag-Erling Smørgrav 	PROC_LOCK_ASSERT(proc, MA_OWNED);
96388596dfSDag-Erling Smørgrav 
97a32ed5ecSDmitry Chagin 	if ((proc->p_flag & P_WEXIT) != 0)
98388596dfSDag-Erling Smørgrav 		return (0);
99a32ed5ecSDmitry Chagin 	if (p_cansee(td, proc) != 0)
100a32ed5ecSDmitry Chagin 		return (0);
101a32ed5ecSDmitry Chagin 	return (pn_vis(td, proc, pn));
102388596dfSDag-Erling Smørgrav }
103388596dfSDag-Erling Smørgrav 
104388596dfSDag-Erling Smørgrav static int
pfs_visible(struct thread * td,struct pfs_node * pn,pid_t pid,struct proc ** p)105ffc161dfSKonstantin Belousov pfs_visible(struct thread *td, struct pfs_node *pn, pid_t pid,
10653011553SMateusz Guzik     struct proc **p)
107198bc14bSDag-Erling Smørgrav {
108198bc14bSDag-Erling Smørgrav 	struct proc *proc;
109198bc14bSDag-Erling Smørgrav 
110198bc14bSDag-Erling Smørgrav 	PFS_TRACE(("%s (pid: %d, req: %d)",
111198bc14bSDag-Erling Smørgrav 	    pn->pn_name, pid, td->td_proc->p_pid));
112b84ce334SDag-Erling Smørgrav 
113f8e3eeb5SJohn Baldwin 	if (p)
114f8e3eeb5SJohn Baldwin 		*p = NULL;
115388596dfSDag-Erling Smørgrav 	if (pid == NO_PID)
116405c0c04SDmitry Chagin 		PFS_RETURN (pn_vis(td, NULL, pn));
11753011553SMateusz Guzik 	proc = pfind(pid);
118ffc161dfSKonstantin Belousov 	if (proc == NULL)
119388596dfSDag-Erling Smørgrav 		PFS_RETURN (0);
120388596dfSDag-Erling Smørgrav 	if (pfs_visible_proc(td, pn, proc)) {
121388596dfSDag-Erling Smørgrav 		if (p)
122388596dfSDag-Erling Smørgrav 			*p = proc;
123388596dfSDag-Erling Smørgrav 		else
124388596dfSDag-Erling Smørgrav 			PROC_UNLOCK(proc);
125388596dfSDag-Erling Smørgrav 		PFS_RETURN (1);
126388596dfSDag-Erling Smørgrav 	}
127388596dfSDag-Erling Smørgrav 	PROC_UNLOCK(proc);
128388596dfSDag-Erling Smørgrav 	PFS_RETURN (0);
129198bc14bSDag-Erling Smørgrav }
130198bc14bSDag-Erling Smørgrav 
131f5791174SMateusz Guzik static int
pfs_lookup_proc(pid_t pid,struct proc ** p)132f5791174SMateusz Guzik pfs_lookup_proc(pid_t pid, struct proc **p)
133f5791174SMateusz Guzik {
134f5791174SMateusz Guzik 	struct proc *proc;
135f5791174SMateusz Guzik 
136f5791174SMateusz Guzik 	proc = pfind(pid);
137f5791174SMateusz Guzik 	if (proc == NULL)
138f5791174SMateusz Guzik 		return (0);
139f5791174SMateusz Guzik 	if ((proc->p_flag & P_WEXIT) != 0) {
140f5791174SMateusz Guzik 		PROC_UNLOCK(proc);
141f5791174SMateusz Guzik 		return (0);
142f5791174SMateusz Guzik 	}
143f5791174SMateusz Guzik 	_PHOLD(proc);
144f5791174SMateusz Guzik 	PROC_UNLOCK(proc);
145f5791174SMateusz Guzik 	*p = proc;
146f5791174SMateusz Guzik 	return (1);
147f5791174SMateusz Guzik }
148f5791174SMateusz Guzik 
149198bc14bSDag-Erling Smørgrav /*
1509733a808SDag-Erling Smørgrav  * Verify permissions
1519733a808SDag-Erling Smørgrav  */
1529733a808SDag-Erling Smørgrav static int
pfs_access(struct vop_access_args * va)1539733a808SDag-Erling Smørgrav pfs_access(struct vop_access_args *va)
1549733a808SDag-Erling Smørgrav {
1559733a808SDag-Erling Smørgrav 	struct vnode *vn = va->a_vp;
156388596dfSDag-Erling Smørgrav 	struct pfs_vdata *pvd = vn->v_data;
1579733a808SDag-Erling Smørgrav 	struct vattr vattr;
1589733a808SDag-Erling Smørgrav 	int error;
1599733a808SDag-Erling Smørgrav 
160388596dfSDag-Erling Smørgrav 	PFS_TRACE(("%s", pvd->pvd_pn->pn_name));
1618edf8ae1SDag-Erling Smørgrav 	(void)pvd;
16280a3cef8SDag-Erling Smørgrav 
1630359a12eSAttilio Rao 	error = VOP_GETATTR(vn, &vattr, va->a_cred);
1649733a808SDag-Erling Smørgrav 	if (error)
165198bc14bSDag-Erling Smørgrav 		PFS_RETURN (error);
166d292b194SMateusz Guzik 	error = vaccess(vn->v_type, vattr.va_mode, vattr.va_uid, vattr.va_gid,
167d292b194SMateusz Guzik 	    va->a_accmode, va->a_cred);
168198bc14bSDag-Erling Smørgrav 	PFS_RETURN (error);
1699733a808SDag-Erling Smørgrav }
1709733a808SDag-Erling Smørgrav 
1719733a808SDag-Erling Smørgrav /*
1729733a808SDag-Erling Smørgrav  * Close a file or directory
1739733a808SDag-Erling Smørgrav  */
1749733a808SDag-Erling Smørgrav static int
pfs_close(struct vop_close_args * va)1759733a808SDag-Erling Smørgrav pfs_close(struct vop_close_args *va)
1769733a808SDag-Erling Smørgrav {
17798c7e22cSDag-Erling Smørgrav 	struct vnode *vn = va->a_vp;
178388596dfSDag-Erling Smørgrav 	struct pfs_vdata *pvd = vn->v_data;
17998c7e22cSDag-Erling Smørgrav 	struct pfs_node *pn = pvd->pvd_pn;
18098c7e22cSDag-Erling Smørgrav 	struct proc *proc;
18198c7e22cSDag-Erling Smørgrav 	int error;
18298c7e22cSDag-Erling Smørgrav 
183388596dfSDag-Erling Smørgrav 	PFS_TRACE(("%s", pn->pn_name));
184388596dfSDag-Erling Smørgrav 	pfs_assert_not_owned(pn);
18598c7e22cSDag-Erling Smørgrav 
18698c7e22cSDag-Erling Smørgrav 	/*
18798c7e22cSDag-Erling Smørgrav 	 * Do nothing unless this is the last close and the node has a
18898c7e22cSDag-Erling Smørgrav 	 * last-close handler.
18998c7e22cSDag-Erling Smørgrav 	 */
1904d93c0beSJeff Roberson 	if (vrefcnt(vn) > 1 || pn->pn_close == NULL)
1917d8f809fSDag-Erling Smørgrav 		PFS_RETURN (0);
19298c7e22cSDag-Erling Smørgrav 
193388596dfSDag-Erling Smørgrav 	if (pvd->pvd_pid != NO_PID) {
19498c7e22cSDag-Erling Smørgrav 		proc = pfind(pvd->pvd_pid);
195388596dfSDag-Erling Smørgrav 	} else {
19698c7e22cSDag-Erling Smørgrav 		proc = NULL;
197388596dfSDag-Erling Smørgrav 	}
19898c7e22cSDag-Erling Smørgrav 
199388596dfSDag-Erling Smørgrav 	error = pn_close(va->a_td, proc, pn);
20098c7e22cSDag-Erling Smørgrav 
20198c7e22cSDag-Erling Smørgrav 	if (proc != NULL)
20298c7e22cSDag-Erling Smørgrav 		PROC_UNLOCK(proc);
20398c7e22cSDag-Erling Smørgrav 
20498c7e22cSDag-Erling Smørgrav 	PFS_RETURN (error);
2059733a808SDag-Erling Smørgrav }
2069733a808SDag-Erling Smørgrav 
2079733a808SDag-Erling Smørgrav /*
2089733a808SDag-Erling Smørgrav  * Get file attributes
2099733a808SDag-Erling Smørgrav  */
2109733a808SDag-Erling Smørgrav static int
pfs_getattr(struct vop_getattr_args * va)2119733a808SDag-Erling Smørgrav pfs_getattr(struct vop_getattr_args *va)
2129733a808SDag-Erling Smørgrav {
2139733a808SDag-Erling Smørgrav 	struct vnode *vn = va->a_vp;
214388596dfSDag-Erling Smørgrav 	struct pfs_vdata *pvd = vn->v_data;
215649ad985SDag-Erling Smørgrav 	struct pfs_node *pn = pvd->pvd_pn;
2169733a808SDag-Erling Smørgrav 	struct vattr *vap = va->a_vap;
21780a3cef8SDag-Erling Smørgrav 	struct proc *proc;
21880a3cef8SDag-Erling Smørgrav 	int error = 0;
21980a3cef8SDag-Erling Smørgrav 
220388596dfSDag-Erling Smørgrav 	PFS_TRACE(("%s", pn->pn_name));
221388596dfSDag-Erling Smørgrav 	pfs_assert_not_owned(pn);
2229733a808SDag-Erling Smørgrav 
22353011553SMateusz Guzik 	if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
224134ce0f9SDag-Erling Smørgrav 		PFS_RETURN (ENOENT);
225134ce0f9SDag-Erling Smørgrav 
2269733a808SDag-Erling Smørgrav 	vap->va_type = vn->v_type;
227388596dfSDag-Erling Smørgrav 	vap->va_fileid = pn_fileno(pn, pvd->pvd_pid);
2289733a808SDag-Erling Smørgrav 	vap->va_flags = 0;
2299733a808SDag-Erling Smørgrav 	vap->va_blocksize = PAGE_SIZE;
2309733a808SDag-Erling Smørgrav 	vap->va_bytes = vap->va_size = 0;
231caf8aec8SKonstantin Belousov 	vap->va_filerev = 0;
2329733a808SDag-Erling Smørgrav 	vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0];
2339733a808SDag-Erling Smørgrav 	vap->va_nlink = 1;
2349733a808SDag-Erling Smørgrav 	nanotime(&vap->va_ctime);
2359733a808SDag-Erling Smørgrav 	vap->va_atime = vap->va_mtime = vap->va_ctime;
2369733a808SDag-Erling Smørgrav 
23780a3cef8SDag-Erling Smørgrav 	switch (pn->pn_type) {
23880a3cef8SDag-Erling Smørgrav 	case pfstype_procdir:
23980a3cef8SDag-Erling Smørgrav 	case pfstype_root:
24080a3cef8SDag-Erling Smørgrav 	case pfstype_dir:
241388596dfSDag-Erling Smørgrav #if 0
242388596dfSDag-Erling Smørgrav 		pfs_lock(pn);
243388596dfSDag-Erling Smørgrav 		/* compute link count */
244388596dfSDag-Erling Smørgrav 		pfs_unlock(pn);
245388596dfSDag-Erling Smørgrav #endif
24680a3cef8SDag-Erling Smørgrav 		vap->va_mode = 0555;
24780a3cef8SDag-Erling Smørgrav 		break;
24880a3cef8SDag-Erling Smørgrav 	case pfstype_file:
24980a3cef8SDag-Erling Smørgrav 	case pfstype_symlink:
2507d8f809fSDag-Erling Smørgrav 		vap->va_mode = 0444;
25180a3cef8SDag-Erling Smørgrav 		break;
25280a3cef8SDag-Erling Smørgrav 	default:
25380a3cef8SDag-Erling Smørgrav 		printf("shouldn't be here!\n");
25480a3cef8SDag-Erling Smørgrav 		vap->va_mode = 0;
25580a3cef8SDag-Erling Smørgrav 		break;
25680a3cef8SDag-Erling Smørgrav 	}
25780a3cef8SDag-Erling Smørgrav 
258f8e3eeb5SJohn Baldwin 	if (proc != NULL) {
25980a3cef8SDag-Erling Smørgrav 		vap->va_uid = proc->p_ucred->cr_ruid;
26080a3cef8SDag-Erling Smørgrav 		vap->va_gid = proc->p_ucred->cr_rgid;
26180a3cef8SDag-Erling Smørgrav 	} else {
26280a3cef8SDag-Erling Smørgrav 		vap->va_uid = 0;
26380a3cef8SDag-Erling Smørgrav 		vap->va_gid = 0;
26480a3cef8SDag-Erling Smørgrav 	}
26580a3cef8SDag-Erling Smørgrav 
266655fcdaaSDag-Erling Smørgrav 	if (pn->pn_attr != NULL)
267655fcdaaSDag-Erling Smørgrav 		error = pn_attr(curthread, proc, pn, vap);
268655fcdaaSDag-Erling Smørgrav 
269655fcdaaSDag-Erling Smørgrav 	if(proc != NULL)
270655fcdaaSDag-Erling Smørgrav 		PROC_UNLOCK(proc);
271655fcdaaSDag-Erling Smørgrav 
27280a3cef8SDag-Erling Smørgrav 	PFS_RETURN (error);
2739733a808SDag-Erling Smørgrav }
2749733a808SDag-Erling Smørgrav 
2759733a808SDag-Erling Smørgrav /*
27618319000SDag-Erling Smørgrav  * Perform an ioctl
27718319000SDag-Erling Smørgrav  */
27818319000SDag-Erling Smørgrav static int
pfs_ioctl(struct vop_ioctl_args * va)27918319000SDag-Erling Smørgrav pfs_ioctl(struct vop_ioctl_args *va)
28018319000SDag-Erling Smørgrav {
281c4df27d5SKonstantin Belousov 	struct vnode *vn;
282c4df27d5SKonstantin Belousov 	struct pfs_vdata *pvd;
283c4df27d5SKonstantin Belousov 	struct pfs_node *pn;
284f8e3eeb5SJohn Baldwin 	struct proc *proc;
28518319000SDag-Erling Smørgrav 	int error;
28618319000SDag-Erling Smørgrav 
287c4df27d5SKonstantin Belousov 	vn = va->a_vp;
288c4df27d5SKonstantin Belousov 	vn_lock(vn, LK_SHARED | LK_RETRY);
289abd80ddbSMateusz Guzik 	if (VN_IS_DOOMED(vn)) {
290b249ce48SMateusz Guzik 		VOP_UNLOCK(vn);
291c4df27d5SKonstantin Belousov 		return (EBADF);
292c4df27d5SKonstantin Belousov 	}
293c4df27d5SKonstantin Belousov 	pvd = vn->v_data;
294c4df27d5SKonstantin Belousov 	pn = pvd->pvd_pn;
295c4df27d5SKonstantin Belousov 
296c07f9fc1SDag-Erling Smørgrav 	PFS_TRACE(("%s: %lx", pn->pn_name, va->a_command));
297388596dfSDag-Erling Smørgrav 	pfs_assert_not_owned(pn);
29818319000SDag-Erling Smørgrav 
299c4df27d5SKonstantin Belousov 	if (vn->v_type != VREG) {
300b249ce48SMateusz Guzik 		VOP_UNLOCK(vn);
30118319000SDag-Erling Smørgrav 		PFS_RETURN (EINVAL);
302c4df27d5SKonstantin Belousov 	}
30359fc1b06SDag-Erling Smørgrav 	KASSERT_PN_IS_FILE(pn);
30418319000SDag-Erling Smørgrav 
305c4df27d5SKonstantin Belousov 	if (pn->pn_ioctl == NULL) {
306b249ce48SMateusz Guzik 		VOP_UNLOCK(vn);
30718319000SDag-Erling Smørgrav 		PFS_RETURN (ENOTTY);
308c4df27d5SKonstantin Belousov 	}
30918319000SDag-Erling Smørgrav 
31018319000SDag-Erling Smørgrav 	/*
311efe0afa9SJohn-Mark Gurney 	 * This is necessary because process' privileges may
31218319000SDag-Erling Smørgrav 	 * have changed since the open() call.
31318319000SDag-Erling Smørgrav 	 */
31453011553SMateusz Guzik 	if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) {
315b249ce48SMateusz Guzik 		VOP_UNLOCK(vn);
31618319000SDag-Erling Smørgrav 		PFS_RETURN (EIO);
317c4df27d5SKonstantin Belousov 	}
31818319000SDag-Erling Smørgrav 
319388596dfSDag-Erling Smørgrav 	error = pn_ioctl(curthread, proc, pn, va->a_command, va->a_data);
32018319000SDag-Erling Smørgrav 
32118319000SDag-Erling Smørgrav 	if (proc != NULL)
322388596dfSDag-Erling Smørgrav 		PROC_UNLOCK(proc);
32318319000SDag-Erling Smørgrav 
324b249ce48SMateusz Guzik 	VOP_UNLOCK(vn);
32518319000SDag-Erling Smørgrav 	PFS_RETURN (error);
32618319000SDag-Erling Smørgrav }
32718319000SDag-Erling Smørgrav 
32818319000SDag-Erling Smørgrav /*
32941a35633SBrian Feldman  * Perform getextattr
33041a35633SBrian Feldman  */
33141a35633SBrian Feldman static int
pfs_getextattr(struct vop_getextattr_args * va)33241a35633SBrian Feldman pfs_getextattr(struct vop_getextattr_args *va)
33341a35633SBrian Feldman {
33441a35633SBrian Feldman 	struct vnode *vn = va->a_vp;
335388596dfSDag-Erling Smørgrav 	struct pfs_vdata *pvd = vn->v_data;
33641a35633SBrian Feldman 	struct pfs_node *pn = pvd->pvd_pn;
337f8e3eeb5SJohn Baldwin 	struct proc *proc;
33841a35633SBrian Feldman 	int error;
33941a35633SBrian Feldman 
340388596dfSDag-Erling Smørgrav 	PFS_TRACE(("%s", pn->pn_name));
341388596dfSDag-Erling Smørgrav 	pfs_assert_not_owned(pn);
34241a35633SBrian Feldman 
34341a35633SBrian Feldman 	/*
34441a35633SBrian Feldman 	 * This is necessary because either process' privileges may
34541a35633SBrian Feldman 	 * have changed since the open() call.
34641a35633SBrian Feldman 	 */
34753011553SMateusz Guzik 	if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
34841a35633SBrian Feldman 		PFS_RETURN (EIO);
34941a35633SBrian Feldman 
350388596dfSDag-Erling Smørgrav 	if (pn->pn_getextattr == NULL)
351388596dfSDag-Erling Smørgrav 		error = EOPNOTSUPP;
352388596dfSDag-Erling Smørgrav 	else
353388596dfSDag-Erling Smørgrav 		error = pn_getextattr(curthread, proc, pn,
354388596dfSDag-Erling Smørgrav 		    va->a_attrnamespace, va->a_name, va->a_uio,
355388596dfSDag-Erling Smørgrav 		    va->a_size, va->a_cred);
35641a35633SBrian Feldman 
35741a35633SBrian Feldman 	if (proc != NULL)
358388596dfSDag-Erling Smørgrav 		PROC_UNLOCK(proc);
35941a35633SBrian Feldman 
36041a35633SBrian Feldman 	PFS_RETURN (error);
36141a35633SBrian Feldman }
36241a35633SBrian Feldman 
36341a35633SBrian Feldman /*
364e7f54c1bSJoe Marcus Clarke  * Convert a vnode to its component name
365e7f54c1bSJoe Marcus Clarke  */
366e7f54c1bSJoe Marcus Clarke static int
pfs_vptocnp(struct vop_vptocnp_args * ap)367e7f54c1bSJoe Marcus Clarke pfs_vptocnp(struct vop_vptocnp_args *ap)
368e7f54c1bSJoe Marcus Clarke {
369e7f54c1bSJoe Marcus Clarke 	struct vnode *vp = ap->a_vp;
370e7f54c1bSJoe Marcus Clarke 	struct vnode **dvp = ap->a_vpp;
371e7f54c1bSJoe Marcus Clarke 	struct pfs_vdata *pvd = vp->v_data;
372e7f54c1bSJoe Marcus Clarke 	struct pfs_node *pd = pvd->pvd_pn;
373e7f54c1bSJoe Marcus Clarke 	struct pfs_node *pn;
374e7f54c1bSJoe Marcus Clarke 	struct mount *mp;
375e7f54c1bSJoe Marcus Clarke 	char *buf = ap->a_buf;
37645757984SMateusz Guzik 	size_t *buflen = ap->a_buflen;
377e7f54c1bSJoe Marcus Clarke 	char pidbuf[PFS_NAMELEN];
378e7f54c1bSJoe Marcus Clarke 	pid_t pid = pvd->pvd_pid;
379e7f54c1bSJoe Marcus Clarke 	int len, i, error, locked;
380e7f54c1bSJoe Marcus Clarke 
381e7f54c1bSJoe Marcus Clarke 	i = *buflen;
382e7f54c1bSJoe Marcus Clarke 	error = 0;
383e7f54c1bSJoe Marcus Clarke 
384e7f54c1bSJoe Marcus Clarke 	pfs_lock(pd);
385e7f54c1bSJoe Marcus Clarke 
386e7f54c1bSJoe Marcus Clarke 	if (vp->v_type == VDIR && pd->pn_type == pfstype_root) {
387e7f54c1bSJoe Marcus Clarke 		*dvp = vp;
388e7f54c1bSJoe Marcus Clarke 		vhold(*dvp);
389e7f54c1bSJoe Marcus Clarke 		pfs_unlock(pd);
390e7f54c1bSJoe Marcus Clarke 		PFS_RETURN (0);
391e7f54c1bSJoe Marcus Clarke 	} else if (vp->v_type == VDIR && pd->pn_type == pfstype_procdir) {
392e7f54c1bSJoe Marcus Clarke 		len = snprintf(pidbuf, sizeof(pidbuf), "%d", pid);
393e7f54c1bSJoe Marcus Clarke 		i -= len;
394e7f54c1bSJoe Marcus Clarke 		if (i < 0) {
395e7f54c1bSJoe Marcus Clarke 			error = ENOMEM;
396e7f54c1bSJoe Marcus Clarke 			goto failed;
397e7f54c1bSJoe Marcus Clarke 		}
398e7f54c1bSJoe Marcus Clarke 		bcopy(pidbuf, buf + i, len);
399e7f54c1bSJoe Marcus Clarke 	} else {
40026088b9dSDag-Erling Smørgrav 		len = strlen(pd->pn_name);
40126088b9dSDag-Erling Smørgrav 		i -= len;
402e7f54c1bSJoe Marcus Clarke 		if (i < 0) {
403e7f54c1bSJoe Marcus Clarke 			error = ENOMEM;
404e7f54c1bSJoe Marcus Clarke 			goto failed;
405e7f54c1bSJoe Marcus Clarke 		}
40626088b9dSDag-Erling Smørgrav 		bcopy(pd->pn_name, buf + i, len);
407e7f54c1bSJoe Marcus Clarke 	}
408e7f54c1bSJoe Marcus Clarke 
409e7f54c1bSJoe Marcus Clarke 	pn = pd->pn_parent;
410e7f54c1bSJoe Marcus Clarke 	pfs_unlock(pd);
411e7f54c1bSJoe Marcus Clarke 
412e7f54c1bSJoe Marcus Clarke 	mp = vp->v_mount;
413e7f54c1bSJoe Marcus Clarke 	error = vfs_busy(mp, 0);
414e7f54c1bSJoe Marcus Clarke 	if (error)
415e7f54c1bSJoe Marcus Clarke 		return (error);
416e7f54c1bSJoe Marcus Clarke 
417e7f54c1bSJoe Marcus Clarke 	/*
418e7f54c1bSJoe Marcus Clarke 	 * vp is held by caller.
419e7f54c1bSJoe Marcus Clarke 	 */
420e7f54c1bSJoe Marcus Clarke 	locked = VOP_ISLOCKED(vp);
421b249ce48SMateusz Guzik 	VOP_UNLOCK(vp);
422e7f54c1bSJoe Marcus Clarke 
423e7f54c1bSJoe Marcus Clarke 	error = pfs_vncache_alloc(mp, dvp, pn, pid);
424e7f54c1bSJoe Marcus Clarke 	if (error) {
425e7f54c1bSJoe Marcus Clarke 		vn_lock(vp, locked | LK_RETRY);
426e7f54c1bSJoe Marcus Clarke 		vfs_unbusy(mp);
427e7f54c1bSJoe Marcus Clarke 		PFS_RETURN(error);
428e7f54c1bSJoe Marcus Clarke 	}
429e7f54c1bSJoe Marcus Clarke 
430e7f54c1bSJoe Marcus Clarke 	*buflen = i;
431b249ce48SMateusz Guzik 	VOP_UNLOCK(*dvp);
432e7f54c1bSJoe Marcus Clarke 	vn_lock(vp, locked | LK_RETRY);
433e7f54c1bSJoe Marcus Clarke 	vfs_unbusy(mp);
434e7f54c1bSJoe Marcus Clarke 
435e7f54c1bSJoe Marcus Clarke 	PFS_RETURN (0);
436e7f54c1bSJoe Marcus Clarke failed:
437e7f54c1bSJoe Marcus Clarke 	pfs_unlock(pd);
438e7f54c1bSJoe Marcus Clarke 	PFS_RETURN(error);
439e7f54c1bSJoe Marcus Clarke }
440e7f54c1bSJoe Marcus Clarke 
441e7f54c1bSJoe Marcus Clarke /*
4429733a808SDag-Erling Smørgrav  * Look up a file or directory
4439733a808SDag-Erling Smørgrav  */
4449733a808SDag-Erling Smørgrav static int
pfs_lookup(struct vop_cachedlookup_args * va)4450e3b5c73SDag-Erling Smørgrav pfs_lookup(struct vop_cachedlookup_args *va)
4469733a808SDag-Erling Smørgrav {
447649ad985SDag-Erling Smørgrav 	struct vnode *vn = va->a_dvp;
4489733a808SDag-Erling Smørgrav 	struct vnode **vpp = va->a_vpp;
4499733a808SDag-Erling Smørgrav 	struct componentname *cnp = va->a_cnp;
450388596dfSDag-Erling Smørgrav 	struct pfs_vdata *pvd = vn->v_data;
451649ad985SDag-Erling Smørgrav 	struct pfs_node *pd = pvd->pvd_pn;
452649ad985SDag-Erling Smørgrav 	struct pfs_node *pn, *pdn = NULL;
45331452ff7SKonstantin Belousov 	struct mount *mp;
454649ad985SDag-Erling Smørgrav 	pid_t pid = pvd->pvd_pid;
4559733a808SDag-Erling Smørgrav 	char *pname;
456388596dfSDag-Erling Smørgrav 	int error, i, namelen, visible;
4579733a808SDag-Erling Smørgrav 
45880a3cef8SDag-Erling Smørgrav 	PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr));
459388596dfSDag-Erling Smørgrav 	pfs_assert_not_owned(pd);
46080a3cef8SDag-Erling Smørgrav 
461649ad985SDag-Erling Smørgrav 	if (vn->v_type != VDIR)
46280a3cef8SDag-Erling Smørgrav 		PFS_RETURN (ENOTDIR);
46359fc1b06SDag-Erling Smørgrav 	KASSERT_PN_IS_DIR(pd);
4649733a808SDag-Erling Smørgrav 
46580a3cef8SDag-Erling Smørgrav 	/*
46680a3cef8SDag-Erling Smørgrav 	 * Don't support DELETE or RENAME.  CREATE is supported so
46780a3cef8SDag-Erling Smørgrav 	 * that O_CREAT will work, but the lookup will still fail if
46880a3cef8SDag-Erling Smørgrav 	 * the file does not exist.
46980a3cef8SDag-Erling Smørgrav 	 */
4700e3b5c73SDag-Erling Smørgrav 	if ((cnp->cn_flags & ISLASTCN) &&
4710e3b5c73SDag-Erling Smørgrav 	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
4727d8f809fSDag-Erling Smørgrav 		PFS_RETURN (EOPNOTSUPP);
4739733a808SDag-Erling Smørgrav 
47480a3cef8SDag-Erling Smørgrav 	/* shortcut: check if the name is too long */
4759733a808SDag-Erling Smørgrav 	if (cnp->cn_namelen >= PFS_NAMELEN)
47680a3cef8SDag-Erling Smørgrav 		PFS_RETURN (ENOENT);
47780a3cef8SDag-Erling Smørgrav 
478f8e3eeb5SJohn Baldwin 	/* check that parent directory is visible... */
47953011553SMateusz Guzik 	if (!pfs_visible(curthread, pd, pvd->pvd_pid, NULL))
48080a3cef8SDag-Erling Smørgrav 		PFS_RETURN (ENOENT);
4819733a808SDag-Erling Smørgrav 
4829733a808SDag-Erling Smørgrav 	/* self */
483649ad985SDag-Erling Smørgrav 	namelen = cnp->cn_namelen;
4849733a808SDag-Erling Smørgrav 	pname = cnp->cn_nameptr;
4850e3b5c73SDag-Erling Smørgrav 	if (namelen == 1 && pname[0] == '.') {
4869733a808SDag-Erling Smørgrav 		pn = pd;
487649ad985SDag-Erling Smørgrav 		*vpp = vn;
488649ad985SDag-Erling Smørgrav 		VREF(vn);
489198bc14bSDag-Erling Smørgrav 		PFS_RETURN (0);
4909733a808SDag-Erling Smørgrav 	}
4919733a808SDag-Erling Smørgrav 
49231452ff7SKonstantin Belousov 	mp = vn->v_mount;
49331452ff7SKonstantin Belousov 
4949733a808SDag-Erling Smørgrav 	/* parent */
4959733a808SDag-Erling Smørgrav 	if (cnp->cn_flags & ISDOTDOT) {
4969733a808SDag-Erling Smørgrav 		if (pd->pn_type == pfstype_root)
49780a3cef8SDag-Erling Smørgrav 			PFS_RETURN (EIO);
49831452ff7SKonstantin Belousov 		error = vfs_busy(mp, MBF_NOWAIT);
49931452ff7SKonstantin Belousov 		if (error != 0) {
50031452ff7SKonstantin Belousov 			vfs_ref(mp);
501b249ce48SMateusz Guzik 			VOP_UNLOCK(vn);
50231452ff7SKonstantin Belousov 			error = vfs_busy(mp, 0);
50331452ff7SKonstantin Belousov 			vn_lock(vn, LK_EXCLUSIVE | LK_RETRY);
50431452ff7SKonstantin Belousov 			vfs_rel(mp);
50531452ff7SKonstantin Belousov 			if (error != 0)
50631452ff7SKonstantin Belousov 				PFS_RETURN(ENOENT);
507abd80ddbSMateusz Guzik 			if (VN_IS_DOOMED(vn)) {
50831452ff7SKonstantin Belousov 				vfs_unbusy(mp);
50931452ff7SKonstantin Belousov 				PFS_RETURN(ENOENT);
51031452ff7SKonstantin Belousov 			}
51131452ff7SKonstantin Belousov 		}
512b249ce48SMateusz Guzik 		VOP_UNLOCK(vn);
513388596dfSDag-Erling Smørgrav 		KASSERT(pd->pn_parent != NULL,
514388596dfSDag-Erling Smørgrav 		    ("%s(): non-root directory has no parent", __func__));
515649ad985SDag-Erling Smørgrav 		/*
516649ad985SDag-Erling Smørgrav 		 * This one is tricky.  Descendents of procdir nodes
517649ad985SDag-Erling Smørgrav 		 * inherit their parent's process affinity, but
518649ad985SDag-Erling Smørgrav 		 * there's no easy reverse mapping.  For simplicity,
519649ad985SDag-Erling Smørgrav 		 * we assume that if this node is a procdir, its
520649ad985SDag-Erling Smørgrav 		 * parent isn't (which is correct as long as
521649ad985SDag-Erling Smørgrav 		 * descendents of procdir nodes are never procdir
522649ad985SDag-Erling Smørgrav 		 * nodes themselves)
523649ad985SDag-Erling Smørgrav 		 */
524649ad985SDag-Erling Smørgrav 		if (pd->pn_type == pfstype_procdir)
525649ad985SDag-Erling Smørgrav 			pid = NO_PID;
526388596dfSDag-Erling Smørgrav 		pfs_lock(pd);
527198bc14bSDag-Erling Smørgrav 		pn = pd->pn_parent;
528388596dfSDag-Erling Smørgrav 		pfs_unlock(pd);
529198bc14bSDag-Erling Smørgrav 		goto got_pnode;
5309733a808SDag-Erling Smørgrav 	}
5319733a808SDag-Erling Smørgrav 
532388596dfSDag-Erling Smørgrav 	pfs_lock(pd);
533388596dfSDag-Erling Smørgrav 
534649ad985SDag-Erling Smørgrav 	/* named node */
53533802b9eSDag-Erling Smørgrav 	for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next)
536649ad985SDag-Erling Smørgrav 		if (pn->pn_type == pfstype_procdir)
537649ad985SDag-Erling Smørgrav 			pdn = pn;
538fc915f1bSMark Johnston 		else if (strncmp(pname, pn->pn_name, namelen) == 0 &&
539fc915f1bSMark Johnston 		    pn->pn_name[namelen] == '\0') {
540388596dfSDag-Erling Smørgrav 			pfs_unlock(pd);
5419733a808SDag-Erling Smørgrav 			goto got_pnode;
542388596dfSDag-Erling Smørgrav 		}
5439733a808SDag-Erling Smørgrav 
544649ad985SDag-Erling Smørgrav 	/* process dependent node */
545649ad985SDag-Erling Smørgrav 	if ((pn = pdn) != NULL) {
546649ad985SDag-Erling Smørgrav 		pid = 0;
547649ad985SDag-Erling Smørgrav 		for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i)
548649ad985SDag-Erling Smørgrav 			if ((pid = pid * 10 + pname[i] - '0') > PID_MAX)
5499733a808SDag-Erling Smørgrav 				break;
550388596dfSDag-Erling Smørgrav 		if (i == cnp->cn_namelen) {
551388596dfSDag-Erling Smørgrav 			pfs_unlock(pd);
5529733a808SDag-Erling Smørgrav 			goto got_pnode;
5539733a808SDag-Erling Smørgrav 		}
554388596dfSDag-Erling Smørgrav 	}
555388596dfSDag-Erling Smørgrav 
556388596dfSDag-Erling Smørgrav 	pfs_unlock(pd);
5579733a808SDag-Erling Smørgrav 
5587d8f809fSDag-Erling Smørgrav 	PFS_RETURN (ENOENT);
559388596dfSDag-Erling Smørgrav 
5609733a808SDag-Erling Smørgrav  got_pnode:
561388596dfSDag-Erling Smørgrav 	pfs_assert_not_owned(pd);
562388596dfSDag-Erling Smørgrav 	pfs_assert_not_owned(pn);
56353011553SMateusz Guzik 	visible = pfs_visible(curthread, pn, pid, NULL);
564388596dfSDag-Erling Smørgrav 	if (!visible) {
565eddcb03dSJeff Roberson 		error = ENOENT;
566eddcb03dSJeff Roberson 		goto failed;
567eddcb03dSJeff Roberson 	}
568922b974aSJeff Roberson 
56931452ff7SKonstantin Belousov 	error = pfs_vncache_alloc(mp, vpp, pn, pid);
5709733a808SDag-Erling Smørgrav 	if (error)
571eddcb03dSJeff Roberson 		goto failed;
572922b974aSJeff Roberson 
57331452ff7SKonstantin Belousov 	if (cnp->cn_flags & ISDOTDOT) {
57431452ff7SKonstantin Belousov 		vfs_unbusy(mp);
575cb05b60aSAttilio Rao 		vn_lock(vn, LK_EXCLUSIVE | LK_RETRY);
576abd80ddbSMateusz Guzik 		if (VN_IS_DOOMED(vn)) {
57731452ff7SKonstantin Belousov 			vput(*vpp);
57831452ff7SKonstantin Belousov 			*vpp = NULL;
57931452ff7SKonstantin Belousov 			PFS_RETURN(ENOENT);
58031452ff7SKonstantin Belousov 		}
58131452ff7SKonstantin Belousov 	}
582abd80ddbSMateusz Guzik 	if (cnp->cn_flags & MAKEENTRY && !VN_IS_DOOMED(vn))
583649ad985SDag-Erling Smørgrav 		cache_enter(vn, *vpp, cnp);
58480a3cef8SDag-Erling Smørgrav 	PFS_RETURN (0);
585eddcb03dSJeff Roberson  failed:
58631452ff7SKonstantin Belousov 	if (cnp->cn_flags & ISDOTDOT) {
58731452ff7SKonstantin Belousov 		vfs_unbusy(mp);
588cb05b60aSAttilio Rao 		vn_lock(vn, LK_EXCLUSIVE | LK_RETRY);
58931452ff7SKonstantin Belousov 		*vpp = NULL;
59031452ff7SKonstantin Belousov 	}
591eddcb03dSJeff Roberson 	PFS_RETURN(error);
5929733a808SDag-Erling Smørgrav }
5939733a808SDag-Erling Smørgrav 
5949733a808SDag-Erling Smørgrav /*
5959733a808SDag-Erling Smørgrav  * Open a file or directory.
5969733a808SDag-Erling Smørgrav  */
5979733a808SDag-Erling Smørgrav static int
pfs_open(struct vop_open_args * va)5989733a808SDag-Erling Smørgrav pfs_open(struct vop_open_args *va)
5999733a808SDag-Erling Smørgrav {
60080a3cef8SDag-Erling Smørgrav 	struct vnode *vn = va->a_vp;
601388596dfSDag-Erling Smørgrav 	struct pfs_vdata *pvd = vn->v_data;
60280a3cef8SDag-Erling Smørgrav 	struct pfs_node *pn = pvd->pvd_pn;
6037d8f809fSDag-Erling Smørgrav 	int mode = va->a_mode;
60480a3cef8SDag-Erling Smørgrav 
6057d8f809fSDag-Erling Smørgrav 	PFS_TRACE(("%s (mode 0x%x)", pn->pn_name, mode));
606388596dfSDag-Erling Smørgrav 	pfs_assert_not_owned(pn);
607198bc14bSDag-Erling Smørgrav 
6087d8f809fSDag-Erling Smørgrav 	/* check if the requested mode is permitted */
6097d8f809fSDag-Erling Smørgrav 	if (((mode & FREAD) && !(mode & PFS_RD)) ||
6107d8f809fSDag-Erling Smørgrav 	    ((mode & FWRITE) && !(mode & PFS_WR)))
6117d8f809fSDag-Erling Smørgrav 		PFS_RETURN (EPERM);
6127d8f809fSDag-Erling Smørgrav 
6137d8f809fSDag-Erling Smørgrav 	/* we don't support locking */
6147d8f809fSDag-Erling Smørgrav 	if ((mode & O_SHLOCK) || (mode & O_EXLOCK))
6157d8f809fSDag-Erling Smørgrav 		PFS_RETURN (EOPNOTSUPP);
61680a3cef8SDag-Erling Smørgrav 
617198bc14bSDag-Erling Smørgrav 	PFS_RETURN (0);
6189733a808SDag-Erling Smørgrav }
6199733a808SDag-Erling Smørgrav 
62020172854SConrad Meyer struct sbuf_seek_helper {
62120172854SConrad Meyer 	off_t		skip_bytes;
62220172854SConrad Meyer 	struct uio	*uio;
62320172854SConrad Meyer };
62420172854SConrad Meyer 
62520172854SConrad Meyer static int
pfs_sbuf_uio_drain(void * arg,const char * data,int len)62620172854SConrad Meyer pfs_sbuf_uio_drain(void *arg, const char *data, int len)
62720172854SConrad Meyer {
62820172854SConrad Meyer 	struct sbuf_seek_helper *ssh;
62920172854SConrad Meyer 	struct uio *uio;
63020172854SConrad Meyer 	int error, skipped;
63120172854SConrad Meyer 
63220172854SConrad Meyer 	ssh = arg;
63320172854SConrad Meyer 	uio = ssh->uio;
63420172854SConrad Meyer 	skipped = 0;
63520172854SConrad Meyer 
63620172854SConrad Meyer 	/* Need to discard first uio_offset bytes. */
63720172854SConrad Meyer 	if (ssh->skip_bytes > 0) {
63820172854SConrad Meyer 		if (ssh->skip_bytes >= len) {
63920172854SConrad Meyer 			ssh->skip_bytes -= len;
64020172854SConrad Meyer 			return (len);
64120172854SConrad Meyer 		}
64220172854SConrad Meyer 
64320172854SConrad Meyer 		data += ssh->skip_bytes;
64420172854SConrad Meyer 		len -= ssh->skip_bytes;
64520172854SConrad Meyer 		skipped = ssh->skip_bytes;
64620172854SConrad Meyer 		ssh->skip_bytes = 0;
64720172854SConrad Meyer 	}
64820172854SConrad Meyer 
64920172854SConrad Meyer 	error = uiomove(__DECONST(void *, data), len, uio);
65020172854SConrad Meyer 	if (error != 0)
65120172854SConrad Meyer 		return (-error);
65220172854SConrad Meyer 
65320172854SConrad Meyer 	/*
65420172854SConrad Meyer 	 * The fill function has more to emit, but the reader is finished.
65520172854SConrad Meyer 	 * This is similar to the truncated read case for non-draining PFS
65620172854SConrad Meyer 	 * sbufs, and should be handled appropriately in fill-routines.
65720172854SConrad Meyer 	 */
65820172854SConrad Meyer 	if (uio->uio_resid == 0)
65920172854SConrad Meyer 		return (-ENOBUFS);
66020172854SConrad Meyer 
66120172854SConrad Meyer 	return (skipped + len);
66220172854SConrad Meyer }
66320172854SConrad Meyer 
6649733a808SDag-Erling Smørgrav /*
6659733a808SDag-Erling Smørgrav  * Read from a file
6669733a808SDag-Erling Smørgrav  */
6679733a808SDag-Erling Smørgrav static int
pfs_read(struct vop_read_args * va)6689733a808SDag-Erling Smørgrav pfs_read(struct vop_read_args *va)
6699733a808SDag-Erling Smørgrav {
6709733a808SDag-Erling Smørgrav 	struct vnode *vn = va->a_vp;
671388596dfSDag-Erling Smørgrav 	struct pfs_vdata *pvd = vn->v_data;
672649ad985SDag-Erling Smørgrav 	struct pfs_node *pn = pvd->pvd_pn;
6739733a808SDag-Erling Smørgrav 	struct uio *uio = va->a_uio;
674f8e3eeb5SJohn Baldwin 	struct proc *proc;
67531f73b3fSDag-Erling Smørgrav 	struct sbuf *sb = NULL;
676505d02eeSKonstantin Belousov 	int error, locked;
67720172854SConrad Meyer 	off_t buflen, buflim;
67820172854SConrad Meyer 	struct sbuf_seek_helper ssh;
6799733a808SDag-Erling Smørgrav 
680388596dfSDag-Erling Smørgrav 	PFS_TRACE(("%s", pn->pn_name));
681388596dfSDag-Erling Smørgrav 	pfs_assert_not_owned(pn);
68280a3cef8SDag-Erling Smørgrav 
6839733a808SDag-Erling Smørgrav 	if (vn->v_type != VREG)
6847d8f809fSDag-Erling Smørgrav 		PFS_RETURN (EINVAL);
68559fc1b06SDag-Erling Smørgrav 	KASSERT_PN_IS_FILE(pn);
6869733a808SDag-Erling Smørgrav 
6877d8f809fSDag-Erling Smørgrav 	if (!(pn->pn_flags & PFS_RD))
6887d8f809fSDag-Erling Smørgrav 		PFS_RETURN (EBADF);
6898712e867SDag-Erling Smørgrav 
690388596dfSDag-Erling Smørgrav 	if (pn->pn_fill == NULL)
69118319000SDag-Erling Smørgrav 		PFS_RETURN (EIO);
69233802b9eSDag-Erling Smørgrav 
693198bc14bSDag-Erling Smørgrav 	/*
694198bc14bSDag-Erling Smørgrav 	 * This is necessary because either process' privileges may
695198bc14bSDag-Erling Smørgrav 	 * have changed since the open() call.
696198bc14bSDag-Erling Smørgrav 	 */
69753011553SMateusz Guzik 	if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
698198bc14bSDag-Erling Smørgrav 		PFS_RETURN (EIO);
699f8e3eeb5SJohn Baldwin 	if (proc != NULL) {
700649ad985SDag-Erling Smørgrav 		_PHOLD(proc);
701649ad985SDag-Erling Smørgrav 		PROC_UNLOCK(proc);
702649ad985SDag-Erling Smørgrav 	}
7039733a808SDag-Erling Smørgrav 
704505d02eeSKonstantin Belousov 	vhold(vn);
705505d02eeSKonstantin Belousov 	locked = VOP_ISLOCKED(vn);
706b249ce48SMateusz Guzik 	VOP_UNLOCK(vn);
707505d02eeSKonstantin Belousov 
7088712e867SDag-Erling Smørgrav 	if (pn->pn_flags & PFS_RAWRD) {
7099f80ce04SKonstantin Belousov 		PFS_TRACE(("%zd resid", uio->uio_resid));
710388596dfSDag-Erling Smørgrav 		error = pn_fill(curthread, proc, pn, NULL, uio);
7119f80ce04SKonstantin Belousov 		PFS_TRACE(("%zd resid", uio->uio_resid));
712505d02eeSKonstantin Belousov 		goto ret;
7138712e867SDag-Erling Smørgrav 	}
7148712e867SDag-Erling Smørgrav 
715587430f2SKonstantin Belousov 	if (uio->uio_resid < 0 || uio->uio_offset < 0 ||
716587430f2SKonstantin Belousov 	    uio->uio_resid > OFF_MAX - uio->uio_offset) {
717505d02eeSKonstantin Belousov 		error = EINVAL;
718505d02eeSKonstantin Belousov 		goto ret;
7198b7358caSJacques Vidrine 	}
72020172854SConrad Meyer 	buflen = uio->uio_offset + uio->uio_resid + 1;
72120172854SConrad Meyer 	if (pn->pn_flags & PFS_AUTODRAIN)
72220172854SConrad Meyer 		/*
72320172854SConrad Meyer 		 * We can use a smaller buffer if we can stream output to the
72420172854SConrad Meyer 		 * consumer.
72520172854SConrad Meyer 		 */
72620172854SConrad Meyer 		buflim = PAGE_SIZE;
72720172854SConrad Meyer 	else
72820172854SConrad Meyer 		buflim = PFS_MAXBUFSIZ;
72920172854SConrad Meyer 	if (buflen > buflim)
73020172854SConrad Meyer 		buflen = buflim;
731388596dfSDag-Erling Smørgrav 
73220172854SConrad Meyer 	sb = sbuf_new(sb, NULL, buflen, 0);
733649ad985SDag-Erling Smørgrav 	if (sb == NULL) {
734505d02eeSKonstantin Belousov 		error = EIO;
735505d02eeSKonstantin Belousov 		goto ret;
736649ad985SDag-Erling Smørgrav 	}
737649ad985SDag-Erling Smørgrav 
73820172854SConrad Meyer 	if (pn->pn_flags & PFS_AUTODRAIN) {
73920172854SConrad Meyer 		ssh.skip_bytes = uio->uio_offset;
74020172854SConrad Meyer 		ssh.uio = uio;
74120172854SConrad Meyer 		sbuf_set_drain(sb, pfs_sbuf_uio_drain, &ssh);
74220172854SConrad Meyer 	}
74320172854SConrad Meyer 
744388596dfSDag-Erling Smørgrav 	error = pn_fill(curthread, proc, pn, sb, uio);
745649ad985SDag-Erling Smørgrav 
746b27acc8dSDag-Erling Smørgrav 	if (error) {
747b27acc8dSDag-Erling Smørgrav 		sbuf_delete(sb);
748505d02eeSKonstantin Belousov 		goto ret;
749b27acc8dSDag-Erling Smørgrav 	}
750b27acc8dSDag-Erling Smørgrav 
751d467c947SJaakko Heinonen 	/*
752d467c947SJaakko Heinonen 	 * XXX: If the buffer overflowed, sbuf_len() will not return
753d467c947SJaakko Heinonen 	 * the data length. Then just use the full length because an
754d467c947SJaakko Heinonen 	 * overflowed sbuf must be full.
755d467c947SJaakko Heinonen 	 */
75620172854SConrad Meyer 	error = sbuf_finish(sb);
75720172854SConrad Meyer 	if ((pn->pn_flags & PFS_AUTODRAIN)) {
75820172854SConrad Meyer 		/*
75920172854SConrad Meyer 		 * ENOBUFS just indicates early termination of the fill
76020172854SConrad Meyer 		 * function as the caller's buffer was already filled.  Squash
76120172854SConrad Meyer 		 * to zero.
76220172854SConrad Meyer 		 */
76320172854SConrad Meyer 		if (uio->uio_resid == 0 && error == ENOBUFS)
76420172854SConrad Meyer 			error = 0;
76520172854SConrad Meyer 	} else {
76620172854SConrad Meyer 		if (error == 0)
767d467c947SJaakko Heinonen 			buflen = sbuf_len(sb);
76820172854SConrad Meyer 		else
76920172854SConrad Meyer 			/* The trailing byte is not valid. */
77020172854SConrad Meyer 			buflen--;
771d467c947SJaakko Heinonen 		error = uiomove_frombuf(sbuf_data(sb), buflen, uio);
77220172854SConrad Meyer 	}
77331f73b3fSDag-Erling Smørgrav 	sbuf_delete(sb);
774505d02eeSKonstantin Belousov ret:
775505d02eeSKonstantin Belousov 	vn_lock(vn, locked | LK_RETRY);
776505d02eeSKonstantin Belousov 	vdrop(vn);
777505d02eeSKonstantin Belousov 	if (proc != NULL)
778505d02eeSKonstantin Belousov 		PRELE(proc);
7797d8f809fSDag-Erling Smørgrav 	PFS_RETURN (error);
7809733a808SDag-Erling Smørgrav }
7819733a808SDag-Erling Smørgrav 
7829733a808SDag-Erling Smørgrav /*
783649ad985SDag-Erling Smørgrav  * Iterate through directory entries
784649ad985SDag-Erling Smørgrav  */
785649ad985SDag-Erling Smørgrav static int
pfs_iterate(struct thread * td,struct proc * proc,struct pfs_node * pd,struct pfs_node ** pn,struct proc ** p)786388596dfSDag-Erling Smørgrav pfs_iterate(struct thread *td, struct proc *proc, struct pfs_node *pd,
78733802b9eSDag-Erling Smørgrav 	    struct pfs_node **pn, struct proc **p)
788649ad985SDag-Erling Smørgrav {
789388596dfSDag-Erling Smørgrav 	int visible;
790388596dfSDag-Erling Smørgrav 
791f8e3eeb5SJohn Baldwin 	sx_assert(&allproc_lock, SX_SLOCKED);
792388596dfSDag-Erling Smørgrav 	pfs_assert_owned(pd);
793198bc14bSDag-Erling Smørgrav  again:
794653fae17SDag-Erling Smørgrav 	if (*pn == NULL) {
795653fae17SDag-Erling Smørgrav 		/* first node */
796653fae17SDag-Erling Smørgrav 		*pn = pd->pn_nodes;
797653fae17SDag-Erling Smørgrav 	} else if ((*pn)->pn_type != pfstype_procdir) {
798653fae17SDag-Erling Smørgrav 		/* next node */
79933802b9eSDag-Erling Smørgrav 		*pn = (*pn)->pn_next;
800653fae17SDag-Erling Smørgrav 	}
801653fae17SDag-Erling Smørgrav 	if (*pn != NULL && (*pn)->pn_type == pfstype_procdir) {
802653fae17SDag-Erling Smørgrav 		/* next process */
803649ad985SDag-Erling Smørgrav 		if (*p == NULL)
804649ad985SDag-Erling Smørgrav 			*p = LIST_FIRST(&allproc);
805649ad985SDag-Erling Smørgrav 		else
806649ad985SDag-Erling Smørgrav 			*p = LIST_NEXT(*p, p_list);
807653fae17SDag-Erling Smørgrav 		/* out of processes: next node */
808653fae17SDag-Erling Smørgrav 		if (*p == NULL)
80933802b9eSDag-Erling Smørgrav 			*pn = (*pn)->pn_next;
810388596dfSDag-Erling Smørgrav 		else
811388596dfSDag-Erling Smørgrav 			PROC_LOCK(*p);
812649ad985SDag-Erling Smørgrav 	}
813649ad985SDag-Erling Smørgrav 
81433802b9eSDag-Erling Smørgrav 	if ((*pn) == NULL)
815649ad985SDag-Erling Smørgrav 		return (-1);
816649ad985SDag-Erling Smørgrav 
817388596dfSDag-Erling Smørgrav 	if (*p != NULL) {
818388596dfSDag-Erling Smørgrav 		visible = pfs_visible_proc(td, *pn, *p);
819388596dfSDag-Erling Smørgrav 		PROC_UNLOCK(*p);
820388596dfSDag-Erling Smørgrav 	} else if (proc != NULL) {
821388596dfSDag-Erling Smørgrav 		visible = pfs_visible_proc(td, *pn, proc);
822388596dfSDag-Erling Smørgrav 	} else {
823405c0c04SDmitry Chagin 		visible = pn_vis(td, NULL, *pn);
824388596dfSDag-Erling Smørgrav 	}
825388596dfSDag-Erling Smørgrav 	if (!visible)
826198bc14bSDag-Erling Smørgrav 		goto again;
827198bc14bSDag-Erling Smørgrav 
828649ad985SDag-Erling Smørgrav 	return (0);
829649ad985SDag-Erling Smørgrav }
830649ad985SDag-Erling Smørgrav 
83150546f8fSPeter Holm /* Directory entry list */
83250546f8fSPeter Holm struct pfsentry {
83350546f8fSPeter Holm 	STAILQ_ENTRY(pfsentry)	link;
83450546f8fSPeter Holm 	struct dirent		entry;
83550546f8fSPeter Holm };
83650546f8fSPeter Holm STAILQ_HEAD(pfsdirentlist, pfsentry);
83750546f8fSPeter Holm 
838649ad985SDag-Erling Smørgrav /*
8399733a808SDag-Erling Smørgrav  * Return directory entries.
8409733a808SDag-Erling Smørgrav  */
8419733a808SDag-Erling Smørgrav static int
pfs_readdir(struct vop_readdir_args * va)8429733a808SDag-Erling Smørgrav pfs_readdir(struct vop_readdir_args *va)
8439733a808SDag-Erling Smørgrav {
8449733a808SDag-Erling Smørgrav 	struct vnode *vn = va->a_vp;
845388596dfSDag-Erling Smørgrav 	struct pfs_vdata *pvd = vn->v_data;
846649ad985SDag-Erling Smørgrav 	struct pfs_node *pd = pvd->pvd_pn;
847198bc14bSDag-Erling Smørgrav 	pid_t pid = pvd->pvd_pid;
848388596dfSDag-Erling Smørgrav 	struct proc *p, *proc;
849649ad985SDag-Erling Smørgrav 	struct pfs_node *pn;
8509733a808SDag-Erling Smørgrav 	struct uio *uio;
85150546f8fSPeter Holm 	struct pfsentry *pfsent, *pfsent2;
85250546f8fSPeter Holm 	struct pfsdirentlist lst;
8539733a808SDag-Erling Smørgrav 	off_t offset;
8549733a808SDag-Erling Smørgrav 	int error, i, resid;
8559733a808SDag-Erling Smørgrav 
85650546f8fSPeter Holm 	STAILQ_INIT(&lst);
85750546f8fSPeter Holm 	error = 0;
858f61bc4eaSDag-Erling Smørgrav 	KASSERT(pd->pn_info == vn->v_mount->mnt_data,
859388596dfSDag-Erling Smørgrav 	    ("%s(): pn_info does not match mountpoint", __func__));
860388596dfSDag-Erling Smørgrav 	PFS_TRACE(("%s pid %lu", pd->pn_name, (unsigned long)pid));
861388596dfSDag-Erling Smørgrav 	pfs_assert_not_owned(pd);
86280a3cef8SDag-Erling Smørgrav 
8639733a808SDag-Erling Smørgrav 	if (vn->v_type != VDIR)
8647d8f809fSDag-Erling Smørgrav 		PFS_RETURN (ENOTDIR);
86559fc1b06SDag-Erling Smørgrav 	KASSERT_PN_IS_DIR(pd);
8669733a808SDag-Erling Smørgrav 	uio = va->a_uio;
8679733a808SDag-Erling Smørgrav 
8689733a808SDag-Erling Smørgrav 	/* only allow reading entire entries */
8699733a808SDag-Erling Smørgrav 	offset = uio->uio_offset;
8709733a808SDag-Erling Smørgrav 	resid = uio->uio_resid;
871bc593ccdSDag-Erling Smørgrav 	if (offset < 0 || offset % PFS_DELEN != 0 ||
872bc593ccdSDag-Erling Smørgrav 	    (resid && resid < PFS_DELEN))
8737d8f809fSDag-Erling Smørgrav 		PFS_RETURN (EINVAL);
874bc593ccdSDag-Erling Smørgrav 	if (resid == 0)
875bc593ccdSDag-Erling Smørgrav 		PFS_RETURN (0);
876195a6b21SDag-Erling Smørgrav 
877f99c5e8dSKyle Evans 	proc = NULL;
878f99c5e8dSKyle Evans 	if (pid != NO_PID && !pfs_lookup_proc(pid, &proc))
879f5791174SMateusz Guzik 		PFS_RETURN (ENOENT);
880f5791174SMateusz Guzik 
881649ad985SDag-Erling Smørgrav 	sx_slock(&allproc_lock);
882388596dfSDag-Erling Smørgrav 	pfs_lock(pd);
883f99c5e8dSKyle Evans 
884f99c5e8dSKyle Evans 	KASSERT(pid == NO_PID || proc != NULL,
885f99c5e8dSKyle Evans 	    ("%s(): no process for pid %lu", __func__, (unsigned long)pid));
886f99c5e8dSKyle Evans 
887f99c5e8dSKyle Evans 	if (pid != NO_PID) {
888f5791174SMateusz Guzik 		PROC_LOCK(proc);
889388596dfSDag-Erling Smørgrav 
890388596dfSDag-Erling Smørgrav 		/* check if the directory is visible to the caller */
891f5791174SMateusz Guzik 		if (!pfs_visible_proc(curthread, pd, proc)) {
892f5791174SMateusz Guzik 			_PRELE(proc);
893f5791174SMateusz Guzik 			PROC_UNLOCK(proc);
894388596dfSDag-Erling Smørgrav 			pfs_unlock(pd);
895b8bb73abSDag-Erling Smørgrav 			sx_sunlock(&allproc_lock);
896388596dfSDag-Erling Smørgrav 			PFS_RETURN (ENOENT);
897388596dfSDag-Erling Smørgrav 		}
898f99c5e8dSKyle Evans 	}
899388596dfSDag-Erling Smørgrav 
900388596dfSDag-Erling Smørgrav 	/* skip unwanted entries */
901388596dfSDag-Erling Smørgrav 	for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN) {
902388596dfSDag-Erling Smørgrav 		if (pfs_iterate(curthread, proc, pd, &pn, &p) == -1) {
903388596dfSDag-Erling Smørgrav 			/* nothing left... */
904f5791174SMateusz Guzik 			if (proc != NULL) {
905f5791174SMateusz Guzik 				_PRELE(proc);
906388596dfSDag-Erling Smørgrav 				PROC_UNLOCK(proc);
907f5791174SMateusz Guzik 			}
908388596dfSDag-Erling Smørgrav 			pfs_unlock(pd);
909388596dfSDag-Erling Smørgrav 			sx_sunlock(&allproc_lock);
91033802b9eSDag-Erling Smørgrav 			PFS_RETURN (0);
91133802b9eSDag-Erling Smørgrav 		}
912388596dfSDag-Erling Smørgrav 	}
9139733a808SDag-Erling Smørgrav 
9149733a808SDag-Erling Smørgrav 	/* fill in entries */
915388596dfSDag-Erling Smørgrav 	while (pfs_iterate(curthread, proc, pd, &pn, &p) != -1 &&
916bc593ccdSDag-Erling Smørgrav 	    resid >= PFS_DELEN) {
91750546f8fSPeter Holm 		if ((pfsent = malloc(sizeof(struct pfsentry), M_IOV,
91850546f8fSPeter Holm 		    M_NOWAIT | M_ZERO)) == NULL) {
91950546f8fSPeter Holm 			error = ENOMEM;
92050546f8fSPeter Holm 			break;
92150546f8fSPeter Holm 		}
92250546f8fSPeter Holm 		pfsent->entry.d_reclen = PFS_DELEN;
92350546f8fSPeter Holm 		pfsent->entry.d_fileno = pn_fileno(pn, pid);
9249733a808SDag-Erling Smørgrav 		/* PFS_DELEN was picked to fit PFS_NAMLEN */
9259733a808SDag-Erling Smørgrav 		for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i)
92650546f8fSPeter Holm 			pfsent->entry.d_name[i] = pn->pn_name[i];
92750546f8fSPeter Holm 		pfsent->entry.d_namlen = i;
9281c4ca778SKonstantin Belousov 		/* NOTE: d_off is the offset of the *next* entry. */
9291c4ca778SKonstantin Belousov 		pfsent->entry.d_off = offset + PFS_DELEN;
9309733a808SDag-Erling Smørgrav 		switch (pn->pn_type) {
931649ad985SDag-Erling Smørgrav 		case pfstype_procdir:
932649ad985SDag-Erling Smørgrav 			KASSERT(p != NULL,
933649ad985SDag-Erling Smørgrav 			    ("reached procdir node with p == NULL"));
93450546f8fSPeter Holm 			pfsent->entry.d_namlen = snprintf(pfsent->entry.d_name,
935649ad985SDag-Erling Smørgrav 			    PFS_NAMELEN, "%d", p->p_pid);
936649ad985SDag-Erling Smørgrav 			/* fall through */
9379733a808SDag-Erling Smørgrav 		case pfstype_root:
9389733a808SDag-Erling Smørgrav 		case pfstype_dir:
9399733a808SDag-Erling Smørgrav 		case pfstype_this:
9409733a808SDag-Erling Smørgrav 		case pfstype_parent:
94150546f8fSPeter Holm 			pfsent->entry.d_type = DT_DIR;
9429733a808SDag-Erling Smørgrav 			break;
9439733a808SDag-Erling Smørgrav 		case pfstype_file:
94450546f8fSPeter Holm 			pfsent->entry.d_type = DT_REG;
9459733a808SDag-Erling Smørgrav 			break;
9469733a808SDag-Erling Smørgrav 		case pfstype_symlink:
94750546f8fSPeter Holm 			pfsent->entry.d_type = DT_LNK;
9489733a808SDag-Erling Smørgrav 			break;
9499733a808SDag-Erling Smørgrav 		default:
9509733a808SDag-Erling Smørgrav 			panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
9519733a808SDag-Erling Smørgrav 		}
95250546f8fSPeter Holm 		PFS_TRACE(("%s", pfsent->entry.d_name));
9536d2e2df7SMark Johnston 		dirent_terminate(&pfsent->entry);
95450546f8fSPeter Holm 		STAILQ_INSERT_TAIL(&lst, pfsent, link);
9559733a808SDag-Erling Smørgrav 		offset += PFS_DELEN;
9569733a808SDag-Erling Smørgrav 		resid -= PFS_DELEN;
9579733a808SDag-Erling Smørgrav 	}
958f5791174SMateusz Guzik 	if (proc != NULL) {
959f5791174SMateusz Guzik 		_PRELE(proc);
960388596dfSDag-Erling Smørgrav 		PROC_UNLOCK(proc);
961f5791174SMateusz Guzik 	}
962388596dfSDag-Erling Smørgrav 	pfs_unlock(pd);
9639733a808SDag-Erling Smørgrav 	sx_sunlock(&allproc_lock);
96450546f8fSPeter Holm 	i = 0;
96550546f8fSPeter Holm 	STAILQ_FOREACH_SAFE(pfsent, &lst, link, pfsent2) {
96650546f8fSPeter Holm 		if (error == 0)
96750546f8fSPeter Holm 			error = uiomove(&pfsent->entry, PFS_DELEN, uio);
96850546f8fSPeter Holm 		free(pfsent, M_IOV);
96950546f8fSPeter Holm 		i++;
97050546f8fSPeter Holm 	}
9716bfe4532SEnji Cooper 	PFS_TRACE(("%ju bytes", (uintmax_t)(i * PFS_DELEN)));
972195a6b21SDag-Erling Smørgrav 	PFS_RETURN (error);
9739733a808SDag-Erling Smørgrav }
9749733a808SDag-Erling Smørgrav 
9759733a808SDag-Erling Smørgrav /*
9769733a808SDag-Erling Smørgrav  * Read a symbolic link
9779733a808SDag-Erling Smørgrav  */
9789733a808SDag-Erling Smørgrav static int
pfs_readlink(struct vop_readlink_args * va)9799733a808SDag-Erling Smørgrav pfs_readlink(struct vop_readlink_args *va)
9809733a808SDag-Erling Smørgrav {
9819733a808SDag-Erling Smørgrav 	struct vnode *vn = va->a_vp;
982388596dfSDag-Erling Smørgrav 	struct pfs_vdata *pvd = vn->v_data;
983649ad985SDag-Erling Smørgrav 	struct pfs_node *pn = pvd->pvd_pn;
9849733a808SDag-Erling Smørgrav 	struct uio *uio = va->a_uio;
985649ad985SDag-Erling Smørgrav 	struct proc *proc = NULL;
986388596dfSDag-Erling Smørgrav 	char buf[PATH_MAX];
9879733a808SDag-Erling Smørgrav 	struct sbuf sb;
988b00098d1SKonstantin Belousov 	int error, locked;
9899733a808SDag-Erling Smørgrav 
990388596dfSDag-Erling Smørgrav 	PFS_TRACE(("%s", pn->pn_name));
991388596dfSDag-Erling Smørgrav 	pfs_assert_not_owned(pn);
99280a3cef8SDag-Erling Smørgrav 
9939733a808SDag-Erling Smørgrav 	if (vn->v_type != VLNK)
9947d8f809fSDag-Erling Smørgrav 		PFS_RETURN (EINVAL);
99559fc1b06SDag-Erling Smørgrav 	KASSERT_PN_IS_LINK(pn);
9969733a808SDag-Erling Smørgrav 
997388596dfSDag-Erling Smørgrav 	if (pn->pn_fill == NULL)
99818319000SDag-Erling Smørgrav 		PFS_RETURN (EIO);
99933802b9eSDag-Erling Smørgrav 
1000649ad985SDag-Erling Smørgrav 	if (pvd->pvd_pid != NO_PID) {
1001649ad985SDag-Erling Smørgrav 		if ((proc = pfind(pvd->pvd_pid)) == NULL)
10027d8f809fSDag-Erling Smørgrav 			PFS_RETURN (EIO);
100306ad42b2SJohn Baldwin 		if (proc->p_flag & P_WEXIT) {
100406ad42b2SJohn Baldwin 			PROC_UNLOCK(proc);
100506ad42b2SJohn Baldwin 			PFS_RETURN (EIO);
100606ad42b2SJohn Baldwin 		}
1007649ad985SDag-Erling Smørgrav 		_PHOLD(proc);
1008649ad985SDag-Erling Smørgrav 		PROC_UNLOCK(proc);
1009649ad985SDag-Erling Smørgrav 	}
1010b00098d1SKonstantin Belousov 	vhold(vn);
1011b00098d1SKonstantin Belousov 	locked = VOP_ISLOCKED(vn);
1012b249ce48SMateusz Guzik 	VOP_UNLOCK(vn);
1013649ad985SDag-Erling Smørgrav 
10149733a808SDag-Erling Smørgrav 	/* sbuf_new() can't fail with a static buffer */
10159733a808SDag-Erling Smørgrav 	sbuf_new(&sb, buf, sizeof buf, 0);
10169733a808SDag-Erling Smørgrav 
1017388596dfSDag-Erling Smørgrav 	error = pn_fill(curthread, proc, pn, &sb, NULL);
1018649ad985SDag-Erling Smørgrav 
1019649ad985SDag-Erling Smørgrav 	if (proc != NULL)
1020649ad985SDag-Erling Smørgrav 		PRELE(proc);
1021b00098d1SKonstantin Belousov 	vn_lock(vn, locked | LK_RETRY);
1022b00098d1SKonstantin Belousov 	vdrop(vn);
10239733a808SDag-Erling Smørgrav 
1024b27acc8dSDag-Erling Smørgrav 	if (error) {
1025b27acc8dSDag-Erling Smørgrav 		sbuf_delete(&sb);
10267d8f809fSDag-Erling Smørgrav 		PFS_RETURN (error);
1027b27acc8dSDag-Erling Smørgrav 	}
1028b27acc8dSDag-Erling Smørgrav 
10299cb24e3cSJaakko Heinonen 	if (sbuf_finish(&sb) != 0) {
10309cb24e3cSJaakko Heinonen 		sbuf_delete(&sb);
10319cb24e3cSJaakko Heinonen 		PFS_RETURN (ENAMETOOLONG);
10329cb24e3cSJaakko Heinonen 	}
10339cb24e3cSJaakko Heinonen 
10348b7358caSJacques Vidrine 	error = uiomove_frombuf(sbuf_data(&sb), sbuf_len(&sb), uio);
10359733a808SDag-Erling Smørgrav 	sbuf_delete(&sb);
10367d8f809fSDag-Erling Smørgrav 	PFS_RETURN (error);
10379733a808SDag-Erling Smørgrav }
10389733a808SDag-Erling Smørgrav 
10399733a808SDag-Erling Smørgrav /*
10409733a808SDag-Erling Smørgrav  * Reclaim a vnode
10419733a808SDag-Erling Smørgrav  */
10429733a808SDag-Erling Smørgrav static int
pfs_reclaim(struct vop_reclaim_args * va)10439733a808SDag-Erling Smørgrav pfs_reclaim(struct vop_reclaim_args *va)
10449733a808SDag-Erling Smørgrav {
1045388596dfSDag-Erling Smørgrav 	struct vnode *vn = va->a_vp;
1046388596dfSDag-Erling Smørgrav 	struct pfs_vdata *pvd = vn->v_data;
1047388596dfSDag-Erling Smørgrav 	struct pfs_node *pn = pvd->pvd_pn;
1048388596dfSDag-Erling Smørgrav 
1049388596dfSDag-Erling Smørgrav 	PFS_TRACE(("%s", pn->pn_name));
1050388596dfSDag-Erling Smørgrav 	pfs_assert_not_owned(pn);
1051198bc14bSDag-Erling Smørgrav 
10529733a808SDag-Erling Smørgrav 	return (pfs_vncache_free(va->a_vp));
10539733a808SDag-Erling Smørgrav }
10549733a808SDag-Erling Smørgrav 
10559733a808SDag-Erling Smørgrav /*
10569733a808SDag-Erling Smørgrav  * Set attributes
10579733a808SDag-Erling Smørgrav  */
10589733a808SDag-Erling Smørgrav static int
pfs_setattr(struct vop_setattr_args * va)10599733a808SDag-Erling Smørgrav pfs_setattr(struct vop_setattr_args *va)
10609733a808SDag-Erling Smørgrav {
1061388596dfSDag-Erling Smørgrav 	struct vnode *vn = va->a_vp;
1062388596dfSDag-Erling Smørgrav 	struct pfs_vdata *pvd = vn->v_data;
1063388596dfSDag-Erling Smørgrav 	struct pfs_node *pn = pvd->pvd_pn;
1064388596dfSDag-Erling Smørgrav 
1065388596dfSDag-Erling Smørgrav 	PFS_TRACE(("%s", pn->pn_name));
1066388596dfSDag-Erling Smørgrav 	pfs_assert_not_owned(pn);
10677d8f809fSDag-Erling Smørgrav 
10681e363d64SJohannes Lundberg 	/* Silently ignore unchangeable attributes. */
10691e363d64SJohannes Lundberg 	PFS_RETURN (0);
10709733a808SDag-Erling Smørgrav }
10719733a808SDag-Erling Smørgrav 
10729733a808SDag-Erling Smørgrav /*
10734cd27a97SDag-Erling Smørgrav  * Write to a file
10749733a808SDag-Erling Smørgrav  */
10758712e867SDag-Erling Smørgrav static int
pfs_write(struct vop_write_args * va)1076aec0fb7bSPoul-Henning Kamp pfs_write(struct vop_write_args *va)
10778712e867SDag-Erling Smørgrav {
10788712e867SDag-Erling Smørgrav 	struct vnode *vn = va->a_vp;
1079388596dfSDag-Erling Smørgrav 	struct pfs_vdata *pvd = vn->v_data;
10808712e867SDag-Erling Smørgrav 	struct pfs_node *pn = pvd->pvd_pn;
10818712e867SDag-Erling Smørgrav 	struct uio *uio = va->a_uio;
1082f8e3eeb5SJohn Baldwin 	struct proc *proc;
108380a3cef8SDag-Erling Smørgrav 	struct sbuf sb;
10848712e867SDag-Erling Smørgrav 	int error;
10858712e867SDag-Erling Smørgrav 
1086388596dfSDag-Erling Smørgrav 	PFS_TRACE(("%s", pn->pn_name));
1087388596dfSDag-Erling Smørgrav 	pfs_assert_not_owned(pn);
108880a3cef8SDag-Erling Smørgrav 
10898712e867SDag-Erling Smørgrav 	if (vn->v_type != VREG)
10907d8f809fSDag-Erling Smørgrav 		PFS_RETURN (EINVAL);
109159fc1b06SDag-Erling Smørgrav 	KASSERT_PN_IS_FILE(pn);
10928712e867SDag-Erling Smørgrav 
10937d8f809fSDag-Erling Smørgrav 	if (!(pn->pn_flags & PFS_WR))
10947d8f809fSDag-Erling Smørgrav 		PFS_RETURN (EBADF);
10958712e867SDag-Erling Smørgrav 
1096388596dfSDag-Erling Smørgrav 	if (pn->pn_fill == NULL)
109718319000SDag-Erling Smørgrav 		PFS_RETURN (EIO);
109833802b9eSDag-Erling Smørgrav 
10995edf7227SKonstantin Belousov 	if (uio->uio_resid > PFS_MAXBUFSIZ)
11005edf7227SKonstantin Belousov 		PFS_RETURN (EIO);
11015edf7227SKonstantin Belousov 
1102198bc14bSDag-Erling Smørgrav 	/*
1103198bc14bSDag-Erling Smørgrav 	 * This is necessary because either process' privileges may
1104198bc14bSDag-Erling Smørgrav 	 * have changed since the open() call.
1105198bc14bSDag-Erling Smørgrav 	 */
110653011553SMateusz Guzik 	if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
1107198bc14bSDag-Erling Smørgrav 		PFS_RETURN (EIO);
1108f8e3eeb5SJohn Baldwin 	if (proc != NULL) {
11098712e867SDag-Erling Smørgrav 		_PHOLD(proc);
11108712e867SDag-Erling Smørgrav 		PROC_UNLOCK(proc);
11118712e867SDag-Erling Smørgrav 	}
11128712e867SDag-Erling Smørgrav 
11138712e867SDag-Erling Smørgrav 	if (pn->pn_flags & PFS_RAWWR) {
1114388596dfSDag-Erling Smørgrav 		error = pn_fill(curthread, proc, pn, NULL, uio);
11158712e867SDag-Erling Smørgrav 		if (proc != NULL)
11168712e867SDag-Erling Smørgrav 			PRELE(proc);
11177d8f809fSDag-Erling Smørgrav 		PFS_RETURN (error);
11188712e867SDag-Erling Smørgrav 	}
11198712e867SDag-Erling Smørgrav 
112080a3cef8SDag-Erling Smørgrav 	sbuf_uionew(&sb, uio, &error);
1121388596dfSDag-Erling Smørgrav 	if (error) {
112280a3cef8SDag-Erling Smørgrav 		if (proc != NULL)
112380a3cef8SDag-Erling Smørgrav 			PRELE(proc);
1124388596dfSDag-Erling Smørgrav 		PFS_RETURN (error);
1125388596dfSDag-Erling Smørgrav 	}
1126388596dfSDag-Erling Smørgrav 
1127388596dfSDag-Erling Smørgrav 	error = pn_fill(curthread, proc, pn, &sb, uio);
112880a3cef8SDag-Erling Smørgrav 
112980a3cef8SDag-Erling Smørgrav 	sbuf_delete(&sb);
1130388596dfSDag-Erling Smørgrav 	if (proc != NULL)
1131388596dfSDag-Erling Smørgrav 		PRELE(proc);
11327d8f809fSDag-Erling Smørgrav 	PFS_RETURN (error);
11338712e867SDag-Erling Smørgrav }
11348712e867SDag-Erling Smørgrav 
11358712e867SDag-Erling Smørgrav /*
11369733a808SDag-Erling Smørgrav  * Vnode operations
11379733a808SDag-Erling Smørgrav  */
1138aec0fb7bSPoul-Henning Kamp struct vop_vector pfs_vnodeops = {
1139aec0fb7bSPoul-Henning Kamp 	.vop_default =		&default_vnodeops,
114083c64397SPoul-Henning Kamp 
1141aec0fb7bSPoul-Henning Kamp 	.vop_access =		pfs_access,
11420e3b5c73SDag-Erling Smørgrav 	.vop_cachedlookup =	pfs_lookup,
1143aec0fb7bSPoul-Henning Kamp 	.vop_close =		pfs_close,
1144aec0fb7bSPoul-Henning Kamp 	.vop_create =		VOP_EOPNOTSUPP,
1145aec0fb7bSPoul-Henning Kamp 	.vop_getattr =		pfs_getattr,
1146aec0fb7bSPoul-Henning Kamp 	.vop_getextattr =	pfs_getextattr,
1147aec0fb7bSPoul-Henning Kamp 	.vop_ioctl =		pfs_ioctl,
1148aec0fb7bSPoul-Henning Kamp 	.vop_link =		VOP_EOPNOTSUPP,
11490e3b5c73SDag-Erling Smørgrav 	.vop_lookup =		vfs_cache_lookup,
1150aec0fb7bSPoul-Henning Kamp 	.vop_mkdir =		VOP_EOPNOTSUPP,
1151aec0fb7bSPoul-Henning Kamp 	.vop_mknod =		VOP_EOPNOTSUPP,
1152aec0fb7bSPoul-Henning Kamp 	.vop_open =		pfs_open,
1153aec0fb7bSPoul-Henning Kamp 	.vop_read =		pfs_read,
1154aec0fb7bSPoul-Henning Kamp 	.vop_readdir =		pfs_readdir,
1155aec0fb7bSPoul-Henning Kamp 	.vop_readlink =		pfs_readlink,
1156aec0fb7bSPoul-Henning Kamp 	.vop_reclaim =		pfs_reclaim,
1157aec0fb7bSPoul-Henning Kamp 	.vop_remove =		VOP_EOPNOTSUPP,
1158aec0fb7bSPoul-Henning Kamp 	.vop_rename =		VOP_EOPNOTSUPP,
1159aec0fb7bSPoul-Henning Kamp 	.vop_rmdir =		VOP_EOPNOTSUPP,
1160aec0fb7bSPoul-Henning Kamp 	.vop_setattr =		pfs_setattr,
1161aec0fb7bSPoul-Henning Kamp 	.vop_symlink =		VOP_EOPNOTSUPP,
1162e7f54c1bSJoe Marcus Clarke 	.vop_vptocnp =		pfs_vptocnp,
1163aec0fb7bSPoul-Henning Kamp 	.vop_write =		pfs_write,
11643ffcfa59SMateusz Guzik 	.vop_add_writecount =	vop_stdadd_writecount_nomsync,
1165aec0fb7bSPoul-Henning Kamp 	/* XXX I've probably forgotten a few that need VOP_EOPNOTSUPP */
11669733a808SDag-Erling Smørgrav };
11676fa079fcSMateusz Guzik VFS_VOP_VECTOR_REGISTER(pfs_vnodeops);
1168