- Conditionalize Giant around VFS operations for ALQ, ktrace, and

generating a coredump as the result of a signal.
- Fix a bug where we could leak a Giant lock if vn_start_write() failed
  in coredump().

Reported by:	jmg (2)
This commit is contained in:
John Baldwin 2006-03-28 21:30:22 +00:00
parent 11178ee4c1
commit 33f19bee6f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=157233
3 changed files with 35 additions and 32 deletions

View File

@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <sys/kthread.h>
#include <sys/lock.h>
#include <sys/mac.h>
#include <sys/mount.h>
#include <sys/mutex.h>
#include <sys/namei.h>
#include <sys/proc.h>
@ -172,8 +173,6 @@ ald_daemon(void)
int needwakeup;
struct alq *alq;
mtx_lock(&Giant);
ald_thread = FIRST_THREAD_IN_PROC(ald_proc);
EVENTHANDLER_REGISTER(shutdown_pre_sync, ald_shutdown, NULL,
@ -250,6 +249,7 @@ alq_doio(struct alq *alq)
struct ale *alstart;
int totlen;
int iov;
int vfslocked;
vp = alq->aq_vp;
td = curthread;
@ -291,6 +291,7 @@ alq_doio(struct alq *alq)
/*
* Do all of the junk required to write now.
*/
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
vn_start_write(vp, &mp, V_WAIT);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
VOP_LEASE(vp, td, alq->aq_cred, LEASE_WRITE);
@ -303,6 +304,7 @@ alq_doio(struct alq *alq)
VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, alq->aq_cred);
VOP_UNLOCK(vp, 0, td);
vn_finished_write(mp);
VFS_UNLOCK_GIANT(vfslocked);
ALQ_LOCK(alq);
alq->aq_flags &= ~AQ_FLUSHING;
@ -345,21 +347,23 @@ alq_open(struct alq **alqp, const char *file, struct ucred *cred, int cmode,
char *bufp;
int flags;
int error;
int i;
int i, vfslocked;
*alqp = NULL;
td = curthread;
NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, file, td);
NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE, UIO_SYSSPACE, file, td);
flags = FWRITE | O_NOFOLLOW | O_CREAT;
error = vn_open_cred(&nd, &flags, cmode, cred, -1);
if (error)
return (error);
vfslocked = NDHASGIANT(&nd);
NDFREE(&nd, NDF_ONLY_PNBUF);
/* We just unlock so we hold a reference */
VOP_UNLOCK(nd.ni_vp, 0, td);
VFS_UNLOCK_GIANT(vfslocked);
alq = malloc(sizeof(*alq), M_ALD, M_WAITOK|M_ZERO);
alq->aq_entbuf = malloc(count * size, M_ALD, M_WAITOK|M_ZERO);

View File

