|
@@ -264,7 +264,7 @@ typedef unsigned char *sk_buff_data_t;
|
|
* @transport_header: Transport layer header
|
|
* @transport_header: Transport layer header
|
|
* @network_header: Network layer header
|
|
* @network_header: Network layer header
|
|
* @mac_header: Link layer header
|
|
* @mac_header: Link layer header
|
|
- * @_skb_dst: destination entry
|
|
|
|
|
|
+ * @_skb_refdst: destination entry (with norefcount bit)
|
|
* @sp: the security path, used for xfrm
|
|
* @sp: the security path, used for xfrm
|
|
* @cb: Control buffer. Free for use by every layer. Put private vars here
|
|
* @cb: Control buffer. Free for use by every layer. Put private vars here
|
|
* @len: Length of actual data
|
|
* @len: Length of actual data
|
|
@@ -328,7 +328,7 @@ struct sk_buff {
|
|
*/
|
|
*/
|
|
char cb[48] __aligned(8);
|
|
char cb[48] __aligned(8);
|
|
|
|
|
|
- unsigned long _skb_dst;
|
|
|
|
|
|
+ unsigned long _skb_refdst;
|
|
#ifdef CONFIG_XFRM
|
|
#ifdef CONFIG_XFRM
|
|
struct sec_path *sp;
|
|
struct sec_path *sp;
|
|
#endif
|
|
#endif
|
|
@@ -419,14 +419,64 @@ struct sk_buff {
|
|
|
|
|
|
#include <asm/system.h>
|
|
#include <asm/system.h>
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * skb might have a dst pointer attached, refcounted or not.
|
|
|
|
+ * _skb_refdst low order bit is set if refcount was _not_ taken
|
|
|
|
+ */
|
|
|
|
+#define SKB_DST_NOREF 1UL
|
|
|
|
+#define SKB_DST_PTRMASK ~(SKB_DST_NOREF)
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * skb_dst - returns skb dst_entry
|
|
|
|
+ * @skb: buffer
|
|
|
|
+ *
|
|
|
|
+ * Returns skb dst_entry, regardless of reference taken or not.
|
|
|
|
+ */
|
|
static inline struct dst_entry *skb_dst(const struct sk_buff *skb)
|
|
static inline struct dst_entry *skb_dst(const struct sk_buff *skb)
|
|
{
|
|
{
|
|
- return (struct dst_entry *)skb->_skb_dst;
|
|
|
|
|
|
+ /* If refdst was not refcounted, check we still are in a
|
|
|
|
+ * rcu_read_lock section
|
|
|
|
+ */
|
|
|
|
+ WARN_ON((skb->_skb_refdst & SKB_DST_NOREF) &&
|
|
|
|
+ !rcu_read_lock_held() &&
|
|
|
|
+ !rcu_read_lock_bh_held());
|
|
|
|
+ return (struct dst_entry *)(skb->_skb_refdst & SKB_DST_PTRMASK);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * skb_dst_set - sets skb dst
|
|
|
|
+ * @skb: buffer
|
|
|
|
+ * @dst: dst entry
|
|
|
|
+ *
|
|
|
|
+ * Sets skb dst, assuming a reference was taken on dst and should
|
|
|
|
+ * be released by skb_dst_drop()
|
|
|
|
+ */
|
|
static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
|
|
static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
|
|
{
|
|
{
|
|
- skb->_skb_dst = (unsigned long)dst;
|
|
|
|
|
|
+ skb->_skb_refdst = (unsigned long)dst;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * skb_dst_set_noref - sets skb dst, without a reference
|
|
|
|
+ * @skb: buffer
|
|
|
|
+ * @dst: dst entry
|
|
|
|
+ *
|
|
|
|
+ * Sets skb dst, assuming a reference was not taken on dst
|
|
|
|
+ * skb_dst_drop() should not dst_release() this dst
|
|
|
|
+ */
|
|
|
|
+static inline void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst)
|
|
|
|
+{
|
|
|
|
+ WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
|
|
|
|
+ skb->_skb_refdst = (unsigned long)dst | SKB_DST_NOREF;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * skb_dst_is_noref - Test if skb dst isnt refcounted
|
|
|
|
+ * @skb: buffer
|
|
|
|
+ */
|
|
|
|
+static inline bool skb_dst_is_noref(const struct sk_buff *skb)
|
|
|
|
+{
|
|
|
|
+ return (skb->_skb_refdst & SKB_DST_NOREF) && skb_dst(skb);
|
|
}
|
|
}
|
|
|
|
|
|
static inline struct rtable *skb_rtable(const struct sk_buff *skb)
|
|
static inline struct rtable *skb_rtable(const struct sk_buff *skb)
|