summaryrefslogtreecommitdiffstats
path: root/sys/compat/linux/linux_mib.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2003-03-13 22:45:43 +0000
committerjhb <jhb@FreeBSD.org>2003-03-13 22:45:43 +0000
commit34c953a7727e28704114630ad33222b9800cb199 (patch)
tree3d9830747caf0da273c7bb49c9d4666c52ee45ce /sys/compat/linux/linux_mib.c
parent129be1daea4bcf956a4f29af69b443113059a502 (diff)
downloadFreeBSD-src-34c953a7727e28704114630ad33222b9800cb199.zip
FreeBSD-src-34c953a7727e28704114630ad33222b9800cb199.tar.gz
- 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.
Diffstat (limited to 'sys/compat/linux/linux_mib.c')
-rw-r--r--sys/compat/linux/linux_mib.c202
1 files changed, 98 insertions, 104 deletions
diff --git a/sys/compat/linux/linux_mib.c b/sys/compat/linux/linux_mib.c
index d9cdd07..53fee72 100644
--- a/sys/compat/linux/linux_mib.c
+++ b/sys/compat/linux/linux_mib.c
@@ -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);
OpenPOWER on IntegriCloud