@ -598,7 +598,7 @@ ktrace(td, uap)
int ops = KTROP(uap->ops);
int descend = uap->ops & KTRFLAG_DESCEND;
int nfound, ret = 0;
int flags, error = 0;
int flags, error = 0, vfslocked;
struct nameidata nd;
struct ucred *cred;
@ -613,25 +613,25 @@ ktrace(td, uap)
/*
* an operation which requires a file argument.
*/
NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->fname, td);
NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE, UIO_USERSPACE,
uap->fname, td);
flags = FREAD | FWRITE | O_NOFOLLOW;
mtx_lock(&Giant);
error = vn_open(&nd, &flags, 0, -1);
if (error) {
mtx_unlock(&Giant);
ktrace_exit(td);
return (error);
}
vfslocked = NDHASGIANT(&nd);
NDFREE(&nd, NDF_ONLY_PNBUF);
vp = nd.ni_vp;
VOP_UNLOCK(vp, 0, td);
if (vp->v_type != VREG) {
(void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td);
mtx_unlock(&Giant);
VFS_UNLOCK_GIANT(vfslocked);
ktrace_exit(td);
return (EACCES);
}
mtx_unlock(&Giant);
VFS_UNLOCK_GIANT(vfslocked);
}
/*
* Clear all uses of the tracefile.
@ -649,10 +649,10 @@ ktrace(td, uap)
p->p_traceflag = 0;
mtx_unlock(&ktrace_mtx);
PROC_UNLOCK(p);
mtx_lock(&Giant);
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
(void) vn_close(vp, FREAD|FWRITE,
cred, td);
mtx_unlock(&Giant);
VFS_UNLOCK_GIANT(vfslocked);
crfree(cred);
} else {
PROC_UNLOCK(p);
@ -732,9 +732,9 @@ ktrace(td, uap)
error = EPERM;
done:
if (vp != NULL) {
mtx_lock(&Giant);
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
(void) vn_close(vp, FWRITE, td->td_ucred, td);
mtx_unlock(&Giant);
VFS_UNLOCK_GIANT(vfslocked);
}
ktrace_exit(td);
return (error);
@ -888,7 +888,7 @@ ktr_writerequest(struct thread *td, struct ktr_request *req)
struct iovec aiov[3];
struct mount *mp;
int datalen, buflen, vrele_count;
int error;
int error, vfslocked;
/*
* We hold the vnode and credential for use in I/O in case ktrace is
@ -944,7 +944,7 @@ ktr_writerequest(struct thread *td, struct ktr_request *req)
auio.uio_iovcnt++;
}
mtx_lock(&Giant);
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
vn_start_write(vp, &mp, V_WAIT);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
(void)VOP_LEASE(vp, td, cred, LEASE_WRITE);
@ -956,7 +956,7 @@ ktr_writerequest(struct thread *td, struct ktr_request *req)
VOP_UNLOCK(vp, 0, td);
vn_finished_write(mp);
vrele(vp);
mtx_unlock(&Giant);
VFS_UNLOCK_GIANT(vfslocked);
if (!error)
return;
/*
@ -1000,10 +1000,10 @@ ktr_writerequest(struct thread *td, struct ktr_request *req)
* them but not yet committed them, as those are per-thread. The
* thread will have to clear it itself on system call return.
*/
mtx_lock(&Giant);
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
while (vrele_count-- > 0)
vrele(vp);
mtx_unlock(&Giant);
VFS_UNLOCK_GIANT(vfslocked);
}
/*

View File

@ -3062,6 +3062,7 @@ coredump(struct thread *td)
struct mount *mp;
char *name; /* name of corefile */
off_t limit;
int vfslocked;
PROC_LOCK_ASSERT(p, MA_OWNED);
MPASS((p->p_flag & P_HADTHREADS) == 0 || p->p_singlethread == td);
@ -3085,21 +3086,17 @@ coredump(struct thread *td)
if (limit == 0)
return (EFBIG);
mtx_lock(&Giant);
restart:
name = expand_name(p->p_comm, td->td_ucred->cr_uid, p->p_pid);
if (name == NULL) {
mtx_unlock(&Giant);
if (name == NULL)
return (EINVAL);
}
NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, name, td); /* XXXKSE */
NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE, UIO_SYSSPACE, name, td);
flags = O_CREAT | FWRITE | O_NOFOLLOW;
error = vn_open(&nd, &flags, S_IRUSR | S_IWUSR, -1);
free(name, M_TEMP);
if (error) {
mtx_unlock(&Giant);
if (error)
return (error);
}
vfslocked = NDHASGIANT(&nd);
NDFREE(&nd, NDF_ONLY_PNBUF);
vp = nd.ni_vp;
@ -3108,7 +3105,7 @@ coredump(struct thread *td)
VOP_GETATTR(vp, &vattr, cred, td) || vattr.va_nlink != 1) {
VOP_UNLOCK(vp, 0, td);
error = EFAULT;
goto out;
goto close;
}
VOP_UNLOCK(vp, 0, td);
@ -3123,9 +3120,10 @@ coredump(struct thread *td)
if (locked)
VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_FLOCK);
if ((error = vn_close(vp, FWRITE, cred, td)) != 0)
return (error);
goto out;
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
return (error);
goto out;
VFS_UNLOCK_GIANT(vfslocked);
goto restart;
}
@ -3150,11 +3148,12 @@ coredump(struct thread *td)
VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_FLOCK);
}
vn_finished_write(mp);
out:
close:
error1 = vn_close(vp, FWRITE, cred, td);
mtx_unlock(&Giant);
if (error == 0)
error = error1;
out:
VFS_UNLOCK_GIANT(vfslocked);
return (error);
}