[NET]: Fix busy waiting in dev_close().
[powerpc.git] / net / core / skbuff.c
index f65b3de..7eab867 100644 (file)
@@ -129,7 +129,7 @@ void skb_under_panic(struct sk_buff *skb, int sz, void *here)
  *     Buffers may only be allocated from interrupts using a @gfp_mask of
  *     %GFP_ATOMIC.
  */
-struct sk_buff *alloc_skb(unsigned int size, int gfp_mask)
+struct sk_buff *alloc_skb(unsigned int size, unsigned int __nocast gfp_mask)
 {
        struct sk_buff *skb;
        u8 *data;
@@ -182,7 +182,8 @@ nodata:
  *     %GFP_ATOMIC.
  */
 struct sk_buff *alloc_skb_from_cache(kmem_cache_t *cp,
-                                    unsigned int size, int gfp_mask)
+                                    unsigned int size,
+                                    unsigned int __nocast gfp_mask)
 {
        struct sk_buff *skb;
        u8 *data;
@@ -322,7 +323,7 @@ void __kfree_skb(struct sk_buff *skb)
  *     %GFP_ATOMIC.
  */
 
-struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask)
+struct sk_buff *skb_clone(struct sk_buff *skb, unsigned int __nocast gfp_mask)
 {
        struct sk_buff *n = kmem_cache_alloc(skbuff_head_cache, gfp_mask);
 
@@ -357,7 +358,6 @@ struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask)
        C(ip_summed);
        C(priority);
        C(protocol);
-       C(security);
        n->destructor = NULL;
 #ifdef CONFIG_NETFILTER
        C(nfmark);
@@ -365,9 +365,6 @@ struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask)
        C(nfct);
        nf_conntrack_get(skb->nfct);
        C(nfctinfo);
-#ifdef CONFIG_NETFILTER_DEBUG
-       C(nf_debug);
-#endif
 #ifdef CONFIG_BRIDGE_NETFILTER
        C(nf_bridge);
        nf_bridge_get(skb->nf_bridge);
@@ -380,8 +377,8 @@ struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask)
        C(tc_index);
 #ifdef CONFIG_NET_CLS_ACT
        n->tc_verd = SET_TC_VERD(skb->tc_verd,0);
-       n->tc_verd = CLR_TC_OK2MUNGE(skb->tc_verd);
-       n->tc_verd = CLR_TC_MUNGED(skb->tc_verd);
+       n->tc_verd = CLR_TC_OK2MUNGE(n->tc_verd);
+       n->tc_verd = CLR_TC_MUNGED(n->tc_verd);
        C(input_dev);
        C(tc_classid);
 #endif
@@ -425,16 +422,12 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
        new->pkt_type   = old->pkt_type;
        new->stamp      = old->stamp;
        new->destructor = NULL;
-       new->security   = old->security;
 #ifdef CONFIG_NETFILTER
        new->nfmark     = old->nfmark;
        new->nfcache    = old->nfcache;
        new->nfct       = old->nfct;
        nf_conntrack_get(old->nfct);
        new->nfctinfo   = old->nfctinfo;
-#ifdef CONFIG_NETFILTER_DEBUG
-       new->nf_debug   = old->nf_debug;
-#endif
 #ifdef CONFIG_BRIDGE_NETFILTER
        new->nf_bridge  = old->nf_bridge;
        nf_bridge_get(old->nf_bridge);
@@ -468,7 +461,7 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
  *     header is going to be modified. Use pskb_copy() instead.
  */
 
-struct sk_buff *skb_copy(const struct sk_buff *skb, int gfp_mask)
+struct sk_buff *skb_copy(const struct sk_buff *skb, unsigned int __nocast gfp_mask)
 {
        int headerlen = skb->data - skb->head;
        /*
@@ -507,7 +500,7 @@ struct sk_buff *skb_copy(const struct sk_buff *skb, int gfp_mask)
  *     The returned buffer has a reference count of 1.
  */
 
-struct sk_buff *pskb_copy(struct sk_buff *skb, int gfp_mask)
+struct sk_buff *pskb_copy(struct sk_buff *skb, unsigned int __nocast gfp_mask)
 {
        /*
         *      Allocate the copy buffer
@@ -565,7 +558,8 @@ out:
  *     reloaded after call to this function.
  */
 
-int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, int gfp_mask)
+int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
+                    unsigned int __nocast gfp_mask)
 {
        int i;
        u8 *data;
@@ -655,7 +649,8 @@ struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom)
  *     only by netfilter in the cases when checksum is recalculated? --ANK
  */
 struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
