static void label_destroy(struct aa_label *label)
{
+ struct aa_label *tmp;
+
AA_BUG(!label);
if (label_is_stale(label))
rcu_assign_pointer(label->proxy->label, NULL);
aa_free_sid(label->sid);
+
+ tmp = rcu_dereference_protected(label->proxy->label, true);
+ if (tmp == label)
+ rcu_assign_pointer(label->proxy->label, NULL);
+
aa_put_proxy(label->proxy);
label->proxy = (struct aa_proxy *) PROXY_POISON + 1;
}
call_rcu(&label->rcu, label_free_rcu);
}
+static void label_free_or_put_new(struct aa_label *label, struct aa_label *new)
+{
+ if (label != new)
+ /* need to free directly to break circular ref with proxy */
+ aa_label_free(new);
+ else
+ aa_put_label(new);
+}
+
bool aa_label_init(struct aa_label *label, int size)
{
AA_BUG(!label);
write_lock_irqsave(&ls->lock, flags);
label = __label_insert(ls, new, false);
write_unlock_irqrestore(&ls->lock, flags);
- aa_put_label(new);
+ label_free_or_put_new(label, new);
return label;
}
goto out;
label = label_merge_insert(new, a, b);
- aa_put_label(new);
+ label_free_or_put_new(label, new);
out:
aa_put_label(a);
aa_put_label(b);
/* ensure label is removed, and redirected correctly */
__label_remove(label, tmp);
write_unlock_irqrestore(&ls->lock, flags);
-
- aa_put_label(new);
+ label_free_or_put_new(tmp, new);
return tmp;
}