int krg_task_alloc(struct task_struct *task, struct pid *pid) { struct task_kddm_object *obj; int nr = pid_knr(pid); task->task_obj = NULL; if (!task->nsproxy->krg_ns) return 0; #ifdef CONFIG_KRG_EPM if (krg_current) return 0; #endif /* Exclude kernel threads and local pids from using task kddm objects. */ /* * At this stage, current->mm points the mm of the task being duplicated * instead of the mm of task for which this struct is being allocated, * but we only need to know whether it is NULL or not, which will be the * same after copy_mm. */ if (!(nr & GLOBAL_PID_MASK) || !current->mm) return 0; obj = krg_task_create_writelock(nr); if (!obj) return -ENOMEM; /* Set the link between task kddm object and tsk */ obj->task = task; task->task_obj = obj; return 0; }
static void __put_pid(struct pid_kddm_object *obj) { struct pid *pid = obj->pid; int nr = pid_knr(pid); int may_put; int grabbed = 0; /* Try to avoid grabing the kddm object */ read_lock(&tasklist_lock); spin_lock(&pid_kddm_lock); may_put = may_put_pid(obj); spin_unlock(&pid_kddm_lock); if (!may_put) goto release_work; read_unlock(&tasklist_lock); /* The pid seems to be unused locally. Have to check globally. */ /* Prevent pidmaps from changing host nodes. */ pidmap_map_read_lock(); fkddm_grab_object(kddm_def_ns, PID_KDDM_ID, nr, KDDM_NO_FT_REQ | KDDM_DONT_KILL); grabbed = 1; read_lock(&tasklist_lock); spin_lock(&pid_kddm_lock); may_put = may_put_pid(obj); if (may_put) { obj->active = 0; obj->node_count--; if (obj->node_count) /* Still used elsewhere */ may_put = 0; } spin_unlock(&pid_kddm_lock); release_work: spin_lock(&put_pid_wq_lock); list_del_init(&obj->wq); spin_unlock(&put_pid_wq_lock); read_unlock(&tasklist_lock); if (may_put) { _kddm_remove_frozen_object(pid_kddm_set, nr); pidmap_map_read_unlock(); } else if (grabbed) { _kddm_put_object(pid_kddm_set, nr); pidmap_map_read_unlock(); } }
int export_pid(struct epm_action *action, ghost_t *ghost, struct pid_link *link) { struct pid *pid = link->pid; int nr = pid_knr(pid); int retval; if (!(nr & GLOBAL_PID_MASK)) return -EPERM; if (ORIG_NODE(nr) == kerrighed_node_id && !pid->kddm_obj && action->type != EPM_CHECKPOINT) { retval = create_pid_kddm_object(pid, 0); if (retval) return retval; } return ghost_write(ghost, &nr, sizeof(nr)); }
static int create_pid_kddm_object(struct pid *pid, int early) { int nr = pid_knr(pid); struct pid_kddm_object *obj; struct task_kddm_object *task_obj; obj = _kddm_grab_object(pid_kddm_set, nr); if (IS_ERR(obj)) { _kddm_put_object(pid_kddm_set, nr); return PTR_ERR(obj); } BUG_ON(!obj); task_obj = krg_task_readlock(nr); spin_lock(&pid_kddm_lock); BUG_ON(early && pid->kddm_obj); if (!pid->kddm_obj) { obj->pid = pid; obj->active = 1; if (early) obj->attach_pending = 1; BUG_ON(obj->task_obj); if (task_obj) { BUG_ON(task_obj->pid_obj); /* * These rcu_assign_pointer are not really needed, * but are cleaner :) */ rcu_assign_pointer(obj->task_obj, task_obj); rcu_assign_pointer(obj->task_obj->pid_obj, obj); } pid->kddm_obj = obj; } BUG_ON(pid->kddm_obj != obj); spin_unlock(&pid_kddm_lock); krg_task_unlock(nr); _kddm_put_object(pid_kddm_set, nr); return 0; }