|
@@ -92,12 +92,6 @@ static LIST_HEAD(devlink_list);
|
|
|
*/
|
|
|
static DEFINE_MUTEX(devlink_mutex);
|
|
|
|
|
|
-/* devlink_port_mutex
|
|
|
- *
|
|
|
- * Shared lock to guard lists of ports in all devlink devices.
|
|
|
- */
|
|
|
-static DEFINE_MUTEX(devlink_port_mutex);
|
|
|
-
|
|
|
static struct net *devlink_net(const struct devlink *devlink)
|
|
|
{
|
|
|
return read_pnet(&devlink->_net);
|
|
@@ -335,15 +329,18 @@ devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb,
|
|
|
#define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0)
|
|
|
#define DEVLINK_NL_FLAG_NEED_PORT BIT(1)
|
|
|
#define DEVLINK_NL_FLAG_NEED_SB BIT(2)
|
|
|
-#define DEVLINK_NL_FLAG_LOCK_PORTS BIT(3)
|
|
|
- /* port is not needed but we need to ensure they don't
|
|
|
- * change in the middle of command
|
|
|
- */
|
|
|
+
|
|
|
+/* The per devlink instance lock is taken by default in the pre-doit
|
|
|
+ * operation, yet several commands do not require this. The global
|
|
|
+ * devlink lock is taken and protects from disruption by user-calls.
|
|
|
+ */
|
|
|
+#define DEVLINK_NL_FLAG_NO_LOCK BIT(3)
|
|
|
|
|
|
static int devlink_nl_pre_doit(const struct genl_ops *ops,
|
|
|
struct sk_buff *skb, struct genl_info *info)
|
|
|
{
|
|
|
struct devlink *devlink;
|
|
|
+ int err;
|
|
|
|
|
|
mutex_lock(&devlink_mutex);
|
|
|
devlink = devlink_get_from_info(info);
|
|
@@ -351,44 +348,47 @@ static int devlink_nl_pre_doit(const struct genl_ops *ops,
|
|
|
mutex_unlock(&devlink_mutex);
|
|
|
return PTR_ERR(devlink);
|
|
|
}
|
|
|
+ if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
|
|
|
+ mutex_lock(&devlink->lock);
|
|
|
if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) {
|
|
|
info->user_ptr[0] = devlink;
|
|
|
} else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
|
|
|
struct devlink_port *devlink_port;
|
|
|
|
|
|
- mutex_lock(&devlink_port_mutex);
|
|
|
devlink_port = devlink_port_get_from_info(devlink, info);
|
|
|
if (IS_ERR(devlink_port)) {
|
|
|
- mutex_unlock(&devlink_port_mutex);
|
|
|
- mutex_unlock(&devlink_mutex);
|
|
|
- return PTR_ERR(devlink_port);
|
|
|
+ err = PTR_ERR(devlink_port);
|
|
|
+ goto unlock;
|
|
|
}
|
|
|
info->user_ptr[0] = devlink_port;
|
|
|
}
|
|
|
- if (ops->internal_flags & DEVLINK_NL_FLAG_LOCK_PORTS) {
|
|
|
- mutex_lock(&devlink_port_mutex);
|
|
|
- }
|
|
|
if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) {
|
|
|
struct devlink_sb *devlink_sb;
|
|
|
|
|
|
devlink_sb = devlink_sb_get_from_info(devlink, info);
|
|
|
if (IS_ERR(devlink_sb)) {
|
|
|
- if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT)
|
|
|
- mutex_unlock(&devlink_port_mutex);
|
|
|
- mutex_unlock(&devlink_mutex);
|
|
|
- return PTR_ERR(devlink_sb);
|
|
|
+ err = PTR_ERR(devlink_sb);
|
|
|
+ goto unlock;
|
|
|
}
|
|
|
info->user_ptr[1] = devlink_sb;
|
|
|
}
|
|
|
return 0;
|
|
|
+
|
|
|
+unlock:
|
|
|
+ if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
+ mutex_unlock(&devlink_mutex);
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
static void devlink_nl_post_doit(const struct genl_ops *ops,
|
|
|
struct sk_buff *skb, struct genl_info *info)
|
|
|
{
|
|
|
- if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT ||
|
|
|
- ops->internal_flags & DEVLINK_NL_FLAG_LOCK_PORTS)
|
|
|
- mutex_unlock(&devlink_port_mutex);
|
|
|
+ struct devlink *devlink;
|
|
|
+
|
|
|
+ devlink = devlink_get_from_info(info);
|
|
|
+ if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
mutex_unlock(&devlink_mutex);
|
|
|
}
|
|
|
|
|
@@ -614,10 +614,10 @@ static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
|
|
|
int err;
|
|
|
|
|
|
mutex_lock(&devlink_mutex);
|
|
|
- mutex_lock(&devlink_port_mutex);
|
|
|
list_for_each_entry(devlink, &devlink_list, list) {
|
|
|
if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
|
|
|
continue;
|
|
|
+ mutex_lock(&devlink->lock);
|
|
|
list_for_each_entry(devlink_port, &devlink->port_list, list) {
|
|
|
if (idx < start) {
|
|
|
idx++;
|
|
@@ -628,13 +628,15 @@ static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
|
|
|
NETLINK_CB(cb->skb).portid,
|
|
|
cb->nlh->nlmsg_seq,
|
|
|
NLM_F_MULTI);
|
|
|
- if (err)
|
|
|
+ if (err) {
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
goto out;
|
|
|
+ }
|
|
|
idx++;
|
|
|
}
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
}
|
|
|
out:
|
|
|
- mutex_unlock(&devlink_port_mutex);
|
|
|
mutex_unlock(&devlink_mutex);
|
|
|
|
|
|
cb->args[0] = idx;
|
|
@@ -801,6 +803,7 @@ static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,
|
|
|
list_for_each_entry(devlink, &devlink_list, list) {
|
|
|
if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
|
|
|
continue;
|
|
|
+ mutex_lock(&devlink->lock);
|
|
|
list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
|
|
|
if (idx < start) {
|
|
|
idx++;
|
|
@@ -811,10 +814,13 @@ static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,
|
|
|
NETLINK_CB(cb->skb).portid,
|
|
|
cb->nlh->nlmsg_seq,
|
|
|
NLM_F_MULTI);
|
|
|
- if (err)
|
|
|
+ if (err) {
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
goto out;
|
|
|
+ }
|
|
|
idx++;
|
|
|
}
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
}
|
|
|
out:
|
|
|
mutex_unlock(&devlink_mutex);
|
|
@@ -935,14 +941,18 @@ static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg,
|
|
|
if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
|
|
|
!devlink->ops || !devlink->ops->sb_pool_get)
|
|
|
continue;
|
|
|
+ mutex_lock(&devlink->lock);
|
|
|
list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
|
|
|
err = __sb_pool_get_dumpit(msg, start, &idx, devlink,
|
|
|
devlink_sb,
|
|
|
NETLINK_CB(cb->skb).portid,
|
|
|
cb->nlh->nlmsg_seq);
|
|
|
- if (err && err != -EOPNOTSUPP)
|
|
|
+ if (err && err != -EOPNOTSUPP) {
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
goto out;
|
|
|
+ }
|
|
|
}
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
}
|
|
|
out:
|
|
|
mutex_unlock(&devlink_mutex);
|
|
@@ -1123,22 +1133,24 @@ static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg,
|
|
|
int err;
|
|
|
|
|
|
mutex_lock(&devlink_mutex);
|
|
|
- mutex_lock(&devlink_port_mutex);
|
|
|
list_for_each_entry(devlink, &devlink_list, list) {
|
|
|
if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
|
|
|
!devlink->ops || !devlink->ops->sb_port_pool_get)
|
|
|
continue;
|
|
|
+ mutex_lock(&devlink->lock);
|
|
|
list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
|
|
|
err = __sb_port_pool_get_dumpit(msg, start, &idx,
|
|
|
devlink, devlink_sb,
|
|
|
NETLINK_CB(cb->skb).portid,
|
|
|
cb->nlh->nlmsg_seq);
|
|
|
- if (err && err != -EOPNOTSUPP)
|
|
|
+ if (err && err != -EOPNOTSUPP) {
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
goto out;
|
|
|
+ }
|
|
|
}
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
}
|
|
|
out:
|
|
|
- mutex_unlock(&devlink_port_mutex);
|
|
|
mutex_unlock(&devlink_mutex);
|
|
|
|
|
|
cb->args[0] = idx;
|
|
@@ -1347,23 +1359,26 @@ devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
|
|
|
int err;
|
|
|
|
|
|
mutex_lock(&devlink_mutex);
|
|
|
- mutex_lock(&devlink_port_mutex);
|
|
|
list_for_each_entry(devlink, &devlink_list, list) {
|
|
|
if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
|
|
|
!devlink->ops || !devlink->ops->sb_tc_pool_bind_get)
|
|
|
continue;
|
|
|
+
|
|
|
+ mutex_lock(&devlink->lock);
|
|
|
list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
|
|
|
err = __sb_tc_pool_bind_get_dumpit(msg, start, &idx,
|
|
|
devlink,
|
|
|
devlink_sb,
|
|
|
NETLINK_CB(cb->skb).portid,
|
|
|
cb->nlh->nlmsg_seq);
|
|
|
- if (err && err != -EOPNOTSUPP)
|
|
|
+ if (err && err != -EOPNOTSUPP) {
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
goto out;
|
|
|
+ }
|
|
|
}
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
}
|
|
|
out:
|
|
|
- mutex_unlock(&devlink_port_mutex);
|
|
|
mutex_unlock(&devlink_mutex);
|
|
|
|
|
|
cb->args[0] = idx;
|
|
@@ -2322,14 +2337,16 @@ static const struct genl_ops devlink_nl_ops[] = {
|
|
|
.doit = devlink_nl_cmd_port_split_doit,
|
|
|
.policy = devlink_nl_policy,
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
|
|
|
+ .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
|
|
|
+ DEVLINK_NL_FLAG_NO_LOCK,
|
|
|
},
|
|
|
{
|
|
|
.cmd = DEVLINK_CMD_PORT_UNSPLIT,
|
|
|
.doit = devlink_nl_cmd_port_unsplit_doit,
|
|
|
.policy = devlink_nl_policy,
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
- .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
|
|
|
+ .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
|
|
|
+ DEVLINK_NL_FLAG_NO_LOCK,
|
|
|
},
|
|
|
{
|
|
|
.cmd = DEVLINK_CMD_SB_GET,
|
|
@@ -2397,8 +2414,7 @@ static const struct genl_ops devlink_nl_ops[] = {
|
|
|
.policy = devlink_nl_policy,
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
|
|
|
- DEVLINK_NL_FLAG_NEED_SB |
|
|
|
- DEVLINK_NL_FLAG_LOCK_PORTS,
|
|
|
+ DEVLINK_NL_FLAG_NEED_SB,
|
|
|
},
|
|
|
{
|
|
|
.cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
|
|
@@ -2406,8 +2422,7 @@ static const struct genl_ops devlink_nl_ops[] = {
|
|
|
.policy = devlink_nl_policy,
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
|
|
|
- DEVLINK_NL_FLAG_NEED_SB |
|
|
|
- DEVLINK_NL_FLAG_LOCK_PORTS,
|
|
|
+ DEVLINK_NL_FLAG_NEED_SB,
|
|
|
},
|
|
|
{
|
|
|
.cmd = DEVLINK_CMD_ESWITCH_GET,
|
|
@@ -2488,6 +2503,7 @@ struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
|
|
|
INIT_LIST_HEAD(&devlink->port_list);
|
|
|
INIT_LIST_HEAD(&devlink->sb_list);
|
|
|
INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
|
|
|
+ mutex_init(&devlink->lock);
|
|
|
return devlink;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(devlink_alloc);
|
|
@@ -2550,16 +2566,16 @@ int devlink_port_register(struct devlink *devlink,
|
|
|
struct devlink_port *devlink_port,
|
|
|
unsigned int port_index)
|
|
|
{
|
|
|
- mutex_lock(&devlink_port_mutex);
|
|
|
+ mutex_lock(&devlink->lock);
|
|
|
if (devlink_port_index_exists(devlink, port_index)) {
|
|
|
- mutex_unlock(&devlink_port_mutex);
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
return -EEXIST;
|
|
|
}
|
|
|
devlink_port->devlink = devlink;
|
|
|
devlink_port->index = port_index;
|
|
|
devlink_port->registered = true;
|
|
|
list_add_tail(&devlink_port->list, &devlink->port_list);
|
|
|
- mutex_unlock(&devlink_port_mutex);
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
|
|
|
return 0;
|
|
|
}
|
|
@@ -2572,10 +2588,12 @@ EXPORT_SYMBOL_GPL(devlink_port_register);
|
|
|
*/
|
|
|
void devlink_port_unregister(struct devlink_port *devlink_port)
|
|
|
{
|
|
|
+ struct devlink *devlink = devlink_port->devlink;
|
|
|
+
|
|
|
devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
|
|
|
- mutex_lock(&devlink_port_mutex);
|
|
|
+ mutex_lock(&devlink->lock);
|
|
|
list_del(&devlink_port->list);
|
|
|
- mutex_unlock(&devlink_port_mutex);
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(devlink_port_unregister);
|
|
|
|
|
@@ -2651,7 +2669,7 @@ int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
|
|
|
struct devlink_sb *devlink_sb;
|
|
|
int err = 0;
|
|
|
|
|
|
- mutex_lock(&devlink_mutex);
|
|
|
+ mutex_lock(&devlink->lock);
|
|
|
if (devlink_sb_index_exists(devlink, sb_index)) {
|
|
|
err = -EEXIST;
|
|
|
goto unlock;
|
|
@@ -2670,7 +2688,7 @@ int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
|
|
|
devlink_sb->egress_tc_count = egress_tc_count;
|
|
|
list_add_tail(&devlink_sb->list, &devlink->sb_list);
|
|
|
unlock:
|
|
|
- mutex_unlock(&devlink_mutex);
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
return err;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(devlink_sb_register);
|
|
@@ -2679,11 +2697,11 @@ void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
|
|
|
{
|
|
|
struct devlink_sb *devlink_sb;
|
|
|
|
|
|
- mutex_lock(&devlink_mutex);
|
|
|
+ mutex_lock(&devlink->lock);
|
|
|
devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
|
|
|
WARN_ON(!devlink_sb);
|
|
|
list_del(&devlink_sb->list);
|
|
|
- mutex_unlock(&devlink_mutex);
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
kfree(devlink_sb);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(devlink_sb_unregister);
|
|
@@ -2699,9 +2717,9 @@ EXPORT_SYMBOL_GPL(devlink_sb_unregister);
|
|
|
int devlink_dpipe_headers_register(struct devlink *devlink,
|
|
|
struct devlink_dpipe_headers *dpipe_headers)
|
|
|
{
|
|
|
- mutex_lock(&devlink_mutex);
|
|
|
+ mutex_lock(&devlink->lock);
|
|
|
devlink->dpipe_headers = dpipe_headers;
|
|
|
- mutex_unlock(&devlink_mutex);
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
return 0;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
|
|
@@ -2715,9 +2733,9 @@ EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
|
|
|
*/
|
|
|
void devlink_dpipe_headers_unregister(struct devlink *devlink)
|
|
|
{
|
|
|
- mutex_lock(&devlink_mutex);
|
|
|
+ mutex_lock(&devlink->lock);
|
|
|
devlink->dpipe_headers = NULL;
|
|
|
- mutex_unlock(&devlink_mutex);
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
|
|
|
|
|
@@ -2783,9 +2801,9 @@ int devlink_dpipe_table_register(struct devlink *devlink,
|
|
|
table->priv = priv;
|
|
|
table->counter_control_extern = counter_control_extern;
|
|
|
|
|
|
- mutex_lock(&devlink_mutex);
|
|
|
+ mutex_lock(&devlink->lock);
|
|
|
list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
|
|
|
- mutex_unlock(&devlink_mutex);
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
return 0;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
|
|
@@ -2801,17 +2819,17 @@ void devlink_dpipe_table_unregister(struct devlink *devlink,
|
|
|
{
|
|
|
struct devlink_dpipe_table *table;
|
|
|
|
|
|
- mutex_lock(&devlink_mutex);
|
|
|
+ mutex_lock(&devlink->lock);
|
|
|
table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
|
|
|
table_name);
|
|
|
if (!table)
|
|
|
goto unlock;
|
|
|
list_del_rcu(&table->list);
|
|
|
- mutex_unlock(&devlink_mutex);
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
kfree_rcu(table, rcu);
|
|
|
return;
|
|
|
unlock:
|
|
|
- mutex_unlock(&devlink_mutex);
|
|
|
+ mutex_unlock(&devlink->lock);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
|
|
|
|