These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / include / linux / netfilter / ipset / ip_set_comment.h
index 21217ea..8d02485 100644 (file)
@@ -16,41 +16,57 @@ ip_set_comment_uget(struct nlattr *tb)
        return nla_data(tb);
 }
 
+/* Called from uadd only, protected by the set spinlock.
+ * The kadt functions don't use the comment extensions in any way.
+ */
 static inline void
 ip_set_init_comment(struct ip_set_comment *comment,
                    const struct ip_set_ext *ext)
 {
+       struct ip_set_comment_rcu *c = rcu_dereference_protected(comment->c, 1);
        size_t len = ext->comment ? strlen(ext->comment) : 0;
 
-       if (unlikely(comment->str)) {
-               kfree(comment->str);
-               comment->str = NULL;
+       if (unlikely(c)) {
+               kfree_rcu(c, rcu);
+               rcu_assign_pointer(comment->c, NULL);
        }
        if (!len)
                return;
        if (unlikely(len > IPSET_MAX_COMMENT_SIZE))
                len = IPSET_MAX_COMMENT_SIZE;
-       comment->str = kzalloc(len + 1, GFP_ATOMIC);
-       if (unlikely(!comment->str))
+       c = kzalloc(sizeof(*c) + len + 1, GFP_ATOMIC);
+       if (unlikely(!c))
                return;
-       strlcpy(comment->str, ext->comment, len + 1);
+       strlcpy(c->str, ext->comment, len + 1);
+       rcu_assign_pointer(comment->c, c);
 }
 
+/* Used only when dumping a set, protected by rcu_read_lock_bh() */
 static inline int
 ip_set_put_comment(struct sk_buff *skb, struct ip_set_comment *comment)
 {
-       if (!comment->str)
+       struct ip_set_comment_rcu *c = rcu_dereference_bh(comment->c);
+
+       if (!c)
                return 0;
-       return nla_put_string(skb, IPSET_ATTR_COMMENT, comment->str);
+       return nla_put_string(skb, IPSET_ATTR_COMMENT, c->str);
 }
 
+/* Called from uadd/udel, flush or the garbage collectors protected
+ * by the set spinlock.
+ * Called when the set is destroyed and when there can't be any user
+ * of the set data anymore.
+ */
 static inline void
 ip_set_comment_free(struct ip_set_comment *comment)
 {
-       if (unlikely(!comment->str))
+       struct ip_set_comment_rcu *c;
+
+       c = rcu_dereference_protected(comment->c, 1);
+       if (unlikely(!c))
                return;
-       kfree(comment->str);
-       comment->str = NULL;
+       kfree_rcu(c, rcu);
+       rcu_assign_pointer(comment->c, NULL);
 }
 
 #endif