This is the second attempt of struct file protection.
1. Filelist, nfiles and operations with them are protected by rwlock.
2. Garbage collector's flags FIF_MARK and FIF_DEFER moved from f_iflags to
new field f_gc_flags (compatibility with pstat was kept).
3. Operations over f_iflags are atomic. FIF_LARVAL set only once and
FIF_HASLOCK isn't set too frequent.
4. Set/unset operations over f_flag are atomic. They are not too frequent.
5. Operations over f_count are atomic. Surely those are frequent though they
can be non atomic on uniprocessor kernel.
6. f_offset field is not protectd now, it should be protected later.
7. Counters are not protected now, they should be protected later.
For test purpose, I moved out sys_close, sys_closefrom, sys_dup, sys_dup2
and sys_dup3 from kernel lock, except little mp locked fragments. I also
moved out sys_read, sys_readv, sys_pread, sys_preadv, sys_write, sys_writev,
sys_pwrite and sys_pwritev syscalls from kernel lock (dofilereadv() and
dofilewritev() are mp locked, of course) for struct file object
capture/release purpose. With this modifications my system rebuilds kernel
in multiple instenses simultaneously.
Index: arch/i386/i386/linux_machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/linux_machdep.c,v
retrieving revision 1.46
diff -u -p -r1.46 linux_machdep.c
--- arch/i386/i386/linux_machdep.c 16 Dec 2014 18:30:03 -0000 1.46
+++ arch/i386/i386/linux_machdep.c 12 Apr 2015 01:27:22 -0000
@@ -440,8 +440,12 @@ linux_machdepioctl(struct proc *p, void
com = SCARG(uap, com);
fdp = p->p_fd;
- if ((fp = fd_getfile(fdp, fd)) == NULL)
+ fdplock(fdp);
+ if (fd_getfile(fdp, fd) == NULL) {
+ fdpunlock(fdp);
return (EBADF);
+ }
+ fdpunlock(fdp);
switch (com) {
#if (NWSDISPLAY > 0 && defined(WSDISPLAY_COMPAT_USL))
@@ -568,12 +572,13 @@ linux_machdepioctl(struct proc *p, void
* XXX hack: if the function returns EJUSTRETURN,
* it has stuffed a sysctl return value in pt.data.
*/
- FREF(fp);
+ if ((fp = fd_getfile_ref(fdp, fd, p)) == NULL)
+ return (EBADF);
ioctlf = fp->f_ops->fo_ioctl;
pt.com = SCARG(uap, com);
pt.data = SCARG(uap, data);
error = ioctlf(fp, PTIOCLINUX, (caddr_t)&pt, p);
- FRELE(fp, p);
+ funref(fp, p);
if (error == EJUSTRETURN) {
retval[0] = (register_t)pt.data;
error = 0;
Index: compat/linux/linux_blkio.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_blkio.c,v
retrieving revision 1.9
diff -u -p -r1.9 linux_blkio.c
--- compat/linux/linux_blkio.c 22 Apr 2012 05:43:14 -0000 1.9
+++ compat/linux/linux_blkio.c 12 Apr 2015 01:28:20 -0000
@@ -70,9 +70,8 @@ linux_ioctl_blkio(struct proc *p, struct
struct disklabel label;
fdp = p->p_fd;
- if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
+ if ((fp = fd_getfile_ref(fdp, SCARG(uap, fd), p)) == NULL)
return (EBADF);
- FREF(fp);
error = 0;
ioctlf = fp->f_ops->fo_ioctl;
com = SCARG(uap, com);
@@ -118,6 +117,6 @@ linux_ioctl_blkio(struct proc *p, struct
error = ENOTTY;
}
- FRELE(fp, p);
+ funref(fp, p);
return error;
}
Index: compat/linux/linux_cdrom.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_cdrom.c,v
retrieving revision 1.11
diff -u -p -r1.11 linux_cdrom.c
--- compat/linux/linux_cdrom.c 26 Mar 2014 05:23:42 -0000 1.11
+++ compat/linux/linux_cdrom.c 12 Apr 2015 01:28:20 -0000
@@ -108,9 +108,8 @@ linux_ioctl_cdrom(p, v, retval)
fdp = p->p_fd;
- if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
+ if ((fp = fd_getfile_ref(fdp, SCARG(uap, fd), p)) == NULL)
return (EBADF);
- FREF(fp);
if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
error = EBADF;
@@ -293,6 +292,6 @@ linux_ioctl_cdrom(p, v, retval)
error = sys_ioctl(p, &ia, retval);
out:
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
Index: compat/linux/linux_fdio.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_fdio.c,v
retrieving revision 1.7
diff -u -p -r1.7 linux_fdio.c
--- compat/linux/linux_fdio.c 22 Apr 2012 05:43:14 -0000 1.7
+++ compat/linux/linux_fdio.c 12 Apr 2015 01:28:20 -0000
@@ -75,10 +75,9 @@ linux_ioctl_fdio(struct proc *p, struct
com = (u_long)SCARG(uap, data);
fdp = p->p_fd;
- if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
+ if ((fp = fd_getfile_ref(fdp, SCARG(uap, fd), p)) == NULL)
return (EBADF);
- FREF(fp);
com = SCARG(uap, com);
ioctlf = fp->f_ops->fo_ioctl;
@@ -145,6 +144,6 @@ linux_ioctl_fdio(struct proc *p, struct
error = EINVAL;
}
- FRELE(fp, p);
+ funref(fp, p);
return 0;
}
Index: compat/linux/linux_file.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_file.c,v
retrieving revision 1.30
diff -u -p -r1.30 linux_file.c
--- compat/linux/linux_file.c 26 Mar 2014 05:23:42 -0000 1.30
+++ compat/linux/linux_file.c 12 Apr 2015 01:28:20 -0000
@@ -196,12 +196,11 @@ linux_sys_open(p, v, retval)
struct filedesc *fdp = p->p_fd;
struct file *fp;
- if ((fp = fd_getfile(fdp, *retval)) == NULL)
+ if ((fp = fd_getfile_ref(fdp, *retval, p)) == NULL)
return (EBADF);
- FREF(fp);
if (fp->f_type == DTYPE_VNODE)
(fp->f_ops->fo_ioctl) (fp, TIOCSCTTY, (caddr_t) 0, p);
- FRELE(fp, p);
+ funref(fp, p);
}
return 0;
}
@@ -416,18 +415,20 @@ linux_sys_fcntl(p, v, retval)
* does not exist.
*/
fdp = p->p_fd;
- if ((fp = fd_getfile(fdp, fd)) == NULL)
+ if ((fp = fd_getfile_ref(fdp, fd, p)) == NULL)
return (EBADF);
if (fp->f_type == DTYPE_SOCKET) {
+ funref(fp, p);
cmd = cmd == LINUX_F_SETOWN ? F_SETOWN : F_GETOWN;
break;
}
vp = (struct vnode *)fp->f_data;
- if (vp->v_type != VCHR)
+ if (vp->v_type != VCHR) {
+ funref(fp, p);
return EINVAL;
- FREF(fp);
+ }
error = VOP_GETATTR(vp, &va, p->p_ucred, p);
- FRELE(fp, p);
+ funref(fp, p);
if (error)
return error;
d_tty = cdevsw[major(va.va_rdev)].d_tty;
Index: compat/linux/linux_hdio.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_hdio.c,v
retrieving revision 1.9
diff -u -p -r1.9 linux_hdio.c
--- compat/linux/linux_hdio.c 26 Mar 2014 05:23:42 -0000 1.9
+++ compat/linux/linux_hdio.c 12 Apr 2015 01:28:20 -0000
@@ -78,10 +78,9 @@ linux_ioctl_hdio(struct proc *p, struct
struct linux_hd_big_geometry hdg_big;
fdp = p->p_fd;
- if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
+ if ((fp = fd_getfile_ref(fdp, SCARG(uap, fd), p)) == NULL)
return (EBADF);
- FREF(fp);
com = SCARG(uap, com);
ioctlf = fp->f_ops->fo_ioctl;
retval[0] = error = 0;
@@ -179,6 +178,6 @@ linux_ioctl_hdio(struct proc *p, struct
error = EINVAL;
}
- FRELE(fp, p);
+ funref(fp, p);
return error;
}
Index: compat/linux/linux_misc.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_misc.c,v
retrieving revision 1.92
diff -u -p -r1.92 linux_misc.c
--- compat/linux/linux_misc.c 16 Nov 2014 12:30:59 -0000 1.92
+++ compat/linux/linux_misc.c 12 Apr 2015 01:28:20 -0000
@@ -1183,13 +1183,13 @@ getdents_common(p, v, retval, is64bit)
int error;
int nbytes = SCARG(uap, count);
- if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
+ if ((error = getvnode(p, p->p_fd, SCARG(uap, fd), &fp)) != 0)
return (error);
if (nbytes == 1) { /* emulating old, broken behaviour */
/* readdir(2) case. Always struct dirent. */
if (is64bit) {
- FRELE(fp, p);
+ funref(fp, p);
return (EINVAL);
}
nbytes = sizeof(struct linux_dirent);
@@ -1209,7 +1209,7 @@ getdents_common(p, v, retval, is64bit)
*retval = nbytes - args.resid;
exit:
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
Index: compat/linux/linux_socket.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_socket.c,v
retrieving revision 1.60
diff -u -p -r1.60 linux_socket.c
--- compat/linux/linux_socket.c 30 Jan 2015 23:38:49 -0000 1.60
+++ compat/linux/linux_socket.c 12 Apr 2015 01:28:20 -0000
@@ -937,7 +937,7 @@ linux_setsockopt(p, v, retval)
if ((error = copyin((caddr_t) uap, (caddr_t) &lsa, sizeof lsa)))
return error;
- if ((error = getsock(p->p_fd, lsa.s, &fp)) != 0)
+ if ((error = getsock(p, p->p_fd, lsa.s, &fp)) != 0)
return error;
level = linux_to_bsd_sopt_level(lsa.level);
@@ -986,7 +986,7 @@ linux_setsockopt(p, v, retval)
bad:
if (m)
m_free(m);
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
@@ -1370,9 +1370,8 @@ linux_ioctl_socket(p, v, retval)
int error = 0, isdev = 0, dosys = 1;
fdp = p->p_fd;
- if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
+ if ((fp = fd_getfile_ref(fdp, SCARG(uap, fd), p)) == NULL)
return (EBADF);
- FREF(fp);
if (fp->f_type == DTYPE_VNODE) {
vp = (struct vnode *)fp->f_data;
@@ -1506,6 +1505,6 @@ out:
}
}
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
Index: compat/linux/linux_termios.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_termios.c,v
retrieving revision 1.17
diff -u -p -r1.17 linux_termios.c
--- compat/linux/linux_termios.c 26 Mar 2014 05:23:42 -0000 1.17
+++ compat/linux/linux_termios.c 12 Apr 2015 01:28:20 -0000
@@ -461,9 +461,8 @@ linux_ioctl_termios(p, v, retval)
int error = 0;
fdp = p->p_fd;
- if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
+ if ((fp = fd_getfile_ref(fdp, SCARG(uap, fd), p)) == NULL)
return (EBADF);
- FREF(fp);
if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
error = EBADF;
@@ -720,6 +719,6 @@ linux_ioctl_termios(p, v, retval)
error = sys_ioctl(p, &ia, retval);
out:
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
Index: compat/ossaudio/ossaudio.c
===================================================================
RCS file: /cvs/src/sys/compat/ossaudio/ossaudio.c,v
retrieving revision 1.16
diff -u -p -r1.16 ossaudio.c
--- compat/ossaudio/ossaudio.c 28 Mar 2013 03:45:32 -0000 1.16
+++ compat/ossaudio/ossaudio.c 12 Apr 2015 01:28:21 -0000
@@ -83,12 +83,11 @@ oss_ioctl_audio(p, uap, retval)
int (*ioctlf)(struct file *, u_long, caddr_t, struct proc *);
fdp = p->p_fd;
- if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
+ if ((fp = fd_getfile_ref(fdp, SCARG(uap, fd), p)) == NULL)
return (EBADF);
- FREF(fp);
if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
- FRELE(fp, p);
+ funref(fp, p);
return (EBADF);
}
@@ -490,7 +489,7 @@ oss_ioctl_audio(p, uap, retval)
break;
}
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
@@ -635,9 +634,8 @@ oss_ioctl_mixer(p, uap, retval)
int (*ioctlf)(struct file *, u_long, caddr_t, struct proc *);
fdp = p->p_fd;
- if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
+ if ((fp = fd_getfile_ref(fdp, SCARG(uap, fd), p)) == NULL)
return (EBADF);
- FREF(fp);
if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
error = EBADF;
@@ -799,7 +797,7 @@ oss_ioctl_mixer(p, uap, retval)
error = copyout(&idat, SCARG(uap, data), sizeof idat);
out:
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
@@ -818,8 +816,12 @@ oss_ioctl_sequencer(p, uap, retval)
struct filedesc *fdp;
fdp = p->p_fd;
- if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
+ fdplock(fdp);
+ if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL) {
+ fdpunlock(fdp);
return (EBADF);
+ }
+ fdpunlock(fdp);
if ((fp->f_flag & (FREAD | FWRITE)) == 0)
return (EBADF);
Index: dev/diskmap.c
===================================================================
RCS file: /cvs/src/sys/dev/diskmap.c,v
retrieving revision 1.9
diff -u -p -r1.9 diskmap.c
--- dev/diskmap.c 16 Dec 2014 18:30:03 -0000 1.9
+++ dev/diskmap.c 12 Apr 2015 01:28:22 -0000
@@ -82,7 +82,7 @@ diskmapioctl(dev_t dev, u_long cmd, cadd
fdp = p->p_fd;
fdplock(fdp);
- if ((error = getvnode(fdp, fd, &fp)) != 0)
+ if ((error = getvnode(p, fdp, fd, &fp)) != 0)
goto bad;
ndp.ni_segflg = UIO_SYSSPACE;
@@ -117,7 +117,7 @@ diskmapioctl(dev_t dev, u_long cmd, cadd
VOP_UNLOCK(vp, 0, p);
- FRELE(fp, p);
+ funref(fp, p);
fdpunlock(fdp);
free(devname, M_DEVBUF, 0);
@@ -127,7 +127,7 @@ bad:
if (vp)
vput(vp);
if (fp)
- FRELE(fp, p);
+ funref(fp, p);
fdpunlock(fdp);
Index: dev/systrace.c
===================================================================
RCS file: /cvs/src/sys/dev/systrace.c,v
retrieving revision 1.74
diff -u -p -r1.74 systrace.c
--- dev/systrace.c 10 Feb 2015 22:03:11 -0000 1.74
+++ dev/systrace.c 12 Apr 2015 01:28:22 -0000
@@ -1077,7 +1077,10 @@ systrace_getcwd(struct fsystrace *fst, s
if (atfd == AT_FDCWD)
dvp = fdp->fd_cdir;
else {
- struct file *fp = fd_getfile(fdp, atfd);
+ struct file *fp;
+ fdplock(fdp);
+ fp = fd_getfile(fdp, atfd);
+ fdpunlock(fdp);
if (fp == NULL || fp->f_type != DTYPE_VNODE)
return (EINVAL);
dvp = (struct vnode *)fp->f_data;
Index: kern/init_sysent.c
===================================================================
RCS file: /cvs/src/sys/kern/init_sysent.c,v
retrieving revision 1.164
diff -u -p -r1.164 init_sysent.c
--- kern/init_sysent.c 9 Feb 2015 13:55:04 -0000 1.164
+++ kern/init_sysent.c 12 Apr 2015 01:28:44 -0000
@@ -24,13 +24,13 @@ struct sysent sysent[] = {
sys_exit }, /* 1 = exit */
{ 0, 0, 0,
sys_fork }, /* 2 = fork */
- { 3, s(struct sys_read_args), 0,
+ { 3, s(struct sys_read_args), SY_NOLOCK | 0,
sys_read }, /* 3 = read */
- { 3, s(struct sys_write_args), 0,
+ { 3, s(struct sys_write_args), SY_NOLOCK | 0,
sys_write }, /* 4 = write */
{ 3, s(struct sys_open_args), 0,
sys_open }, /* 5 = open */
- { 1, s(struct sys_close_args), 0,
+ { 1, s(struct sys_close_args), SY_NOLOCK | 0,
sys_close }, /* 6 = close */
{ 2, s(struct sys_getentropy_args), SY_NOLOCK | 0,
sys_getentropy }, /* 7 = getentropy */
@@ -105,7 +105,7 @@ struct sysent sysent[] = {
sys_getppid }, /* 39 = getppid */
{ 2, s(struct sys_lstat_args), 0,
sys_lstat }, /* 40 = lstat */
- { 1, s(struct sys_dup_args), 0,
+ { 1, s(struct sys_dup_args), SY_NOLOCK | 0,
sys_dup }, /* 41 = dup */
{ 4, s(struct sys_fstatat_args), 0,
sys_fstatat }, /* 42 = fstatat */
@@ -213,7 +213,7 @@ struct sysent sysent[] = {
sys_clock_settime }, /* 88 = clock_settime */
{ 2, s(struct sys_clock_getres_args), SY_NOLOCK | 0,
sys_clock_getres }, /* 89 = clock_getres */
- { 2, s(struct sys_dup2_args), 0,
+ { 2, s(struct sys_dup2_args), SY_NOLOCK | 0,
sys_dup2 }, /* 90 = dup2 */
{ 2, s(struct sys_nanosleep_args), 0,
sys_nanosleep }, /* 91 = nanosleep */
@@ -237,7 +237,7 @@ struct sysent sysent[] = {
sys_getpriority }, /* 100 = getpriority */
{ 2, s(struct sys_pipe2_args), 0,
sys_pipe2 }, /* 101 = pipe2 */
- { 3, s(struct sys_dup3_args), 0,
+ { 3, s(struct sys_dup3_args), SY_NOLOCK | 0,
sys_dup3 }, /* 102 = dup3 */
{ 1, s(struct sys_sigreturn_args), 0,
sys_sigreturn }, /* 103 = sigreturn */
@@ -273,9 +273,9 @@ struct sysent sysent[] = {
sys_getsockopt }, /* 118 = getsockopt */
{ 0, 0, 0,
sys_nosys }, /* 119 = obsolete resuba */
- { 3, s(struct sys_readv_args), 0,
+ { 3, s(struct sys_readv_args), SY_NOLOCK | 0,
sys_readv }, /* 120 = readv */
- { 3, s(struct sys_writev_args), 0,
+ { 3, s(struct sys_writev_args), SY_NOLOCK | 0,
sys_writev }, /* 121 = writev */
{ 0, 0, 0,
sys_nosys }, /* 122 = obsolete
t32_settimeofday */
@@ -384,9 +384,9 @@ struct sysent sysent[] = {
sys_nosys }, /* 171 = obsolete shmsys10 */
{ 0, 0, 0,
sys_nosys }, /* 172 = unimplemented */
- { 5, s(struct sys_pread_args), 0,
+ { 5, s(struct sys_pread_args), SY_NOLOCK | 0,
sys_pread }, /* 173 = pread */
- { 5, s(struct sys_pwrite_args), 0,
+ { 5, s(struct sys_pwrite_args), SY_NOLOCK | 0,
sys_pwrite }, /* 174 = pwrite */
{ 0, 0, 0,
sys_nosys }, /* 175 = unimplemented
ntp_gettime */
@@ -599,9 +599,9 @@ struct sysent sysent[] = {
sys_nosys }, /* 265 = unimplemented */
{ 0, 0, 0,
sys_nosys }, /* 266 = unimplemented */
- { 5, s(struct sys_preadv_args), 0,
+ { 5, s(struct sys_preadv_args), SY_NOLOCK | 0,
sys_preadv }, /* 267 = preadv */
- { 5, s(struct sys_pwritev_args), 0,
+ { 5, s(struct sys_pwritev_args), SY_NOLOCK | 0,
sys_pwritev }, /* 268 = pwritev */
{ 0, 0, 0,
sys_kqueue }, /* 269 = kqueue */
@@ -639,7 +639,7 @@ struct sysent sysent[] = {
sys_nosys }, /* 285 = obsolete sys_omquery */
{ 7, s(struct sys_mquery_args), 0,
sys_mquery }, /* 286 = mquery */
- { 1, s(struct sys_closefrom_args), 0,
+ { 1, s(struct sys_closefrom_args), SY_NOLOCK | 0,
sys_closefrom }, /* 287 = closefrom */
{ 2, s(struct sys_sigaltstack_args), 0,
sys_sigaltstack }, /* 288 = sigaltstack */
Index: kern/kern_descrip.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_descrip.c,v
retrieving revision 1.116
diff -u -p -r1.116 kern_descrip.c
--- kern/kern_descrip.c 19 Jan 2015 01:19:17 -0000 1.116
+++ kern/kern_descrip.c 12 Apr 2015 01:28:44 -0000
@@ -61,6 +61,7 @@
#include <sys/event.h>
#include <sys/pool.h>
#include <sys/ktrace.h>
+#include <sys/rwlock.h>
#include <sys/pipe.h>
@@ -69,6 +70,7 @@
*/
struct filelist filehead; /* head of list of open files */
int nfiles; /* actual number of open files */
+struct rwlock __filelist_lock; /* lock for them */
static __inline void fd_used(struct filedesc *, int);
static __inline void fd_unused(struct filedesc *, int);
@@ -88,6 +90,7 @@ filedesc_init(void)
pool_init(&fdesc_pool, sizeof(struct filedesc0), 0, 0, PR_WAITOK,
"fdescpl", NULL);
LIST_INIT(&filehead);
+ rw_init(&__filelist_lock, "filelist_lock");
}
static __inline int
@@ -163,6 +166,8 @@ fd_unused(struct filedesc *fdp, int fd)
{
u_int off = fd >> NDENTRYSHIFT;
+ fdpassertlocked(fdp);
+
if (fd < fdp->fd_freefile)
fdp->fd_freefile = fd;
@@ -184,6 +189,8 @@ fd_getfile(struct filedesc *fdp, int fd)
{
struct file *fp;
+ fdpassertlocked(fdp);
+
if ((u_int)fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL)
return (NULL);
@@ -193,6 +200,43 @@ fd_getfile(struct filedesc *fdp, int fd)
return (fp);
}
+struct file *
+fd_getfile_ref(struct filedesc *fdp, int fd, struct proc *p)
+{
+ struct file *fp;
+ unsigned long count;
+
+ /*
+ * Looks like fdp can be unlocked here
+ */
+
+ if(fd <0 || fd >= fdp->fd_nfiles) {
+ return NULL;
+ }
+
+restart:
+ if ((fp = fdp->fd_ofiles[fd]) == NULL)
+ return NULL;
+
+ if ((count = fp->f_count) == 0)
+ return NULL;
+
+ if (atomic_cas_ulong(&fp->f_count, count, count + 1) != count)
+ goto restart;
+
+ if ((fp != fdp->fd_ofiles[fd])) {
+ funref(fp, p);
+ goto restart;
+ }
+
+ if (!FILE_IS_USABLE(fp)) {
+ funref(fp, p);
+ return (NULL);
+ }
+
+ return fp;
+}
+
/*
* System calls on descriptors.
*/
@@ -214,12 +258,12 @@ sys_dup(struct proc *p, void *v, registe
int error;
restart:
- if ((fp = fd_getfile(fdp, old)) == NULL)
+ if ((fp = fd_getfile_ref(fdp, old, p)) == NULL)
return (EBADF);
- FREF(fp);
+
fdplock(fdp);
if ((error = fdalloc(p, 0, &new)) != 0) {
- FRELE(fp, p);
+ funref(fp, p);
if (error == ENOSPC) {
fdexpand(p);
fdpunlock(fdp);
@@ -273,25 +317,28 @@ dodup3(struct proc *p, int old, int new,
int i, error;
restart:
- if ((fp = fd_getfile(fdp, old)) == NULL)
+ if ((fp = fd_getfile_ref(fdp, old, p)) == NULL)
return (EBADF);
if ((u_int)new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
- (u_int)new >= maxfiles)
+ (u_int)new >= maxfiles) {
+ funref(fp, p);
return (EBADF);
+ }
if (old == new) {
/*
* NOTE! This doesn't clear the close-on-exec flag. This might
* or might not be the intended behavior from the start, but
* this is what everyone else does.
*/
+ funref(fp, p);
*retval = new;
return (0);
}
- FREF(fp);
+
fdplock(fdp);
if (new >= fdp->fd_nfiles) {
if ((error = fdalloc(p, new, &i)) != 0) {
- FRELE(fp, p);
+ funref(fp, p);
if (error == ENOSPC) {
fdexpand(p);
fdpunlock(fdp);
@@ -331,12 +378,13 @@ sys_fcntl(struct proc *p, void *v, regis
struct vnode *vp;
int i, tmp, newmin, flg = F_POSIX;
struct flock fl;
+ int oflag, nflag;
int error = 0;
restart:
- if ((fp = fd_getfile(fdp, fd)) == NULL)
+ if ((fp = fd_getfile_ref(fdp, fd, p)) == NULL)
return (EBADF);
- FREF(fp);
+
switch (SCARG(uap, cmd)) {
case F_DUPFD:
@@ -349,7 +397,7 @@ restart:
}
fdplock(fdp);
if ((error = fdalloc(p, newmin, &i)) != 0) {
- FRELE(fp, p);
+ funref(fp, p);
if (error == ENOSPC) {
fdexpand(p);
fdpunlock(fdp);
@@ -384,17 +432,21 @@ restart:
break;
case F_SETFL:
- fp->f_flag &= ~FCNTLFLAGS;
- fp->f_flag |= FFLAGS((long)SCARG(uap, arg)) & FCNTLFLAGS;
- tmp = fp->f_flag & FNONBLOCK;
+ do {
+ oflag = fp->f_flag;
+ nflag = oflag & ~FCNTLFLAGS;
+ nflag |= FFLAGS((long)SCARG(uap, arg)) & FCNTLFLAGS;
+ } while (atomic_cas_uint(&fp->f_flag, oflag, nflag) != oflag);
+
+ tmp = nflag & FNONBLOCK;
error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
if (error)
break;
- tmp = fp->f_flag & FASYNC;
+ tmp = nflag & FASYNC;
error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
if (!error)
break;
- fp->f_flag &= ~FNONBLOCK;
+ atomic_clearbits_int(&fp->f_flag, FNONBLOCK);
tmp = 0;
(void) (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
break;
@@ -483,8 +535,14 @@ restart:
error = EINVAL;
goto out;
}
-
+
+ /*
+ * FIXME: can't happen?
+ */
+
+ fdplock(fdp);
if (fp != fd_getfile(fdp, fd)) {
+ panic("%s() We lost the race with close()", __func__);
/*
* We have lost the race with close() or dup2();
* unlock, pretend that we've won the race and that
@@ -496,6 +554,7 @@ restart:
VOP_ADVLOCK(vp, fdp, F_UNLCK, &fl, F_POSIX);
fl.l_type = F_UNLCK;
}
+ fdpunlock(fdp);
goto out;
@@ -537,7 +596,7 @@ restart:
break;
}
out:
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
@@ -552,8 +611,8 @@ finishdup(struct proc *p, struct file *f
struct filedesc *fdp = p->p_fd;
fdpassertlocked(fdp);
- if (fp->f_count == LONG_MAX-2) {
- FRELE(fp, p);
+ if (fp->f_count == ULONG_MAX-2) {
+ funref(fp, p);
return (EDEADLK);
}
@@ -562,13 +621,10 @@ finishdup(struct proc *p, struct file *f
* closef can deal with that.
*/
oldfp = fdp->fd_ofiles[new];
- if (oldfp != NULL)
- FREF(oldfp);
fdp->fd_ofiles[new] = fp;
fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] & ~UF_EXCLOSE;
- fp->f_count++;
- FRELE(fp, p);
+
if (dup2 && oldfp == NULL)
fd_used(fdp, new);
*retval = new;
@@ -606,11 +662,14 @@ fdrelease(struct proc *p, int fd)
fp = *fpp;
if (fp == NULL)
return (EBADF);
- FREF(fp);
*fpp = NULL;
fd_unused(fdp, fd);
- if (fd < fdp->fd_knlistsize)
+ if (fd < fdp->fd_knlistsize) {
+ KERNEL_LOCK();
knote_fdclose(p, fd);
+ KERNEL_UNLOCK();
+ }
+
return (closef(fp, p));
}
@@ -627,9 +686,12 @@ sys_close(struct proc *p, void *v, regis
int fd = SCARG(uap, fd), error;
struct filedesc *fdp = p->p_fd;
- if (fd_getfile(fdp, fd) == NULL)
- return (EBADF);
fdplock(fdp);
+ if (fd_getfile(fdp, fd) == NULL) {
+ fdpunlock(fdp);
+ return (EBADF);
+ }
+
error = fdrelease(p, fd);
fdpunlock(fdp);
@@ -652,11 +714,11 @@ sys_fstat(struct proc *p, void *v, regis
struct stat ub;
int error;
- if ((fp = fd_getfile(fdp, fd)) == NULL)
+ if ((fp = fd_getfile_ref(fdp, fd, p)) == NULL)
return (EBADF);
- FREF(fp);
error = (*fp->f_ops->fo_stat)(fp, &ub, p);
- FRELE(fp, p);
+ funref(fp, p);
+
if (error == 0) {
/*
* Don't let non-root see generation numbers
@@ -691,9 +753,8 @@ sys_fpathconf(struct proc *p, void *v, r
struct vnode *vp;
int error;
- if ((fp = fd_getfile(fdp, fd)) == NULL)
+ if ((fp = fd_getfile_ref(fdp, fd, p)) == NULL)
return (EBADF);
- FREF(fp);
switch (fp->f_type) {
case DTYPE_PIPE:
case DTYPE_SOCKET:
@@ -716,7 +777,7 @@ sys_fpathconf(struct proc *p, void *v, r
error = EOPNOTSUPP;
break;
}
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
@@ -729,6 +790,8 @@ fdalloc(struct proc *p, int want, int *r
struct filedesc *fdp = p->p_fd;
int lim, last, i;
u_int new, off;
+
+ KERNEL_LOCK();
/*
* Search for a free descriptor starting at the higher
@@ -762,11 +825,16 @@ restart:
fdp->fd_freefile = i;
*result = i;
fdp->fd_ofileflags[i] = 0;
+ KERNEL_UNLOCK();
return (0);
}
}
- if (fdp->fd_nfiles >= lim)
+ if (fdp->fd_nfiles >= lim) {
+ KERNEL_UNLOCK();
return (EMFILE);
+ }
+
+ KERNEL_UNLOCK();
return (ENOSPC);
}
@@ -783,6 +851,8 @@ fdexpand(struct proc *p)
fdpassertlocked(fdp);
+ KERNEL_LOCK();
+
/*
* No space in current array.
*/
@@ -835,6 +905,7 @@ fdexpand(struct proc *p)
fdp->fd_ofiles = newofile;
fdp->fd_ofileflags = newofileflags;
fdp->fd_nfiles = nfiles;
+ KERNEL_UNLOCK();
}
/*
@@ -856,34 +927,43 @@ restart:
}
return (error);
}
- if (nfiles >= maxfiles) {
- fd_unused(p->p_fd, i);
- tablefull("file");
- return (ENFILE);
- }
+
/*
* Allocate a new file descriptor.
* If the process has file descriptor zero open, add to the list
* of open files at that point, otherwise put it at the front of
* the list of open files.
*/
- nfiles++;
fp = pool_get(&file_pool, PR_WAITOK|PR_ZERO);
fp->f_iflags = FIF_LARVAL;
+ fp->f_count = 1;
+ fp->f_cred = p->p_ucred;
+ crhold(fp->f_cred);
+
+ p->p_fd->fd_ofiles[i] = fp;
+
+ filelist_lock();
+ if (nfiles >= maxfiles) {
+ filelist_unlock();
+ fd_unused(p->p_fd, i);
+ tablefull("file");
+ pool_put(&file_pool, fp);
+ return (ENFILE);
+ }
+
+ nfiles++;
if ((fq = p->p_fd->fd_ofiles[0]) != NULL) {
LIST_INSERT_AFTER(fq, fp, f_list);
} else {
LIST_INSERT_HEAD(&filehead, fp, f_list);
}
- p->p_fd->fd_ofiles[i] = fp;
- fp->f_count = 1;
- fp->f_cred = p->p_ucred;
- crhold(fp->f_cred);
+ filelist_unlock();
+
if (resultfp)
*resultfp = fp;
if (resultfd)
*resultfd = i;
- FREF(fp);
+
return (0);
}
@@ -997,12 +1077,12 @@ fdcopy(struct process *pr)
* tied to the process that opened them to enforce
* their internal consistency, so close them here.
*/
- if ((*fpp)->f_count == LONG_MAX-2 ||
+ if ((*fpp)->f_count == ULONG_MAX-2 ||
(*fpp)->f_type == DTYPE_KQUEUE ||
(*fpp)->f_type == DTYPE_SYSTRACE)
fdremove(newfdp, i);
else
- (*fpp)->f_count++;
+ fref(*fpp);
}
/* finish cleaning up kq bits */
@@ -1033,7 +1113,6 @@ fdfree(struct proc *p)
for (i = fdp->fd_lastfile; i >= 0; i--, fpp++) {
fp = *fpp;
if (fp != NULL) {
- FREF(fp);
*fpp = NULL;
(void) closef(fp, p);
}
@@ -1073,10 +1152,9 @@ closef(struct file *fp, struct proc *p)
return (0);
#ifdef DIAGNOSTIC
- if (fp->f_count < 2)
- panic("closef: count (%ld) < 2", fp->f_count);
+ if (fp->f_count < 1)
+ panic("closef: count (%ld) < 1", fp->f_count);
#endif
- fp->f_count--;
/*
* POSIX record locking dictates that any close releases ALL
@@ -1097,10 +1175,12 @@ closef(struct file *fp, struct proc *p)
lf.l_start = 0;
lf.l_len = 0;
lf.l_type = F_UNLCK;
+ KERNEL_LOCK();
(void) VOP_ADVLOCK(vp, fdp, F_UNLCK, &lf, F_POSIX);
+ KERNEL_UNLOCK();
}
- return (FRELE(fp, p));
+ return (funref(fp, p));
}
int
@@ -1113,16 +1193,23 @@ fdrop(struct file *fp, struct proc *p)
panic("fdrop: count (%ld) != 0", fp->f_count);
#endif
- if (fp->f_ops)
+ if (fp->f_ops) {
+ KERNEL_LOCK();
error = (*fp->f_ops->fo_close)(fp, p);
- else
+ KERNEL_UNLOCK();
+ } else
error = 0;
- /* Free fp */
+ filelist_lock();
LIST_REMOVE(fp, f_list);
- crfree(fp->f_cred);
nfiles--;
+ filelist_unlock();
+
+ KERNEL_LOCK();
+ /* Free fp */
+ crfree(fp->f_cred);
pool_put(&file_pool, fp);
+ KERNEL_UNLOCK();
return (error);
}
@@ -1149,18 +1236,20 @@ sys_flock(struct proc *p, void *v, regis
struct flock lf;
int error;
- if ((fp = fd_getfile(fdp, fd)) == NULL)
+ if ((fp = fd_getfile_ref(fdp, fd, p)) == NULL)
return (EBADF);
- if (fp->f_type != DTYPE_VNODE)
+ if (fp->f_type != DTYPE_VNODE) {
+ funref(fp, p);
return (EOPNOTSUPP);
- FREF(fp);
+ }
+
vp = (struct vnode *)fp->f_data;
lf.l_whence = SEEK_SET;
lf.l_start = 0;
lf.l_len = 0;
if (how & LOCK_UN) {
lf.l_type = F_UNLCK;
- fp->f_iflags &= ~FIF_HASLOCK;
+ atomic_clearbits_int(&fp->f_iflags, FIF_HASLOCK);
error = VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK);
goto out;
}
@@ -1172,13 +1261,13 @@ sys_flock(struct proc *p, void *v, regis
error = EINVAL;
goto out;
}
- fp->f_iflags |= FIF_HASLOCK;
+ atomic_setbits_int(&fp->f_iflags, FIF_HASLOCK);
if (how & LOCK_NB)
error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK);
else
error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf,
F_FLOCK|F_WAIT);
out:
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
@@ -1244,13 +1333,13 @@ dupfdopen(struct filedesc *fdp, int indx
*/
if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
return (EACCES);
- if (wfp->f_count == LONG_MAX-2)
+ if (wfp->f_count == ULONG_MAX-2)
return (EDEADLK);
fdp->fd_ofiles[indx] = wfp;
fdp->fd_ofileflags[indx] = (fdp->fd_ofileflags[indx] & UF_EXCLOSE) |
(fdp->fd_ofileflags[dfd] & ~UF_EXCLOSE);
- wfp->f_count++;
+ fref(wfp);
fd_used(fdp, indx);
return (0);
}
Index: kern/kern_event.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_event.c,v
retrieving revision 1.61
diff -u -p -r1.61 kern_event.c
--- kern/kern_event.c 19 Dec 2014 05:59:21 -0000 1.61
+++ kern/kern_event.c 12 Apr 2015 01:28:44 -0000
@@ -480,11 +480,12 @@ sys_kevent(struct proc *p, void *v, regi
struct timespec ts;
int i, n, nerrors, error;
- if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL ||
- (fp->f_type != DTYPE_KQUEUE))
+ if ((fp = fd_getfile_ref(fdp, SCARG(uap, fd), p)) == NULL)
return (EBADF);
-
- FREF(fp);
+ if (fp->f_type != DTYPE_KQUEUE) {
+ funref(fp, p);
+ return (EBADF);
+ }
if (SCARG(uap, timeout) != NULL) {
error = copyin(SCARG(uap, timeout), &ts, sizeof(ts));
@@ -535,7 +536,7 @@ sys_kevent(struct proc *p, void *v, regi
}
KQREF(kq);
- FRELE(fp, p);
+ funref(fp, p);
error = kqueue_scan(kq, SCARG(uap, nevents), SCARG(uap, eventlist),
SCARG(uap, timeout), p, &n);
KQRELE(kq);
@@ -543,7 +544,7 @@ sys_kevent(struct proc *p, void *v, regi
return (error);
done:
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
@@ -573,9 +574,8 @@ kqueue_register(struct kqueue *kq, struc
if (fops->f_isfd) {
/* validate descriptor */
- if ((fp = fd_getfile(fdp, kev->ident)) == NULL)
+ if ((fp = fd_getfile_ref(fdp, kev->ident, p)) == NULL)
return (EBADF);
- FREF(fp);
if (kev->ident < fdp->fd_knlistsize) {
SLIST_FOREACH(kn, &fdp->fd_knlist[kev->ident], kn_link)
@@ -674,7 +674,7 @@ kqueue_register(struct kqueue *kq, struc
done:
if (fp != NULL)
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
@@ -889,7 +889,7 @@ kqueue_close(struct file *fp, struct pro
kn0 = SLIST_NEXT(kn, kn_link);
if (kq == kn->kn_kq) {
kn->kn_fop->f_detach(kn);
- FRELE(kn->kn_fp, p);
+ funref(kn->kn_fp, p);
knote_free(kn);
*knp = kn0;
} else {
@@ -1056,7 +1056,7 @@ knote_drop(struct knote *kn, struct proc
if (kn->kn_status & KN_QUEUED)
knote_dequeue(kn);
if (kn->kn_fop->f_isfd) {
- FRELE(kn->kn_fp, p);
+ funref(kn->kn_fp, p);
}
knote_free(kn);
}
Index: kern/kern_sysctl.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_sysctl.c,v
retrieving revision 1.283
diff -u -p -r1.283 kern_sysctl.c
--- kern/kern_sysctl.c 11 Feb 2015 05:09:33 -0000 1.283
+++ kern/kern_sysctl.c 12 Apr 2015 01:28:44 -0000
@@ -1012,7 +1012,8 @@ fill_file(struct kinfo_file *kf, struct
if (show_pointers)
kf->f_fileaddr = PTRTOINT64(fp);
kf->f_flag = fp->f_flag;
- kf->f_iflags = fp->f_iflags;
+ kf->f_iflags = (fp->f_iflags & (FIF_HASLOCK | FIF_LARVAL)) |
+ fp->f_gc_flags;
kf->f_type = fp->f_type;
kf->f_count = fp->f_count;
kf->f_msgcount = fp->f_msgcount;
@@ -1209,7 +1210,7 @@ sysctl_file(int *name, u_int namelen, ch
{
struct kinfo_file *kf;
struct filedesc *fdp;
- struct file *fp;
+ struct file *fp, *tfp;
struct process *pr;
size_t buflen, elem_size, elem_count, outsize;
char *dp = where;
@@ -1251,13 +1252,25 @@ sysctl_file(int *name, u_int namelen, ch
switch (op) {
case KERN_FILE_BYFILE:
- LIST_FOREACH(fp, &filehead, f_list) {
- if (fp->f_count == 0)
+ filelist_lock();
+ LIST_FOREACH_SAFE(fp, &filehead, f_list, tfp) {
+ filelist_unlock();
+ if (fref_try(fp) == 0) {
+ filelist_lock();
continue;
- if (arg != 0 && fp->f_type != arg)
+ }
+
+ if (arg != 0 && fp->f_type != arg) {
+ funref(fp, NULL);
+ filelist_lock();
continue;
+ }
+
FILLIT(fp, NULL, 0, NULL, NULL);
+ funref(fp, NULL);
+ filelist_lock();
}
+ filelist_unlock();
break;
case KERN_FILE_BYPID:
/* A arg of -1 indicates all processes */
Index: kern/subr_log.c
===================================================================
RCS file: /cvs/src/sys/kern/subr_log.c,v
retrieving revision 1.28
diff -u -p -r1.28 subr_log.c
--- kern/subr_log.c 10 Feb 2015 21:56:09 -0000 1.28
+++ kern/subr_log.c 12 Apr 2015 01:28:44 -0000
@@ -167,7 +167,7 @@ logclose(dev_t dev, int flag, int mode,
{
if (syslogf)
- FRELE(syslogf, p);
+ funref(syslogf, p);
syslogf = NULL;
log_open = 0;
logsoftc.sc_state = 0;
@@ -335,10 +335,10 @@ logioctl(dev_t dev, u_long com, caddr_t
case LIOCSFD:
if ((error = suser(p, 0)) != 0)
return (error);
- if ((error = getsock(p->p_fd, *(int *)data, &fp)) != 0)
+ if ((error = getsock(p, p->p_fd, *(int *)data, &fp)) != 0)
return (error);
if (syslogf)
- FRELE(syslogf, p);
+ funref(syslogf, p);
syslogf = fp;
break;
@@ -368,7 +368,7 @@ sys_sendsyslog(struct proc *p, void *v,
if (syslogf == NULL)
return (ENOTCONN);
f = syslogf;
- FREF(f);
+ fref(f);
aiov.iov_base = (char *)SCARG(uap, buf);
aiov.iov_len = SCARG(uap, nbyte);
@@ -401,6 +401,6 @@ sys_sendsyslog(struct proc *p, void *v,
free(ktriov, M_TEMP, iovlen);
}
#endif
- FRELE(f, p);
+ funref(f, p);
return error;
}
Index: kern/sys_generic.c
===================================================================
RCS file: /cvs/src/sys/kern/sys_generic.c,v
retrieving revision 1.96
diff -u -p -r1.96 sys_generic.c
--- kern/sys_generic.c 12 Feb 2015 22:27:04 -0000 1.96
+++ kern/sys_generic.c 12 Apr 2015 01:28:44 -0000
@@ -52,6 +52,7 @@
#include <sys/stat.h>
#include <sys/malloc.h>
#include <sys/poll.h>
+#include <sys/atomic.h>
#ifdef KTRACE
#include <sys/ktrace.h>
#endif
@@ -86,19 +87,25 @@ sys_read(struct proc *p, void *v, regist
int fd = SCARG(uap, fd);
struct file *fp;
struct filedesc *fdp = p->p_fd;
+ int error;
- if ((fp = fd_getfile(fdp, fd)) == NULL)
- return (EBADF);
- if ((fp->f_flag & FREAD) == 0)
+ if ((fp = fd_getfile_ref(fdp, fd, p)) == NULL)
return (EBADF);
+ if ((fp->f_flag & FREAD) == 0) {
+ error = EBADF;
+ goto out;
+ }
iov.iov_base = SCARG(uap, buf);
iov.iov_len = SCARG(uap, nbyte);
- FREF(fp);
+ KERNEL_LOCK();
+ error = dofilereadv(p, fd, fp, &iov, 1, 0, &fp->f_offset, retval);
+ KERNEL_UNLOCK();
- /* dofilereadv() will FRELE the descriptor for us */
- return (dofilereadv(p, fd, fp, &iov, 1, 0, &fp->f_offset, retval));
+out:
+ funref(fp, p);
+ return error;
}
/*
@@ -115,17 +122,23 @@ sys_readv(struct proc *p, void *v, regis
int fd = SCARG(uap, fd);
struct file *fp;
struct filedesc *fdp = p->p_fd;
+ int error;
- if ((fp = fd_getfile(fdp, fd)) == NULL)
- return (EBADF);
- if ((fp->f_flag & FREAD) == 0)
+ if ((fp = fd_getfile_ref(fdp, fd, p)) == NULL)
return (EBADF);
+ if ((fp->f_flag & FREAD) == 0) {
+ error = EBADF;
+ goto out;
+ }
- FREF(fp);
+ KERNEL_LOCK();
+ error = dofilereadv(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), 1,
+ &fp->f_offset, retval);
+ KERNEL_UNLOCK();
- /* dofilereadv() will FRELE the descriptor for us */
- return (dofilereadv(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), 1,
- &fp->f_offset, retval));
+out:
+ funref(fp, p);
+ return error;
}
int
@@ -220,7 +233,6 @@ dofilereadv(struct proc *p, int fd, stru
if (needfree)
free(needfree, M_IOV, iovlen);
out:
- FRELE(fp, p);
return (error);
}
@@ -239,19 +251,24 @@ sys_write(struct proc *p, void *v, regis
int fd = SCARG(uap, fd);
struct file *fp;
struct filedesc *fdp = p->p_fd;
+ int error;
- if ((fp = fd_getfile(fdp, fd)) == NULL)
- return (EBADF);
- if ((fp->f_flag & FWRITE) == 0)
+ if ((fp = fd_getfile_ref(fdp, fd, p)) == NULL)
return (EBADF);
+ if ((fp->f_flag & FWRITE) == 0) {
+ error = EBADF;
+ goto out;
+ }
iov.iov_base = (void *)SCARG(uap, buf);
iov.iov_len = SCARG(uap, nbyte);
- FREF(fp);
-
- /* dofilewritev() will FRELE the descriptor for us */
- return (dofilewritev(p, fd, fp, &iov, 1, 0, &fp->f_offset, retval));
+ KERNEL_LOCK();
+ error = dofilewritev(p, fd, fp, &iov, 1, 0, &fp->f_offset, retval);
+ KERNEL_UNLOCK();
+out:
+ funref(fp, p);
+ return error;
}
/*
@@ -268,17 +285,22 @@ sys_writev(struct proc *p, void *v, regi
int fd = SCARG(uap, fd);
struct file *fp;
struct filedesc *fdp = p->p_fd;
+ int error;
- if ((fp = fd_getfile(fdp, fd)) == NULL)
- return (EBADF);
- if ((fp->f_flag & FWRITE) == 0)
+ if ((fp = fd_getfile_ref(fdp, fd, p)) == NULL)
return (EBADF);
+ if ((fp->f_flag & FWRITE) == 0) {
+ error = EBADF;
+ goto out;
+ }
- FREF(fp);
-
- /* dofilewritev() will FRELE the descriptor for us */
- return (dofilewritev(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), 1,
- &fp->f_offset, retval));
+ KERNEL_LOCK();
+ error = dofilewritev(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), 1,
+ &fp->f_offset, retval);
+ KERNEL_UNLOCK();
+out:
+ funref(fp, p);
+ return error;
}
int
@@ -376,7 +398,6 @@ dofilewritev(struct proc *p, int fd, str
if (needfree)
free(needfree, M_IOV, iovlen);
out:
- FRELE(fp, p);
return (error);
}
@@ -403,11 +424,13 @@ sys_ioctl(struct proc *p, void *v, regis
long long stkbuf[STK_PARAMS / sizeof(long long)];
fdp = p->p_fd;
- if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
+ if ((fp = fd_getfile_ref(fdp, SCARG(uap, fd), p)) == NULL)
return (EBADF);
- if ((fp->f_flag & (FREAD | FWRITE)) == 0)
+ if ((fp->f_flag & (FREAD | FWRITE)) == 0){
+ funref(fp, p);
return (EBADF);
+ }
switch (com = SCARG(uap, com)) {
case FIONCLEX:
@@ -418,6 +441,7 @@ sys_ioctl(struct proc *p, void *v, regis
else
fdp->fd_ofileflags[SCARG(uap, fd)] |= UF_EXCLOSE;
fdpunlock(fdp);
+ funref(fp, p);
return (0);
}
@@ -426,9 +450,10 @@ sys_ioctl(struct proc *p, void *v, regis
* copied to/from the user's address space.
*/
size = IOCPARM_LEN(com);
- if (size > IOCPARM_MAX)
+ if (size > IOCPARM_MAX) {
+ funref(fp, p);
return (ENOTTY);
- FREF(fp);
+ }
memp = NULL;
if (size > sizeof (stkbuf)) {
memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
@@ -456,17 +481,17 @@ sys_ioctl(struct proc *p, void *v, regis
case FIONBIO:
if ((tmp = *(int *)data) != 0)
- fp->f_flag |= FNONBLOCK;
+ atomic_setbits_int(&fp->f_flag, FNONBLOCK);
else
- fp->f_flag &= ~FNONBLOCK;
+ atomic_clearbits_int(&fp->f_flag, FNONBLOCK);
error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
break;
case FIOASYNC:
if ((tmp = *(int *)data) != 0)
- fp->f_flag |= FASYNC;
+ atomic_setbits_int(&fp->f_flag, FASYNC);
else
- fp->f_flag &= ~FASYNC;
+ atomic_clearbits_int(&fp->f_flag, FASYNC);
error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
break;
@@ -516,7 +541,7 @@ sys_ioctl(struct proc *p, void *v, regis
if (error == 0 && (com&IOC_OUT) && size)
error = copyout(data, SCARG(uap, data), (u_int)size);
out:
- FRELE(fp, p);
+ funref(fp, p);
if (memp)
free(memp, M_IOCTLOPS, size);
return (error);
@@ -735,14 +760,13 @@ selscan(struct proc *p, fd_set *ibits, f
bits = pibits->fds_bits[i/NFDBITS];
while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
bits &= ~(1 << j);
- if ((fp = fd_getfile(fdp, fd)) == NULL)
+ if ((fp = fd_getfile_ref(fdp, fd, p)) == NULL)
return (EBADF);
- FREF(fp);
if ((*fp->f_ops->fo_poll)(fp, flag[msk], p)) {
FD_SET(fd, pobits);
n++;
}
- FRELE(fp, p);
+ funref(fp, p);
}
}
}
@@ -830,14 +854,13 @@ pollscan(struct proc *p, struct pollfd *
pl->revents = 0;
continue;
}
- if ((fp = fd_getfile(fdp, pl->fd)) == NULL) {
+ if ((fp = fd_getfile_ref(fdp, pl->fd, p)) == NULL) {
pl->revents = POLLNVAL;
n++;
continue;
}
- FREF(fp);
pl->revents = (*fp->f_ops->fo_poll)(fp, pl->events, p);
- FRELE(fp, p);
+ funref(fp, p);
if (pl->revents != 0)
n++;
}
Index: kern/uipc_socket.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_socket.c,v
retrieving revision 1.136
diff -u -p -r1.136 uipc_socket.c
--- kern/uipc_socket.c 10 Feb 2015 21:56:10 -0000 1.136
+++ kern/uipc_socket.c 12 Apr 2015 01:28:44 -0000
@@ -1077,7 +1077,7 @@ sosplice(struct socket *so, int fd, off_
return (EINVAL);
/* Find sosp, the drain socket where data will be spliced into. */
- if ((error = getsock(curproc->p_fd, fd, &fp)) != 0)
+ if ((error = getsock(curproc, curproc->p_fd, fd, &fp)) != 0)
return (error);
sosp = fp->f_data;
if (sosp->so_sp == NULL)
@@ -1086,12 +1086,12 @@ sosplice(struct socket *so, int fd, off_
/* Lock both receive and send buffer. */
if ((error = sblock(&so->so_rcv,
(so->so_state & SS_NBIO) ? M_NOWAIT : M_WAITOK)) != 0) {
- FRELE(fp, curproc);
+ funref(fp, curproc);
return (error);
}
if ((error = sblock(&sosp->so_snd, M_WAITOK)) != 0) {
sbunlock(&so->so_rcv);
- FRELE(fp, curproc);
+ funref(fp, curproc);
return (error);
}
s = splsoftnet();
@@ -1137,7 +1137,7 @@ sosplice(struct socket *so, int fd, off_
splx(s);
sbunlock(&sosp->so_snd);
sbunlock(&so->so_rcv);
- FRELE(fp, curproc);
+ funref(fp, curproc);
return (error);
}
Index: kern/uipc_syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_syscalls.c,v
retrieving revision 1.99
diff -u -p -r1.99 uipc_syscalls.c
--- kern/uipc_syscalls.c 19 Jan 2015 19:57:59 -0000 1.99
+++ kern/uipc_syscalls.c 12 Apr 2015 01:28:44 -0000
@@ -121,7 +121,7 @@ sys_bind(struct proc *p, void *v, regist
struct mbuf *nam;
int error;
- if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
+ if ((error = getsock(p, p->p_fd, SCARG(uap, s), &fp)) != 0)
return (error);
error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen),
MT_SONAME);
@@ -133,7 +133,7 @@ sys_bind(struct proc *p, void *v, regist
error = sobind(fp->f_data, nam, p);
m_freem(nam);
}
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
@@ -148,10 +148,10 @@ sys_listen(struct proc *p, void *v, regi
struct file *fp;
int error;
- if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
+ if ((error = getsock(p, p->p_fd, SCARG(uap, s), &fp)) != 0)
return (error);
error = solisten(fp->f_data, SCARG(uap, backlog));
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
@@ -199,7 +199,7 @@ doaccept(struct proc *p, int sock, struc
if (name && (error = copyin(anamelen, &namelen, sizeof (namelen))))
return (error);
- if ((error = getsock(fdp, sock, &fp)) != 0)
+ if ((error = getsock(p, fdp, sock, &fp)) != 0)
return (error);
headfp = fp;
s = splsoftnet();
@@ -298,7 +298,7 @@ redo:
m_freem(nam);
bad:
splx(s);
- FRELE(headfp, p);
+ funref(headfp, p);
return (error);
}
@@ -316,11 +316,11 @@ sys_connect(struct proc *p, void *v, reg
struct mbuf *nam = NULL;
int error, s;
- if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
+ if ((error = getsock(p, p->p_fd, SCARG(uap, s), &fp)) != 0)
return (error);
so = fp->f_data;
if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
- FRELE(fp, p);
+ funref(fp, p);
return (EALREADY);
}
error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen),
@@ -335,7 +335,7 @@ sys_connect(struct proc *p, void *v, reg
if (error)
goto bad;
if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
- FRELE(fp, p);
+ funref(fp, p);
m_freem(nam);
return (EINPROGRESS);
}
@@ -352,7 +352,7 @@ sys_connect(struct proc *p, void *v, reg
splx(s);
bad:
so->so_state &= ~SS_ISCONNECTING;
- FRELE(fp, p);
+ funref(fp, p);
if (nam)
m_freem(nam);
if (error == ERESTART)
@@ -519,7 +519,7 @@ sendit(struct proc *p, int s, struct msg
to = NULL;
- if ((error = getsock(p->p_fd, s, &fp)) != 0)
+ if ((error = getsock(p, p->p_fd, s, &fp)) != 0)
return (error);
auio.uio_iov = mp->msg_iov;
auio.uio_iovcnt = mp->msg_iovlen;
@@ -589,7 +589,7 @@ sendit(struct proc *p, int s, struct msg
}
#endif
bad:
- FRELE(fp, p);
+ funref(fp, p);
if (to)
m_freem(to);
return (error);
@@ -685,7 +685,7 @@ recvit(struct proc *p, int s, struct msg
int iovlen = 0;
#endif
- if ((error = getsock(p->p_fd, s, &fp)) != 0)
+ if ((error = getsock(p, p->p_fd, s, &fp)) != 0)
return (error);
auio.uio_iov = mp->msg_iov;
auio.uio_iovcnt = mp->msg_iovlen;
@@ -785,7 +785,7 @@ recvit(struct proc *p, int s, struct msg
fp->f_rbytes += *retsize;
}
out:
- FRELE(fp, p);
+ funref(fp, p);
if (from)
m_freem(from);
if (control)
@@ -804,10 +804,10 @@ sys_shutdown(struct proc *p, void *v, re
struct file *fp;
int error;
- if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
+ if ((error = getsock(p, p->p_fd, SCARG(uap, s), &fp)) != 0)
return (error);
error = soshutdown(fp->f_data, SCARG(uap, how));
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
@@ -826,7 +826,7 @@ sys_setsockopt(struct proc *p, void *v,
struct mbuf *m = NULL;
int error;
- if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
+ if ((error = getsock(p, p->p_fd, SCARG(uap, s), &fp)) != 0)
return (error);
if (SCARG(uap, valsize) > MCLBYTES) {
error = EINVAL;
@@ -857,7 +857,7 @@ sys_setsockopt(struct proc *p, void *v,
bad:
if (m)
m_freem(m);
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
@@ -877,7 +877,7 @@ sys_getsockopt(struct proc *p, void *v,
socklen_t valsize;
int error;
- if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
+ if ((error = getsock(p, p->p_fd, SCARG(uap, s), &fp)) != 0)
return (error);
if (SCARG(uap, val)) {
error = copyin(SCARG(uap, avalsize),
@@ -897,7 +897,7 @@ sys_getsockopt(struct proc *p, void *v,
SCARG(uap, avalsize), sizeof (valsize));
}
out:
- FRELE(fp, p);
+ funref(fp, p);
if (m != NULL)
(void)m_free(m);
return (error);
@@ -921,7 +921,7 @@ sys_getsockname(struct proc *p, void *v,
socklen_t len;
int error;
- if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0)
+ if ((error = getsock(p, p->p_fd, SCARG(uap, fdes), &fp)) != 0)
return (error);
error = copyin(SCARG(uap, alen), &len, sizeof (len));
if (error)
@@ -933,7 +933,7 @@ sys_getsockname(struct proc *p, void *v,
goto bad;
error = copyaddrout(p, m, SCARG(uap, asa), len, SCARG(uap, alen));
bad:
- FRELE(fp, p);
+ funref(fp, p);
if (m)
m_freem(m);
return (error);
@@ -957,11 +957,11 @@ sys_getpeername(struct proc *p, void *v,
socklen_t len;
int error;
- if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0)
+ if ((error = getsock(p, p->p_fd, SCARG(uap, fdes), &fp)) != 0)
return (error);
so = fp->f_data;
if ((so->so_state & SS_ISCONNECTED) == 0) {
- FRELE(fp, p);
+ funref(fp, p);
return (ENOTCONN);
}
error = copyin(SCARG(uap, alen), &len, sizeof (len));
@@ -973,7 +973,7 @@ sys_getpeername(struct proc *p, void *v,
goto bad;
error = copyaddrout(p, m, SCARG(uap, asa), len, SCARG(uap, alen));
bad:
- FRELE(fp, p);
+ funref(fp, p);
m_freem(m);
return (error);
}
@@ -1017,16 +1017,17 @@ sockargs(struct mbuf **mp, const void *b
}
int
-getsock(struct filedesc *fdp, int fdes, struct file **fpp)
+getsock(struct proc *p, struct filedesc *fdp, int fdes, struct file **fpp)
{
struct file *fp;
- if ((fp = fd_getfile(fdp, fdes)) == NULL)
+ if ((fp = fd_getfile_ref(fdp, fdes, p)) == NULL)
return (EBADF);
- if (fp->f_type != DTYPE_SOCKET)
+ if (fp->f_type != DTYPE_SOCKET) {
+ funref(fp, p);
return (ENOTSOCK);
+ }
*fpp = fp;
- FREF(fp);
return (0);
}
Index: kern/uipc_usrreq.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_usrreq.c,v
retrieving revision 1.79
diff -u -p -r1.79 uipc_usrreq.c
--- kern/uipc_usrreq.c 11 Dec 2014 19:21:57 -0000 1.79
+++ kern/uipc_usrreq.c 12 Apr 2015 01:28:44 -0000
@@ -833,7 +833,12 @@ morespace:
for (i = 0; i < nfds; i++) {
memcpy(&fd, ip, sizeof fd);
ip--;
- if ((fp = fd_getfile(fdp, fd)) == NULL) {
+
+ fdplock(fdp);
+ fp=fd_getfile(fdp, fd);
+ fdpunlock(fdp);
+
+ if (fp == NULL) {
error = EBADF;
goto fail;
}
@@ -874,7 +879,7 @@ extern struct domain unixdomain;
void
unp_gc(void)
{
- struct file *fp, *nextfp;
+ struct file *fp, *tfp;
struct socket *so;
struct file **extra_ref, **fpp;
int nunref, i;
@@ -883,29 +888,59 @@ unp_gc(void)
return;
unp_gcing = 1;
unp_defer = 0;
- LIST_FOREACH(fp, &filehead, f_list)
- fp->f_iflags &= ~(FIF_MARK|FIF_DEFER);
+
+ filelist_lock();
+ LIST_FOREACH_SAFE(fp, &filehead, f_list, tfp) {
+ filelist_unlock();
+ if (fref_try(fp) == 0) {
+ filelist_lock();
+ continue;
+ }
+ fp->f_gc_flags &= ~(F_GC_MARK|F_GC_DEFER);
+ funref(fp, NULL);
+ filelist_lock();
+ }
+ filelist_unlock();
+
do {
- LIST_FOREACH(fp, &filehead, f_list) {
- if (fp->f_iflags & FIF_DEFER) {
- fp->f_iflags &= ~FIF_DEFER;
+ filelist_lock();
+ LIST_FOREACH_SAFE(fp, &filehead, f_list, tfp) {
+ filelist_unlock();
+ if (fref_try(fp) == 0) {
+ filelist_lock();
+ continue;
+ }
+
+ if (fp->f_gc_flags & F_GC_DEFER) {
+ fp->f_gc_flags &= ~F_GC_DEFER;
unp_defer--;
} else {
- if (fp->f_count == 0)
- continue;
- if (fp->f_iflags & FIF_MARK)
+ if (fp->f_gc_flags & F_GC_MARK) {
+ funref(fp, NULL);
+ filelist_lock();
continue;
- if (fp->f_count == fp->f_msgcount)
+ }
+
+ if (fp->f_count == fp->f_msgcount) {
+ funref(fp, NULL);
+ filelist_lock();
continue;
+ }
}
- fp->f_iflags |= FIF_MARK;
+ fp->f_gc_flags |= F_GC_MARK;
if (fp->f_type != DTYPE_SOCKET ||
- (so = fp->f_data) == NULL)
+ (so = fp->f_data) == NULL){
+ funref(fp, NULL);
+ filelist_lock();
continue;
+ }
if (so->so_proto->pr_domain != &unixdomain ||
- (so->so_proto->pr_flags&PR_RIGHTS) == 0)
+ (so->so_proto->pr_flags&PR_RIGHTS) == 0){
+ funref(fp, NULL);
+ filelist_lock();
continue;
+ }
#ifdef notdef
if (so->so_rcv.sb_flags & SB_LOCK) {
/*
@@ -923,7 +958,10 @@ unp_gc(void)
}
#endif
unp_scan(so->so_rcv.sb_mb, unp_mark, 0);
+ funref(fp, NULL);
+ filelist_lock();
}
+ filelist_unlock();
} while (unp_defer);
/*
* We grab an extra reference to each of the file table entries
@@ -964,20 +1002,32 @@ unp_gc(void)
*
* 91/09/19, [email protected]
*/
- extra_ref = mallocarray(nfiles, sizeof(struct file *), M_FILE,
M_WAITOK);
- for (nunref = 0, fp = LIST_FIRST(&filehead), fpp = extra_ref;
- fp != NULL; fp = nextfp) {
- nextfp = LIST_NEXT(fp, f_list);
- if (fp->f_count == 0)
+ extra_ref = mallocarray(nfiles, sizeof(struct file *),
+ M_FILE, M_WAITOK);
+
+ nunref=0;
+ fpp = extra_ref;
+
+ filelist_lock();
+ LIST_FOREACH_SAFE(fp, &filehead, f_list, tfp) {
+ filelist_unlock();
+ if (fref_try(fp) == 0) {
+ filelist_lock();
continue;
+ }
if (fp->f_count == fp->f_msgcount &&
- !(fp->f_iflags & FIF_MARK)) {
+ !(fp->f_gc_flags & F_GC_MARK)) {
*fpp++ = fp;
nunref++;
- FREF(fp);
- fp->f_count++;
+
+ /* hack for closef() call */
+ fref(fp);
}
+ funref(fp, NULL);
+ filelist_lock();
}
+ filelist_unlock();
+
for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)
if ((*fpp)->f_type == DTYPE_SOCKET && (*fpp)->f_data != NULL)
sorflush((*fpp)->f_data);
@@ -1035,14 +1085,14 @@ unp_mark(struct file *fp)
if (fp == NULL)
return;
- if (fp->f_iflags & (FIF_MARK|FIF_DEFER))
+ if (fp->f_gc_flags & (F_GC_MARK|F_GC_DEFER))
return;
if (fp->f_type == DTYPE_SOCKET) {
unp_defer++;
- fp->f_iflags |= FIF_DEFER;
+ fp->f_gc_flags |= F_GC_DEFER;
} else {
- fp->f_iflags |= FIF_MARK;
+ fp->f_gc_flags |= F_GC_MARK;
}
}
@@ -1052,7 +1102,6 @@ unp_discard(struct file *fp)
if (fp == NULL)
return;
- FREF(fp);
fp->f_msgcount--;
unp_rights--;
(void) closef(fp, NULL);
Index: kern/vfs_lookup.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_lookup.c,v
retrieving revision 1.51
diff -u -p -r1.51 vfs_lookup.c
--- kern/vfs_lookup.c 19 Jan 2015 18:05:41 -0000 1.51
+++ kern/vfs_lookup.c 12 Apr 2015 01:28:44 -0000
@@ -175,7 +175,12 @@ namei(struct nameidata *ndp)
dp = fdp->fd_cdir;
vref(dp);
} else {
- struct file *fp = fd_getfile(fdp, ndp->ni_dirfd);
+ struct file *fp;
+
+ fdplock(fdp);
+ fp = fd_getfile(fdp, ndp->ni_dirfd);
+ fdpunlock(fdp);
+
if (fp == NULL) {
pool_put(&namei_pool, cnp->cn_pnbuf);
return (EBADF);
Index: kern/vfs_syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.216
diff -u -p -r1.216 vfs_syscalls.c
--- kern/vfs_syscalls.c 16 Dec 2014 18:30:04 -0000 1.216
+++ kern/vfs_syscalls.c 12 Apr 2015 01:28:44 -0000
@@ -592,16 +592,16 @@ sys_fstatfs(struct proc *p, void *v, reg
struct statfs *sp;
int error;
- if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
+ if ((error = getvnode(p, p->p_fd, SCARG(uap, fd), &fp)) != 0)
return (error);
mp = ((struct vnode *)fp->f_data)->v_mount;
if (!mp) {
- FRELE(fp, p);
+ funref(fp, p);
return (ENOENT);
}
sp = &mp->mnt_stat;
error = VFS_STATFS(mp, sp, p);
- FRELE(fp, p);
+ funref(fp, p);
if (error)
return (error);
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
@@ -686,7 +686,11 @@ sys_fchdir(struct proc *p, void *v, regi
struct file *fp;
int error;
- if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
+ fdplock(fdp);
+ fp = fd_getfile(fdp, SCARG(uap, fd));
+ fdpunlock(fdp);
+
+ if (fp == NULL)
return (EBADF);
vp = (struct vnode *)fp->f_data;
if (fp->f_type != DTYPE_VNODE || vp->v_type != VDIR)
@@ -901,7 +905,7 @@ doopenat(struct proc *p, int fd, const c
goto out;
}
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
- fp->f_iflags |= FIF_HASLOCK;
+ atomic_setbits_int(&fp->f_iflags, FIF_HASLOCK);
}
if (localtrunc) {
if ((fp->f_flag & FWRITE) == 0)
@@ -1083,7 +1087,7 @@ sys_fhopen(struct proc *p, void *v, regi
goto bad;
}
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
- fp->f_iflags |= FIF_HASLOCK;
+ atomic_setbits_int(&fp->f_iflags, FIF_HASLOCK);
}
VOP_UNLOCK(vp, 0, p);
*retval = indx;
@@ -1533,14 +1537,17 @@ sys_lseek(struct proc *p, void *v, regis
off_t offarg, newoff;
int error, special;
- if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
+ if ((fp = fd_getfile_ref(fdp, SCARG(uap, fd), p)) == NULL)
return (EBADF);
- if (fp->f_type != DTYPE_VNODE)
+ if (fp->f_type != DTYPE_VNODE) {
+ funref(fp, p);
return (ESPIPE);
+ }
vp = (struct vnode *)fp->f_data;
- if (vp->v_type == VFIFO)
+ if (vp->v_type == VFIFO) {
+ funref(fp, p);
return (ESPIPE);
- FREF(fp);
+ }
if (vp->v_type == VCHR)
special = 1;
else
@@ -1574,7 +1581,7 @@ sys_lseek(struct proc *p, void *v, regis
fp->f_seek++;
error = 0;
bad:
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
@@ -1884,11 +1891,11 @@ sys_fchflags(struct proc *p, void *v, re
struct vnode *vp;
int error;
- if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
+ if ((error = getvnode(p, p->p_fd, SCARG(uap, fd), &fp)) != 0)
return (error);
vp = fp->f_data;
vref(vp);
- FRELE(fp, p);
+ funref(fp, p);
return (dovchflags(p, vp, SCARG(uap, flags)));
}
@@ -2000,7 +2007,7 @@ sys_fchmod(struct proc *p, void *v, regi
if (SCARG(uap, mode) & ~(S_IFMT | ALLPERMS))
return (EINVAL);
- if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
+ if ((error = getvnode(p, p->p_fd, SCARG(uap, fd), &fp)) != 0)
return (error);
vp = (struct vnode *)fp->f_data;
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
@@ -2012,7 +2019,7 @@ sys_fchmod(struct proc *p, void *v, regi
error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
}
VOP_UNLOCK(vp, 0, p);
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
@@ -2162,7 +2169,7 @@ sys_fchown(struct proc *p, void *v, regi
uid_t uid = SCARG(uap, uid);
gid_t gid = SCARG(uap, gid);
- if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
+ if ((error = getvnode(p, p->p_fd, SCARG(uap, fd), &fp)) != 0)
return (error);
vp = (struct vnode *)fp->f_data;
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
@@ -2187,7 +2194,7 @@ sys_fchown(struct proc *p, void *v, regi
}
out:
VOP_UNLOCK(vp, 0, p);
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
@@ -2380,11 +2387,11 @@ dofutimens(struct proc *p, int fd, struc
struct vnode *vp;
int error;
- if ((error = getvnode(p->p_fd, fd, &fp)) != 0)
+ if ((error = getvnode(p, p->p_fd, fd, &fp)) != 0)
return (error);
vp = (struct vnode *)fp->f_data;
vref(vp);
- FRELE(fp, p);
+ funref(fp, p);
return (dovutimens(p, vp, ts));
}
@@ -2441,7 +2448,7 @@ sys_ftruncate(struct proc *p, void *v, r
off_t len;
int error;
- if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
+ if ((error = getvnode(p, p->p_fd, SCARG(uap, fd), &fp)) != 0)
return (error);
len = SCARG(uap, length);
if ((fp->f_flag & FWRITE) == 0 || len < 0) {
@@ -2459,7 +2466,7 @@ sys_ftruncate(struct proc *p, void *v, r
}
VOP_UNLOCK(vp, 0, p);
bad:
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
@@ -2477,7 +2484,7 @@ sys_fsync(struct proc *p, void *v, regis
struct file *fp;
int error;
- if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
+ if ((error = getvnode(p, p->p_fd, SCARG(uap, fd), &fp)) != 0)
return (error);
vp = (struct vnode *)fp->f_data;
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
@@ -2488,7 +2495,7 @@ sys_fsync(struct proc *p, void *v, regis
#endif
VOP_UNLOCK(vp, 0, p);
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
@@ -2696,7 +2703,7 @@ sys_getdents(struct proc *p, void *v, re
if (buflen > INT_MAX)
return EINVAL;
- if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
+ if ((error = getvnode(p, p->p_fd, SCARG(uap, fd), &fp)) != 0)
return (error);
if ((fp->f_flag & FREAD) == 0) {
error = EBADF;
@@ -2728,7 +2735,7 @@ sys_getdents(struct proc *p, void *v, re
goto bad;
*retval = buflen - auio.uio_resid;
bad:
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
@@ -2787,22 +2794,25 @@ out:
* On return *fpp is FREF:ed.
*/
int
-getvnode(struct filedesc *fdp, int fd, struct file **fpp)
+getvnode(struct proc *p, struct filedesc *fdp, int fd, struct file **fpp)
{
struct file *fp;
struct vnode *vp;
- if ((fp = fd_getfile(fdp, fd)) == NULL)
+ if ((fp = fd_getfile_ref(fdp, fd, p)) == NULL)
return (EBADF);
- if (fp->f_type != DTYPE_VNODE)
+ if (fp->f_type != DTYPE_VNODE) {
+ funref(fp, p);
return (EINVAL);
+ }
vp = (struct vnode *)fp->f_data;
- if (vp->v_type == VBAD)
+ if (vp->v_type == VBAD) {
+ funref(fp, p);
return (EBADF);
+ }
- FREF(fp);
*fpp = fp;
return (0);
@@ -2827,29 +2837,38 @@ sys_pread(struct proc *p, void *v, regis
struct vnode *vp;
off_t offset;
int fd = SCARG(uap, fd);
+ int error;
- if ((fp = fd_getfile(fdp, fd)) == NULL)
- return (EBADF);
- if ((fp->f_flag & FREAD) == 0)
+ if ((fp = fd_getfile_ref(fdp, fd, p)) == NULL)
return (EBADF);
+ if ((fp->f_flag & FREAD) == 0) {
+ error = EBADF;
+ goto out;
+ }
vp = (struct vnode *)fp->f_data;
if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO ||
(vp->v_flag & VISTTY)) {
- return (ESPIPE);
+ error = ESPIPE;
+ goto out;
}
iov.iov_base = SCARG(uap, buf);
iov.iov_len = SCARG(uap, nbyte);
offset = SCARG(uap, offset);
- if (offset < 0 && vp->v_type != VCHR)
- return (EINVAL);
+ if (offset < 0 && vp->v_type != VCHR) {
+ error = EINVAL;
+ goto out;
+ }
- FREF(fp);
+ KERNEL_LOCK();
+ error = dofilereadv(p, fd, fp, &iov, 1, 0, &offset, retval);
+ KERNEL_UNLOCK();
- /* dofilereadv() will FRELE the descriptor for us */
- return (dofilereadv(p, fd, fp, &iov, 1, 0, &offset, retval));
+out:
+ funref(fp, p);
+ return error;
}
/*
@@ -2870,27 +2889,35 @@ sys_preadv(struct proc *p, void *v, regi
struct vnode *vp;
off_t offset;
int fd = SCARG(uap, fd);
+ int error;
- if ((fp = fd_getfile(fdp, fd)) == NULL)
- return (EBADF);
- if ((fp->f_flag & FREAD) == 0)
+ if ((fp = fd_getfile_ref(fdp, fd, p)) == NULL)
return (EBADF);
+ if ((fp->f_flag & FREAD) == 0) {
+ error = EBADF;
+ goto out;
+ }
vp = (struct vnode *)fp->f_data;
if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO ||
(vp->v_flag & VISTTY)) {
- return (ESPIPE);
+ error = ESPIPE;
+ goto out;
}
offset = SCARG(uap, offset);
- if (offset < 0 && vp->v_type != VCHR)
- return (EINVAL);
-
- FREF(fp);
+ if (offset < 0 && vp->v_type != VCHR) {
+ error = EINVAL;
+ goto out;
+ }
- /* dofilereadv() will FRELE the descriptor for us */
- return (dofilereadv(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), 1,
- &offset, retval));
+ KERNEL_LOCK();
+ error = dofilereadv(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), 1,
+ &offset, retval);
+ KERNEL_UNLOCK();
+out:
+ funref(fp, p);
+ return error;
}
/*
@@ -2912,29 +2939,37 @@ sys_pwrite(struct proc *p, void *v, regi
struct vnode *vp;
off_t offset;
int fd = SCARG(uap, fd);
+ int error;
- if ((fp = fd_getfile(fdp, fd)) == NULL)
- return (EBADF);
- if ((fp->f_flag & FWRITE) == 0)
+ if ((fp = fd_getfile_ref(fdp, fd, p)) == NULL)
return (EBADF);
+ if ((fp->f_flag & FWRITE) == 0) {
+ error = EBADF;
+ goto out;
+ }
vp = (struct vnode *)fp->f_data;
if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO ||
(vp->v_flag & VISTTY)) {
- return (ESPIPE);
+ error = ESPIPE;
+ goto out;
}
iov.iov_base = (void *)SCARG(uap, buf);
iov.iov_len = SCARG(uap, nbyte);
offset = SCARG(uap, offset);
- if (offset < 0 && vp->v_type != VCHR)
- return (EINVAL);
-
- FREF(fp);
+ if (offset < 0 && vp->v_type != VCHR) {
+ error = EINVAL;
+ goto out;
+ }
- /* dofilewritev() will FRELE the descriptor for us */
- return (dofilewritev(p, fd, fp, &iov, 1, 0, &offset, retval));
+ KERNEL_LOCK();
+ error = dofilewritev(p, fd, fp, &iov, 1, 0, &offset, retval);
+ KERNEL_UNLOCK();
+out:
+ funref(fp, p);
+ return error;
}
/*
@@ -2955,26 +2990,34 @@ sys_pwritev(struct proc *p, void *v, reg
struct vnode *vp;
off_t offset;
int fd = SCARG(uap, fd);
+ int error;
- if ((fp = fd_getfile(fdp, fd)) == NULL)
- return (EBADF);
- if ((fp->f_flag & FWRITE) == 0)
+ if ((fp = fd_getfile_ref(fdp, fd, p)) == NULL)
return (EBADF);
+ if ((fp->f_flag & FWRITE) == 0) {
+ error = EBADF;
+ goto out;
+ }
vp = (struct vnode *)fp->f_data;
if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO ||
(vp->v_flag & VISTTY)) {
- return (ESPIPE);
+ error = ESPIPE;
+ goto out;
}
offset = SCARG(uap, offset);
- if (offset < 0 && vp->v_type != VCHR)
- return (EINVAL);
-
- FREF(fp);
+ if (offset < 0 && vp->v_type != VCHR) {
+ error = EINVAL;
+ goto out;
+ }
- /* dofilewritev() will FRELE the descriptor for us */
- return (dofilewritev(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
- 1, &offset, retval));
+ KERNEL_LOCK();
+ error = dofilewritev(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
+ 1, &offset, retval);
+ KERNEL_UNLOCK();
+out:
+ funref(fp, p);
+ return error;
}
Index: miscfs/fuse/fuse_vfsops.c
===================================================================
RCS file: /cvs/src/sys/miscfs/fuse/fuse_vfsops.c,v
retrieving revision 1.15
diff -u -p -r1.15 fuse_vfsops.c
--- miscfs/fuse/fuse_vfsops.c 23 Dec 2014 04:54:45 -0000 1.15
+++ miscfs/fuse/fuse_vfsops.c 12 Apr 2015 01:28:52 -0000
@@ -85,7 +85,11 @@ fusefs_mount(struct mount *mp, const cha
if (error)
return (error);
- if ((fp = fd_getfile(p->p_fd, args.fd)) == NULL)
+ fdplock(p->p_fd);
+ fp = fd_getfile(p->p_fd, args.fd);
+ fdpunlock(p->p_fd);
+
+ if (fp == NULL)
return (EBADF);
if (fp->f_type != DTYPE_VNODE)
Index: nfs/nfs_syscalls.c
===================================================================
RCS file: /cvs/src/sys/nfs/nfs_syscalls.c,v
retrieving revision 1.98
diff -u -p -r1.98 nfs_syscalls.c
--- nfs/nfs_syscalls.c 15 Nov 2014 00:03:12 -0000 1.98
+++ nfs/nfs_syscalls.c 12 Apr 2015 01:28:54 -0000
@@ -167,7 +167,7 @@ sys_nfssvc(struct proc *p, void *v, regi
if (error)
return (error);
- error = getsock(p->p_fd, nfsdarg.sock, &fp);
+ error = getsock(p, p->p_fd, nfsdarg.sock, &fp);
if (error)
return (error);
@@ -180,12 +180,12 @@ sys_nfssvc(struct proc *p, void *v, regi
error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen,
MT_SONAME);
if (error) {
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
}
error = nfssvc_addsock(fp, nam);
- FRELE(fp, p);
+ funref(fp, p);
break;
case NFSSVC_NFSD:
error = copyin(SCARG(uap, argp), nsd, sizeof(*nsd));
@@ -479,7 +479,6 @@ nfsrv_zapsock(struct nfssvc_sock *slp)
slp->ns_flag &= ~SLP_ALLFLAGS;
fp = slp->ns_fp;
if (fp) {
- FREF(fp);
slp->ns_fp = NULL;
so = slp->ns_so;
so->so_upcall = NULL;
Index: sys/file.h
===================================================================
RCS file: /cvs/src/sys/sys/file.h,v
retrieving revision 1.34
diff -u -p -r1.34 file.h
--- sys/file.h 18 Nov 2014 15:16:35 -0000 1.34
+++ sys/file.h 12 Apr 2015 01:28:55 -0000
@@ -36,6 +36,7 @@
#ifdef _KERNEL
#include <sys/queue.h>
+#include <sys/atomic.h>
struct proc;
struct uio;
@@ -63,7 +64,7 @@ struct fileops {
*/
struct file {
LIST_ENTRY(file) f_list;/* list of active files */
- short f_flag; /* see fcntl.h */
+ volatile int f_flag; /* see fcntl.h */
#define DTYPE_VNODE 1 /* file */
#define DTYPE_SOCKET 2 /* communications endpoint */
#define DTYPE_PIPE 3 /* pipe */
@@ -71,34 +72,41 @@ struct file {
/* was define DTYPE_CRYPTO 5 */
#define DTYPE_SYSTRACE 6 /* system call tracing */
short f_type; /* descriptor type */
- long f_count; /* reference count */
+ volatile unsigned long f_count; /* reference count */
long f_msgcount; /* references from message queue */
struct ucred *f_cred; /* credentials associated with descriptor */
struct fileops *f_ops;
off_t f_offset;
void *f_data; /* private data */
- int f_iflags; /* internal flags */
+ volatile int f_iflags; /* internal flags */
u_int64_t f_rxfer; /* total number of read transfers */
u_int64_t f_wxfer; /* total number of write transfers */
u_int64_t f_seek; /* total independent seek operations */
u_int64_t f_rbytes; /* total bytes read */
u_int64_t f_wbytes; /* total bytes written */
+ int f_gc_flags; /* garbage collector flags */
};
#define FIF_HASLOCK 0x01 /* descriptor holds advisory lock */
#define FIF_LARVAL 0x02 /* not fully constructed, don't use */
+
+/*
+ * Shouldn't be set in f_iflags
+ */
#define FIF_MARK 0x04 /* mark during gc() */
#define FIF_DEFER 0x08 /* defer for next gc() pass */
+/*
+ * Garbage collector flags
+ */
+#define F_GC_MARK FIF_MARK
+#define F_GC_DEFER FIF_DEFER
+
#define FILE_IS_USABLE(fp) \
(((fp)->f_iflags & FIF_LARVAL) == 0)
-#define FREF(fp) do { (fp)->f_count++; } while (0)
-#define FRELE(fp,p) (--(fp)->f_count == 0 ? fdrop(fp, p) : 0)
-
-#define FILE_SET_MATURE(fp,p) do { \
- (fp)->f_iflags &= ~FIF_LARVAL; \
- FRELE(fp, p); \
+#define FILE_SET_MATURE(_fp, _p) do { \
+ atomic_clearbits_int(&(_fp)->f_iflags, FIF_LARVAL); \
} while (0)
int fdrop(struct file *, struct proc *);
@@ -108,5 +116,47 @@ extern struct filelist filehead; /* head
extern int maxfiles; /* kernel limit on number of open files
*/
extern int nfiles; /* actual number of open files */
extern struct fileops vnops; /* vnode operations for files */
+
+static __inline void
+filelist_lock(void)
+{
+ extern struct rwlock __filelist_lock;
+ rw_enter_write(&__filelist_lock);
+}
+
+static __inline void
+filelist_unlock(void)
+{
+ extern struct rwlock __filelist_lock;
+ rw_exit_write(&__filelist_lock);
+}
+
+static __inline void
+fref(struct file *fp)
+{
+ atomic_inc_long(&fp->f_count);
+}
+
+static __inline int
+fref_try(struct file *fp)
+{
+ unsigned long count;
+
+ do {
+ if ((count = fp->f_count) == 0)
+ return 0;
+ } while (atomic_cas_ulong(&fp->f_count, count, count + 1) != count);
+
+ return 1;
+}
+
+static __inline int
+funref(struct file *fp, struct proc *p)
+{
+ if (atomic_dec_long_nv(&fp->f_count) == 0)
+ return fdrop(fp, p);
+
+ return 0;
+}
#endif /* _KERNEL */
Index: sys/filedesc.h
===================================================================
RCS file: /cvs/src/sys/sys/filedesc.h,v
retrieving revision 1.28
diff -u -p -r1.28 filedesc.h
--- sys/filedesc.h 15 May 2014 03:52:25 -0000 1.28
+++ sys/filedesc.h 12 Apr 2015 01:28:55 -0000
@@ -133,9 +133,10 @@ int fdrelease(struct proc *p, int);
void fdremove(struct filedesc *, int);
void fdcloseexec(struct proc *);
struct file *fd_getfile(struct filedesc *, int fd);
+struct file *fd_getfile_ref(struct filedesc *, int fd, struct proc *p);
int closef(struct file *, struct proc *);
-int getsock(struct filedesc *, int, struct file **);
+int getsock(struct proc *, struct filedesc *, int, struct file **);
#define fdplock(fdp) rw_enter_write(&(fdp)->fd_lock)
#define fdpunlock(fdp) rw_exit_write(&(fdp)->fd_lock)
Index: sys/vnode.h
===================================================================
RCS file: /cvs/src/sys/sys/vnode.h,v
retrieving revision 1.129
diff -u -p -r1.129 vnode.h
--- sys/vnode.h 9 Jan 2015 05:01:57 -0000 1.129
+++ sys/vnode.h 12 Apr 2015 01:28:55 -0000
@@ -650,7 +650,7 @@ void vn_syncer_add_to_worklist(struct vn
/* misc */
int vn_isdisk(struct vnode *, int *);
int softdep_fsync(struct vnode *);
-int getvnode(struct filedesc *, int, struct file **);
+int getvnode(struct proc *p, struct filedesc *, int, struct file **);
/* uvm */
void uvm_vnp_setsize(struct vnode *, off_t);
Index: uvm/uvm_mmap.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_mmap.c,v
retrieving revision 1.107
diff -u -p -r1.107 uvm_mmap.c
--- uvm/uvm_mmap.c 13 Feb 2015 13:35:03 -0000 1.107
+++ uvm/uvm_mmap.c 12 Apr 2015 01:28:57 -0000
@@ -141,7 +141,7 @@ sys_mquery(struct proc *p, void *v, regi
flags |= UVM_FLAG_FIXED;
if (fd >= 0) {
- if ((error = getvnode(p->p_fd, fd, &fp)) != 0)
+ if ((error = getvnode(p, p->p_fd, fd, &fp)) != 0)
return (error);
uobj = &((struct vnode *)fp->f_data)->v_uvm->u_obj;
uoff = SCARG(uap, pos);
@@ -160,7 +160,7 @@ sys_mquery(struct proc *p, void *v, regi
*retval = (register_t)(vaddr);
if (fp != NULL)
- FRELE(fp, p);
+ funref(fp, p);
return (error);
}
@@ -383,13 +383,11 @@ sys_mmap(struct proc *p, void *v, regist
/* check for file mappings (i.e. not anonymous) and verify file. */
if ((flags & MAP_ANON) == 0) {
KERNEL_LOCK();
- if ((fp = fd_getfile(fdp, fd)) == NULL) {
+ if ((fp = fd_getfile_ref(fdp, fd, p)) == NULL) {
KERNEL_UNLOCK();
return (EBADF);
}
- FREF(fp);
-
if (fp->f_type != DTYPE_VNODE) {
error = ENODEV; /* only mmap vnodes! */
goto out;
@@ -410,7 +408,7 @@ sys_mmap(struct proc *p, void *v, regist
/* special case: catch SunOS style /dev/zero */
if (vp->v_type == VCHR && iszerodev(vp->v_rdev)) {
flags |= MAP_ANON;
- FRELE(fp, p);
+ funref(fp, p);
fp = NULL;
/* XXX */
KERNEL_UNLOCK();
@@ -519,7 +517,7 @@ is_anon: /* label for SunOS style /dev/z
out:
if (fp) {
- FRELE(fp, p);
+ funref(fp, p);
KERNEL_UNLOCK();
}
return (error);