[PATCH] proc: readdir race fix (take 3)
[pandora-kernel.git] / kernel / pid.c
index 93e212f..ed89a73 100644 (file)
@@ -145,6 +145,23 @@ static int alloc_pidmap(void)
        return -1;
 }
 
+static int next_pidmap(int last)
+{
+       int offset;
+       pidmap_t *map;
+
+       offset = (last + 1) & BITS_PER_PAGE_MASK;
+       map = &pidmap_array[(last + 1)/BITS_PER_PAGE];
+       for (; map < &pidmap_array[PIDMAP_ENTRIES]; map++, offset = 0) {
+               if (unlikely(!map->page))
+                       continue;
+               offset = find_next_bit((map)->page, BITS_PER_PAGE, offset);
+               if (offset < BITS_PER_PAGE)
+                       return mk_pid(map, offset);
+       }
+       return -1;
+}
+
 fastcall void put_pid(struct pid *pid)
 {
        if (!pid)
@@ -223,9 +240,6 @@ int fastcall attach_pid(struct task_struct *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]);
@@ -252,6 +266,15 @@ void fastcall detach_pid(struct task_struct *task, enum pid_type type)
        free_pid(pid);
 }
 
+/* transfer_pid is an optimization of attach_pid(new), detach_pid(old) */
+void fastcall transfer_pid(struct task_struct *old, struct task_struct *new,
+                          enum pid_type type)
+{
+       new->pids[type].pid = old->pids[type].pid;
+       hlist_replace_rcu(&old->pids[type].node, &new->pids[type].node);
+       old->pids[type].pid = NULL;
+}
+
 struct task_struct * fastcall pid_task(struct pid *pid, enum pid_type type)
 {
        struct task_struct *result = NULL;
@@ -296,6 +319,25 @@ struct pid *find_get_pid(pid_t nr)
        return pid;
 }
 
+/*
+ * Used by proc to find the first pid that is greater then or equal to nr.
+ *
+ * If there is a pid at nr this function is exactly the same as find_pid.
+ */
+struct pid *find_ge_pid(int nr)
+{
+       struct pid *pid;
+
+       do {
+               pid = find_pid(nr);
+               if (pid)
+                       break;
+               nr = next_pidmap(nr);
+       } while (nr > 0);
+
+       return pid;
+}
+
 /*
  * The pid hash table is scaled according to the amount of memory in the
  * machine.  From a minimum of 16 slots up to 4096 slots at one gigabyte or