Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F152913510
D23884.id68965.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
24 KB
Referenced Files
None
Subscribers
None
D23884.id68965.diff
View Options
Index: lib/libprocstat/libprocstat.c
===================================================================
--- lib/libprocstat/libprocstat.c
+++ lib/libprocstat/libprocstat.c
@@ -459,6 +459,7 @@
{
struct file file;
struct filedesc filed;
+ struct pwd pwd;
struct vm_map_entry vmentry;
struct vm_object object;
struct vmspace vmspace;
@@ -485,6 +486,11 @@
warnx("can't read filedesc at %p", (void *)kp->ki_fd);
return (NULL);
}
+ if (!kvm_read_all(kd, (unsigned long)filed.fd_pwd, &pwd,
+ sizeof(pwd))) {
+ warnx("can't read fd_pwd at %p", (void *)filed.fd_pwd);
+ return (NULL);
+ }
/*
* Allocate list head.
@@ -495,25 +501,27 @@
STAILQ_INIT(head);
/* root directory vnode, if one. */
- if (filed.fd_rdir) {
- entry = filestat_new_entry(filed.fd_rdir, PS_FST_TYPE_VNODE, -1,
- PS_FST_FFLAG_READ, PS_FST_UFLAG_RDIR, 0, 0, NULL, NULL);
- if (entry != NULL)
- STAILQ_INSERT_TAIL(head, entry, next);
- }
- /* current working directory vnode. */
- if (filed.fd_cdir) {
- entry = filestat_new_entry(filed.fd_cdir, PS_FST_TYPE_VNODE, -1,
- PS_FST_FFLAG_READ, PS_FST_UFLAG_CDIR, 0, 0, NULL, NULL);
- if (entry != NULL)
- STAILQ_INSERT_TAIL(head, entry, next);
- }
- /* jail root, if any. */
- if (filed.fd_jdir) {
- entry = filestat_new_entry(filed.fd_jdir, PS_FST_TYPE_VNODE, -1,
- PS_FST_FFLAG_READ, PS_FST_UFLAG_JAIL, 0, 0, NULL, NULL);
- if (entry != NULL)
- STAILQ_INSERT_TAIL(head, entry, next);
+ if (pwd != NULL) {
+ if (pwd.pwd_rdir) {
+ entry = filestat_new_entry(pwd.pwd_rdir, PS_FST_TYPE_VNODE, -1,
+ PS_FST_FFLAG_READ, PS_FST_UFLAG_RDIR, 0, 0, NULL, NULL);
+ if (entry != NULL)
+ STAILQ_INSERT_TAIL(head, entry, next);
+ }
+ /* current working directory vnode. */
+ if (pwd.pwd_cdir) {
+ entry = filestat_new_entry(pwd.pwd_cdir, PS_FST_TYPE_VNODE, -1,
+ PS_FST_FFLAG_READ, PS_FST_UFLAG_CDIR, 0, 0, NULL, NULL);
+ if (entry != NULL)
+ STAILQ_INSERT_TAIL(head, entry, next);
+ }
+ /* jail root, if any. */
+ if (pwd.pwd_jdir) {
+ entry = filestat_new_entry(pwd.pwd_jdir, PS_FST_TYPE_VNODE, -1,
+ PS_FST_FFLAG_READ, PS_FST_UFLAG_JAIL, 0, 0, NULL, NULL);
+ if (entry != NULL)
+ STAILQ_INSERT_TAIL(head, entry, next);
+ }
}
/* ktrace vnode, if one */
if (kp->ki_tracep) {
Index: sys/compat/linprocfs/linprocfs.c
===================================================================
--- sys/compat/linprocfs/linprocfs.c
+++ sys/compat/linprocfs/linprocfs.c
@@ -1028,23 +1028,16 @@
static int
linprocfs_doproccwd(PFS_FILL_ARGS)
{
- struct filedesc *fdp;
- struct vnode *vp;
+ struct pwd *pwd;
char *fullpath = "unknown";
char *freepath = NULL;
- fdp = p->p_fd;
- FILEDESC_SLOCK(fdp);
- vp = fdp->fd_cdir;
- if (vp != NULL)
- VREF(vp);
- FILEDESC_SUNLOCK(fdp);
- vn_fullpath(td, vp, &fullpath, &freepath);
- if (vp != NULL)
- vrele(vp);
+ pwd = pwd_hold(td);
+ vn_fullpath(td, pwd->pwd_cdir, &fullpath, &freepath);
sbuf_printf(sb, "%s", fullpath);
if (freepath)
free(freepath, M_TEMP);
+ pwd_drop(pwd);
return (0);
}
@@ -1054,23 +1047,18 @@
static int
linprocfs_doprocroot(PFS_FILL_ARGS)
{
- struct filedesc *fdp;
+ struct pwd *pwd;
struct vnode *vp;
char *fullpath = "unknown";
char *freepath = NULL;
- fdp = p->p_fd;
- FILEDESC_SLOCK(fdp);
- vp = jailed(p->p_ucred) ? fdp->fd_jdir : fdp->fd_rdir;
- if (vp != NULL)
- VREF(vp);
- FILEDESC_SUNLOCK(fdp);
+ pwd = pwd_hold(td);
+ vp = jailed(p->p_ucred) ? pwd->pwd_jdir : pwd->pwd_rdir;
vn_fullpath(td, vp, &fullpath, &freepath);
- if (vp != NULL)
- vrele(vp);
sbuf_printf(sb, "%s", fullpath);
if (freepath)
free(freepath, M_TEMP);
+ pwd_drop(pwd);
return (0);
}
Index: sys/kern/kern_descrip.c
===================================================================
--- sys/kern/kern_descrip.c
+++ sys/kern/kern_descrip.c
@@ -91,6 +91,7 @@
#include <ddb/ddb.h>
static MALLOC_DEFINE(M_FILEDESC, "filedesc", "Open file descriptor table");
+static MALLOC_DEFINE(M_PWD, "pwd", "Descriptor table vnodes");
static MALLOC_DEFINE(M_FILEDESC_TO_LEADER, "filedesc_to_leader",
"file desc to leader structures");
static MALLOC_DEFINE(M_SIGIO, "sigio", "sigio structures");
@@ -116,6 +117,8 @@
static u_long *filecaps_free_prep(struct filecaps *fcaps);
static void filecaps_free_finish(u_long *ioctls);
+static struct pwd *pwd_alloc(void);
+
/*
* Each process has:
*
@@ -314,24 +317,6 @@
fdunused(fdp, fd);
}
-void
-pwd_ensure_dirs(void)
-{
- struct filedesc *fdp;
-
- fdp = curproc->p_fd;
- FILEDESC_XLOCK(fdp);
- if (fdp->fd_cdir == NULL) {
- fdp->fd_cdir = rootvnode;
- vrefact(rootvnode);
- }
- if (fdp->fd_rdir == NULL) {
- fdp->fd_rdir = rootvnode;
- vrefact(rootvnode);
- }
- FILEDESC_XUNLOCK(fdp);
-}
-
/*
* System calls on descriptors.
*/
@@ -2014,22 +1999,16 @@
newfdp->fd_files = (struct fdescenttbl *)&newfdp0->fd_dfiles;
newfdp->fd_files->fdt_nfiles = NDFILE;
- if (fdp == NULL)
+ if (fdp == NULL) {
+ newfdp->fd_pwd = pwd_alloc();
return (newfdp);
+ }
if (prepfiles && fdp->fd_lastfile >= newfdp->fd_nfiles)
fdgrowtable(newfdp, fdp->fd_lastfile + 1);
FILEDESC_SLOCK(fdp);
- newfdp->fd_cdir = fdp->fd_cdir;
- if (newfdp->fd_cdir)
- vrefact(newfdp->fd_cdir);
- newfdp->fd_rdir = fdp->fd_rdir;
- if (newfdp->fd_rdir)
- vrefact(newfdp->fd_rdir);
- newfdp->fd_jdir = fdp->fd_jdir;
- if (newfdp->fd_jdir)
- vrefact(newfdp->fd_jdir);
+ newfdp->fd_pwd = pwd_hold_filedesc(fdp);
if (!prepfiles) {
FILEDESC_SUNLOCK(fdp);
@@ -2327,7 +2306,7 @@
{
struct proc *p;
struct filedesc *fdp;
- struct vnode *cdir, *jdir, *rdir;
+ struct pwd *pwd;
p = td->td_proc;
fdp = p->p_fd;
@@ -2349,20 +2328,11 @@
return;
FILEDESC_XLOCK(fdp);
- cdir = fdp->fd_cdir;
- fdp->fd_cdir = NULL;
- rdir = fdp->fd_rdir;
- fdp->fd_rdir = NULL;
- jdir = fdp->fd_jdir;
- fdp->fd_jdir = NULL;
+ pwd = fdp->fd_pwd;
+ pwd_set(fdp, NULL);
FILEDESC_XUNLOCK(fdp);
- if (cdir != NULL)
- vrele(cdir);
- if (rdir != NULL)
- vrele(rdir);
- if (jdir != NULL)
- vrele(jdir);
+ pwd_drop(pwd);
fdescfree_fds(td, fdp, 1);
}
@@ -2371,13 +2341,7 @@
fdescfree_remapped(struct filedesc *fdp)
{
- if (fdp->fd_cdir != NULL)
- vrele(fdp->fd_cdir);
- if (fdp->fd_rdir != NULL)
- vrele(fdp->fd_rdir);
- if (fdp->fd_jdir != NULL)
- vrele(fdp->fd_jdir);
-
+ pwd_drop(fdp->fd_pwd);
fdescfree_fds(curthread, fdp, 0);
}
@@ -3287,37 +3251,116 @@
return (0);
}
+static void
+pwd_fill(struct pwd *oldpwd, struct pwd *newpwd)
+{
+
+ if (newpwd->pwd_cdir == NULL && oldpwd->pwd_cdir != NULL) {
+ vrefact(oldpwd->pwd_cdir);
+ newpwd->pwd_cdir = oldpwd->pwd_cdir;
+ }
+
+ if (newpwd->pwd_rdir == NULL && oldpwd->pwd_rdir != NULL) {
+ vrefact(oldpwd->pwd_rdir);
+ newpwd->pwd_rdir = oldpwd->pwd_rdir;
+ }
+
+ if (newpwd->pwd_jdir == NULL && oldpwd->pwd_jdir != NULL) {
+ vrefact(oldpwd->pwd_jdir);
+ newpwd->pwd_jdir = oldpwd->pwd_jdir;
+ }
+}
+
+struct pwd *
+pwd_hold_filedesc(struct filedesc *fdp)
+{
+ struct pwd *pwd;
+
+ FILEDESC_LOCK_ASSERT(fdp);
+ pwd = fdp->fd_pwd;
+ if (pwd != NULL)
+ refcount_acquire(&pwd->pwd_refcount);
+ return (pwd);
+}
+
+struct pwd *
+pwd_hold(struct thread *td)
+{
+ struct filedesc *fdp;
+ struct pwd *pwd;
+
+ fdp = td->td_proc->p_fd;
+
+ FILEDESC_SLOCK(fdp);
+ pwd = fdp->fd_pwd;
+ MPASS(pwd != NULL);
+ refcount_acquire(&pwd->pwd_refcount);
+ FILEDESC_SUNLOCK(fdp);
+ return (pwd);
+}
+
+static struct pwd *
+pwd_alloc(void)
+{
+ struct pwd *pwd;
+
+ pwd = malloc(sizeof(*pwd), M_PWD, M_WAITOK | M_ZERO);
+ refcount_init(&pwd->pwd_refcount, 1);
+ return (pwd);
+}
+
+void
+pwd_drop(struct pwd *pwd)
+{
+
+ if (!refcount_release(&pwd->pwd_refcount))
+ return;
+
+ if (pwd->pwd_cdir != NULL)
+ vrele(pwd->pwd_cdir);
+ if (pwd->pwd_rdir != NULL)
+ vrele(pwd->pwd_rdir);
+ if (pwd->pwd_jdir != NULL)
+ vrele(pwd->pwd_jdir);
+ free(pwd, M_PWD);
+}
+
/*
- * Common routine for kern_chroot() and jail_attach(). The caller is
- * responsible for invoking priv_check() and mac_vnode_check_chroot() to
- * authorize this operation.
- */
+* Common routine for kern_chroot() and jail_attach(). The caller is
+* responsible for invoking priv_check() and mac_vnode_check_chroot() to
+* authorize this operation.
+*/
int
pwd_chroot(struct thread *td, struct vnode *vp)
{
struct filedesc *fdp;
- struct vnode *oldvp;
+ struct pwd *newpwd, *oldpwd;
int error;
fdp = td->td_proc->p_fd;
+ newpwd = pwd_alloc();
FILEDESC_XLOCK(fdp);
+ oldpwd = fdp->fd_pwd;
if (chroot_allow_open_directories == 0 ||
- (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) {
+ (chroot_allow_open_directories == 1 &&
+ oldpwd->pwd_rdir != rootvnode)) {
error = chroot_refuse_vdir_fds(fdp);
if (error != 0) {
FILEDESC_XUNLOCK(fdp);
+ pwd_drop(newpwd);
return (error);
}
}
- oldvp = fdp->fd_rdir;
+
vrefact(vp);
- fdp->fd_rdir = vp;
- if (fdp->fd_jdir == NULL) {
+ newpwd->pwd_rdir = vp;
+ if (oldpwd->pwd_jdir == NULL) {
vrefact(vp);
- fdp->fd_jdir = vp;
+ newpwd->pwd_jdir = vp;
}
+ pwd_set(fdp, newpwd);
FILEDESC_XUNLOCK(fdp);
- vrele(oldvp);
+ pwd_drop(oldpwd);
return (0);
}
@@ -3325,16 +3368,51 @@
pwd_chdir(struct thread *td, struct vnode *vp)
{
struct filedesc *fdp;
- struct vnode *oldvp;
+ struct pwd *newpwd, *oldpwd;
+ VNPASS(vp->v_usecount > 0, vp);
+
+ newpwd = pwd_alloc();
fdp = td->td_proc->p_fd;
FILEDESC_XLOCK(fdp);
- VNASSERT(vp->v_usecount > 0, vp,
- ("chdir to a vnode with zero usecount"));
- oldvp = fdp->fd_cdir;
- fdp->fd_cdir = vp;
+ oldpwd = fdp->fd_pwd;
+ newpwd->pwd_cdir = vp;
+ pwd_fill(oldpwd, newpwd);
+ pwd_set(fdp, newpwd);
FILEDESC_XUNLOCK(fdp);
- vrele(oldvp);
+ pwd_drop(oldpwd);
+}
+
+void
+pwd_ensure_dirs(void)
+{
+ struct filedesc *fdp;
+ struct pwd *oldpwd, *newpwd;
+
+ fdp = curproc->p_fd;
+ FILEDESC_XLOCK(fdp);
+ oldpwd = fdp->fd_pwd;
+ if (oldpwd->pwd_cdir != NULL && oldpwd->pwd_rdir != NULL) {
+ FILEDESC_XUNLOCK(fdp);
+ return;
+ }
+ FILEDESC_XUNLOCK(fdp);
+
+ newpwd = pwd_alloc();
+ FILEDESC_XLOCK(fdp);
+ oldpwd = fdp->fd_pwd;
+ pwd_fill(oldpwd, newpwd);
+ if (newpwd->pwd_cdir == NULL) {
+ vrefact(rootvnode);
+ newpwd->pwd_cdir = rootvnode;
+ }
+ if (newpwd->pwd_rdir == NULL) {
+ vrefact(rootvnode);
+ newpwd->pwd_rdir = rootvnode;
+ }
+ pwd_set(fdp, newpwd);
+ FILEDESC_XUNLOCK(fdp);
+ pwd_drop(oldpwd);
}
/*
@@ -3345,6 +3423,7 @@
mountcheckdirs(struct vnode *olddp, struct vnode *newdp)
{
struct filedesc *fdp;
+ struct pwd *newpwd, *oldpwd;
struct prison *pr;
struct proc *p;
int nrele;
@@ -3352,6 +3431,7 @@
if (vrefcnt(olddp) == 1)
return;
nrele = 0;
+ newpwd = pwd_alloc();
sx_slock(&allproc_lock);
FOREACH_PROC_IN_SYSTEM(p) {
PROC_LOCK(p);
@@ -3360,25 +3440,35 @@
if (fdp == NULL)
continue;
FILEDESC_XLOCK(fdp);
- if (fdp->fd_cdir == olddp) {
+ oldpwd = fdp->fd_pwd;
+ if (oldpwd == NULL ||
+ (oldpwd->pwd_cdir != olddp &&
+ oldpwd->pwd_rdir != olddp &&
+ oldpwd->pwd_jdir != olddp)) {
+ FILEDESC_XUNLOCK(fdp);
+ fddrop(fdp);
+ continue;
+ }
+ if (oldpwd->pwd_cdir == olddp) {
vrefact(newdp);
- fdp->fd_cdir = newdp;
- nrele++;
+ newpwd->pwd_cdir = newdp;
}
- if (fdp->fd_rdir == olddp) {
+ if (oldpwd->pwd_rdir == olddp) {
vrefact(newdp);
- fdp->fd_rdir = newdp;
- nrele++;
+ newpwd->pwd_rdir = newdp;
}
- if (fdp->fd_jdir == olddp) {
+ if (oldpwd->pwd_jdir == olddp) {
vrefact(newdp);
- fdp->fd_jdir = newdp;
- nrele++;
+ newpwd->pwd_jdir = newdp;
}
+ pwd_set(fdp, newpwd);
FILEDESC_XUNLOCK(fdp);
+ pwd_drop(oldpwd);
fddrop(fdp);
+ newpwd = pwd_alloc();
}
sx_sunlock(&allproc_lock);
+ pwd_drop(newpwd);
if (rootvnode == olddp) {
vrefact(newdp);
rootvnode = newdp;
@@ -3714,6 +3804,7 @@
struct filedesc *fdp;
struct export_fd_buf *efbuf;
struct vnode *cttyvp, *textvp, *tracevp;
+ struct pwd *pwd;
int error, i;
cap_rights_t rights;
@@ -3754,20 +3845,24 @@
goto fail;
efbuf->fdp = fdp;
FILEDESC_SLOCK(fdp);
- /* working directory */
- if (fdp->fd_cdir != NULL) {
- vrefact(fdp->fd_cdir);
- export_vnode_to_sb(fdp->fd_cdir, KF_FD_TYPE_CWD, FREAD, efbuf);
- }
- /* root directory */
- if (fdp->fd_rdir != NULL) {
- vrefact(fdp->fd_rdir);
- export_vnode_to_sb(fdp->fd_rdir, KF_FD_TYPE_ROOT, FREAD, efbuf);
- }
- /* jail directory */
- if (fdp->fd_jdir != NULL) {
- vrefact(fdp->fd_jdir);
- export_vnode_to_sb(fdp->fd_jdir, KF_FD_TYPE_JAIL, FREAD, efbuf);
+ pwd = pwd_hold_filedesc(fdp);
+ if (pwd != NULL) {
+ /* working directory */
+ if (pwd->pwd_cdir != NULL) {
+ vrefact(pwd->pwd_cdir);
+ export_vnode_to_sb(pwd->pwd_cdir, KF_FD_TYPE_CWD, FREAD, efbuf);
+ }
+ /* root directory */
+ if (pwd->pwd_rdir != NULL) {
+ vrefact(pwd->pwd_rdir);
+ export_vnode_to_sb(pwd->pwd_rdir, KF_FD_TYPE_ROOT, FREAD, efbuf);
+ }
+ /* jail directory */
+ if (pwd->pwd_jdir != NULL) {
+ vrefact(pwd->pwd_jdir);
+ export_vnode_to_sb(pwd->pwd_jdir, KF_FD_TYPE_JAIL, FREAD, efbuf);
+ }
+ pwd_drop(pwd);
}
for (i = 0; fdp->fd_refcnt > 0 && i <= fdp->fd_lastfile; i++) {
if ((fp = fdp->fd_ofiles[i].fde_file) == NULL)
@@ -3882,6 +3977,7 @@
struct kinfo_ofile *okif;
struct kinfo_file *kif;
struct filedesc *fdp;
+ struct pwd *pwd;
int error, i, *name;
struct file *fp;
struct proc *p;
@@ -3897,15 +3993,19 @@
kif = malloc(sizeof(*kif), M_TEMP, M_WAITOK);
okif = malloc(sizeof(*okif), M_TEMP, M_WAITOK);
FILEDESC_SLOCK(fdp);
- if (fdp->fd_cdir != NULL)
- export_vnode_for_osysctl(fdp->fd_cdir, KF_FD_TYPE_CWD, kif,
- okif, fdp, req);
- if (fdp->fd_rdir != NULL)
- export_vnode_for_osysctl(fdp->fd_rdir, KF_FD_TYPE_ROOT, kif,
- okif, fdp, req);
- if (fdp->fd_jdir != NULL)
- export_vnode_for_osysctl(fdp->fd_jdir, KF_FD_TYPE_JAIL, kif,
- okif, fdp, req);
+ pwd = pwd_hold_filedesc(fdp);
+ if (pwd != NULL) {
+ if (pwd->pwd_cdir != NULL)
+ export_vnode_for_osysctl(pwd->pwd_cdir, KF_FD_TYPE_CWD, kif,
+ okif, fdp, req);
+ if (pwd->pwd_rdir != NULL)
+ export_vnode_for_osysctl(pwd->pwd_rdir, KF_FD_TYPE_ROOT, kif,
+ okif, fdp, req);
+ if (pwd->pwd_jdir != NULL)
+ export_vnode_for_osysctl(pwd->pwd_jdir, KF_FD_TYPE_JAIL, kif,
+ okif, fdp, req);
+ pwd_drop(pwd);
+ }
for (i = 0; fdp->fd_refcnt > 0 && i <= fdp->fd_lastfile; i++) {
if ((fp = fdp->fd_ofiles[i].fde_file) == NULL)
continue;
@@ -3973,6 +4073,7 @@
{
struct filedesc *fdp;
struct export_fd_buf *efbuf;
+ struct vnode *cdir;
int error;
PROC_LOCK_ASSERT(p, MA_OWNED);
@@ -3988,12 +4089,12 @@
efbuf->remainder = maxlen;
FILEDESC_SLOCK(fdp);
- if (fdp->fd_cdir == NULL)
+ cdir = fdp->fd_pwd->pwd_cdir;
+ if (cdir == NULL) {
error = EINVAL;
- else {
- vrefact(fdp->fd_cdir);
- error = export_vnode_to_sb(fdp->fd_cdir, KF_FD_TYPE_CWD,
- FREAD, efbuf);
+ } else {
+ vrefact(cdir);
+ error = export_vnode_to_sb(cdir, KF_FD_TYPE_CWD, FREAD, efbuf);
}
FILEDESC_SUNLOCK(fdp);
fddrop(fdp);
Index: sys/kern/kern_linker.c
===================================================================
--- sys/kern/kern_linker.c
+++ sys/kern/kern_linker.c
@@ -2085,14 +2085,14 @@
KASSERT(verinfo == NULL, ("linker_load_module: verinfo"
" is not NULL"));
/* check if root file system is not mounted */
- if (rootvnode == NULL || curproc->p_fd->fd_rdir == NULL)
+ if (rootvnode == NULL || curproc->p_fd->fd_pwd->pwd_rdir == NULL)
return (ENXIO);
pathname = linker_search_kld(kldname);
} else {
if (modlist_lookup2(modname, verinfo) != NULL)
return (EEXIST);
/* check if root file system is not mounted */
- if (rootvnode == NULL || curproc->p_fd->fd_rdir == NULL)
+ if (rootvnode == NULL || curproc->p_fd->fd_pwd->pwd_rdir == NULL)
return (ENXIO);
if (kldname != NULL)
pathname = strdup(kldname, M_LINKER);
Index: sys/kern/vfs_cache.c
===================================================================
--- sys/kern/vfs_cache.c
+++ sys/kern/vfs_cache.c
@@ -2196,20 +2196,12 @@
int
vn_getcwd(struct thread *td, char *buf, char **retbuf, size_t *buflen)
{
- struct filedesc *fdp;
- struct vnode *cdir, *rdir;
+ struct pwd *pwd;
int error;
- fdp = td->td_proc->p_fd;
- FILEDESC_SLOCK(fdp);
- cdir = fdp->fd_cdir;
- vrefact(cdir);
- rdir = fdp->fd_rdir;
- vrefact(rdir);
- FILEDESC_SUNLOCK(fdp);
- error = vn_fullpath_any(td, cdir, rdir, buf, retbuf, buflen);
- vrele(rdir);
- vrele(cdir);
+ pwd = pwd_hold(td);
+ error = vn_fullpath_any(td, pwd->pwd_cdir, pwd->pwd_rdir, buf, retbuf, buflen);
+ pwd_drop(pwd);
#ifdef KTRACE
if (KTRPOINT(curthread, KTR_NAMEI) && error == 0)
@@ -2256,9 +2248,8 @@
int
vn_fullpath(struct thread *td, struct vnode *vn, char **retbuf, char **freebuf)
{
+ struct pwd *pwd;
char *buf;
- struct filedesc *fdp;
- struct vnode *rdir;
size_t buflen;
int error;
@@ -2267,13 +2258,9 @@
buflen = MAXPATHLEN;
buf = malloc(buflen, M_TEMP, M_WAITOK);
- fdp = td->td_proc->p_fd;
- FILEDESC_SLOCK(fdp);
- rdir = fdp->fd_rdir;
- vrefact(rdir);
- FILEDESC_SUNLOCK(fdp);
- error = vn_fullpath_any(td, vn, rdir, buf, retbuf, &buflen);
- vrele(rdir);
+ pwd = pwd_hold(td);
+ error = vn_fullpath_any(td, vn, pwd->pwd_rdir, buf, retbuf, &buflen);
+ pwd_drop(pwd);
if (!error)
*freebuf = buf;
@@ -2541,8 +2528,7 @@
char **freebuf, size_t *buflen)
{
char *buf, *tmpbuf;
- struct filedesc *fdp;
- struct vnode *rdir;
+ struct pwd *pwd;
struct componentname *cnp;
struct vnode *vp;
size_t addend;
@@ -2557,11 +2543,7 @@
slash_prefixed = false;
buf = malloc(*buflen, M_TEMP, M_WAITOK);
- fdp = td->td_proc->p_fd;
- FILEDESC_SLOCK(fdp);
- rdir = fdp->fd_rdir;
- vrefact(rdir);
- FILEDESC_SUNLOCK(fdp);
+ pwd = pwd_hold(td);
addend = 0;
vp = ndp->ni_vp;
@@ -2582,16 +2564,17 @@
}
vref(vp);
- error = vn_fullpath_dir(td, vp, rdir, buf, retbuf, buflen, slash_prefixed, addend);
+ error = vn_fullpath_dir(td, vp, pwd->pwd_rdir, buf, retbuf, buflen,
+ slash_prefixed, addend);
if (error != 0)
goto out_bad;
- vrele(rdir);
+ pwd_drop(pwd);
*freebuf = buf;
return (0);
out_bad:
- vrele(rdir);
+ pwd_drop(pwd);
free(buf, M_TEMP);
return (error);
}
Index: sys/kern/vfs_lookup.c
===================================================================
--- sys/kern/vfs_lookup.c
+++ sys/kern/vfs_lookup.c
@@ -303,7 +303,6 @@
int
namei(struct nameidata *ndp)
{
- struct filedesc *fdp; /* pointer to file descriptor state */
char *cp; /* pointer into pathname argument */
struct vnode *dp; /* the directory we are searching */
struct iovec aiov; /* uio for reading symbolic links */
@@ -311,6 +310,7 @@
struct file *dfp;
struct thread *td;
struct proc *p;
+ struct pwd *pwd;
cap_rights_t rights;
struct filecaps dirfd_caps;
struct uio auio;
@@ -327,7 +327,6 @@
("namei: flags contaminated with nameiops"));
MPASS(ndp->ni_startdir == NULL || ndp->ni_startdir->v_type == VDIR ||
ndp->ni_startdir->v_type == VBAD);
- fdp = p->p_fd;
TAILQ_INIT(&ndp->ni_cap_tracker);
ndp->ni_lcf = 0;
@@ -395,13 +394,13 @@
/*
* Get starting point for the translation.
*/
- FILEDESC_SLOCK(fdp);
+ pwd = pwd_hold(td);
/*
* The reference on ni_rootdir is acquired in the block below to avoid
* back-to-back atomics for absolute lookups.
*/
- ndp->ni_rootdir = fdp->fd_rdir;
- ndp->ni_topdir = fdp->fd_jdir;
+ ndp->ni_rootdir = pwd->pwd_rdir;
+ ndp->ni_topdir = pwd->pwd_jdir;
startdir_used = 0;
dp = NULL;
@@ -422,7 +421,7 @@
dp = ndp->ni_startdir;
startdir_used = 1;
} else if (ndp->ni_dirfd == AT_FDCWD) {
- dp = fdp->fd_cdir;
+ dp = pwd->pwd_cdir;
if (dp == ndp->ni_rootdir) {
vrefactn(dp, 2);
} else {
@@ -442,7 +441,7 @@
* Effectively inlined fgetvp_rights, because we need to
* inspect the file as well as grabbing the vnode.
*/
- error = fget_cap_locked(fdp, ndp->ni_dirfd, &rights,
+ error = fget_cap(td, ndp->ni_dirfd, &rights,
&dfp, &ndp->ni_filecaps);
if (error != 0) {
/*
@@ -481,7 +480,7 @@
}
if (error == 0 && (cnp->cn_flags & BENEATH) != 0) {
if (ndp->ni_dirfd == AT_FDCWD) {
- ndp->ni_beneath_latch = fdp->fd_cdir;
+ ndp->ni_beneath_latch = pwd->pwd_cdir;
vrefact(ndp->ni_beneath_latch);
} else {
rights = ndp->ni_rightsneeded;
@@ -496,7 +495,6 @@
if (error == 0)
ndp->ni_lcf |= NI_LCF_LATCH;
}
- FILEDESC_SUNLOCK(fdp);
/*
* If we are auditing the kernel pathname, save the user pathname.
*/
@@ -542,6 +540,7 @@
nameicap_cleanup(ndp, true);
SDT_PROBE2(vfs, namei, lookup, return, error,
(error == 0 ? ndp->ni_vp : NULL));
+ pwd_drop(pwd);
return (error);
}
if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
@@ -617,6 +616,7 @@
namei_cleanup_cnp(cnp);
nameicap_cleanup(ndp, true);
SDT_PROBE2(vfs, namei, lookup, return, error, NULL);
+ pwd_drop(pwd);
return (error);
}
Index: sys/kern/vfs_mountroot.c
===================================================================
--- sys/kern/vfs_mountroot.c
+++ sys/kern/vfs_mountroot.c
@@ -237,27 +237,13 @@
static void
set_rootvnode(void)
{
- struct proc *p;
if (VFS_ROOT(TAILQ_FIRST(&mountlist), LK_EXCLUSIVE, &rootvnode))
panic("set_rootvnode: Cannot find root vnode");
VOP_UNLOCK(rootvnode);
- p = curthread->td_proc;
- FILEDESC_XLOCK(p->p_fd);
-
- if (p->p_fd->fd_cdir != NULL)
- vrele(p->p_fd->fd_cdir);
- p->p_fd->fd_cdir = rootvnode;
- VREF(rootvnode);
-
- if (p->p_fd->fd_rdir != NULL)
- vrele(p->p_fd->fd_rdir);
- p->p_fd->fd_rdir = rootvnode;
- VREF(rootvnode);
-
- FILEDESC_XUNLOCK(p->p_fd);
+ pwd_ensure_dirs();
}
static int
Index: sys/security/audit/audit_bsm_klib.c
===================================================================
--- sys/security/audit/audit_bsm_klib.c
+++ sys/security/audit/audit_bsm_klib.c
@@ -493,38 +493,35 @@
audit_canon_path(struct thread *td, int dirfd, char *path, char *cpath)
{
struct vnode *cdir, *rdir;
- struct filedesc *fdp;
+ struct pwd *pwd;
cap_rights_t rights;
int error;
+ bool vrele_cdir;
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "%s: at %s:%d",
__func__, __FILE__, __LINE__);
- rdir = cdir = NULL;
- fdp = td->td_proc->p_fd;
- FILEDESC_SLOCK(fdp);
- if (*path == '/') {
- rdir = fdp->fd_rdir;
- vrefact(rdir);
- } else {
+ pwd = pwd_hold(td);
+ rdir = pwd->pwd_rdir;
+ cdir = NULL;
+ vrele_cdir = false;
+ if (*path != '/') {
if (dirfd == AT_FDCWD) {
- cdir = fdp->fd_cdir;
- vrefact(cdir);
+ cdir = pwd->pwd_cdir;
} else {
error = fgetvp(td, dirfd, cap_rights_init(&rights), &cdir);
if (error != 0) {
- FILEDESC_SUNLOCK(fdp);
cpath[0] = '\0';
+ pwd_drop(pwd);
return;
}
+ vrele_cdir = true;
}
}
- FILEDESC_SUNLOCK(fdp);
audit_canon_path_vp(td, rdir, cdir, path, cpath);
- if (rdir != NULL)
- vrele(rdir);
- if (cdir != NULL)
+ pwd_drop(pwd);
+ if (vrele_cdir)
vrele(cdir);
}
Index: sys/sys/filedesc.h
===================================================================
--- sys/sys/filedesc.h
+++ sys/sys/filedesc.h
@@ -76,11 +76,16 @@
*/
#define NDSLOTTYPE u_long
+struct pwd {
+ volatile u_int pwd_refcount;
+ struct vnode *pwd_cdir; /* current directory */
+ struct vnode *pwd_rdir; /* root directory */
+ struct vnode *pwd_jdir; /* jail root directory */
+};
+
struct filedesc {
struct fdescenttbl *fd_files; /* open files table */
- struct vnode *fd_cdir; /* current directory */
- struct vnode *fd_rdir; /* root directory */
- struct vnode *fd_jdir; /* jail root directory */
+ struct pwd *fd_pwd; /* directories */
NDSLOTTYPE *fd_map; /* bitmap of free fds */
int fd_lastfile; /* high-water mark of fd_ofiles */
int fd_freefile; /* approx. next free file */
@@ -253,6 +258,17 @@
int pwd_chroot(struct thread *td, struct vnode *vp);
void pwd_ensure_dirs(void);
+struct pwd *pwd_hold_filedesc(struct filedesc *fdp);
+struct pwd *pwd_hold(struct thread *td);
+void pwd_drop(struct pwd *pwd);
+static inline void
+pwd_set(struct filedesc *fdp, struct pwd *newpwd)
+{
+
+ FILEDESC_XLOCK_ASSERT(fdp);
+ fdp->fd_pwd = newpwd;
+}
+
#endif /* _KERNEL */
#endif /* !_SYS_FILEDESC_H_ */
Index: sys/ufs/ffs/ffs_alloc.c
===================================================================
--- sys/ufs/ffs/ffs_alloc.c
+++ sys/ufs/ffs/ffs_alloc.c
@@ -3190,6 +3190,7 @@
struct inode *ip, *dp;
struct mount *mp;
struct fs *fs;
+ struct pwd *pwd;
ufs2_daddr_t blkno;
long blkcnt, blksize;
u_long key;
@@ -3448,11 +3449,11 @@
/*
* Now we get and lock the child directory containing "..".
*/
- FILEDESC_SLOCK(td->td_proc->p_fd);
- dvp = td->td_proc->p_fd->fd_cdir;
- FILEDESC_SUNLOCK(td->td_proc->p_fd);
+ pwd = pwd_hold(td);
+ dvp = pwd->pwd_cdir;
if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) {
vput(fdvp);
+ pwd_drop(pwd);
break;
}
dp = VTOI(dvp);
@@ -3463,6 +3464,7 @@
cache_purge(dvp);
vput(dvp);
vput(fdvp);
+ pwd_drop(pwd);
break;
case FFS_UNLINK:
@@ -3607,7 +3609,7 @@
return (EINVAL);
fdp = td->td_proc->p_fd;
FILEDESC_SLOCK(fdp);
- vp = fdp->fd_cdir;
+ vp = fdp->fd_pwd->pwd_cdir;
vref(vp);
FILEDESC_SUNLOCK(fdp);
vn_lock(vp, LK_SHARED | LK_RETRY);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Apr 19, 12:08 AM (16 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31710340
Default Alt Text
D23884.id68965.diff (24 KB)
Attached To
Mode
D23884: (pwd 2/3) fd: move vnodes out of filedesc into a dedicated structure
Attached
Detach File
Event Timeline
Log In to Comment