7a238fcba0
Fix exit race by splitting the nsproxy putting into two pieces. First piece reduces the nsproxy refcount. If we dropped the last reference, then it puts the mnt_ns, and returns the nsproxy as a hint to the caller. Else it returns NULL. The second piece of exiting task namespaces sets tsk->nsproxy to NULL, and drops the references to other namespaces and frees the nsproxy only if an nsproxy was passed in. A little awkward and should probably be reworked, but hopefully it fixes the NFS oops. Signed-off-by: Serge E. Hallyn <serue@us.ibm.com> Cc: Herbert Poetzl <herbert@13thfloor.at> Cc: Oleg Nesterov <oleg@tv-sign.ru> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Cc: Cedric Le Goater <clg@fr.ibm.com> Cc: Daniel Hokka Zakrisson <daniel@hozac.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
65 lines
1.6 KiB
C
65 lines
1.6 KiB
C
#ifndef _LINUX_NSPROXY_H
|
|
#define _LINUX_NSPROXY_H
|
|
|
|
#include <linux/spinlock.h>
|
|
#include <linux/sched.h>
|
|
|
|
struct mnt_namespace;
|
|
struct uts_namespace;
|
|
struct ipc_namespace;
|
|
struct pid_namespace;
|
|
|
|
/*
|
|
* A structure to contain pointers to all per-process
|
|
* namespaces - fs (mount), uts, network, sysvipc, etc.
|
|
*
|
|
* 'count' is the number of tasks holding a reference.
|
|
* The count for each namespace, then, will be the number
|
|
* of nsproxies pointing to it, not the number of tasks.
|
|
*
|
|
* The nsproxy is shared by tasks which share all namespaces.
|
|
* As soon as a single namespace is cloned or unshared, the
|
|
* nsproxy is copied.
|
|
*/
|
|
struct nsproxy {
|
|
atomic_t count;
|
|
spinlock_t nslock;
|
|
struct uts_namespace *uts_ns;
|
|
struct ipc_namespace *ipc_ns;
|
|
struct mnt_namespace *mnt_ns;
|
|
struct pid_namespace *pid_ns;
|
|
};
|
|
extern struct nsproxy init_nsproxy;
|
|
|
|
struct nsproxy *dup_namespaces(struct nsproxy *orig);
|
|
int copy_namespaces(int flags, struct task_struct *tsk);
|
|
void get_task_namespaces(struct task_struct *tsk);
|
|
void free_nsproxy(struct nsproxy *ns);
|
|
struct nsproxy *put_nsproxy(struct nsproxy *ns);
|
|
|
|
static inline void finalize_put_nsproxy(struct nsproxy *ns)
|
|
{
|
|
if (ns)
|
|
free_nsproxy(ns);
|
|
}
|
|
|
|
static inline void put_and_finalize_nsproxy(struct nsproxy *ns)
|
|
{
|
|
finalize_put_nsproxy(put_nsproxy(ns));
|
|
}
|
|
|
|
static inline struct nsproxy *preexit_task_namespaces(struct task_struct *p)
|
|
{
|
|
return put_nsproxy(p->nsproxy);
|
|
}
|
|
|
|
static inline void exit_task_namespaces(struct task_struct *p,
|
|
struct nsproxy *ns)
|
|
{
|
|
task_lock(p);
|
|
p->nsproxy = NULL;
|
|
task_unlock(p);
|
|
finalize_put_nsproxy(ns);
|
|
}
|
|
#endif
|