Received: by 2002:a25:e7d8:0:0:0:0:0 with SMTP id e207csp897748ybh; Thu, 12 Mar 2020 13:08:43 -0700 (PDT) X-Google-Smtp-Source: ADFU+vs3VpFHNDuK8rEJMSViNRy5FX78o4dlwj90HElDzVZm8HSVUSTGxGSOtd/qw7IzzuO2iEc+ X-Received: by 2002:a05:6830:1410:: with SMTP id v16mr3847240otp.315.1584043723088; Thu, 12 Mar 2020 13:08:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1584043723; cv=none; d=google.com; s=arc-20160816; b=gNu+yZiOIxhTlEILrYOmCmSXgt5iizfqZoGwazDIbStDLFa6q6XQVqxJjLZwftnIHf 3nF/1ndtMIbhiVI8Y5HN3fuN3Qs6GsgO5VtDeUVzDr0ejFKcavWq5Wgi1e9rx1679Xcp wCFF+RLup5BEHAnjOKLpcDRCZT2FbvR2nSlzH22m4iSGgOvlkUQeE6+j6tZsWATu9flr MU2U1O6wJ5wYjcb7jgyUz9YWP5h/i8xCKSdMdQe4ga54iXZi5rfVLj3/4b+m3VPpqGWC HhrQS+3jIGpOGK/qZbj0VoWVGY+RlKcz4KeCntM6N8wzp2Xf2vs1Y/TSaoiBIbCPrHYp +p2Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:date:cc:to:subject:from:references :in-reply-to:message-id; bh=xYRGLYIVcPHaHSSIsZFhfdXk2JJZUA1u+xTmv5MfRP4=; b=gbL6EXcqZ4o0sH87DJYSiiKfZmcsA9AhvqR2xm7Cwl5gjQ4+kdGbK2mSzokD1iaIga eh07IL7bNu7r/J6xN3m3Fk27DQe+di4g07rmPrj6xq8PsMfc0IpCImtu9fSwE1jm9gUB GQhjQhxU9uIwz8t525S/QpEhDhP3Y//kxwzFoJtdvZM4JG71qMIGZhdr4zRtxKx8H/it qt2rDcvlTd5ahLsLEYNHjQ6A4mpVO+J2C54kozkx+QgLmfgnLSqW9LCpks3TzQDYSpMx 6TELyaOmnvpy1fi35HhVK8morIhuCBeMj/Q+LH+Sam1DgvgyQWRkUgH1xPQSdyob4CGr ENjA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id d20si3361757oti.311.2020.03.12.13.08.31; Thu, 12 Mar 2020 13:08:43 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727150AbgCLUH5 (ORCPT + 99 others); Thu, 12 Mar 2020 16:07:57 -0400 Received: from mx2.suse.de ([195.135.220.15]:45172 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727133AbgCLUHz (ORCPT ); Thu, 12 Mar 2020 16:07:55 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id D1383ADFF; Thu, 12 Mar 2020 20:07:53 +0000 (UTC) Received: by unicorn.suse.cz (Postfix, from userid 1000) id 8275BE0C79; Thu, 12 Mar 2020 21:07:53 +0100 (CET) Message-Id: <2fb9d667997ea5628ebc0d601639e0b7dd59cb35.1584043144.git.mkubecek@suse.cz> In-Reply-To: References: From: Michal Kubecek Subject: [PATCH net-next v2 04/15] ethtool: add ethnl_parse_bitset() helper To: David Miller , Jakub Kicinski , netdev@vger.kernel.org Cc: Jiri Pirko , Andrew Lunn , Florian Fainelli , John Linville , Johannes Berg , linux-kernel@vger.kernel.org Date: Thu, 12 Mar 2020 21:07:53 +0100 (CET) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Unlike other SET type commands, modifying netdev features is required to provide a reply telling userspace what was actually changed, compared to what was requested. For that purpose, the "modified" flag provided by ethnl_update_bitset() is not sufficient, we need full information which bits were requested to change. Therefore provide ethnl_parse_bitset() returning effective value and mask bitmaps equivalent to the contents of a bitset nested attribute. v2: use non-atomic __set_bit() (suggested by David Miller) Signed-off-by: Michal Kubecek --- net/ethtool/bitset.c | 94 ++++++++++++++++++++++++++++++++++++++++++++ net/ethtool/bitset.h | 4 ++ 2 files changed, 98 insertions(+) diff --git a/net/ethtool/bitset.c b/net/ethtool/bitset.c index ef9197541cb3..dae7402eaca3 100644 --- a/net/ethtool/bitset.c +++ b/net/ethtool/bitset.c @@ -588,6 +588,100 @@ int ethnl_update_bitset32(u32 *bitmap, unsigned int nbits, return 0; } +/** + * ethnl_parse_bitset() - Compute effective value and mask from bitset nest + * @val: unsigned long based bitmap to put value into + * @mask: unsigned long based bitmap to put mask into + * @nbits: size of @val and @mask bitmaps + * @attr: nest attribute to parse and apply + * @names: array of bit names; may be null for compact format + * @extack: extack for error reporting + * + * Provide @nbits size long bitmaps for value and mask so that + * x = (val & mask) | (x & ~mask) would modify any @nbits sized bitmap x + * the same way ethnl_update_bitset() with the same bitset attribute would. + * + * Return: negative error code on failure, 0 on success + */ +int ethnl_parse_bitset(unsigned long *val, unsigned long *mask, + unsigned int nbits, const struct nlattr *attr, + ethnl_string_array_t names, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[ETHTOOL_A_BITSET_MAX + 1]; + const struct nlattr *bit_attr; + bool no_mask; + int rem; + int ret; + + if (!attr) + return 0; + ret = nla_parse_nested(tb, ETHTOOL_A_BITSET_MAX, attr, bitset_policy, + extack); + if (ret < 0) + return ret; + no_mask = tb[ETHTOOL_A_BITSET_NOMASK]; + + if (!tb[ETHTOOL_A_BITSET_BITS]) { + unsigned int change_bits; + + ret = ethnl_compact_sanity_checks(nbits, attr, tb, extack); + if (ret < 0) + return ret; + + change_bits = nla_get_u32(tb[ETHTOOL_A_BITSET_SIZE]); + bitmap_from_arr32(val, nla_data(tb[ETHTOOL_A_BITSET_VALUE]), + change_bits); + if (change_bits < nbits) + bitmap_clear(val, change_bits, nbits - change_bits); + if (no_mask) { + bitmap_fill(mask, nbits); + } else { + bitmap_from_arr32(mask, + nla_data(tb[ETHTOOL_A_BITSET_MASK]), + change_bits); + if (change_bits < nbits) + bitmap_clear(mask, change_bits, + nbits - change_bits); + } + + return 0; + } + + if (tb[ETHTOOL_A_BITSET_VALUE]) { + NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_VALUE], + "value only allowed in compact bitset"); + return -EINVAL; + } + if (tb[ETHTOOL_A_BITSET_MASK]) { + NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK], + "mask only allowed in compact bitset"); + return -EINVAL; + } + + bitmap_zero(val, nbits); + if (no_mask) + bitmap_fill(mask, nbits); + else + bitmap_zero(mask, nbits); + + nla_for_each_nested(bit_attr, tb[ETHTOOL_A_BITSET_BITS], rem) { + unsigned int idx; + bool bit_val; + + ret = ethnl_parse_bit(&idx, &bit_val, nbits, bit_attr, no_mask, + names, extack); + if (ret < 0) + return ret; + if (bit_val) + __set_bit(idx, val); + if (!no_mask) + __set_bit(idx, mask); + } + + return 0; +} + #if BITS_PER_LONG == 64 && defined(__BIG_ENDIAN) /* 64-bit big endian architectures are the only case when u32 based bitmaps diff --git a/net/ethtool/bitset.h b/net/ethtool/bitset.h index b849f9d19676..c2c2e0051d00 100644 --- a/net/ethtool/bitset.h +++ b/net/ethtool/bitset.h @@ -26,5 +26,9 @@ int ethnl_update_bitset(unsigned long *bitmap, unsigned int nbits, int ethnl_update_bitset32(u32 *bitmap, unsigned int nbits, const struct nlattr *attr, ethnl_string_array_t names, struct netlink_ext_ack *extack, bool *mod); +int ethnl_parse_bitset(unsigned long *val, unsigned long *mask, + unsigned int nbits, const struct nlattr *attr, + ethnl_string_array_t names, + struct netlink_ext_ack *extack); #endif /* _NET_ETHTOOL_BITSET_H */ -- 2.25.1