int next_offset = offsetof(struct sw_flow_actions, actions) +
(*sfa)->actions_len;
- if (req_size <= (ksize(*sfa) - next_offset))
+ if (req_size <= ((*sfa)->buf_size - next_offset))
goto out;
- new_acts_size = ksize(*sfa) * 2;
+ new_acts_size = (*sfa)->buf_size * 2;
if (new_acts_size > MAX_ACTIONS_BUFSIZE) {
if ((MAX_ACTIONS_BUFSIZE - next_offset) < req_size)
memcpy(acts->actions, (*sfa)->actions, (*sfa)->actions_len);
acts->actions_len = (*sfa)->actions_len;
- kfree(*sfa);
+ ovs_flow_actions_free(*sfa);
*sfa = acts;
out:
return 0;
err_kfree:
- kfree(acts);
+ ovs_flow_actions_free(acts);
error:
return error;
}
if (size > MAX_ACTIONS_BUFSIZE)
return ERR_PTR(-EINVAL);
- sfa = kmalloc(sizeof(*sfa) + size, GFP_KERNEL);
+ size += sizeof(*sfa);
+ if (size <= MAX_ACTIONS_BUFSIZE_KMALLOC)
+ sfa = kmalloc(size, GFP_KERNEL);
+ else
+ sfa = vmalloc(size);
+
if (!sfa)
return ERR_PTR(-ENOMEM);
sfa->actions_len = 0;
+ sfa->buf_size = size;
+
return sfa;
}
+void ovs_flow_actions_free(struct sw_flow_actions *sfa)
+{
+ if (sfa->buf_size <= MAX_ACTIONS_BUFSIZE_KMALLOC)
+ kfree(sfa);
+ else
+ vfree(sfa);
+}
+
struct sw_flow *ovs_flow_alloc(void)
{
struct sw_flow *flow;
{
struct sw_flow_actions *sf_acts = container_of(rcu,
struct sw_flow_actions, rcu);
- kfree(sf_acts);
+ ovs_flow_actions_free(sf_acts);
}
/* Schedules 'sf_acts' to be freed after the next RCU grace period.
struct sw_flow_actions {
struct rcu_head rcu;
u32 actions_len;
+ int buf_size;
struct nlattr actions[];
};
void ovs_flow_free(struct sw_flow *);
struct sw_flow_actions *ovs_flow_actions_alloc(int actions_len);
+void ovs_flow_actions_free(struct sw_flow_actions *sfa);
void ovs_flow_deferred_free_acts(struct sw_flow_actions *);
int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *,
int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len,
const struct nlattr *attr);
-#define MAX_ACTIONS_BUFSIZE (16 * 1024)
+#define MAX_ACTIONS_BUFSIZE (32 * 1024)
+#define MAX_ACTIONS_BUFSIZE_KMALLOC PAGE_SIZE
#define TBL_MIN_BUCKETS 1024
struct flow_table {