-                               int newheadroom, int newtailroom, int gfp_mask)
+                               int newheadroom, int newtailroom,
+                               unsigned int __nocast gfp_mask)
 {
        /*
         *      Allocate the copy buffer
@@ -1506,6 +1501,159 @@ void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len)
                skb_split_no_header(skb, skb1, len, pos);
 }
 
+/**
+ * skb_prepare_seq_read - Prepare a sequential read of skb data
+ * @skb: the buffer to read
+ * @from: lower offset of data to be read
+ * @to: upper offset of data to be read
+ * @st: state variable
+ *
+ * Initializes the specified state variable. Must be called before
+ * invoking skb_seq_read() for the first time.
+ */
+void skb_prepare_seq_read(struct sk_buff *skb, unsigned int from,
+                         unsigned int to, struct skb_seq_state *st)
+{
+       st->lower_offset = from;
+       st->upper_offset = to;
+       st->root_skb = st->cur_skb = skb;
+       st->frag_idx = st->stepped_offset = 0;
+       st->frag_data = NULL;
+}
+
+/**
+ * skb_seq_read - Sequentially read skb data
+ * @consumed: number of bytes consumed by the caller so far
+ * @data: destination pointer for data to be returned
+ * @st: state variable
+ *
+ * Reads a block of skb data at &consumed relative to the
+ * lower offset specified to skb_prepare_seq_read(). Assigns
+ * the head of the data block to &data and returns the length
+ * of the block or 0 if the end of the skb data or the upper
+ * offset has been reached.
+ *
+ * The caller is not required to consume all of the data
+ * returned, i.e. &consumed is typically set to the number
+ * of bytes already consumed and the next call to
+ * skb_seq_read() will return the remaining part of the block.
+ *
+ * Note: The size of each block of data returned can be arbitary,
+ *       this limitation is the cost for zerocopy seqeuental
+ *       reads of potentially non linear data.
+ *
+ * Note: Fragment lists within fragments are not implemented
+ *       at the moment, state->root_skb could be replaced with
+ *       a stack for this purpose.
+ */
+unsigned int skb_seq_read(unsigned int consumed, const u8 **data,
+                         struct skb_seq_state *st)
+{
+       unsigned int block_limit, abs_offset = consumed + st->lower_offset;
+       skb_frag_t *frag;
+
+       if (unlikely(abs_offset >= st->upper_offset))
+               return 0;
+
+next_skb:
+       block_limit = skb_headlen(st->cur_skb);
+
+       if (abs_offset < block_limit) {
+               *data = st->cur_skb->data + abs_offset;
+               return block_limit - abs_offset;
+       }
+
+       if (st->frag_idx == 0 && !st->frag_data)
+               st->stepped_offset += skb_headlen(st->cur_skb);
+
+       while (st->frag_idx < skb_shinfo(st->cur_skb)->nr_frags) {
+               frag = &skb_shinfo(st->cur_skb)->frags[st->frag_idx];
+               block_limit = frag->size + st->stepped_offset;
+
+               if (abs_offset < block_limit) {
+                       if (!st->frag_data)
+                               st->frag_data = kmap_skb_frag(frag);
+
+                       *data = (u8 *) st->frag_data + frag->page_offset +
+                               (abs_offset - st->stepped_offset);
+
+                       return block_limit - abs_offset;
+               }
+
+               if (st->frag_data) {
+                       kunmap_skb_frag(st->frag_data);
+                       st->frag_data = NULL;
+               }
+
+               st->frag_idx++;
+               st->stepped_offset += frag->size;
+       }
+
+       if (st->cur_skb->next) {
+               st->cur_skb = st->cur_skb->next;
+               st->frag_idx = 0;
+               goto next_skb;
+       } else if (st->root_skb == st->cur_skb &&
+                  skb_shinfo(st->root_skb)->frag_list) {
+               st->cur_skb = skb_shinfo(st->root_skb)->frag_list;
+               goto next_skb;
+       }
+
+       return 0;
+}
+
+/**
+ * skb_abort_seq_read - Abort a sequential read of skb data
+ * @st: state variable
+ *
+ * Must be called if skb_seq_read() was not called until it
+ * returned 0.
+ */
+void skb_abort_seq_read(struct skb_seq_state *st)
+{
+       if (st->frag_data)
+               kunmap_skb_frag(st->frag_data);
+}
+
+#define TS_SKB_CB(state)       ((struct skb_seq_state *) &((state)->cb))
+
+static unsigned int skb_ts_get_next_block(unsigned int offset, const u8 **text,
+                                         struct ts_config *conf,
+                                         struct ts_state *state)
+{
+       return skb_seq_read(offset, text, TS_SKB_CB(state));
+}
+
+static void skb_ts_finish(struct ts_config *conf, struct ts_state *state)
+{
+       skb_abort_seq_read(TS_SKB_CB(state));
+}
+
+/**
+ * skb_find_text - Find a text pattern in skb data
+ * @skb: the buffer to look in
+ * @from: search offset
+ * @to: search limit
+ * @config: textsearch configuration
+ * @state: uninitialized textsearch state variable
+ *
+ * Finds a pattern in the skb data according to the specified
+ * textsearch configuration. Use textsearch_next() to retrieve
+ * subsequent occurrences of the pattern. Returns the offset
+ * to the first occurrence or UINT_MAX if no match was found.
+ */
+unsigned int skb_find_text(struct sk_buff *skb, unsigned int from,
+                          unsigned int to, struct ts_config *config,
+                          struct ts_state *state)
+{
+       config->get_next_block = skb_ts_get_next_block;
+       config->finish = skb_ts_finish;
+
+       skb_prepare_seq_read(skb, from, to, TS_SKB_CB(state));
+
+       return textsearch_find(config, state);
+}
+
 void __init skb_init(void)
 {
        skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
@@ -1544,3 +1692,7 @@ EXPORT_SYMBOL(skb_queue_tail);
 EXPORT_SYMBOL(skb_unlink);
 EXPORT_SYMBOL(skb_append);
 EXPORT_SYMBOL(skb_split);
+EXPORT_SYMBOL(skb_prepare_seq_read);
+EXPORT_SYMBOL(skb_seq_read);
+EXPORT_SYMBOL(skb_abort_seq_read);
+EXPORT_SYMBOL(skb_find_text);