summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/kern/kern_descrip.c163
1 files changed, 99 insertions, 64 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 4dfb005..29a3f9a 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -341,6 +341,18 @@ fcntl(struct thread *td, struct fcntl_args *uap)
return (error);
}
+static inline struct file *
+fdtofp(int fd, struct filedesc *fdp)
+{
+ struct file *fp;
+
+ FILEDESC_LOCK_ASSERT(fdp);
+ if ((unsigned)fd >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[fd]) == NULL)
+ return (NULL);
+ return (fp);
+}
+
int
kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
{
@@ -352,46 +364,23 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
struct vnode *vp;
u_int newmin;
int error, flg, tmp;
- int giant_locked;
-
- /*
- * XXXRW: Some fcntl() calls require Giant -- others don't. Try to
- * avoid grabbing Giant for calls we know don't need it.
- */
- switch (cmd) {
- case F_DUPFD:
- case F_GETFD:
- case F_SETFD:
- case F_GETFL:
- giant_locked = 0;
- break;
-
- default:
- giant_locked = 1;
- mtx_lock(&Giant);
- }
+ int vfslocked;
+ vfslocked = 0;
error = 0;
flg = F_POSIX;
p = td->td_proc;
fdp = p->p_fd;
- /*
- * XXXRW: It could be an exclusive lock is not [always] needed here.
- */
- FILEDESC_XLOCK(fdp);
- if ((unsigned)fd >= fdp->fd_nfiles ||
- (fp = fdp->fd_ofiles[fd]) == NULL) {
- FILEDESC_XUNLOCK(fdp);
- error = EBADF;
- goto done2;
- }
- pop = &fdp->fd_ofileflags[fd];
-
switch (cmd) {
case F_DUPFD:
- /* mtx_assert(&Giant, MA_NOTOWNED); */
- FILEDESC_XUNLOCK(fdp);
+ FILEDESC_SLOCK(fdp);
+ if ((fp = fdtofp(fd, fdp)) == NULL) {
+ FILEDESC_SUNLOCK(fdp);
+ error = EBADF;
+ break;
+ }
+ FILEDESC_SUNLOCK(fdp);
newmin = arg;
PROC_LOCK(p);
if (newmin >= lim_cur(p, RLIMIT_NOFILE) ||
@@ -405,34 +394,56 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
break;
case F_GETFD:
- /* mtx_assert(&Giant, MA_NOTOWNED); */
+ FILEDESC_SLOCK(fdp);
+ if ((fp = fdtofp(fd, fdp)) == NULL) {
+ FILEDESC_SUNLOCK(fdp);
+ error = EBADF;
+ break;
+ }
+ pop = &fdp->fd_ofileflags[fd];
td->td_retval[0] = (*pop & UF_EXCLOSE) ? FD_CLOEXEC : 0;
- FILEDESC_XUNLOCK(fdp);
+ FILEDESC_SUNLOCK(fdp);
break;
case F_SETFD:
- /* mtx_assert(&Giant, MA_NOTOWNED); */
+ FILEDESC_XLOCK(fdp);
+ if ((fp = fdtofp(fd, fdp)) == NULL) {
+ FILEDESC_XUNLOCK(fdp);
+ error = EBADF;
+ break;
+ }
+ pop = &fdp->fd_ofileflags[fd];
*pop = (*pop &~ UF_EXCLOSE) |
(arg & FD_CLOEXEC ? UF_EXCLOSE : 0);
FILEDESC_XUNLOCK(fdp);
break;
case F_GETFL:
- /* mtx_assert(&Giant, MA_NOTOWNED); */
+ FILEDESC_SLOCK(fdp);
+ if ((fp = fdtofp(fd, fdp)) == NULL) {
+ FILEDESC_SUNLOCK(fdp);
+ error = EBADF;
+ break;
+ }
FILE_LOCK(fp);
td->td_retval[0] = OFLAGS(fp->f_flag);
FILE_UNLOCK(fp);
- FILEDESC_XUNLOCK(fdp);
+ FILEDESC_SUNLOCK(fdp);
break;
case F_SETFL:
- mtx_assert(&Giant, MA_OWNED);
+ FILEDESC_SLOCK(fdp);
+ if ((fp = fdtofp(fd, fdp)) == NULL) {
+ FILEDESC_SUNLOCK(fdp);
+ error = EBADF;
+ break;
+ }
FILE_LOCK(fp);
fhold_locked(fp);
fp->f_flag &= ~FCNTLFLAGS;
fp->f_flag |= FFLAGS(arg & ~O_ACCMODE) & FCNTLFLAGS;
FILE_UNLOCK(fp);
- FILEDESC_XUNLOCK(fdp);
+ FILEDESC_SUNLOCK(fdp);
tmp = fp->f_flag & FNONBLOCK;
error = fo_ioctl(fp, FIONBIO, &tmp, td->td_ucred, td);
if (error) {
@@ -454,9 +465,14 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
break;
case F_GETOWN:
- mtx_assert(&Giant, MA_OWNED);
+ FILEDESC_SLOCK(fdp);
+ if ((fp = fdtofp(fd, fdp)) == NULL) {
+ FILEDESC_SUNLOCK(fdp);
+ error = EBADF;
+ break;
+ }
fhold(fp);
- FILEDESC_XUNLOCK(fdp);
+ FILEDESC_SUNLOCK(fdp);
error = fo_ioctl(fp, FIOGETOWN, &tmp, td->td_ucred, td);
if (error == 0)
td->td_retval[0] = tmp;
@@ -464,33 +480,41 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
break;
case F_SETOWN:
- mtx_assert(&Giant, MA_OWNED);
+ FILEDESC_SLOCK(fdp);
+ if ((fp = fdtofp(fd, fdp)) == NULL) {
+ FILEDESC_SUNLOCK(fdp);
+ error = EBADF;
+ break;
+ }
fhold(fp);
- FILEDESC_XUNLOCK(fdp);
+ FILEDESC_SUNLOCK(fdp);
tmp = arg;
error = fo_ioctl(fp, FIOSETOWN, &tmp, td->td_ucred, td);
fdrop(fp, td);
break;
case F_SETLKW:
- mtx_assert(&Giant, MA_OWNED);
flg |= F_WAIT;
/* FALLTHROUGH F_SETLK */
case F_SETLK:
- mtx_assert(&Giant, MA_OWNED);
+ FILEDESC_SLOCK(fdp);
+ if ((fp = fdtofp(fd, fdp)) == NULL) {
+ FILEDESC_SUNLOCK(fdp);
+ error = EBADF;
+ break;
+ }
if (fp->f_type != DTYPE_VNODE) {
- FILEDESC_XUNLOCK(fdp);
+ FILEDESC_SUNLOCK(fdp);
error = EBADF;
break;
}
-
flp = (struct flock *)arg;
if (flp->l_whence == SEEK_CUR) {
if (fp->f_offset < 0 ||
(flp->l_start > 0 &&
fp->f_offset > OFF_MAX - flp->l_start)) {
- FILEDESC_XUNLOCK(fdp);
+ FILEDESC_SUNLOCK(fdp);
error = EOVERFLOW;
break;
}
@@ -501,9 +525,9 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
* VOP_ADVLOCK() may block.
*/
fhold(fp);
- FILEDESC_XUNLOCK(fdp);
+ FILEDESC_SUNLOCK(fdp);
vp = fp->f_vnode;
-
+ vfslocked = VFS_LOCK_GIANT(vp->v_mount);
switch (flp->l_type) {
case F_RDLCK:
if ((fp->f_flag & FREAD) == 0) {
@@ -535,33 +559,43 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
error = EINVAL;
break;
}
+ VFS_UNLOCK_GIANT(vfslocked);
+ vfslocked = 0;
/* Check for race with close */
- FILEDESC_XLOCK(fdp);
+ FILEDESC_SLOCK(fdp);
if ((unsigned) fd >= fdp->fd_nfiles ||
fp != fdp->fd_ofiles[fd]) {
- FILEDESC_XUNLOCK(fdp);
+ FILEDESC_SUNLOCK(fdp);
flp->l_whence = SEEK_SET;
flp->l_start = 0;
flp->l_len = 0;
flp->l_type = F_UNLCK;
+ vfslocked = VFS_LOCK_GIANT(vp->v_mount);
(void) VOP_ADVLOCK(vp, (caddr_t)p->p_leader,
F_UNLCK, flp, F_POSIX);
+ VFS_UNLOCK_GIANT(vfslocked);
+ vfslocked = 0;
} else
- FILEDESC_XUNLOCK(fdp);
+ FILEDESC_SUNLOCK(fdp);
fdrop(fp, td);
break;
case F_GETLK:
- mtx_assert(&Giant, MA_OWNED);
+ FILEDESC_SLOCK(fdp);
+ if ((fp = fdtofp(fd, fdp)) == NULL) {
+ FILEDESC_SUNLOCK(fdp);
+ error = EBADF;
+ break;
+ }
if (fp->f_type != DTYPE_VNODE) {
- FILEDESC_XUNLOCK(fdp);
+ FILEDESC_SUNLOCK(fdp);
error = EBADF;
break;
}
flp = (struct flock *)arg;
if (flp->l_type != F_RDLCK && flp->l_type != F_WRLCK &&
flp->l_type != F_UNLCK) {
- FILEDESC_XUNLOCK(fdp);
+ FILEDESC_SUNLOCK(fdp);
error = EINVAL;
break;
}
@@ -570,7 +604,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
fp->f_offset > OFF_MAX - flp->l_start) ||
(flp->l_start < 0 &&
fp->f_offset < OFF_MIN - flp->l_start)) {
- FILEDESC_XUNLOCK(fdp);
+ FILEDESC_SUNLOCK(fdp);
error = EOVERFLOW;
break;
}
@@ -580,20 +614,20 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
* VOP_ADVLOCK() may block.
*/
fhold(fp);
- FILEDESC_XUNLOCK(fdp);
+ FILEDESC_SUNLOCK(fdp);
vp = fp->f_vnode;
+ vfslocked = VFS_LOCK_GIANT(vp->v_mount);
error = VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_GETLK, flp,
F_POSIX);
+ VFS_UNLOCK_GIANT(vfslocked);
+ vfslocked = 0;
fdrop(fp, td);
break;
default:
- FILEDESC_XUNLOCK(fdp);
error = EINVAL;
break;
}
-done2:
- if (giant_locked)
- mtx_unlock(&Giant);
+ VFS_UNLOCK_GIANT(vfslocked);
return (error);
}
@@ -2174,6 +2208,7 @@ flock(struct thread *td, struct flock_args *uap)
struct file *fp;
struct vnode *vp;
struct flock lf;
+ int vfslocked;
int error;
if ((error = fget(td, uap->fd, &fp)) != 0)
@@ -2183,8 +2218,8 @@ flock(struct thread *td, struct flock_args *uap)
return (EOPNOTSUPP);
}
- mtx_lock(&Giant);
vp = fp->f_vnode;
+ vfslocked = VFS_LOCK_GIANT(vp->v_mount);
lf.l_whence = SEEK_SET;
lf.l_start = 0;
lf.l_len = 0;
@@ -2211,7 +2246,7 @@ flock(struct thread *td, struct flock_args *uap)
(uap->how & LOCK_NB) ? F_FLOCK : F_FLOCK | F_WAIT);
done2:
fdrop(fp, td);
- mtx_unlock(&Giant);
+ VFS_UNLOCK_GIANT(vfslocked);
return (error);
}
/*
OpenPOWER on IntegriCloud