Skip to content

Commit 910c478

Browse files
kmaincentkuba-moo
authored andcommitted
ethtool: Fix wrong mod state in case of verbose and no_mask bitset
A bitset without mask in a _SET request means we want exactly the bits in the bitset to be set. This works correctly for compact format but when verbose format is parsed, ethnl_update_bitset32_verbose() only sets the bits present in the request bitset but does not clear the rest. The commit 6699170 ("ethtool: fix application of verbose no_mask bitset") fixes this issue by clearing the whole target bitmap before we start iterating. The solution proposed brought an issue with the behavior of the mod variable. As the bitset is always cleared the old value will always differ to the new value. Fix it by adding a new function to compare bitmaps and a temporary variable which save the state of the old bitmap. Fixes: 6699170 ("ethtool: fix application of verbose no_mask bitset") Signed-off-by: Kory Maincent <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 50b9420 commit 910c478

File tree

1 file changed

+44
-4
lines changed

1 file changed

+44
-4
lines changed

net/ethtool/bitset.c

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -425,12 +425,32 @@ static int ethnl_parse_bit(unsigned int *index, bool *val, unsigned int nbits,
425425
return 0;
426426
}
427427

428+
/**
429+
* ethnl_bitmap32_equal() - Compare two bitmaps
430+
* @map1: first bitmap
431+
* @map2: second bitmap
432+
* @nbits: bit size to compare
433+
*
434+
* Return: true if first @nbits are equal, false if not
435+
*/
436+
static bool ethnl_bitmap32_equal(const u32 *map1, const u32 *map2,
437+
unsigned int nbits)
438+
{
439+
if (memcmp(map1, map2, nbits / 32 * sizeof(u32)))
440+
return false;
441+
if (nbits % 32 == 0)
442+
return true;
443+
return !((map1[nbits / 32] ^ map2[nbits / 32]) &
444+
ethnl_lower_bits(nbits % 32));
445+
}
446+
428447
static int
429448
ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
430449
const struct nlattr *attr, struct nlattr **tb,
431450
ethnl_string_array_t names,
432451
struct netlink_ext_ack *extack, bool *mod)
433452
{
453+
u32 *saved_bitmap = NULL;
434454
struct nlattr *bit_attr;
435455
bool no_mask;
436456
int rem;
@@ -448,8 +468,20 @@ ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
448468
}
449469

450470
no_mask = tb[ETHTOOL_A_BITSET_NOMASK];
451-
if (no_mask)
452-
ethnl_bitmap32_clear(bitmap, 0, nbits, mod);
471+
if (no_mask) {
472+
unsigned int nwords = DIV_ROUND_UP(nbits, 32);
473+
unsigned int nbytes = nwords * sizeof(u32);
474+
bool dummy;
475+
476+
/* The bitmap size is only the size of the map part without
477+
* its mask part.
478+
*/
479+
saved_bitmap = kcalloc(nwords, sizeof(u32), GFP_KERNEL);
480+
if (!saved_bitmap)
481+
return -ENOMEM;
482+
memcpy(saved_bitmap, bitmap, nbytes);
483+
ethnl_bitmap32_clear(bitmap, 0, nbits, &dummy);
484+
}
453485

454486
nla_for_each_nested(bit_attr, tb[ETHTOOL_A_BITSET_BITS], rem) {
455487
bool old_val, new_val;
@@ -458,22 +490,30 @@ ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
458490
if (nla_type(bit_attr) != ETHTOOL_A_BITSET_BITS_BIT) {
459491
NL_SET_ERR_MSG_ATTR(extack, bit_attr,
460492
"only ETHTOOL_A_BITSET_BITS_BIT allowed in ETHTOOL_A_BITSET_BITS");
493+
kfree(saved_bitmap);
461494
return -EINVAL;
462495
}
463496
ret = ethnl_parse_bit(&idx, &new_val, nbits, bit_attr, no_mask,
464497
names, extack);
465-
if (ret < 0)
498+
if (ret < 0) {
499+
kfree(saved_bitmap);
466500
return ret;
501+
}
467502
old_val = bitmap[idx / 32] & ((u32)1 << (idx % 32));
468503
if (new_val != old_val) {
469504
if (new_val)
470505
bitmap[idx / 32] |= ((u32)1 << (idx % 32));
471506
else
472507
bitmap[idx / 32] &= ~((u32)1 << (idx % 32));
473-
*mod = true;
508+
if (!no_mask)
509+
*mod = true;
474510
}
475511
}
476512

513+
if (no_mask && !ethnl_bitmap32_equal(saved_bitmap, bitmap, nbits))
514+
*mod = true;
515+
516+
kfree(saved_bitmap);
477517
return 0;
478518
}
479519

0 commit comments

Comments
 (0)