summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/kern_descrip.c60
-rw-r--r--sys/kern/kern_sysctl.c4
-rw-r--r--sys/kern/syscalls.master6
-rw-r--r--sys/kern/uipc_syscalls.c12
-rw-r--r--sys/kern/uipc_usrreq.c10
-rw-r--r--sys/sys/file.h22
6 files changed, 82 insertions, 32 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 7ccc3e49f03..f6c17c8a67e 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_descrip.c,v 1.166 2018/06/18 09:15:05 mpi Exp $ */
+/* $OpenBSD: kern_descrip.c,v 1.167 2018/06/20 10:52:49 mpi Exp $ */
/* $NetBSD: kern_descrip.c,v 1.42 1996/03/30 22:24:38 christos Exp $ */
/*
@@ -66,7 +66,11 @@
/*
* Descriptor management.
+ *
+ * We need to block interrupts as long as `fhdlk' is being taken
+ * with and without the KERNEL_LOCK().
*/
+struct mutex fhdlk = MUTEX_INITIALIZER(IPL_MPFLOOR);
struct filelist filehead; /* head of list of open files */
int numfiles; /* actual number of open files */
@@ -195,16 +199,18 @@ fd_iterfile(struct file *fp, struct proc *p)
{
struct file *nfp;
+ mtx_enter(&fhdlk);
if (fp == NULL)
nfp = LIST_FIRST(&filehead);
else
nfp = LIST_NEXT(fp, f_list);
- /* don't FREF when f_count == 0 to avoid race in fdrop() */
+ /* don't refcount when f_count == 0 to avoid race in fdrop() */
while (nfp != NULL && nfp->f_count == 0)
nfp = LIST_NEXT(nfp, f_list);
if (nfp != NULL)
- FREF(nfp);
+ nfp->f_count++;
+ mtx_leave(&fhdlk);
if (fp != NULL)
FRELE(fp, p);
@@ -217,10 +223,17 @@ fd_getfile(struct filedesc *fdp, int fd)
{
struct file *fp;
- if ((u_int)fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL)
+ vfs_stall_barrier();
+
+ if ((u_int)fd >= fdp->fd_nfiles)
return (NULL);
- FREF(fp);
+ mtx_enter(&fhdlk);
+ fp = fdp->fd_ofiles[fd];
+ if (fp != NULL)
+ fp->f_count++;
+ mtx_leave(&fhdlk);
+
return (fp);
}
@@ -671,6 +684,8 @@ fdinsert(struct filedesc *fdp, int fd, int flags, struct file *fp)
struct file *fq;
fdpassertlocked(fdp);
+
+ mtx_enter(&fhdlk);
if ((fq = fdp->fd_ofiles[0]) != NULL) {
LIST_INSERT_AFTER(fq, fp, f_list);
} else {
@@ -680,6 +695,7 @@ fdinsert(struct filedesc *fdp, int fd, int flags, struct file *fp)
fdp->fd_ofiles[fd] = fp;
fdp->fd_ofileflags[fd] |= (flags & UF_EXCLOSE);
fp->f_iflags |= FIF_INSERTED;
+ mtx_leave(&fhdlk);
}
void
@@ -978,7 +994,11 @@ restart:
crhold(fp->f_cred);
*resultfp = fp;
*resultfd = i;
- FREF(fp);
+
+ mtx_enter(&fhdlk);
+ fp->f_count++;
+ mtx_leave(&fhdlk);
+
return (0);
}
@@ -1069,6 +1089,7 @@ fdcopy(struct process *pr)
newfdp->fd_flags = fdp->fd_flags;
newfdp->fd_cmask = fdp->fd_cmask;
+ mtx_enter(&fhdlk);
for (i = 0; i <= fdp->fd_lastfile; i++) {
struct file *fp = fdp->fd_ofiles[i];
@@ -1085,12 +1106,13 @@ fdcopy(struct process *pr)
fp->f_type == DTYPE_KQUEUE)
continue;
- FREF(fp);
+ fp->f_count++;
newfdp->fd_ofiles[i] = fp;
newfdp->fd_ofileflags[i] = fdp->fd_ofileflags[i];
fd_used(newfdp, i);
}
}
+ mtx_leave(&fhdlk);
fdpunlock(fdp);
return (newfdp);
@@ -1112,8 +1134,9 @@ fdfree(struct proc *p)
for (i = fdp->fd_lastfile; i >= 0; i--, fpp++) {
fp = *fpp;
if (fp != NULL) {
- FREF(fp);
*fpp = NULL;
+ /* closef() expects a refcount of 2 */
+ FREF(fp);
(void) closef(fp, p);
}
}
@@ -1149,11 +1172,11 @@ closef(struct file *fp, struct proc *p)
if (fp == NULL)
return (0);
-#ifdef DIAGNOSTIC
- if (fp->f_count < 2)
- panic("closef: count (%ld) < 2", fp->f_count);
-#endif
+ KASSERTMSG(fp->f_count >= 2, "count (%ld) < 2", fp->f_count);
+
+ mtx_enter(&fhdlk);
fp->f_count--;
+ mtx_leave(&fhdlk);
/*
* POSIX record locking dictates that any close releases ALL
@@ -1185,18 +1208,19 @@ fdrop(struct file *fp, struct proc *p)
{
int error;
-#ifdef DIAGNOSTIC
- if (fp->f_count != 0)
- panic("fdrop: count (%ld) != 0", fp->f_count);
-#endif
+ MUTEX_ASSERT_LOCKED(&fhdlk);
+
+ KASSERTMSG(fp->f_count == 0, "count (%ld) != 0", fp->f_count);
+
+ if (fp->f_iflags & FIF_INSERTED)
+ LIST_REMOVE(fp, f_list);
+ mtx_leave(&fhdlk);
if (fp->f_ops)
error = (*fp->f_ops->fo_close)(fp, p);
else
error = 0;
- if (fp->f_iflags & FIF_INSERTED)
- LIST_REMOVE(fp, f_list);
crfree(fp->f_cred);
numfiles--;
pool_put(&file_pool, fp);
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index 3b4c0071bd7..a33d6ae9d19 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_sysctl.c,v 1.342 2018/06/19 19:29:52 kettenis Exp $ */
+/* $OpenBSD: kern_sysctl.c,v 1.343 2018/06/20 10:52:49 mpi Exp $ */
/* $NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $ */
/*-
@@ -1077,7 +1077,9 @@ fill_file(struct kinfo_file *kf, struct file *fp, struct filedesc *fdp,
kf->f_flag = fp->f_flag;
kf->f_iflags = fp->f_iflags;
kf->f_type = fp->f_type;
+ mtx_enter(&fhdlk);
kf->f_count = fp->f_count;
+ mtx_leave(&fhdlk);
if (show_pointers)
kf->f_ucred = PTRTOINT64(fp->f_cred);
kf->f_uid = fp->f_cred->cr_uid;
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index 8578e3e276e..96fb61be7f3 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -1,4 +1,4 @@
-; $OpenBSD: syscalls.master,v 1.181 2018/05/28 09:17:11 mpi Exp $
+; $OpenBSD: syscalls.master,v 1.182 2018/06/20 10:52:49 mpi Exp $
; $NetBSD: syscalls.master,v 1.32 1996/04/23 10:24:21 mycroft Exp $
; @(#)syscalls.master 8.2 (Berkeley) 1/13/94
@@ -90,7 +90,7 @@
#endif
27 STD { ssize_t sys_recvmsg(int s, struct msghdr *msg, \
int flags); }
-28 STD { ssize_t sys_sendmsg(int s, \
+28 STD NOLOCK { ssize_t sys_sendmsg(int s, \
const struct msghdr *msg, int flags); }
29 STD { ssize_t sys_recvfrom(int s, void *buf, size_t len, \
int flags, struct sockaddr *from, \
@@ -261,7 +261,7 @@
130 OBSOL oftruncate
131 STD { int sys_flock(int fd, int how); }
132 STD { int sys_mkfifo(const char *path, mode_t mode); }
-133 STD { ssize_t sys_sendto(int s, const void *buf, \
+133 STD NOLOCK { ssize_t sys_sendto(int s, const void *buf, \
size_t len, int flags, const struct sockaddr *to, \
socklen_t tolen); }
134 STD { int sys_shutdown(int s, int how); }
diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
index 09ae2fdf5ab..6548079b6b3 100644
--- a/sys/kern/uipc_syscalls.c
+++ b/sys/kern/uipc_syscalls.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uipc_syscalls.c,v 1.176 2018/06/18 09:15:05 mpi Exp $ */
+/* $OpenBSD: uipc_syscalls.c,v 1.177 2018/06/20 10:52:49 mpi Exp $ */
/* $NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $ */
/*
@@ -691,13 +691,16 @@ sendit(struct proc *p, int s, struct msghdr *mp, int flags, register_t *retsize)
}
#endif
len = auio.uio_resid;
- error = sosend(fp->f_data, to, &auio, NULL, control, flags);
+ error = sosend(so, to, &auio, NULL, control, flags);
if (error) {
if (auio.uio_resid != len && (error == ERESTART ||
error == EINTR || error == EWOULDBLOCK))
error = 0;
- if (error == EPIPE && (flags & MSG_NOSIGNAL) == 0)
+ if (error == EPIPE && (flags & MSG_NOSIGNAL) == 0) {
+ KERNEL_LOCK();
ptsignal(p, SIGPIPE, STHREAD);
+ KERNEL_UNLOCK();
+ }
}
if (error == 0) {
*retsize = len - auio.uio_resid;
@@ -1176,7 +1179,8 @@ getsock(struct proc *p, int fdes, struct file **fpp)
{
struct file *fp;
- if ((fp = fd_getfile(p->p_fd, fdes)) == NULL)
+ fp = fd_getfile(p->p_fd, fdes);
+ if (fp == NULL)
return (EBADF);
if (fp->f_type != DTYPE_SOCKET) {
FRELE(fp, p);
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index f7892e1fe7d..f45fed57225 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uipc_usrreq.c,v 1.129 2018/06/11 08:57:35 mpi Exp $ */
+/* $OpenBSD: uipc_usrreq.c,v 1.130 2018/06/20 10:52:49 mpi Exp $ */
/* $NetBSD: uipc_usrreq.c,v 1.18 1996/02/09 19:00:50 christos Exp $ */
/*
@@ -906,6 +906,7 @@ unp_gc(void *arg __unused)
fp = defer->ud_fp[i].fp;
if (fp == NULL)
continue;
+ /* closef() expects a refcount of 2 */
FREF(fp);
if ((unp = fptounp(fp)) != NULL)
unp->unp_msgcount--;
@@ -922,6 +923,8 @@ unp_gc(void *arg __unused)
do {
nunref = 0;
LIST_FOREACH(unp, &unp_head, unp_link) {
+ mtx_enter(&fhdlk);
+ fp = unp->unp_file;
if (unp->unp_flags & UNP_GCDEFER) {
/*
* This socket is referenced by another
@@ -932,8 +935,9 @@ unp_gc(void *arg __unused)
unp_defer--;
} else if (unp->unp_flags & UNP_GCMARK) {
/* marked as live in previous pass */
+ mtx_leave(&fhdlk);
continue;
- } else if ((fp = unp->unp_file) == NULL) {
+ } else if (fp == NULL) {
/* not being passed, so can't be in loop */
} else if (fp->f_count == 0) {
/*
@@ -950,9 +954,11 @@ unp_gc(void *arg __unused)
if (fp->f_count == unp->unp_msgcount) {
nunref++;
unp->unp_flags |= UNP_GCDEAD;
+ mtx_leave(&fhdlk);
continue;
}
}
+ mtx_leave(&fhdlk);
/*
* This is the first time we've seen this socket on
diff --git a/sys/sys/file.h b/sys/sys/file.h
index 49f325cc8d0..40604f2b57c 100644
--- a/sys/sys/file.h
+++ b/sys/sys/file.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: file.h,v 1.48 2018/06/18 09:15:05 mpi Exp $ */
+/* $OpenBSD: file.h,v 1.49 2018/06/20 10:52:49 mpi Exp $ */
/* $NetBSD: file.h,v 1.11 1995/03/26 20:24:13 jtc Exp $ */
/*
@@ -65,6 +65,7 @@ struct fileops {
*
* Locks used to protect struct members in this file:
* I immutable after creation
+ * F global `fhdlk' mutex
* f per file `f_mtx'
* k kernel lock
*/
@@ -77,11 +78,11 @@ struct file {
#define DTYPE_PIPE 3 /* pipe */
#define DTYPE_KQUEUE 4 /* event queue */
short f_type; /* [I] descriptor type */
- long f_count; /* [k] reference count */
+ long f_count; /* [F] reference count */
struct ucred *f_cred; /* [I] credentials associated with descriptor */
struct fileops *f_ops; /* [I] file operation pointers */
off_t f_offset; /* [k] */
- void *f_data; /* [k] private data */
+ void *f_data; /* [I] private data */
int f_iflags; /* [k] internal flags */
uint64_t f_rxfer; /* [f] total number of read transfers */
uint64_t f_wxfer; /* [f] total number of write transfers */
@@ -97,12 +98,25 @@ struct file {
do { \
extern void vfs_stall_barrier(void); \
vfs_stall_barrier(); \
+ mtx_enter(&fhdlk); \
(fp)->f_count++; \
+ mtx_leave(&fhdlk); \
} while (0)
-#define FRELE(fp,p) (--(fp)->f_count == 0 ? fdrop(fp, p) : 0)
+
+#define FRELE(fp,p) \
+({ \
+ int rv = 0; \
+ mtx_enter(&fhdlk); \
+ if (--(fp)->f_count == 0) \
+ rv = fdrop(fp, p); \
+ else \
+ mtx_leave(&fhdlk); \
+ rv; \
+})
int fdrop(struct file *, struct proc *);
+extern struct mutex fhdlk; /* protects `filehead' and f_count */
LIST_HEAD(filelist, file);
extern int maxfiles; /* kernel limit on number of open files */
extern int numfiles; /* actual number of open files */