Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F164544910
D23889.id69241.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
18 KB
Referenced Files
None
Subscribers
None
D23889.id69241.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D23889: fd: use SMR for managing struct pwd
Attached
Detach File
Event Timeline
Log In to Comment