X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=kernel%2Fpid.c;h=a864bf8a4535887977d8f4db81a63b55d326b5e7;hb=76828883507a47dae78837ab5dec5a5b4513c667;hp=eeb836b65ca4ec887e6dc83c73e73004ac066978;hpb=43bc926fffd92024b46cafaf7350d669ba9ca884;p=linux-2.6.git diff --git a/kernel/pid.c b/kernel/pid.c index eeb836b65..a864bf8a4 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -26,11 +26,11 @@ #include #include #include +#include #define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift) -static struct hlist_head *pid_hash; +static struct hlist_head *pid_hash[PIDTYPE_MAX]; static int pidhash_shift; -static kmem_cache_t *pid_cachep; int pid_max = PID_MAX_DEFAULT; int last_pid; @@ -61,22 +61,9 @@ typedef struct pidmap { static pidmap_t pidmap_array[PIDMAP_ENTRIES] = { [ 0 ... PIDMAP_ENTRIES-1 ] = { ATOMIC_INIT(BITS_PER_PAGE), NULL } }; -/* - * Note: disable interrupts while the pidmap_lock is held as an - * interrupt might come in and do read_lock(&tasklist_lock). - * - * If we don't disable interrupts there is a nasty deadlock between - * detach_pid()->free_pid() and another cpu that does - * spin_lock(&pidmap_lock) followed by an interrupt routine that does - * read_lock(&tasklist_lock); - * - * After we clean up the tasklist_lock and know there are no - * irq handlers that take it we can leave the interrupts enabled. - * For now it is easier to be safe than to prove it can't happen. - */ static __cacheline_aligned_in_smp DEFINE_SPINLOCK(pidmap_lock); -static fastcall void free_pidmap(int pid) +fastcall void free_pidmap(int pid) { pidmap_t *map = pidmap_array + pid / BITS_PER_PAGE; int offset = pid & BITS_PER_PAGE_MASK; @@ -85,7 +72,7 @@ static fastcall void free_pidmap(int pid) atomic_inc(&map->nr_free); } -static int alloc_pidmap(void) +int alloc_pidmap(void) { int i, offset, max_scan, pid, last = last_pid; pidmap_t *map; @@ -103,12 +90,12 @@ static int alloc_pidmap(void) * Free the page if someone raced with us * installing it: */ - spin_lock_irq(&pidmap_lock); + spin_lock(&pidmap_lock); if (map->page) free_page(page); else map->page = (void *)page; - spin_unlock_irq(&pidmap_lock); + spin_unlock(&pidmap_lock); if (unlikely(!map->page)) break; } @@ -145,73 +132,13 @@ static int alloc_pidmap(void) return -1; } -fastcall void put_pid(struct pid *pid) -{ - if (!pid) - return; - if ((atomic_read(&pid->count) == 1) || - atomic_dec_and_test(&pid->count)) - kmem_cache_free(pid_cachep, pid); -} - -static void delayed_put_pid(struct rcu_head *rhp) -{ - struct pid *pid = container_of(rhp, struct pid, rcu); - put_pid(pid); -} - -fastcall void free_pid(struct pid *pid) -{ - /* We can be called with write_lock_irq(&tasklist_lock) held */ - unsigned long flags; - - spin_lock_irqsave(&pidmap_lock, flags); - hlist_del_rcu(&pid->pid_chain); - spin_unlock_irqrestore(&pidmap_lock, flags); - - free_pidmap(pid->nr); - call_rcu(&pid->rcu, delayed_put_pid); -} - -struct pid *alloc_pid(void) -{ - struct pid *pid; - enum pid_type type; - int nr = -1; - - pid = kmem_cache_alloc(pid_cachep, GFP_KERNEL); - if (!pid) - goto out; - - nr = alloc_pidmap(); - if (nr < 0) - goto out_free; - - atomic_set(&pid->count, 1); - pid->nr = nr; - for (type = 0; type < PIDTYPE_MAX; ++type) - INIT_HLIST_HEAD(&pid->tasks[type]); - - spin_lock_irq(&pidmap_lock); - hlist_add_head_rcu(&pid->pid_chain, &pid_hash[pid_hashfn(pid->nr)]); - spin_unlock_irq(&pidmap_lock); - -out: - return pid; - -out_free: - kmem_cache_free(pid_cachep, pid); - pid = NULL; - goto out; -} - -struct pid * fastcall find_pid(int nr) +struct pid * fastcall find_pid(enum pid_type type, int nr) { struct hlist_node *elem; struct pid *pid; hlist_for_each_entry_rcu(pid, elem, - &pid_hash[pid_hashfn(nr)], pid_chain) { + &pid_hash[type][pid_hashfn(nr)], pid_chain) { if (pid->nr == nr) return pid; } @@ -220,80 +147,110 @@ struct pid * fastcall find_pid(int nr) int fastcall attach_pid(task_t *task, enum pid_type type, int nr) { - struct pid_link *link; - struct pid *pid; - - WARN_ON(!task->pid); /* to be removed soon */ - WARN_ON(!nr); /* to be removed soon */ - - link = &task->pids[type]; - link->pid = pid = find_pid(nr); - hlist_add_head_rcu(&link->node, &pid->tasks[type]); + struct pid *pid, *task_pid; + + task_pid = &task->pids[type]; + pid = find_pid(type, nr); + task_pid->nr = nr; + if (pid == NULL) { + INIT_LIST_HEAD(&task_pid->pid_list); + hlist_add_head_rcu(&task_pid->pid_chain, + &pid_hash[type][pid_hashfn(nr)]); + } else { + INIT_HLIST_NODE(&task_pid->pid_chain); + list_add_tail_rcu(&task_pid->pid_list, &pid->pid_list); + } return 0; } -void fastcall detach_pid(task_t *task, enum pid_type type) +static fastcall int __detach_pid(task_t *task, enum pid_type type) { - struct pid_link *link; - struct pid *pid; - int tmp; + struct pid *pid, *pid_next; + int nr = 0; - link = &task->pids[type]; - pid = link->pid; + pid = &task->pids[type]; + if (!hlist_unhashed(&pid->pid_chain)) { - hlist_del_rcu(&link->node); - link->pid = NULL; + if (list_empty(&pid->pid_list)) { + nr = pid->nr; + hlist_del_rcu(&pid->pid_chain); + } else { + pid_next = list_entry(pid->pid_list.next, + struct pid, pid_list); + /* insert next pid from pid_list to hash */ + hlist_replace_rcu(&pid->pid_chain, + &pid_next->pid_chain); + } + } - for (tmp = PIDTYPE_MAX; --tmp >= 0; ) - if (!hlist_empty(&pid->tasks[tmp])) - return; + list_del_rcu(&pid->pid_list); + pid->nr = 0; - free_pid(pid); + return nr; } -struct task_struct * fastcall pid_task(struct pid *pid, enum pid_type type) +void fastcall detach_pid(task_t *task, enum pid_type type) { - struct task_struct *result = NULL; - if (pid) { - struct hlist_node *first; - first = rcu_dereference(pid->tasks[type].first); - if (first) - result = hlist_entry(first, struct task_struct, pids[(type)].node); - } - return result; -} + int tmp, nr; -/* - * Must be called under rcu_read_lock() or with tasklist_lock read-held. - */ -task_t *find_task_by_pid_type(int type, int nr) -{ - return pid_task(find_pid(nr), type); -} + nr = __detach_pid(task, type); + if (!nr) + return; -EXPORT_SYMBOL(find_task_by_pid_type); + for (tmp = PIDTYPE_MAX; --tmp >= 0; ) + if (tmp != type && find_pid(tmp, nr)) + return; -struct task_struct *fastcall get_pid_task(struct pid *pid, enum pid_type type) -{ - struct task_struct *result; - rcu_read_lock(); - result = pid_task(pid, type); - if (result) - get_task_struct(result); - rcu_read_unlock(); - return result; + free_pidmap(nr); } -struct pid *find_get_pid(pid_t nr) +task_t *find_task_by_pid_type(int type, int nr) { struct pid *pid; - rcu_read_lock(); - pid = get_pid(find_pid(nr)); - rcu_read_unlock(); + if (type == PIDTYPE_REALPID) + type = PIDTYPE_PID; + else if (type == PIDTYPE_PID) + nr = vx_rmap_pid(nr); + + pid = find_pid(type, nr); + if (!pid) + return NULL; + + return pid_task(&pid->pid_list, type); +} + +EXPORT_SYMBOL(find_task_by_pid_type); - return pid; +/* + * This function switches the PIDs if a non-leader thread calls + * sys_execve() - this must be done without releasing the PID. + * (which a detach_pid() would eventually do.) + */ +void switch_exec_pids(task_t *leader, task_t *thread) +{ + __detach_pid(leader, PIDTYPE_PID); + __detach_pid(leader, PIDTYPE_TGID); + __detach_pid(leader, PIDTYPE_PGID); + __detach_pid(leader, PIDTYPE_SID); + + __detach_pid(thread, PIDTYPE_PID); + __detach_pid(thread, PIDTYPE_TGID); + + leader->pid = leader->tgid = thread->pid; + thread->pid = thread->tgid; + + attach_pid(thread, PIDTYPE_PID, thread->pid); + attach_pid(thread, PIDTYPE_TGID, thread->tgid); + attach_pid(thread, PIDTYPE_PGID, thread->signal->pgrp); + attach_pid(thread, PIDTYPE_SID, thread->signal->session); + list_add_tail(&thread->tasks, &init_task.tasks); + + attach_pid(leader, PIDTYPE_PID, leader->pid); + attach_pid(leader, PIDTYPE_TGID, leader->tgid); + attach_pid(leader, PIDTYPE_PGID, leader->signal->pgrp); + attach_pid(leader, PIDTYPE_SID, leader->signal->session); } /* @@ -303,7 +260,7 @@ struct pid *find_get_pid(pid_t nr) */ void __init pidhash_init(void) { - int i, pidhash_size; + int i, j, pidhash_size; unsigned long megabytes = nr_kernel_pages >> (20 - PAGE_SHIFT); pidhash_shift = max(4, fls(megabytes * 4)); @@ -312,23 +269,30 @@ void __init pidhash_init(void) printk("PID hash table entries: %d (order: %d, %Zd bytes)\n", pidhash_size, pidhash_shift, - pidhash_size * sizeof(struct hlist_head)); - - pid_hash = alloc_bootmem(pidhash_size * sizeof(*(pid_hash))); - if (!pid_hash) - panic("Could not alloc pidhash!\n"); - for (i = 0; i < pidhash_size; i++) - INIT_HLIST_HEAD(&pid_hash[i]); + PIDTYPE_MAX * pidhash_size * sizeof(struct hlist_head)); + + for (i = 0; i < PIDTYPE_MAX; i++) { + pid_hash[i] = alloc_bootmem(pidhash_size * + sizeof(*(pid_hash[i]))); + if (!pid_hash[i]) + panic("Could not alloc pidhash!\n"); + for (j = 0; j < pidhash_size; j++) + INIT_HLIST_HEAD(&pid_hash[i][j]); + } } void __init pidmap_init(void) { + int i; + pidmap_array->page = (void *)get_zeroed_page(GFP_KERNEL); - /* Reserve PID 0. We never call free_pidmap(0) */ set_bit(0, pidmap_array->page); atomic_dec(&pidmap_array->nr_free); - pid_cachep = kmem_cache_create("pid", sizeof(struct pid), - __alignof__(struct pid), - SLAB_PANIC, NULL, NULL); + /* + * Allocate PID 0, and hash it via all PID types: + */ + + for (i = 0; i < PIDTYPE_MAX; i++) + attach_pid(current, i, 0); }