* V0.09 revert to non RCU for now
* V0.10 and back to working RCU hash
* V0.11 and back to locking again
+ * V0.12 have __create claim() the vxi
*
*/
-#include <linux/config.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/namespace.h>
#include <linux/vserver/legacy.h>
#include <linux/vserver/limit.h>
#include <linux/vserver/debug.h>
+#include <linux/vserver/limit_int.h>
#include <linux/vs_context.h>
+#include <linux/vs_limit.h>
#include <linux/vserver/context_cmd.h>
#include <linux/err.h>
memset (new, 0, sizeof(struct vx_info));
new->vx_id = xid;
- // INIT_RCU_HEAD(&new->vx_rcu);
INIT_HLIST_NODE(&new->vx_hlist);
atomic_set(&new->vx_usecnt, 0);
atomic_set(&new->vx_tasks, 0);
new->vx_parent = NULL;
new->vx_state = 0;
- new->vx_lock = SPIN_LOCK_UNLOCKED;
- init_waitqueue_head(&new->vx_exit);
+ init_waitqueue_head(&new->vx_wait);
+
+ /* prepare reaper */
+ get_task_struct(child_reaper);
+ new->vx_reaper = child_reaper;
/* rest of init goes here */
vx_info_init_limit(&new->limit);
vx_info_init_cvirt(&new->cvirt);
vx_info_init_cacct(&new->cacct);
-
- new->vx_flags = VXF_STATE_SETUP|VXF_STATE_INIT;
+ new->vx_flags = VXF_INIT_SET;
new->vx_bcaps = CAP_INIT_EFF_SET;
new->vx_ccaps = 0;
+ new->reboot_cmd = 0;
+ new->exit_code = 0;
+
vxdprintk(VXD_CBIT(xid, 0),
"alloc_vx_info(%d) = %p", xid, new);
vxh_alloc_vx_info(new);
kfree(vxi);
}
-void __shutdown_vx_info(struct vx_info *vxi)
+static void __shutdown_vx_info(struct vx_info *vxi)
{
struct namespace *namespace;
struct fs_struct *fs;
might_sleep();
- vs_context_state(vxi, VS_CONTEXT_DESTROY);
+ vxi->vx_state |= VXS_SHUTDOWN;
+ vs_state_change(vxi, VSC_SHUTDOWN);
namespace = xchg(&vxi->vx_namespace, NULL);
if (namespace)
void free_vx_info(struct vx_info *vxi)
{
/* context shutdown is mandatory */
- // BUG_ON(vxi->vx_state != VXS_SHUTDOWN);
+ BUG_ON(!vx_info_state(vxi, VXS_SHUTDOWN));
BUG_ON(atomic_read(&vxi->vx_usecnt));
BUG_ON(atomic_read(&vxi->vx_tasks));
BUG_ON(vx_info_state(vxi, VXS_HASHED));
- // BUG_ON(!vx_state(vxi, VXS_DEFUNCT));
BUG_ON(vxi->vx_namespace);
BUG_ON(vxi->vx_fs);
vxh_hash_vx_info(vxi);
/* context must not be hashed */
- BUG_ON(vxi->vx_state & VXS_HASHED);
+ BUG_ON(vx_info_state(vxi, VXS_HASHED));
- get_vx_info(vxi);
vxi->vx_state |= VXS_HASHED;
head = &vx_info_hash[__hashval(vxi->vx_id)];
hlist_add_head(&vxi->vx_hlist, head);
static inline void __unhash_vx_info(struct vx_info *vxi)
{
- vxd_assert_lock(&vx_info_hash_lock);
vxdprintk(VXD_CBIT(xid, 4),
"__unhash_vx_info: %p[#%d]", vxi, vxi->vx_id);
+ spin_lock(&vx_info_hash_lock);
vxh_unhash_vx_info(vxi);
- /* maybe warn on that? */
- if (!(vxi->vx_state & VXS_HASHED))
- return;
+ /* context must be hashed */
+ BUG_ON(!vx_info_state(vxi, VXS_HASHED));
vxi->vx_state &= ~VXS_HASHED;
hlist_del(&vxi->vx_hlist);
- put_vx_info(vxi);
+ spin_unlock(&vx_info_hash_lock);
}
vxdprintk(VXD_CBIT(xid, 0),
"__lookup_vx_info(#%u): %p[#%u]",
xid, vxi, vxi?vxi->vx_id:0);
- vxh_lookup_vx_info(xid, vxi);
+ vxh_lookup_vx_info(vxi, xid);
return vxi;
}
out_unlock:
spin_unlock(&vx_info_hash_lock);
- vxh_loc_vx_info(id, vxi);
+ vxh_loc_vx_info(vxi, id);
if (new)
__dealloc_vx_info(new);
return vxi;
/* __create_vx_info()
* create the requested context
- * get() it and hash it */
+ * get(), claim() and hash it */
static struct vx_info * __create_vx_info(int id)
{
vxdprintk(VXD_CBIT(xid, 1), "create_vx_info(%d)*", id);
- if (!(new = __alloc_vx_info(id))) {
+ if (!(new = __alloc_vx_info(id)))
return ERR_PTR(-ENOMEM);
- }
/* required to make dynamic xids unique */
spin_lock(&vx_info_hash_lock);
}
new->vx_id = id;
}
- /* existing context requested */
+ /* static context requested */
else if ((vxi = __lookup_vx_info(id))) {
vxdprintk(VXD_CBIT(xid, 0),
"create_vx_info(%d) = %p (already there)", id, vxi);
goto out_unlock;
}
- /* new context requested */
+ /* new context */
vxdprintk(VXD_CBIT(xid, 0),
"create_vx_info(%d) = %p (new)", id, new);
+ claim_vx_info(new, NULL);
__hash_vx_info(get_vx_info(new));
vxi = new, new = NULL;
out_unlock:
spin_unlock(&vx_info_hash_lock);
- vxh_create_vx_info(id, IS_ERR(vxi)?NULL:vxi);
+ vxh_create_vx_info(IS_ERR(vxi)?NULL:vxi, id);
if (new)
__dealloc_vx_info(new);
return vxi;
void unhash_vx_info(struct vx_info *vxi)
{
__shutdown_vx_info(vxi);
- spin_lock(&vx_info_hash_lock);
__unhash_vx_info(vxi);
- spin_unlock(&vx_info_hash_lock);
+ __wakeup_vx_info(vxi);
}
-/* locate_vx_info()
+/* lookup_vx_info()
* search for a vx_info and get() it
* negative id means current */
-struct vx_info *locate_vx_info(int id)
+struct vx_info *lookup_vx_info(int id)
{
struct vx_info *vxi = NULL;
#ifdef CONFIG_VSERVER_LEGACY
-struct vx_info *locate_or_create_vx_info(int id)
+struct vx_info *lookup_or_create_vx_info(int id)
{
int err;
}
#endif
+
int vx_migrate_user(struct task_struct *p, struct vx_info *vxi)
{
struct user_struct *new_user, *old_user;
return 0;
}
-void vx_mask_bcaps(struct task_struct *p)
+void vx_mask_bcaps(struct vx_info *vxi, struct task_struct *p)
{
- struct vx_info *vxi = p->vx_info;
-
p->cap_effective &= vxi->vx_bcaps;
p->cap_inheritable &= vxi->vx_bcaps;
p->cap_permitted &= vxi->vx_bcaps;
static int vx_openfd_task(struct task_struct *tsk)
{
struct files_struct *files = tsk->files;
+ struct fdtable *fdt;
const unsigned long *bptr;
int count, total;
+ /* no rcu_read_lock() because of spin_lock() */
spin_lock(&files->file_lock);
- bptr = files->open_fds->fds_bits;
- count = files->max_fds / (sizeof(unsigned long) * 8);
+ fdt = files_fdtable(files);
+ bptr = fdt->open_fds->fds_bits;
+ count = fdt->max_fds / (sizeof(unsigned long) * 8);
for (total = 0; count > 0; count--) {
if (*bptr)
total += hweight_long(*bptr);
"moved task %p into vxi:%p[#%d]",
p, vxi, vxi->vx_id);
- vx_mask_bcaps(p);
+ vx_mask_bcaps(vxi, p);
task_unlock(p);
}
out:
return ret;
}
+int vx_set_reaper(struct vx_info *vxi, struct task_struct *p)
+{
+ struct task_struct *old_reaper;
+
+ if (!vxi)
+ return -EINVAL;
+
+ vxdprintk(VXD_CBIT(xid, 6),
+ "vx_set_reaper(%p[#%d],%p[#%d,%d])",
+ vxi, vxi->vx_id, p, p->xid, p->pid);
+
+ old_reaper = vxi->vx_reaper;
+ if (old_reaper == p)
+ return 0;
+
+ /* set new child reaper */
+ get_task_struct(p);
+ vxi->vx_reaper = p;
+ put_task_struct(old_reaper);
+ return 0;
+}
+
int vx_set_init(struct vx_info *vxi, struct task_struct *p)
{
if (!vxi)
return -EINVAL;
- if (vxi->vx_initpid)
- return -EPERM;
vxdprintk(VXD_CBIT(xid, 6),
"vx_set_init(%p[#%d],%p[#%d,%d,%d])",
vxi, vxi->vx_id, p, p->xid, p->pid, p->tgid);
+ vxi->vx_flags &= ~VXF_STATE_INIT;
vxi->vx_initpid = p->tgid;
return 0;
}
+void vx_exit_init(struct vx_info *vxi, struct task_struct *p, int code)
+{
+ vxdprintk(VXD_CBIT(xid, 6),
+ "vx_exit_init(%p[#%d],%p[#%d,%d,%d])",
+ vxi, vxi->vx_id, p, p->xid, p->pid, p->tgid);
+
+ vxi->exit_code = code;
+ vxi->vx_initpid = 0;
+}
+
+void vx_set_persistent(struct vx_info *vxi)
+{
+ vxdprintk(VXD_CBIT(xid, 6),
+ "vx_set_persistent(%p[#%d])", vxi, vxi->vx_id);
+
+ get_vx_info(vxi);
+ claim_vx_info(vxi, NULL);
+}
+
+void vx_clear_persistent(struct vx_info *vxi)
+{
+ vxdprintk(VXD_CBIT(xid, 6),
+ "vx_clear_persistent(%p[#%d])", vxi, vxi->vx_id);
+
+ release_vx_info(vxi, NULL);
+ put_vx_info(vxi);
+}
+
+void vx_update_persistent(struct vx_info *vxi)
+{
+ if (vx_info_flags(vxi, VXF_PERSISTENT, 0))
+ vx_set_persistent(vxi);
+ else
+ vx_clear_persistent(vxi);
+}
+
+
+/* task must be current or locked */
+
+void exit_vx_info(struct task_struct *p, int code)
+{
+ struct vx_info *vxi = p->vx_info;
+
+ if (vxi) {
+ atomic_dec(&vxi->cvirt.nr_threads);
+ vx_nproc_dec(p);
+
+ vxi->exit_code = code;
+ release_vx_info(vxi, p);
+ }
+}
+
+void exit_vx_info_early(struct task_struct *p, int code)
+{
+ struct vx_info *vxi = p->vx_info;
+
+ if (vxi) {
+ if (vxi->vx_initpid == p->tgid)
+ vx_exit_init(vxi, p, code);
+ if (vxi->vx_reaper == p)
+ vx_set_reaper(vxi, child_reaper);
+ }
+}
+
/* vserver syscall commands below here */
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE))
return -EPERM;
- vxi = locate_vx_info(id);
+ vxi = lookup_vx_info(id);
if (!vxi)
return -ESRCH;
int vc_ctx_create(uint32_t xid, void __user *data)
{
+ struct vcmd_ctx_create vc_data = { .flagword = VXF_INIT_SET };
struct vx_info *new_vxi;
int ret;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
+ if (data && copy_from_user (&vc_data, data, sizeof(vc_data)))
+ return -EFAULT;
if ((xid > MAX_S_CONTEXT) && (xid != VX_DYNAMIC_ID))
return -EINVAL;
-
if (xid < 2)
return -EINVAL;
if (IS_ERR(new_vxi))
return PTR_ERR(new_vxi);
- vs_context_state(new_vxi, VS_CONTEXT_CREATED);
+ /* initial flags */
+ new_vxi->vx_flags = vc_data.flagword;
+
+ ret = -ENOEXEC;
+ if (vs_state_change(new_vxi, VSC_STARTUP))
+ goto out;
+
+ ret = vx_migrate_task(current, new_vxi);
+ if (ret)
+ goto out;
+
+ /* return context id on success */
ret = new_vxi->vx_id;
- vx_migrate_task(current, new_vxi);
- /* if this fails, we might end up with a hashed vx_info */
+
+ /* get a reference for persistent contexts */
+ if ((vc_data.flagword & VXF_PERSISTENT))
+ vx_set_persistent(new_vxi);
+out:
+ release_vx_info(new_vxi, NULL);
put_vx_info(new_vxi);
return ret;
}
int vc_ctx_migrate(uint32_t id, void __user *data)
{
+ struct vcmd_ctx_migrate vc_data = { .flagword = 0 };
struct vx_info *vxi;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
+ if (data && copy_from_user (&vc_data, data, sizeof(vc_data)))
+ return -EFAULT;
/* dirty hack until Spectator becomes a cap */
if (id == 1) {
return 0;
}
- vxi = locate_vx_info(id);
+ vxi = lookup_vx_info(id);
if (!vxi)
return -ESRCH;
vx_migrate_task(current, vxi);
+ if (vc_data.flagword & VXM_SET_INIT)
+ vx_set_init(vxi, current);
+ if (vc_data.flagword & VXM_SET_REAPER)
+ vx_set_reaper(vxi, current);
put_vx_info(vxi);
return 0;
}
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- vxi = locate_vx_info(id);
+ vxi = lookup_vx_info(id);
if (!vxi)
return -ESRCH;
if (copy_from_user (&vc_data, data, sizeof(vc_data)))
return -EFAULT;
- vxi = locate_vx_info(id);
+ vxi = lookup_vx_info(id);
if (!vxi)
return -ESRCH;
mask = vx_mask_mask(vc_data.mask, vxi->vx_flags, VXF_ONE_TIME);
trigger = (mask & vxi->vx_flags) ^ (mask & vc_data.flagword);
- if (trigger & VXF_STATE_SETUP)
- vx_mask_bcaps(current);
- if (trigger & VXF_STATE_INIT)
- if (vxi == current->vx_info)
+ if (vxi == current->vx_info) {
+ if (trigger & VXF_STATE_SETUP)
+ vx_mask_bcaps(vxi, current);
+ if (trigger & VXF_STATE_INIT) {
vx_set_init(vxi, current);
+ vx_set_reaper(vxi, current);
+ }
+ }
vxi->vx_flags = vx_mask_flags(vxi->vx_flags,
vc_data.flagword, mask);
+ if (trigger & VXF_PERSISTENT)
+ vx_update_persistent(vxi);
+
put_vx_info(vxi);
return 0;
}
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- vxi = locate_vx_info(id);
+ vxi = lookup_vx_info(id);
if (!vxi)
return -ESRCH;
if (copy_from_user (&vc_data, data, sizeof(vc_data)))
return -EFAULT;
- vxi = locate_vx_info(id);
+ vxi = lookup_vx_info(id);
if (!vxi)
return -ESRCH;