|
@@ -122,6 +122,43 @@ static void free_pidmap(struct upid *upid)
|
|
|
atomic_inc(&map->nr_free);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * If we started walking pids at 'base', is 'a' seen before 'b'?
|
|
|
+ */
|
|
|
+static int pid_before(int base, int a, int b)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * This is the same as saying
|
|
|
+ *
|
|
|
+ * (a - base + MAXUINT) % MAXUINT < (b - base + MAXUINT) % MAXUINT
|
|
|
+ * and that mapping orders 'a' and 'b' with respect to 'base'.
|
|
|
+ */
|
|
|
+ return (unsigned)(a - base) < (unsigned)(b - base);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * We might be racing with someone else trying to set pid_ns->last_pid.
|
|
|
+ * We want the winner to have the "later" value, because if the
|
|
|
+ * "earlier" value prevails, then a pid may get reused immediately.
|
|
|
+ *
|
|
|
+ * Since pids rollover, it is not sufficient to just pick the bigger
|
|
|
+ * value. We have to consider where we started counting from.
|
|
|
+ *
|
|
|
+ * 'base' is the value of pid_ns->last_pid that we observed when
|
|
|
+ * we started looking for a pid.
|
|
|
+ *
|
|
|
+ * 'pid' is the pid that we eventually found.
|
|
|
+ */
|
|
|
+static void set_last_pid(struct pid_namespace *pid_ns, int base, int pid)
|
|
|
+{
|
|
|
+ int prev;
|
|
|
+ int last_write = base;
|
|
|
+ do {
|
|
|
+ prev = last_write;
|
|
|
+ last_write = cmpxchg(&pid_ns->last_pid, prev, pid);
|
|
|
+ } while ((prev != last_write) && (pid_before(base, last_write, pid)));
|
|
|
+}
|
|
|
+
|
|
|
static int alloc_pidmap(struct pid_namespace *pid_ns)
|
|
|
{
|
|
|
int i, offset, max_scan, pid, last = pid_ns->last_pid;
|
|
@@ -154,7 +191,7 @@ static int alloc_pidmap(struct pid_namespace *pid_ns)
|
|
|
do {
|
|
|
if (!test_and_set_bit(offset, map->page)) {
|
|
|
atomic_dec(&map->nr_free);
|
|
|
- pid_ns->last_pid = pid;
|
|
|
+ set_last_pid(pid_ns, last, pid);
|
|
|
return pid;
|
|
|
}
|
|
|
offset = find_next_offset(map, offset);
|