--- x/net/core/flow_offload.c +++ y/net/core/flow_offload.c @@ -334,6 +334,7 @@ bool flow_block_cb_is_busy(flow_setup_cb } EXPORT_SYMBOL(flow_block_cb_is_busy); +static DEFINE_MUTEX(setup_lock); int flow_block_cb_setup_simple(struct flow_block_offload *f, struct list_head *driver_block_list, flow_setup_cb_t *cb, @@ -348,27 +349,37 @@ int flow_block_cb_setup_simple(struct fl f->driver_block_list = driver_block_list; + mutex_lock(&setup_lock); switch (f->command) { case FLOW_BLOCK_BIND: - if (flow_block_cb_is_busy(cb, cb_ident, driver_block_list)) + if (flow_block_cb_is_busy(cb, cb_ident, driver_block_list)) { + mutex_unlock(&setup_lock); return -EBUSY; + } block_cb = flow_block_cb_alloc(cb, cb_ident, cb_priv, NULL); - if (IS_ERR(block_cb)) + if (IS_ERR(block_cb)) { + mutex_unlock(&setup_lock); return PTR_ERR(block_cb); + } flow_block_cb_add(block_cb, f); list_add_tail(&block_cb->driver_list, driver_block_list); + mutex_unlock(&setup_lock); return 0; case FLOW_BLOCK_UNBIND: block_cb = flow_block_cb_lookup(f->block, cb, cb_ident); - if (!block_cb) + if (!block_cb) { + mutex_unlock(&setup_lock); return -ENOENT; + } flow_block_cb_remove(block_cb, f); list_del(&block_cb->driver_list); + mutex_unlock(&setup_lock); return 0; default: + mutex_unlock(&setup_lock); return -EOPNOTSUPP; } }