- 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:
parent
a9bf9cd835
commit
bd2a1c12dc
@ -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__ ")"
|
||||
|
@ -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)));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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_ */
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user