*/
 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);
 #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);
                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);
 }
 
        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++;
                                                   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;
        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++;
                                                 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);
                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);
        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;
        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;
                .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,
                .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,
                .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,
        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);
                          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;
 }
  */
 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);
 
        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;
        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);
 {
        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);
 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);
  */
 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);
 
        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);
 {
        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);