Merge branch 'for-linus2' of git://git.kernel.dk/linux-2.6-block
[safe/jmp/linux-2.6] / net / netfilter / nf_conntrack_extend.c
index bcc19fa..fdc8fb4 100644 (file)
@@ -65,6 +65,12 @@ nf_ct_ext_create(struct nf_ct_ext **ext, enum nf_ct_ext_id id, gfp_t gfp)
        return (void *)(*ext) + off;
 }
 
+static void __nf_ct_ext_free_rcu(struct rcu_head *head)
+{
+       struct nf_ct_ext *ext = container_of(head, struct nf_ct_ext, rcu);
+       kfree(ext);
+}
+
 void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
 {
        struct nf_ct_ext *new;
@@ -88,13 +94,11 @@ void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
        newlen = newoff + t->len;
        rcu_read_unlock();
 
-       if (newlen >= ksize(ct->ext)) {
-               new = kmalloc(newlen, gfp);
-               if (!new)
-                       return NULL;
-
-               memcpy(new, ct->ext, ct->ext->len);
+       new = __krealloc(ct->ext, newlen, gfp);
+       if (!new)
+               return NULL;
 
+       if (new != ct->ext) {
                for (i = 0; i < NF_CT_EXT_NUM; i++) {
                        if (!nf_ct_ext_exist(ct, i))
                                continue;
@@ -106,14 +110,14 @@ void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
                                        (void *)ct->ext + ct->ext->offset[i]);
                        rcu_read_unlock();
                }
-               kfree(ct->ext);
+               call_rcu(&ct->ext->rcu, __nf_ct_ext_free_rcu);
                ct->ext = new;
        }
 
-       ct->ext->offset[id] = newoff;
-       ct->ext->len = newlen;
-       memset((void *)ct->ext + newoff, 0, newlen - newoff);
-       return (void *)ct->ext + newoff;
+       new->offset[id] = newoff;
+       new->len = newlen;
+       memset((void *)new + newoff, 0, newlen - newoff);
+       return (void *)new + newoff;
 }
 EXPORT_SYMBOL(__nf_ct_ext_add);
 
@@ -181,6 +185,6 @@ void nf_ct_extend_unregister(struct nf_ct_ext_type *type)
        rcu_assign_pointer(nf_ct_ext_types[type->id], NULL);
        update_alloc_size(type);
        mutex_unlock(&nf_ct_ext_type_mutex);
-       synchronize_rcu();
+       rcu_barrier(); /* Wait for completion of call_rcu()'s */
 }
 EXPORT_SYMBOL_GPL(nf_ct_extend_unregister);