net: add a noref bit on skb dst
[pandora-kernel.git] / include / net / dst.h
index aac5a5f..27207a1 100644 (file)
@@ -168,6 +168,12 @@ static inline void dst_use(struct dst_entry *dst, unsigned long time)
        dst->lastuse = time;
 }
 
+static inline void dst_use_noref(struct dst_entry *dst, unsigned long time)
+{
+       dst->__use++;
+       dst->lastuse = time;
+}
+
 static inline
 struct dst_entry * dst_clone(struct dst_entry * dst)
 {
@@ -177,11 +183,47 @@ struct dst_entry * dst_clone(struct dst_entry * dst)
 }
 
 extern void dst_release(struct dst_entry *dst);
+
+static inline void refdst_drop(unsigned long refdst)
+{
+       if (!(refdst & SKB_DST_NOREF))
+               dst_release((struct dst_entry *)(refdst & SKB_DST_PTRMASK));
+}
+
+/**
+ * skb_dst_drop - drops skb dst
+ * @skb: buffer
+ *
+ * Drops dst reference count if a reference was taken.
+ */
 static inline void skb_dst_drop(struct sk_buff *skb)
 {
-       if (skb->_skb_dst)
-               dst_release(skb_dst(skb));
-       skb->_skb_dst = 0UL;
+       if (skb->_skb_refdst) {
+               refdst_drop(skb->_skb_refdst);
+               skb->_skb_refdst = 0UL;
+       }
+}
+
+static inline void skb_dst_copy(struct sk_buff *nskb, const struct sk_buff *oskb)
+{
+       nskb->_skb_refdst = oskb->_skb_refdst;
+       if (!(nskb->_skb_refdst & SKB_DST_NOREF))
+               dst_clone(skb_dst(nskb));
+}
+
+/**
+ * skb_dst_force - makes sure skb dst is refcounted
+ * @skb: buffer
+ *
+ * If dst is not yet refcounted, let's do it
+ */
+static inline void skb_dst_force(struct sk_buff *skb)
+{
+       if (skb_dst_is_noref(skb)) {
+               WARN_ON(!rcu_read_lock_held());
+               skb->_skb_refdst &= ~SKB_DST_NOREF;
+               dst_clone(skb_dst(skb));
+       }
 }
 
 /* Children define the path of the packet through the