Changeset View
Changeset View
Standalone View
Standalone View
sys/fs/pseudofs/pseudofs_vnops.c
Show First 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | pn_fileno(struct pfs_node *pn, pid_t pid) | ||||
KASSERT(pn->pn_fileno > 0, | KASSERT(pn->pn_fileno > 0, | ||||
("%s(): no fileno allocated", __func__)); | ("%s(): no fileno allocated", __func__)); | ||||
if (pid != NO_PID) | if (pid != NO_PID) | ||||
return (pn->pn_fileno * NO_PID + pid); | return (pn->pn_fileno * NO_PID + pid); | ||||
return (pn->pn_fileno); | return (pn->pn_fileno); | ||||
} | } | ||||
static struct proc * | |||||
pfs_pfind(pid_t pid, struct pfs_node *pn) | |||||
{ | |||||
return (PFS_VISIBILITY(pn) ? pfind_any(pid) : pfind(pid)); | |||||
} | |||||
/* | /* | ||||
* Returns non-zero if given file is visible to given thread. | * Returns non-zero if given file is visible to given thread. | ||||
*/ | */ | ||||
static int | static int | ||||
pfs_visible_proc(struct thread *td, struct pfs_node *pn, struct proc *proc) | pfs_visible_proc(struct thread *td, struct pfs_node *pn, struct proc *proc) | ||||
{ | { | ||||
int visible; | int visible; | ||||
if (proc == NULL) | if (proc == NULL) | ||||
return (0); | return (0); | ||||
PROC_LOCK_ASSERT(proc, MA_OWNED); | PROC_LOCK_ASSERT(proc, MA_OWNED); | ||||
visible = PFS_VISIBILITY(pn); | |||||
if (!visible) | |||||
visible = ((proc->p_flag & P_WEXIT) == 0); | visible = ((proc->p_flag & P_WEXIT) == 0); | ||||
if (visible) | if (visible) | ||||
visible = (p_cansee(td, proc) == 0); | visible = (p_cansee(td, proc) == 0); | ||||
if (visible && pn->pn_vis != NULL) | if (visible && pn->pn_vis != NULL) | ||||
visible = pn_vis(td, proc, pn); | visible = pn_vis(td, proc, pn); | ||||
if (!visible) | if (!visible) | ||||
return (0); | return (0); | ||||
return (1); | return (1); | ||||
} | } | ||||
static int | static int | ||||
pfs_visible(struct thread *td, struct pfs_node *pn, pid_t pid, | pfs_visible(struct thread *td, struct pfs_node *pn, pid_t pid, | ||||
struct proc **p) | struct proc **p) | ||||
{ | { | ||||
struct proc *proc; | struct proc *proc; | ||||
PFS_TRACE(("%s (pid: %d, req: %d)", | PFS_TRACE(("%s (pid: %d, req: %d)", | ||||
pn->pn_name, pid, td->td_proc->p_pid)); | pn->pn_name, pid, td->td_proc->p_pid)); | ||||
if (p) | if (p) | ||||
*p = NULL; | *p = NULL; | ||||
if (pid == NO_PID) | if (pid == NO_PID) | ||||
PFS_RETURN (1); | PFS_RETURN (1); | ||||
proc = pfind(pid); | proc = pfs_pfind(pid, pn); | ||||
if (proc == NULL) | if (proc == NULL) | ||||
PFS_RETURN (0); | PFS_RETURN (0); | ||||
if (pfs_visible_proc(td, pn, proc)) { | if (pfs_visible_proc(td, pn, proc)) { | ||||
if (p) | if (p) | ||||
*p = proc; | *p = proc; | ||||
else | else | ||||
PROC_UNLOCK(proc); | PROC_UNLOCK(proc); | ||||
PFS_RETURN (1); | PFS_RETURN (1); | ||||
} | } | ||||
PROC_UNLOCK(proc); | PROC_UNLOCK(proc); | ||||
PFS_RETURN (0); | PFS_RETURN (0); | ||||
} | } | ||||
static int | static int | ||||
pfs_lookup_proc(pid_t pid, struct proc **p) | pfs_lookup_proc(struct pfs_node *pn, pid_t pid, struct proc **p) | ||||
{ | { | ||||
struct proc *proc; | struct proc *proc; | ||||
proc = pfind(pid); | proc = pfs_pfind(pid, pn); | ||||
if (proc == NULL) | if (proc == NULL) | ||||
return (0); | return (0); | ||||
if ((proc->p_flag & P_WEXIT) != 0) { | _PFS_PHOLD(pn, proc); | ||||
PROC_UNLOCK(proc); | PROC_UNLOCK(proc); | ||||
return (0); | |||||
} | |||||
_PHOLD(proc); | |||||
PROC_UNLOCK(proc); | |||||
*p = proc; | *p = proc; | ||||
return (1); | return (1); | ||||
} | } | ||||
/* | /* | ||||
* Verify permissions | * Verify permissions | ||||
*/ | */ | ||||
static int | static int | ||||
Show All 33 Lines | pfs_close(struct vop_close_args *va) | ||||
/* | /* | ||||
* Do nothing unless this is the last close and the node has a | * Do nothing unless this is the last close and the node has a | ||||
* last-close handler. | * last-close handler. | ||||
*/ | */ | ||||
if (vrefcnt(vn) > 1 || pn->pn_close == NULL) | if (vrefcnt(vn) > 1 || pn->pn_close == NULL) | ||||
PFS_RETURN (0); | PFS_RETURN (0); | ||||
if (pvd->pvd_pid != NO_PID) { | if (pvd->pvd_pid != NO_PID) { | ||||
proc = pfind(pvd->pvd_pid); | proc = pfs_pfind(pvd->pvd_pid, pn); | ||||
} else { | } else { | ||||
proc = NULL; | proc = NULL; | ||||
} | } | ||||
error = pn_close(va->a_td, proc, pn); | error = pn_close(va->a_td, proc, pn); | ||||
if (proc != NULL) | if (proc != NULL) | ||||
PROC_UNLOCK(proc); | PROC_UNLOCK(proc); | ||||
▲ Show 20 Lines • Show All 489 Lines • ▼ Show 20 Lines | pfs_read(struct vop_read_args *va) | ||||
/* | /* | ||||
* This is necessary because either process' privileges may | * This is necessary because either process' privileges may | ||||
* have changed since the open() call. | * have changed since the open() call. | ||||
*/ | */ | ||||
if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) | if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) | ||||
PFS_RETURN (EIO); | PFS_RETURN (EIO); | ||||
if (proc != NULL) { | if (proc != NULL) { | ||||
_PHOLD(proc); | _PFS_PHOLD(pn, proc); | ||||
PROC_UNLOCK(proc); | PROC_UNLOCK(proc); | ||||
} | } | ||||
vhold(vn); | vhold(vn); | ||||
locked = VOP_ISLOCKED(vn); | locked = VOP_ISLOCKED(vn); | ||||
VOP_UNLOCK(vn); | VOP_UNLOCK(vn); | ||||
if (pn->pn_flags & PFS_RAWRD) { | if (pn->pn_flags & PFS_RAWRD) { | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | else | ||||
buflen--; | buflen--; | ||||
error = uiomove_frombuf(sbuf_data(sb), buflen, uio); | error = uiomove_frombuf(sbuf_data(sb), buflen, uio); | ||||
} | } | ||||
sbuf_delete(sb); | sbuf_delete(sb); | ||||
ret: | ret: | ||||
vn_lock(vn, locked | LK_RETRY); | vn_lock(vn, locked | LK_RETRY); | ||||
vdrop(vn); | vdrop(vn); | ||||
if (proc != NULL) | if (proc != NULL) | ||||
PRELE(proc); | PFS_PRELE(pn, proc); | ||||
PFS_RETURN (error); | PFS_RETURN (error); | ||||
} | } | ||||
/* | /* | ||||
* Iterate through directory entries | * Iterate through directory entries | ||||
*/ | */ | ||||
static int | static int | ||||
pfs_iterate(struct thread *td, struct proc *proc, struct pfs_node *pd, | pfs_iterate(struct thread *td, struct proc *proc, struct pfs_node *pd, | ||||
▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | pfs_readdir(struct vop_readdir_args *va) | ||||
resid = uio->uio_resid; | resid = uio->uio_resid; | ||||
if (offset < 0 || offset % PFS_DELEN != 0 || | if (offset < 0 || offset % PFS_DELEN != 0 || | ||||
(resid && resid < PFS_DELEN)) | (resid && resid < PFS_DELEN)) | ||||
PFS_RETURN (EINVAL); | PFS_RETURN (EINVAL); | ||||
if (resid == 0) | if (resid == 0) | ||||
PFS_RETURN (0); | PFS_RETURN (0); | ||||
proc = NULL; | proc = NULL; | ||||
if (pid != NO_PID && !pfs_lookup_proc(pid, &proc)) | if (pid != NO_PID && !pfs_lookup_proc(pd, pid, &proc)) | ||||
PFS_RETURN (ENOENT); | PFS_RETURN (ENOENT); | ||||
sx_slock(&allproc_lock); | sx_slock(&allproc_lock); | ||||
pfs_lock(pd); | pfs_lock(pd); | ||||
KASSERT(pid == NO_PID || proc != NULL, | KASSERT(pid == NO_PID || proc != NULL, | ||||
("%s(): no process for pid %lu", __func__, (unsigned long)pid)); | ("%s(): no process for pid %lu", __func__, (unsigned long)pid)); | ||||
if (pid != NO_PID) { | if (pid != NO_PID) { | ||||
PROC_LOCK(proc); | PROC_LOCK(proc); | ||||
/* check if the directory is visible to the caller */ | /* check if the directory is visible to the caller */ | ||||
if (!pfs_visible_proc(curthread, pd, proc)) { | if (!pfs_visible_proc(curthread, pd, proc)) { | ||||
_PRELE(proc); | _PFS_PRELE(pd, proc); | ||||
PROC_UNLOCK(proc); | PROC_UNLOCK(proc); | ||||
sx_sunlock(&allproc_lock); | sx_sunlock(&allproc_lock); | ||||
pfs_unlock(pd); | pfs_unlock(pd); | ||||
PFS_RETURN (ENOENT); | PFS_RETURN (ENOENT); | ||||
} | } | ||||
} | } | ||||
/* skip unwanted entries */ | /* skip unwanted entries */ | ||||
for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN) { | for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN) { | ||||
if (pfs_iterate(curthread, proc, pd, &pn, &p) == -1) { | if (pfs_iterate(curthread, proc, pd, &pn, &p) == -1) { | ||||
/* nothing left... */ | /* nothing left... */ | ||||
if (proc != NULL) { | if (proc != NULL) { | ||||
_PRELE(proc); | _PFS_PRELE(pd, proc); | ||||
PROC_UNLOCK(proc); | PROC_UNLOCK(proc); | ||||
} | } | ||||
pfs_unlock(pd); | pfs_unlock(pd); | ||||
sx_sunlock(&allproc_lock); | sx_sunlock(&allproc_lock); | ||||
PFS_RETURN (0); | PFS_RETURN (0); | ||||
} | } | ||||
} | } | ||||
Show All 37 Lines | while (pfs_iterate(curthread, proc, pd, &pn, &p) != -1 && | ||||
} | } | ||||
PFS_TRACE(("%s", pfsent->entry.d_name)); | PFS_TRACE(("%s", pfsent->entry.d_name)); | ||||
dirent_terminate(&pfsent->entry); | dirent_terminate(&pfsent->entry); | ||||
STAILQ_INSERT_TAIL(&lst, pfsent, link); | STAILQ_INSERT_TAIL(&lst, pfsent, link); | ||||
offset += PFS_DELEN; | offset += PFS_DELEN; | ||||
resid -= PFS_DELEN; | resid -= PFS_DELEN; | ||||
} | } | ||||
if (proc != NULL) { | if (proc != NULL) { | ||||
_PRELE(proc); | _PFS_PRELE(pd, proc); | ||||
PROC_UNLOCK(proc); | PROC_UNLOCK(proc); | ||||
} | } | ||||
pfs_unlock(pd); | pfs_unlock(pd); | ||||
sx_sunlock(&allproc_lock); | sx_sunlock(&allproc_lock); | ||||
i = 0; | i = 0; | ||||
STAILQ_FOREACH_SAFE(pfsent, &lst, link, pfsent2) { | STAILQ_FOREACH_SAFE(pfsent, &lst, link, pfsent2) { | ||||
if (error == 0) | if (error == 0) | ||||
error = uiomove(&pfsent->entry, PFS_DELEN, uio); | error = uiomove(&pfsent->entry, PFS_DELEN, uio); | ||||
Show All 25 Lines | pfs_readlink(struct vop_readlink_args *va) | ||||
if (vn->v_type != VLNK) | if (vn->v_type != VLNK) | ||||
PFS_RETURN (EINVAL); | PFS_RETURN (EINVAL); | ||||
KASSERT_PN_IS_LINK(pn); | KASSERT_PN_IS_LINK(pn); | ||||
if (pn->pn_fill == NULL) | if (pn->pn_fill == NULL) | ||||
PFS_RETURN (EIO); | PFS_RETURN (EIO); | ||||
if (pvd->pvd_pid != NO_PID) { | if (pvd->pvd_pid != NO_PID) { | ||||
if ((proc = pfind(pvd->pvd_pid)) == NULL) | if ((proc = pfs_pfind(pvd->pvd_pid, pn)) == NULL) | ||||
PFS_RETURN (EIO); | PFS_RETURN (EIO); | ||||
if (proc->p_flag & P_WEXIT) { | _PFS_PHOLD(pn, proc); | ||||
PROC_UNLOCK(proc); | PROC_UNLOCK(proc); | ||||
PFS_RETURN (EIO); | |||||
} | } | ||||
_PHOLD(proc); | |||||
PROC_UNLOCK(proc); | |||||
} | |||||
vhold(vn); | vhold(vn); | ||||
locked = VOP_ISLOCKED(vn); | locked = VOP_ISLOCKED(vn); | ||||
VOP_UNLOCK(vn); | VOP_UNLOCK(vn); | ||||
/* sbuf_new() can't fail with a static buffer */ | /* sbuf_new() can't fail with a static buffer */ | ||||
sbuf_new(&sb, buf, sizeof buf, 0); | sbuf_new(&sb, buf, sizeof buf, 0); | ||||
error = pn_fill(curthread, proc, pn, &sb, NULL); | error = pn_fill(curthread, proc, pn, &sb, NULL); | ||||
if (proc != NULL) | if (proc != NULL) | ||||
PRELE(proc); | PFS_PRELE(pn, proc); | ||||
vn_lock(vn, locked | LK_RETRY); | vn_lock(vn, locked | LK_RETRY); | ||||
vdrop(vn); | vdrop(vn); | ||||
if (error) { | if (error) { | ||||
sbuf_delete(&sb); | sbuf_delete(&sb); | ||||
PFS_RETURN (error); | PFS_RETURN (error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | pfs_write(struct vop_write_args *va) | ||||
/* | /* | ||||
* This is necessary because either process' privileges may | * This is necessary because either process' privileges may | ||||
* have changed since the open() call. | * have changed since the open() call. | ||||
*/ | */ | ||||
if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) | if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) | ||||
PFS_RETURN (EIO); | PFS_RETURN (EIO); | ||||
if (proc != NULL) { | if (proc != NULL) { | ||||
_PHOLD(proc); | _PFS_PHOLD(pn, proc); | ||||
PROC_UNLOCK(proc); | PROC_UNLOCK(proc); | ||||
} | } | ||||
if (pn->pn_flags & PFS_RAWWR) { | if (pn->pn_flags & PFS_RAWWR) { | ||||
error = pn_fill(curthread, proc, pn, NULL, uio); | error = pn_fill(curthread, proc, pn, NULL, uio); | ||||
if (proc != NULL) | goto out; | ||||
PRELE(proc); | |||||
PFS_RETURN (error); | |||||
} | } | ||||
sbuf_uionew(&sb, uio, &error); | sbuf_uionew(&sb, uio, &error); | ||||
if (error) { | if (error) | ||||
if (proc != NULL) | goto out; | ||||
PRELE(proc); | |||||
PFS_RETURN (error); | |||||
} | |||||
error = pn_fill(curthread, proc, pn, &sb, uio); | error = pn_fill(curthread, proc, pn, &sb, uio); | ||||
sbuf_delete(&sb); | sbuf_delete(&sb); | ||||
out: | |||||
if (proc != NULL) | if (proc != NULL) | ||||
PRELE(proc); | PFS_PRELE(pn, proc); | ||||
PFS_RETURN (error); | PFS_RETURN (error); | ||||
} | } | ||||
/* | /* | ||||
* Vnode operations | * Vnode operations | ||||
*/ | */ | ||||
struct vop_vector pfs_vnodeops = { | struct vop_vector pfs_vnodeops = { | ||||
.vop_default = &default_vnodeops, | .vop_default = &default_vnodeops, | ||||
Show All 28 Lines |