Page MenuHomeFreeBSD

D23889.id69241.diff
No OneTemporary

D23889.id69241.diff

Index: lib/libprocstat/libprocstat.c
===================================================================
--- lib/libprocstat/libprocstat.c
+++ lib/libprocstat/libprocstat.c
@@ -460,6 +460,7 @@
struct file file;
struct filedesc filed;
struct pwd pwd;
+ unsigned long pwd_addr;
struct vm_map_entry vmentry;
struct vm_object object;
struct vmspace vmspace;
@@ -488,10 +489,10 @@
return (NULL);
}
haspwd = false;
- if (filed.fd_pwd != 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);
+ pwd_addr = (unsigned long)(FILEDESC_KVM_LOAD_PWD(&filed));
+ if (pwd_addr != 0) {
+ if (!kvm_read_all(kd, pwd_addr, &pwd, sizeof(pwd))) {
+ warnx("can't read fd_pwd at %p", (void *)pwd_addr);
return (NULL);
}
haspwd = true;
Index: sys/kern/kern_descrip.c
===================================================================
--- sys/kern/kern_descrip.c
+++ sys/kern/kern_descrip.c
@@ -69,6 +69,7 @@
#include <sys/sbuf.h>
#include <sys/signalvar.h>
#include <sys/kdb.h>
+#include <sys/smr.h>
#include <sys/stat.h>
#include <sys/sx.h>
#include <sys/syscallsubr.h>
@@ -101,6 +102,8 @@
static __read_mostly uma_zone_t file_zone;
static __read_mostly uma_zone_t filedesc0_zone;
+static __read_mostly uma_zone_t pwd_zone;
+static __read_mostly smr_t pwd_smr;
static int closefp(struct filedesc *fdp, int fd, struct file *fp,
struct thread *td, int holdleaders);
@@ -1985,6 +1988,7 @@
{
struct filedesc0 *newfdp0;
struct filedesc *newfdp;
+ struct pwd *newpwd;
newfdp0 = uma_zalloc(filedesc0_zone, M_WAITOK | M_ZERO);
newfdp = &newfdp0->fd_fd;
@@ -2000,7 +2004,8 @@
newfdp->fd_files->fdt_nfiles = NDFILE;
if (fdp == NULL) {
- newfdp->fd_pwd = pwd_alloc();
+ newpwd = pwd_alloc();
+ smr_serialized_store(&newfdp->fd_pwd, newpwd, true);
return (newfdp);
}
@@ -2008,7 +2013,8 @@
fdgrowtable(newfdp, fdp->fd_lastfile + 1);
FILEDESC_SLOCK(fdp);
- newfdp->fd_pwd = pwd_hold_filedesc(fdp);
+ newpwd = pwd_hold_filedesc(fdp);
+ smr_serialized_store(&newfdp->fd_pwd, newpwd, true);
if (!prepfiles) {
FILEDESC_SUNLOCK(fdp);
@@ -2328,7 +2334,7 @@
return;
FILEDESC_XLOCK(fdp);
- pwd = fdp->fd_pwd;
+ pwd = FILEDESC_XLOCKED_LOAD_PWD(fdp);
pwd_set(fdp, NULL);
FILEDESC_XUNLOCK(fdp);
@@ -2341,7 +2347,7 @@
fdescfree_remapped(struct filedesc *fdp)
{
- pwd_drop(fdp->fd_pwd);
+ pwd_drop(smr_serialized_load(&fdp->fd_pwd, true));
fdescfree_fds(curthread, fdp, 0);
}
@@ -3277,7 +3283,7 @@
struct pwd *pwd;
FILEDESC_LOCK_ASSERT(fdp);
- pwd = fdp->fd_pwd;
+ pwd = FILEDESC_LOCKED_LOAD_PWD(fdp);
if (pwd != NULL)
refcount_acquire(&pwd->pwd_refcount);
return (pwd);
@@ -3291,11 +3297,14 @@
fdp = td->td_proc->p_fd;
- FILEDESC_SLOCK(fdp);
- pwd = fdp->fd_pwd;
- MPASS(pwd != NULL);
- refcount_acquire(&pwd->pwd_refcount);
- FILEDESC_SUNLOCK(fdp);
+ smr_enter(pwd_smr);
+ for (;;) {
+ pwd = smr_entered_load(&fdp->fd_pwd, pwd_smr);
+ MPASS(pwd != NULL);
+ if (refcount_acquire_if_not_zero(&pwd->pwd_refcount))
+ break;
+ }
+ smr_exit(pwd_smr);
return (pwd);
}
@@ -3304,7 +3313,8 @@
{
struct pwd *pwd;
- pwd = malloc(sizeof(*pwd), M_PWD, M_WAITOK | M_ZERO);
+ pwd = uma_zalloc_smr(pwd_zone, M_WAITOK);
+ bzero(pwd, sizeof(*pwd));
refcount_init(&pwd->pwd_refcount, 1);
return (pwd);
}
@@ -3322,7 +3332,7 @@
vrele(pwd->pwd_rdir);
if (pwd->pwd_jdir != NULL)
vrele(pwd->pwd_jdir);
- free(pwd, M_PWD);
+ uma_zfree_smr(pwd_zone, pwd);
}
/*
@@ -3340,7 +3350,7 @@
fdp = td->td_proc->p_fd;
newpwd = pwd_alloc();
FILEDESC_XLOCK(fdp);
- oldpwd = fdp->fd_pwd;
+ oldpwd = FILEDESC_XLOCKED_LOAD_PWD(fdp);
if (chroot_allow_open_directories == 0 ||
(chroot_allow_open_directories == 1 &&
oldpwd->pwd_rdir != rootvnode)) {
@@ -3376,7 +3386,7 @@
newpwd = pwd_alloc();
fdp = td->td_proc->p_fd;
FILEDESC_XLOCK(fdp);
- oldpwd = fdp->fd_pwd;
+ oldpwd = FILEDESC_XLOCKED_LOAD_PWD(fdp);
newpwd->pwd_cdir = vp;
pwd_fill(oldpwd, newpwd);
pwd_set(fdp, newpwd);
@@ -3392,7 +3402,7 @@
fdp = curproc->p_fd;
FILEDESC_XLOCK(fdp);
- oldpwd = fdp->fd_pwd;
+ oldpwd = FILEDESC_XLOCKED_LOAD_PWD(fdp);
if (oldpwd->pwd_cdir != NULL && oldpwd->pwd_rdir != NULL) {
FILEDESC_XUNLOCK(fdp);
return;
@@ -3401,7 +3411,7 @@
newpwd = pwd_alloc();
FILEDESC_XLOCK(fdp);
- oldpwd = fdp->fd_pwd;
+ oldpwd = FILEDESC_XLOCKED_LOAD_PWD(fdp);
pwd_fill(oldpwd, newpwd);
if (newpwd->pwd_cdir == NULL) {
vrefact(rootvnode);
@@ -3441,7 +3451,7 @@
if (fdp == NULL)
continue;
FILEDESC_XLOCK(fdp);
- oldpwd = fdp->fd_pwd;
+ oldpwd = FILEDESC_XLOCKED_LOAD_PWD(fdp);
if (oldpwd == NULL ||
(oldpwd->pwd_cdir != olddp &&
oldpwd->pwd_rdir != olddp &&
@@ -4074,6 +4084,7 @@
kern_proc_cwd_out(struct proc *p, struct sbuf *sb, ssize_t maxlen)
{
struct filedesc *fdp;
+ struct pwd *pwd;
struct export_fd_buf *efbuf;
struct vnode *cdir;
int error;
@@ -4091,7 +4102,8 @@
efbuf->remainder = maxlen;
FILEDESC_SLOCK(fdp);
- cdir = fdp->fd_pwd->pwd_cdir;
+ pwd = FILEDESC_LOCKED_LOAD_PWD(fdp);
+ cdir = pwd->pwd_cdir;
if (cdir == NULL) {
error = EINVAL;
} else {
@@ -4279,6 +4291,9 @@
NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
filedesc0_zone = uma_zcreate("filedesc0", sizeof(struct filedesc0),
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
+ pwd_zone = uma_zcreate("PWD", sizeof(struct pwd), NULL, NULL,
+ NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_SMR);
+ pwd_smr = uma_zone_get_smr(pwd_zone);
mtx_init(&sigio_lock, "sigio lock", NULL, MTX_DEF);
}
SYSINIT(select, SI_SUB_LOCK, SI_ORDER_FIRST, filelistinit, NULL);
Index: sys/kern/kern_linker.c
===================================================================
--- sys/kern/kern_linker.c
+++ sys/kern/kern_linker.c
@@ -2063,6 +2063,22 @@
}
#endif
+/* check if root file system is not mounted */
+static bool
+linker_root_mounted(void)
+{
+ struct pwd *pwd;
+ bool ret;
+
+ if (rootvnode == NULL)
+ return (false);
+
+ pwd = pwd_hold(curthread);
+ ret = pwd->pwd_rdir != NULL;
+ pwd_drop(pwd);
+ return (ret);
+}
+
/*
* Find a file which contains given module and load it, if "parent" is not
* NULL, register a reference to it.
@@ -2084,15 +2100,13 @@
*/
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_pwd->pwd_rdir == NULL)
+ if (!linker_root_mounted())
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_pwd->pwd_rdir == NULL)
+ if (!linker_root_mounted())
return (ENXIO);
if (kldname != NULL)
pathname = strdup(kldname, M_LINKER);
Index: sys/sys/_smr.h
===================================================================
--- sys/sys/_smr.h
+++ sys/sys/_smr.h
@@ -35,4 +35,122 @@
typedef int32_t smr_delta_t;
typedef struct smr *smr_t;
+#define SMR_ENTERED(smr) \
+ (curthread->td_critnest != 0 && zpcpu_get((smr))->c_seq != SMR_SEQ_INVALID)
+
+#define SMR_ASSERT_ENTERED(smr) \
+ KASSERT(SMR_ENTERED(smr), ("Not in smr section"))
+
+#define SMR_ASSERT_NOT_ENTERED(smr) \
+ KASSERT(!SMR_ENTERED(smr), ("In smr section."));
+
+#define SMR_ASSERT(ex, fn) \
+ KASSERT((ex), (fn ": Assertion " #ex " failed at %s:%d", __FILE__, __LINE__))
+
+/* Type restricting pointer access to force smr accessors. */
+#define SMR_TYPE_DECLARE(smrtype, type) \
+typedef struct { \
+ type __ptr; /* Do not access directly */ \
+} smrtype
+
+#ifdef _KERNEL
+/*
+ * SMR Accessors are meant to provide safe access to SMR protected
+ * pointers and prevent misuse and accidental access.
+ *
+ * Accessors are grouped by type:
+ * entered - Use while in a read section (between smr_enter/smr_exit())
+ * serialized - Use while holding a lock that serializes writers. Updates
+ * are synchronized with readers via included barriers.
+ * unserialized - Use after the memory is out of scope and not visible to
+ * readers.
+ *
+ * All acceses include a parameter for an assert to verify the required
+ * synchronization. For example, a writer might use:
+ *
+ * smr_serialized_store(pointer, value, mtx_owned(&writelock));
+ *
+ * These are only enabled in INVARIANTS kernels.
+ */
+
+/*
+ * Read from an SMR protected pointer while in a read section.
+ */
+#define smr_entered_load(p, smr) ({ \
+ SMR_ASSERT(SMR_ENTERED((smr)), "smr_entered_load"); \
+ (__typeof((p)->__ptr))atomic_load_acq_ptr((uintptr_t *)&(p)->__ptr); \
+})
+
+/*
+ * Read from an SMR protected pointer while serialized by an
+ * external mechanism. 'ex' should contain an assert that the
+ * external mechanism is held. i.e. mtx_owned()
+ */
+#define smr_serialized_load(p, ex) ({ \
+ SMR_ASSERT(ex, "smr_serialized_load"); \
+ (__typeof((p)->__ptr))atomic_load_ptr(&(p)->__ptr); \
+})
+
+/*
+ * Store 'v' to an SMR protected pointer while serialized by an
+ * external mechanism. 'ex' should contain an assert that the
+ * external mechanism is held. i.e. mtx_owned()
+ *
+ * Writers that are serialized with mutual exclusion or on a single
+ * thread should use smr_serialized_store() rather than swap.
+ */
+#define smr_serialized_store(p, v, ex) do { \
+ SMR_ASSERT(ex, "smr_serialized_store"); \
+ __typeof((p)->__ptr) _v = (v); \
+ atomic_store_rel_ptr((uintptr_t *)&(p)->__ptr, (uintptr_t)_v); \
+} while (0)
+
+/*
+ * swap 'v' with an SMR protected pointer and return the old value
+ * while serialized by an external mechanism. 'ex' should contain
+ * an assert that the external mechanism is provided. i.e. mtx_owned()
+ *
+ * Swap permits multiple writers to update a pointer concurrently.
+ */
+#define smr_serialized_swap(p, v, ex) ({ \
+ SMR_ASSERT(ex, "smr_serialized_swap"); \
+ __typeof((p)->__ptr) _v = (v); \
+ /* Release barrier guarantees contents are visible to reader */ \
+ atomic_thread_fence_rel(); \
+ (__typeof((p)->__ptr))atomic_swap_ptr( \
+ (uintptr_t *)&(p)->__ptr, (uintptr_t)_v); \
+})
+
+/*
+ * Read from an SMR protected pointer when no serialization is required
+ * such as in the destructor callback or when the caller guarantees other
+ * synchronization.
+ */
+#define smr_unserialized_load(p, ex) ({ \
+ SMR_ASSERT(ex, "smr_unserialized_load"); \
+ (__typeof((p)->__ptr))atomic_load_ptr(&(p)->__ptr); \
+})
+
+/*
+ * Store to an SMR protected pointer when no serialiation is required
+ * such as in the destructor callback or when the caller guarantees other
+ * synchronization.
+ */
+#define smr_unserialized_store(p, v, ex) do { \
+ SMR_ASSERT(ex, "smr_unserialized_store"); \
+ __typeof((p)->__ptr) _v = (v); \
+ atomic_store_ptr((uintptr_t *)&(p)->__ptr, (uintptr_t)_v); \
+} while (0)
+
+#else /* !_KERNEL */
+
+/*
+ * Special case to handle headers which are partially shared with userspace.
+ */
+#define smr_kvm_load(p) ({ \
+ (__typeof((p)->__ptr))atomic_load_ptr((uintptr_t *)&(p)->__ptr); \
+})
+
+#endif
+
#endif /* __SYS_SMR_H_ */
Index: sys/sys/filedesc.h
===================================================================
--- sys/sys/filedesc.h
+++ sys/sys/filedesc.h
@@ -42,6 +42,7 @@
#include <sys/priority.h>
#include <sys/seqc.h>
#include <sys/sx.h>
+#include <sys/_smr.h>
#include <machine/_limits.h>
@@ -76,16 +77,23 @@
*/
#define NDSLOTTYPE u_long
+/*
+ * This struct is copy-on-write and allocated from an SMR zone.
+ * All fields are constant after initialization apart from the reference count.
+ *
+ * Check pwd_* routines for usage.
+ */
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 */
};
+SMR_TYPE_DECLARE(smrpwd_t, struct pwd *);
struct filedesc {
struct fdescenttbl *fd_files; /* open files table */
- struct pwd *fd_pwd; /* directories */
+ smrpwd_t 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 */
@@ -141,6 +149,38 @@
SX_NOTRECURSED)
#define FILEDESC_UNLOCK_ASSERT(fdp) sx_assert(&(fdp)->fd_sx, SX_UNLOCKED)
+#define FILEDESC_LOCKED_LOAD_PWD(fdp) ({ \
+ struct filedesc *_fdp = (fdp); \
+ struct pwd *_pwd; \
+ _pwd = smr_serialized_load(&(_fdp)->fd_pwd, \
+ (FILEDESC_LOCK_ASSERT(_fdp), true)); \
+ _pwd; \
+})
+
+#define FILEDESC_XLOCKED_LOAD_PWD(fdp) ({ \
+ struct filedesc *_fdp = (fdp); \
+ struct pwd *_pwd; \
+ _pwd = smr_serialized_load(&(_fdp)->fd_pwd, \
+ (FILEDESC_XLOCK_ASSERT(_fdp), true)); \
+ _pwd; \
+})
+
+#else
+
+/*
+ * Accessor for libkvm et al.
+ */
+#define FILEDESC_KVM_LOAD_PWD(fdp) ({ \
+ struct filedesc *_fdp = (fdp); \
+ struct pwd *_pwd; \
+ _pwd = smr_kvm_load(&(_fdp)->fd_pwd); \
+ _pwd; \
+})
+
+#endif
+
+#ifdef _KERNEL
+
/* Operation types for kern_dup(). */
enum {
FDDUP_NORMAL, /* dup() behavior. */
@@ -265,8 +305,8 @@
pwd_set(struct filedesc *fdp, struct pwd *newpwd)
{
- FILEDESC_XLOCK_ASSERT(fdp);
- fdp->fd_pwd = newpwd;
+ smr_serialized_store(&fdp->fd_pwd, newpwd,
+ (FILEDESC_XLOCK_ASSERT(fdp), true));
}
#endif /* _KERNEL */
Index: sys/sys/smr.h
===================================================================
--- sys/sys/smr.h
+++ sys/sys/smr.h
@@ -82,111 +82,9 @@
#define SMR_LAZY 0x0001 /* Higher latency write, fast read. */
#define SMR_DEFERRED 0x0002 /* Aggregate updates to wr_seq. */
-#define SMR_ENTERED(smr) \
- (curthread->td_critnest != 0 && zpcpu_get((smr))->c_seq != SMR_SEQ_INVALID)
-
-#define SMR_ASSERT_ENTERED(smr) \
- KASSERT(SMR_ENTERED(smr), ("Not in smr section"))
-
-#define SMR_ASSERT_NOT_ENTERED(smr) \
- KASSERT(!SMR_ENTERED(smr), ("In smr section."));
-
-#define SMR_ASSERT(ex, fn) \
- KASSERT((ex), (fn ": Assertion " #ex " failed at %s:%d", __FILE__, __LINE__))
-
-/*
- * SMR Accessors are meant to provide safe access to SMR protected
- * pointers and prevent misuse and accidental access.
- *
- * Accessors are grouped by type:
- * entered - Use while in a read section (between smr_enter/smr_exit())
- * serialized - Use while holding a lock that serializes writers. Updates
- * are synchronized with readers via included barriers.
- * unserialized - Use after the memory is out of scope and not visible to
- * readers.
- *
- * All acceses include a parameter for an assert to verify the required
- * synchronization. For example, a writer might use:
- *
- * smr_serialized_store(pointer, value, mtx_owned(&writelock));
- *
- * These are only enabled in INVARIANTS kernels.
- */
-
-/* Type restricting pointer access to force smr accessors. */
-#define SMR_TYPE_DECLARE(smrtype, type) \
-typedef struct { \
- type __ptr; /* Do not access directly */ \
-} smrtype
-
-/*
- * Read from an SMR protected pointer while in a read section.
- */
-#define smr_entered_load(p, smr) ({ \
- SMR_ASSERT(SMR_ENTERED((smr)), "smr_entered_load"); \
- (__typeof((p)->__ptr))atomic_load_acq_ptr((uintptr_t *)&(p)->__ptr); \
-})
-
-/*
- * Read from an SMR protected pointer while serialized by an
- * external mechanism. 'ex' should contain an assert that the
- * external mechanism is held. i.e. mtx_owned()
- */
-#define smr_serialized_load(p, ex) ({ \
- SMR_ASSERT(ex, "smr_serialized_load"); \
- (__typeof((p)->__ptr))atomic_load_ptr(&(p)->__ptr); \
-})
-
-/*
- * Store 'v' to an SMR protected pointer while serialized by an
- * external mechanism. 'ex' should contain an assert that the
- * external mechanism is held. i.e. mtx_owned()
- *
- * Writers that are serialized with mutual exclusion or on a single
- * thread should use smr_serialized_store() rather than swap.
- */
-#define smr_serialized_store(p, v, ex) do { \
- SMR_ASSERT(ex, "smr_serialized_store"); \
- __typeof((p)->__ptr) _v = (v); \
- atomic_store_rel_ptr((uintptr_t *)&(p)->__ptr, (uintptr_t)_v); \
-} while (0)
-
-/*
- * swap 'v' with an SMR protected pointer and return the old value
- * while serialized by an external mechanism. 'ex' should contain
- * an assert that the external mechanism is provided. i.e. mtx_owned()
- *
- * Swap permits multiple writers to update a pointer concurrently.
- */
-#define smr_serialized_swap(p, v, ex) ({ \
- SMR_ASSERT(ex, "smr_serialized_swap"); \
- __typeof((p)->__ptr) _v = (v); \
- /* Release barrier guarantees contents are visible to reader */ \
- atomic_thread_fence_rel(); \
- (__typeof((p)->__ptr))atomic_swap_ptr( \
- (uintptr_t *)&(p)->__ptr, (uintptr_t)_v); \
-})
-
-/*
- * Read from an SMR protected pointer when no serialization is required
- * such as in the destructor callback or when the caller guarantees other
- * synchronization.
- */
-#define smr_unserialized_load(p, ex) ({ \
- SMR_ASSERT(ex, "smr_unserialized_load"); \
- (__typeof((p)->__ptr))atomic_load_ptr(&(p)->__ptr); \
-})
-
/*
- * Store to an SMR protected pointer when no serialiation is required
- * such as in the destructor callback or when the caller guarantees other
- * synchronization.
+ * This API provides accessors for safe use. See sys/_smr.h.
*/
-#define smr_unserialized_store(p, v, ex) do { \
- SMR_ASSERT(ex, "smr_unserialized_store"); \
- __typeof((p)->__ptr) _v = (v); \
- atomic_store_ptr((uintptr_t *)&(p)->__ptr, (uintptr_t)_v); \
-} while (0)
/*
* Return the current write sequence number. This is not the same as the
Index: sys/ufs/ffs/ffs_alloc.c
===================================================================
--- sys/ufs/ffs/ffs_alloc.c
+++ sys/ufs/ffs/ffs_alloc.c
@@ -3590,6 +3590,7 @@
int flags;
struct thread *td;
{
+ struct pwd *pwd;
struct vnode *devvp, *vp;
struct inode *ip;
struct buf *bp;
@@ -3609,7 +3610,8 @@
return (EINVAL);
fdp = td->td_proc->p_fd;
FILEDESC_SLOCK(fdp);
- vp = fdp->fd_pwd->pwd_cdir;
+ pwd = FILEDESC_LOCKED_LOAD_PWD(fdp);
+ vp = pwd->pwd_cdir;
vref(vp);
FILEDESC_SUNLOCK(fdp);
vn_lock(vp, LK_SHARED | LK_RETRY);

File Metadata

Mime Type
text/plain
Expires
Mon, Aug 3, 12:45 AM (29 m, 40 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35875819
Default Alt Text
D23889.id69241.diff (18 KB)

Event Timeline