From nobody Fri Dec 19 04:25:14 2025 Received: from forward103d.mail.yandex.net (forward103d.mail.yandex.net [178.154.239.214]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6D41F17E0; Sat, 22 Mar 2025 14:39:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=178.154.239.214 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1742654364; cv=none; b=c9wMk6RhRZ9fuB0yj/V+i6IeDPe+O7GCQP3rN5mIwtyvpa89H/fn8gaVljywlPvnxpXfvg+XgyTb/ntD7snXKqevwbHAMkg/+Il9+YGiLr7jKqTH+X4D2EvPeFWVx270i7Di+il5A/LswgNOv01SL8ePjgBP+fWokIhCXUID/Ps= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1742654364; c=relaxed/simple; bh=TYEVKHS9ufJhPvW+5YwFwnlX6LMo7aN+etRQN2y+bPw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=rpCpShbKfsYejEJKHALnS/ewP+5Jk1Bqs+x6sBjhTslbzAwBB2yBULGE4/G0DjqFW/eRLdh0x/fbUbiaH27InDduKgX4jOlRNEVbG+CX508pqobgYHEvvGmhlfMmG7ddUDB5vg4ddOP/sQc24WUklqBYj8m/+kVivcdPTyUL5PY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ya.ru; spf=pass smtp.mailfrom=ya.ru; dkim=pass (1024-bit key) header.d=ya.ru header.i=@ya.ru header.b=PS4o/Qck; arc=none smtp.client-ip=178.154.239.214 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ya.ru Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ya.ru Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ya.ru header.i=@ya.ru header.b="PS4o/Qck" Received: from mail-nwsmtp-smtp-production-main-77.klg.yp-c.yandex.net (mail-nwsmtp-smtp-production-main-77.klg.yp-c.yandex.net [IPv6:2a02:6b8:c42:3bcd:0:640:dc38:0]) by forward103d.mail.yandex.net (Yandex) with ESMTPS id 8888E6001D; Sat, 22 Mar 2025 17:39:20 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-77.klg.yp-c.yandex.net (smtp/Yandex) with ESMTPSA id IdNbOcULla60-csc2eLM5; Sat, 22 Mar 2025 17:39:20 +0300 X-Yandex-Fwd: 1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ya.ru; s=mail; t=1742654360; bh=KIWNcEaP9b73qItYSdAbWzNE3+LulZ1uY+P85m4l/wU=; h=Cc:Message-ID:References:Date:In-Reply-To:Subject:To:From; b=PS4o/QckyFSVDZVTeX/J13pNZFhMe/j1cAen8GnSetUsXFhLAQ7wwRePCtrijIRUB RhYOhCgLJs+r8KmQx1rRjEDE0lNSV4AUr/r4lngWf8hkDvG4OekL7t4emkQbh/BlFV bUZjHZsSCYo5RsKBWLkbss4brgsXUwX7odzvZlow= Authentication-Results: mail-nwsmtp-smtp-production-main-77.klg.yp-c.yandex.net; dkim=pass header.i=@ya.ru From: Kirill Tkhai To: netdev@vger.kernel.org, linux-kernel@vger.kernel.org Cc: tkhai@ya.ru Subject: [PATCH NET-PREV 11/51] net: Make master and slaves (any dependent devices) share the same nd_lock in .setlink etc Date: Sat, 22 Mar 2025 17:39:18 +0300 Message-ID: <174265435817.356712.639144257882603362.stgit@pro.pro> X-Mailer: git-send-email 2.47.2 In-Reply-To: <174265415457.356712.10472727127735290090.stgit@pro.pro> References: <174265415457.356712.10472727127735290090.stgit@pro.pro> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Signed-off-by: Kirill Tkhai --- net/core/rtnetlink.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++= ++-- 1 file changed, 129 insertions(+), 5 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index cf060ba4cd1d..67b4b0610d14 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2696,9 +2696,16 @@ static int do_set_master(struct net_device *dev, str= uct net_device *master, } =20 if (master) { + struct nd_lock *nd_lock =3D rcu_access_pointer(dev->nd_lock); + struct nd_lock *nd_lock2 =3D rcu_access_pointer(master->nd_lock); + upper_dev =3D master; ops =3D upper_dev->netdev_ops; if (ops->ndo_add_slave) { + /* Devices linked as upper<->lower must relate + * to the same nd_lock. + */ + nd_lock_transfer_devices(&nd_lock, &nd_lock2); err =3D ops->ndo_add_slave(upper_dev, dev, extack); if (err) return err; @@ -3173,6 +3180,7 @@ static int rtnl_setlink(struct sk_buff *skb, struct n= lmsghdr *nlh, struct net *net =3D sock_net(skb->sk); struct ifinfomsg *ifm; struct net_device *dev, *master =3D NULL; + struct nd_lock *nd_lock, *nd_lock2; struct net *target_net =3D NULL; int err; struct nlattr *tb[IFLA_MAX+1]; @@ -3217,7 +3225,9 @@ static int rtnl_setlink(struct sk_buff *skb, struct n= lmsghdr *nlh, if (err < 0) goto errout; =20 + double_lock_netdev(dev, &nd_lock, master, &nd_lock2); err =3D do_setlink(target_net, skb, dev, master, ifm, extack, tb, 0); + double_unlock_netdev(nd_lock, nd_lock2); errout: if (target_net) put_net(target_net); @@ -3458,6 +3468,7 @@ static int rtnl_group_changelink(const struct sk_buff= *skb, struct nlattr **tb) { struct net_device *dev, *aux, *master =3D NULL; + struct nd_lock *nd_lock, *nd_lock2; struct net *target_net; int err; =20 @@ -3479,7 +3490,9 @@ static int rtnl_group_changelink(const struct sk_buff= *skb, err =3D validate_linkmsg(dev, tb, extack); if (err < 0) break; + double_lock_netdev(dev, &nd_lock, master, &nd_lock2); err =3D do_setlink(target_net, skb, dev, master, ifm, extack, tb, 0); + double_unlock_netdev(nd_lock, nd_lock2); if (err < 0) break; } @@ -3495,6 +3508,74 @@ struct link_deps generic_newlink_deps =3D { }; EXPORT_SYMBOL_GPL(generic_newlink_deps); =20 +static struct net_device *__resolve_deps_locks(struct net *net, + struct net_device *dev, + struct nlattr **attr, + const int deps[], + bool mandatory) +{ + struct nd_lock *nd_lock, *nd_lock2; + struct net_device *dev2; + int i, key, ifindex; + + for (i =3D 0; i <=3D MAX_LINK_DEPS; i++) { + key =3D deps[i]; + if (!key) + break; + if (!attr[key]) { + if (mandatory) + return ERR_PTR(-ENODEV); + continue; + } + ifindex =3D nla_get_u32(attr[key]); + + if (!dev) { + dev =3D __dev_get_by_index(net, ifindex); + if (!dev && mandatory) + return ERR_PTR(-ENODEV); + continue; + } + + dev2 =3D __dev_get_by_index(net, ifindex); + if (!dev2) { + if (mandatory) + return ERR_PTR(-ENODEV); + continue; + } + double_lock_netdev(dev, &nd_lock, dev2, &nd_lock2); + nd_lock_transfer_devices(&nd_lock, &nd_lock2); + double_unlock_netdev(nd_lock, nd_lock2); + } + + return dev; +} + +/* Transfer all dependencies to the same nd_lock. + * Note, here we use that list of nd_lock devices + * can't be split in pieces. + */ +static struct net_device *resolve_deps_locks(struct net *net, + const struct link_deps *deps, + struct nlattr **tb, + struct nlattr **data) +{ + struct net_device *dev =3D NULL; + + if (!deps) + return NULL; + + dev =3D __resolve_deps_locks(net, dev, tb, deps->mandatory.tb, true); + if (IS_ERR(dev)) + return dev; + dev =3D __resolve_deps_locks(net, dev, data, deps->mandatory.data, true); + if (IS_ERR(dev)) + return dev; + dev =3D __resolve_deps_locks(net, dev, tb, deps->optional.tb, false); + dev =3D __resolve_deps_locks(net, dev, tb, deps->optional.data, false); + + return dev; +} + static int rtnl_newlink_create(struct sk_buff *skb, struct ifinfomsg *ifm, const struct rtnl_link_ops *ops, const struct nlmsghdr *nlh, @@ -3506,7 +3587,8 @@ static int rtnl_newlink_create(struct sk_buff *skb, s= truct ifinfomsg *ifm, struct net *net =3D sock_net(skb->sk); u32 portid =3D NETLINK_CB(skb).portid; struct net *link_net; - struct net_device *dev, *master =3D NULL; + struct net_device *dev, *master =3D NULL, *link_dev =3D NULL; + struct nd_lock *nd_lock, *nd_lock2; char ifname[IFNAMSIZ]; LIST_HEAD(list_kill); int err; @@ -3554,13 +3636,36 @@ static int rtnl_newlink_create(struct sk_buff *skb,= struct ifinfomsg *ifm, goto out; } =20 + link_dev =3D resolve_deps_locks(link_net ? : net, ops->newlink_deps, tb, = data); + if (IS_ERR(link_dev)) { + err =3D -EINVAL; + goto out; + } + + if (master && link_dev) { + double_lock_netdev(master, &nd_lock, link_dev, &nd_lock2); + nd_lock_transfer_devices(&nd_lock, &nd_lock2); + if (nd_lock !=3D nd_lock2) + unlock_netdev(nd_lock); + } else if (master || link_dev) { + lock_netdev(master ? : link_dev, &nd_lock); + } else { + nd_lock =3D alloc_nd_lock(); + err =3D -ENOMEM; + if (!nd_lock) + goto out; + mutex_lock(&nd_lock->mutex); + } + attach_nd_lock(dev, nd_lock); + if (ops->newlink) err =3D ops->newlink(link_net ? : net, dev, tb, data, extack); else - err =3D register_netdevice(dev); + err =3D __register_netdevice(dev); if (err < 0) { + detach_nd_lock(dev); free_netdev(dev); - goto out; + goto unlock; } =20 err =3D rtnl_configure_link(dev, ifm, portid, nlh); @@ -3576,6 +3681,8 @@ static int rtnl_newlink_create(struct sk_buff *skb, s= truct ifinfomsg *ifm, if (err) goto out_unregister; } +unlock: + unlock_netdev(nd_lock); out: if (link_net) put_net(link_net); @@ -3587,7 +3694,7 @@ static int rtnl_newlink_create(struct sk_buff *skb, s= truct ifinfomsg *ifm, unregister_netdevice_queue(dev, &list_kill); } unregister_netdevice_many(&list_kill); - goto out; + goto unlock; } =20 struct rtnl_newlink_tbs { @@ -3608,7 +3715,8 @@ static int __rtnl_newlink_setlink(struct sk_buff *skb= , struct nlmsghdr *nlh, struct ifinfomsg *ifm =3D nlmsg_data(nlh); struct nlattr ** const tb =3D tbs->tb; struct nlattr **slave_data =3D NULL; - struct net_device *master_dev; + struct net_device *master_dev, *link_dev; + struct nd_lock *nd_lock, *nd_lock2; int err, status =3D 0; =20 if (nlh->nlmsg_flags & NLM_F_EXCL) @@ -3620,6 +3728,21 @@ static int __rtnl_newlink_setlink(struct sk_buff *sk= b, struct nlmsghdr *nlh, if (err < 0) return err; =20 + if (ops && ops =3D=3D dev->rtnl_link_ops && linkinfo[IFLA_INFO_DATA]) { + link_dev =3D resolve_deps_locks(dev_net(dev), + ops->changelink_deps, + tb, data); + if (IS_ERR(link_dev)) + return PTR_ERR(link_dev); + + if (link_dev) { + double_lock_netdev(dev, &nd_lock, link_dev, &nd_lock2); + nd_lock_transfer_devices(&nd_lock, &nd_lock2); + double_unlock_netdev(nd_lock, nd_lock2); + } + } + + double_lock_netdev(dev, &nd_lock, new_master, &nd_lock2); master_dev =3D netdev_master_upper_dev_get(dev); if (master_dev) m_ops =3D master_dev->rtnl_link_ops; @@ -3668,6 +3791,7 @@ static int __rtnl_newlink_setlink(struct sk_buff *skb= , struct nlmsghdr *nlh, =20 err =3D do_setlink(target_net, skb, dev, new_master, ifm, extack, tb, sta= tus); out: + double_unlock_netdev(nd_lock, nd_lock2); return err; }