- Change the linux_[gs]et_os{name, release, s_version}() functions to

take a thread instead of a proc for their first argument.
- Add a mutex to protect the system-wide Linux osname, osrelease, and
  oss_version variables.
- Change linux_get_prison() to take a thread instead of a proc for its
  first argument and to use td_ucred rather than p_ucred.  This is ok
  because a thread's prison does not change even though it's ucred might.
- Also, change linux_get_prison() to return a struct prison * instead of
  a struct linux_prison * since it returns with the struct prison locked
  and this makes it easier to safely unlock the prison when we are done
  messing with it.
This commit is contained in:
jhb 2003-03-13 22:45:43 +00:00
parent a9bf9cd835
commit bd2a1c12dc
5 changed files with 109 additions and 115 deletions

View File

@ -449,8 +449,8 @@ linprocfs_doversion(PFS_FILL_ARGS)
char osname[LINUX_MAX_UTSNAME];
char osrelease[LINUX_MAX_UTSNAME];
linux_get_osname(td->td_proc, osname);
linux_get_osrelease(td->td_proc, osrelease);
linux_get_osname(td, osname);
linux_get_osrelease(td, osrelease);
sbuf_printf(sb,
"%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"

View File

@ -1596,7 +1596,7 @@ linux_ioctl_sound(struct thread *td, struct linux_ioctl_args *args)
return (ioctl(td, (struct ioctl_args *)args));
case LINUX_OSS_GETVERSION: {
int version = linux_get_oss_version(td->td_proc);
int version = linux_get_oss_version(td);
return (copyout(&version, (void *)args->arg, sizeof(int)));
}

View File

@ -50,6 +50,9 @@ struct linux_prison {
SYSCTL_NODE(_compat, OID_AUTO, linux, CTLFLAG_RW, 0,
"Linux mode");
static struct mtx osname_lock;
MTX_SYSINIT(linux_osname, &osname_lock, "linux osname", MTX_DEF);
static char linux_osname[LINUX_MAX_UTSNAME] = "Linux";
static int
@ -58,11 +61,11 @@ linux_sysctl_osname(SYSCTL_HANDLER_ARGS)
char osname[LINUX_MAX_UTSNAME];
int error;
linux_get_osname(req->td->td_proc, osname);
linux_get_osname(req->td, osname);
error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req);
if (error || req->newptr == NULL)
return (error);
error = linux_set_osname(req->td->td_proc, osname);
error = linux_set_osname(req->td, osname);
return (error);
}
@ -79,11 +82,11 @@ linux_sysctl_osrelease(SYSCTL_HANDLER_ARGS)
char osrelease[LINUX_MAX_UTSNAME];
int error;
linux_get_osrelease(req->td->td_proc, osrelease);
linux_get_osrelease(req->td, osrelease);
error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req);
if (error || req->newptr == NULL)
return (error);
error = linux_set_osrelease(req->td->td_proc, osrelease);
error = linux_set_osrelease(req->td, osrelease);
return (error);
}
@ -100,11 +103,11 @@ linux_sysctl_oss_version(SYSCTL_HANDLER_ARGS)
int oss_version;
int error;
oss_version = linux_get_oss_version(req->td->td_proc);
oss_version = linux_get_oss_version(req->td);
error = sysctl_handle_int(oidp, &oss_version, 0, req);
if (error || req->newptr == NULL)
return (error);
error = linux_set_oss_version(req->td->td_proc, oss_version);
error = linux_set_oss_version(req->td, oss_version);
return (error);
}
@ -116,177 +119,168 @@ SYSCTL_PROC(_compat_linux, OID_AUTO, oss_version,
/*
* Returns holding the prison mutex if return non-NULL.
*/
static struct linux_prison *
linux_get_prison(struct proc *p)
static struct prison *
linux_get_prison(struct thread *td)
{
register struct prison *pr;
register struct linux_prison *lpr;
if (!jailed(p->p_ucred))
KASSERT(td == curthread, ("linux_get_prison() called on !curthread"));
if (!jailed(td->td_ucred))
return (NULL);
pr = p->p_ucred->cr_prison;
/*
* Rather than hold the prison mutex during allocation, check to
* see if we need to allocate while holding the mutex, release it,
* allocate, then once we've allocated the memory, check again to
* see if it's still needed, and set if appropriate. If it's not,
* we release the mutex again to FREE(), and grab it again so as
* to release holding the lock.
*/
pr = td->td_ucred->cr_prison;
mtx_lock(&pr->pr_mtx);
if (pr->pr_linux == NULL) {
/*
* If we don't have a linux prison structure yet, allocate
* one. We have to handle the race where another thread
* could be adding a linux prison to this process already.
*/
mtx_unlock(&pr->pr_mtx);
MALLOC(lpr, struct linux_prison *, sizeof *lpr,
M_PRISON, M_WAITOK|M_ZERO);
lpr = malloc(sizeof(struct linux_prison), M_PRISON,
M_WAITOK | M_ZERO);
mtx_lock(&pr->pr_mtx);
if (pr->pr_linux == NULL) {
if (pr->pr_linux == NULL)
pr->pr_linux = lpr;
} else {
mtx_unlock(&pr->pr_mtx);
FREE(lpr, M_PRISON);
mtx_lock(&pr->pr_mtx);
}
else
free(lpr, M_PRISON);
}
return (pr->pr_linux);
return (pr);
}
void
linux_get_osname(p, dst)
struct proc *p;
char *dst;
linux_get_osname(struct thread *td, char *dst)
{
register struct prison *pr;
register struct linux_prison *lpr;
if (p->p_ucred->cr_prison == NULL) {
bcopy(linux_osname, dst, LINUX_MAX_UTSNAME);
return;
}
pr = p->p_ucred->cr_prison;
mtx_lock(&pr->pr_mtx);
if (pr->pr_linux != NULL) {
lpr = (struct linux_prison *)pr->pr_linux;
if (lpr->pr_osname[0]) {
bcopy(lpr->pr_osname, dst, LINUX_MAX_UTSNAME);
mtx_unlock(&pr->pr_mtx);
return;
pr = td->td_ucred->cr_prison;
if (pr != NULL) {
mtx_lock(&pr->pr_mtx);
if (pr->pr_linux != NULL) {
lpr = (struct linux_prison *)pr->pr_linux;
if (lpr->pr_osname[0]) {
bcopy(lpr->pr_osname, dst, LINUX_MAX_UTSNAME);
mtx_unlock(&pr->pr_mtx);
return;
}
}
mtx_unlock(&pr->pr_mtx);
}
mtx_unlock(&pr->pr_mtx);
mtx_lock(&osname_lock);
bcopy(linux_osname, dst, LINUX_MAX_UTSNAME);
mtx_unlock(&osname_lock);
}
int
linux_set_osname(p, osname)
struct proc *p;
char *osname;
linux_set_osname(struct thread *td, char *osname)
{
register struct linux_prison *lpr;
struct prison *pr;
struct linux_prison *lpr;
lpr = linux_get_prison(p);
if (lpr != NULL) {
pr = linux_get_prison(td);
if (pr != NULL) {
lpr = (struct linux_prison *)pr->pr_linux;
strcpy(lpr->pr_osname, osname);
mtx_unlock(&p->p_ucred->cr_prison->pr_mtx);
mtx_unlock(&pr->pr_mtx);
} else {
mtx_lock(&osname_lock);
strcpy(linux_osname, osname);
mtx_unlock(&osname_lock);
}
return (0);
}
void
linux_get_osrelease(p, dst)
struct proc *p;
char *dst;
linux_get_osrelease(struct thread *td, char *dst)
{
register struct prison *pr;
struct linux_prison *lpr;
if (p->p_ucred->cr_prison == NULL) {
bcopy(linux_osrelease, dst, LINUX_MAX_UTSNAME);
return;
}
pr = p->p_ucred->cr_prison;
mtx_lock(&pr->pr_mtx);
if (pr->pr_linux != NULL) {
lpr = (struct linux_prison *) pr->pr_linux;
if (lpr->pr_osrelease[0]) {
bcopy(lpr->pr_osrelease, dst, LINUX_MAX_UTSNAME);
mtx_unlock(&pr->pr_mtx);
return;
pr = td->td_ucred->cr_prison;
if (pr != NULL) {
mtx_lock(&pr->pr_mtx);
if (pr->pr_linux != NULL) {
lpr = (struct linux_prison *)pr->pr_linux;
if (lpr->pr_osrelease[0]) {
bcopy(lpr->pr_osrelease, dst,
LINUX_MAX_UTSNAME);
mtx_unlock(&pr->pr_mtx);
return;
}
}
mtx_unlock(&pr->pr_mtx);
}
mtx_unlock(&pr->pr_mtx);
mtx_lock(&osname_lock);
bcopy(linux_osrelease, dst, LINUX_MAX_UTSNAME);
mtx_unlock(&osname_lock);
}
int
linux_set_osrelease(p, osrelease)
struct proc *p;
char *osrelease;
linux_set_osrelease(struct thread *td, char *osrelease)
{
register struct linux_prison *lpr;
struct prison *pr;
struct linux_prison *lpr;
lpr = linux_get_prison(p);
if (lpr != NULL) {
pr = linux_get_prison(td);
if (pr != NULL) {
lpr = (struct linux_prison *)pr->pr_linux;
strcpy(lpr->pr_osrelease, osrelease);
mtx_unlock(&p->p_ucred->cr_prison->pr_mtx);
mtx_unlock(&pr->pr_mtx);
} else {
mtx_lock(&osname_lock);
strcpy(linux_osrelease, osrelease);
mtx_unlock(&osname_lock);
}
return (0);
}
int
linux_get_oss_version(p)
struct proc *p;
linux_get_oss_version(struct thread *td)
{
register struct prison *pr;
register struct linux_prison *lpr;
int version;
if (p->p_ucred->cr_prison == NULL)
return (linux_oss_version);
pr = p->p_ucred->cr_prison;
mtx_lock(&pr->pr_mtx);
if (pr->pr_linux != NULL) {
lpr = (struct linux_prison *) pr->pr_linux;
if (lpr->pr_oss_version) {
version = lpr->pr_oss_version;
} else {
version = linux_oss_version;
pr = td->td_ucred->cr_prison;
if (pr != NULL) {
mtx_lock(&pr->pr_mtx);
if (pr->pr_linux != NULL) {
lpr = (struct linux_prison *)pr->pr_linux;
if (lpr->pr_oss_version) {
version = lpr->pr_oss_version;
mtx_unlock(&pr->pr_mtx);
return (version);
}
}
} else {
version = linux_oss_version;
mtx_unlock(&pr->pr_mtx);
}
mtx_unlock(&pr->pr_mtx);
mtx_lock(&osname_lock);
version = linux_oss_version;
mtx_unlock(&osname_lock);
return (version);
}
int
linux_set_oss_version(p, oss_version)
struct proc *p;
int oss_version;
linux_set_oss_version(struct thread *td, int oss_version)
{
register struct linux_prison *lpr;
struct prison *pr;
struct linux_prison *lpr;
lpr = linux_get_prison(p);
if (lpr != NULL) {
pr = linux_get_prison(td);
if (pr != NULL) {
lpr = (struct linux_prison *)pr->pr_linux;
lpr->pr_oss_version = oss_version;
mtx_unlock(&p->p_ucred->cr_prison->pr_mtx);
mtx_unlock(&pr->pr_mtx);
} else {
mtx_lock(&osname_lock);
linux_oss_version = oss_version;
mtx_unlock(&osname_lock);
}
return (0);

View File

@ -31,13 +31,13 @@
#ifndef _LINUX_MIB_H_
#define _LINUX_MIB_H_
void linux_get_osname(struct proc *p, char *dst);
int linux_set_osname(struct proc *p, char *osname);
void linux_get_osname(struct thread *td, char *dst);
int linux_set_osname(struct thread *td, char *osname);
void linux_get_osrelease(struct proc *p, char *dst);
int linux_set_osrelease(struct proc *p, char *osrelease);
void linux_get_osrelease(struct thread *td, char *dst);
int linux_set_osrelease(struct thread *td, char *osrelease);
int linux_get_oss_version(struct proc *p);
int linux_set_oss_version(struct proc *p, int oss_version);
int linux_get_oss_version(struct thread *td);
int linux_set_oss_version(struct thread *td, int oss_version);
#endif /* _LINUX_MIB_H_ */

View File

@ -697,8 +697,8 @@ linux_newuname(struct thread *td, struct linux_newuname_args *args)
printf(ARGS(newuname, "*"));
#endif
linux_get_osname(td->td_proc, osname);
linux_get_osrelease(td->td_proc, osrelease);
linux_get_osname(td, osname);
linux_get_osrelease(td, osrelease);
bzero(&utsname, sizeof(utsname));
strlcpy(utsname.sysname, osname, LINUX_MAX_UTSNAME);