Skip to content

Commit 108a36d

Browse files
kmaincentkuba-moo
authored andcommitted
ethtool: Fix mod state of verbose 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 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 val will always differ to the new val. Fix it by adding a new 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]> Reviewed-by: Simon Horman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent b52acd0 commit 108a36d

File tree

1 file changed

+26
-6
lines changed

1 file changed

+26
-6
lines changed

net/ethtool/bitset.c

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -431,8 +431,10 @@ ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
431431
ethnl_string_array_t names,
432432
struct netlink_ext_ack *extack, bool *mod)
433433
{
434+
u32 *orig_bitmap, *saved_bitmap = NULL;
434435
struct nlattr *bit_attr;
435436
bool no_mask;
437+
bool dummy;
436438
int rem;
437439
int ret;
438440

@@ -448,8 +450,22 @@ ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
448450
}
449451

450452
no_mask = tb[ETHTOOL_A_BITSET_NOMASK];
451-
if (no_mask)
452-
ethnl_bitmap32_clear(bitmap, 0, nbits, mod);
453+
if (no_mask) {
454+
unsigned int nwords = DIV_ROUND_UP(nbits, 32);
455+
unsigned int nbytes = nwords * sizeof(u32);
456+
457+
/* The bitmap size is only the size of the map part without
458+
* its mask part.
459+
*/
460+
saved_bitmap = kcalloc(nwords, sizeof(u32), GFP_KERNEL);
461+
if (!saved_bitmap)
462+
return -ENOMEM;
463+
memcpy(saved_bitmap, bitmap, nbytes);
464+
ethnl_bitmap32_clear(bitmap, 0, nbits, &dummy);
465+
orig_bitmap = saved_bitmap;
466+
} else {
467+
orig_bitmap = bitmap;
468+
}
453469

454470
nla_for_each_nested(bit_attr, tb[ETHTOOL_A_BITSET_BITS], rem) {
455471
bool old_val, new_val;
@@ -458,13 +474,14 @@ ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
458474
if (nla_type(bit_attr) != ETHTOOL_A_BITSET_BITS_BIT) {
459475
NL_SET_ERR_MSG_ATTR(extack, bit_attr,
460476
"only ETHTOOL_A_BITSET_BITS_BIT allowed in ETHTOOL_A_BITSET_BITS");
461-
return -EINVAL;
477+
ret = -EINVAL;
478+
goto out;
462479
}
463480
ret = ethnl_parse_bit(&idx, &new_val, nbits, bit_attr, no_mask,
464481
names, extack);
465482
if (ret < 0)
466-
return ret;
467-
old_val = bitmap[idx / 32] & ((u32)1 << (idx % 32));
483+
goto out;
484+
old_val = orig_bitmap[idx / 32] & ((u32)1 << (idx % 32));
468485
if (new_val != old_val) {
469486
if (new_val)
470487
bitmap[idx / 32] |= ((u32)1 << (idx % 32));
@@ -474,7 +491,10 @@ ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
474491
}
475492
}
476493

477-
return 0;
494+
ret = 0;
495+
out:
496+
kfree(saved_bitmap);
497+
return ret;
478498
}
479499

480500
static int ethnl_compact_sanity_checks(unsigned int nbits,

0 commit comments

Comments
 (0)