Skip to content

Commit 6b7b40a

Browse files
ecsvsimonwunderlich
authored andcommitted
batman-adv: Add inconsistent local TT netlink dump detection
The netlink dump functionality transfers a large number of entries from the kernel to userspace. It is rather likely that the transfer has to interrupted and later continued. During that time, it can happen that either new entries are added or removed. The userspace could than either receive some entries multiple times or miss entries. Commit 670dc28 ("netlink: advertise incomplete dumps") introduced a mechanism to inform userspace about this problem. Userspace can then decide whether it is necessary or not to retry dumping the information again. The netlink dump functions have to be switched to exclusive locks to avoid changes while the current message is prepared. The already existing generation sequence counter from the hash helper can be used for this simple hash. Reported-by: Matthias Schiffer <[email protected]> Signed-off-by: Sven Eckelmann <[email protected]> Signed-off-by: Simon Wunderlich <[email protected]>
1 parent 6f81652 commit 6b7b40a

File tree

1 file changed

+23
-18
lines changed

1 file changed

+23
-18
lines changed

net/batman-adv/translation-table.c

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,14 +1145,15 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
11451145
* batadv_tt_local_dump_entry() - Dump one TT local entry into a message
11461146
* @msg :Netlink message to dump into
11471147
* @portid: Port making netlink request
1148-
* @seq: Sequence number of netlink message
1148+
* @cb: Control block containing additional options
11491149
* @bat_priv: The bat priv with all the soft interface information
11501150
* @common: tt local & tt global common data
11511151
*
11521152
* Return: Error code, or 0 on success
11531153
*/
11541154
static int
1155-
batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
1155+
batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid,
1156+
struct netlink_callback *cb,
11561157
struct batadv_priv *bat_priv,
11571158
struct batadv_tt_common_entry *common)
11581159
{
@@ -1173,12 +1174,14 @@ batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
11731174

11741175
batadv_softif_vlan_put(vlan);
11751176

1176-
hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
1177-
NLM_F_MULTI,
1177+
hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
1178+
&batadv_netlink_family, NLM_F_MULTI,
11781179
BATADV_CMD_GET_TRANSTABLE_LOCAL);
11791180
if (!hdr)
11801181
return -ENOBUFS;
11811182

1183+
genl_dump_check_consistent(cb, hdr);
1184+
11821185
if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) ||
11831186
nla_put_u32(msg, BATADV_ATTR_TT_CRC32, crc) ||
11841187
nla_put_u16(msg, BATADV_ATTR_TT_VID, common->vid) ||
@@ -1201,34 +1204,39 @@ batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
12011204
* batadv_tt_local_dump_bucket() - Dump one TT local bucket into a message
12021205
* @msg: Netlink message to dump into
12031206
* @portid: Port making netlink request
1204-
* @seq: Sequence number of netlink message
1207+
* @cb: Control block containing additional options
12051208
* @bat_priv: The bat priv with all the soft interface information
1206-
* @head: Pointer to the list containing the local tt entries
1209+
* @hash: hash to dump
1210+
* @bucket: bucket index to dump
12071211
* @idx_s: Number of entries to skip
12081212
*
12091213
* Return: Error code, or 0 on success
12101214
*/
12111215
static int
1212-
batadv_tt_local_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
1216+
batadv_tt_local_dump_bucket(struct sk_buff *msg, u32 portid,
1217+
struct netlink_callback *cb,
12131218
struct batadv_priv *bat_priv,
1214-
struct hlist_head *head, int *idx_s)
1219+
struct batadv_hashtable *hash, unsigned int bucket,
1220+
int *idx_s)
12151221
{
12161222
struct batadv_tt_common_entry *common;
12171223
int idx = 0;
12181224

1219-
rcu_read_lock();
1220-
hlist_for_each_entry_rcu(common, head, hash_entry) {
1225+
spin_lock_bh(&hash->list_locks[bucket]);
1226+
cb->seq = atomic_read(&hash->generation) << 1 | 1;
1227+
1228+
hlist_for_each_entry(common, &hash->table[bucket], hash_entry) {
12211229
if (idx++ < *idx_s)
12221230
continue;
12231231

1224-
if (batadv_tt_local_dump_entry(msg, portid, seq, bat_priv,
1232+
if (batadv_tt_local_dump_entry(msg, portid, cb, bat_priv,
12251233
common)) {
1226-
rcu_read_unlock();
1234+
spin_unlock_bh(&hash->list_locks[bucket]);
12271235
*idx_s = idx - 1;
12281236
return -EMSGSIZE;
12291237
}
12301238
}
1231-
rcu_read_unlock();
1239+
spin_unlock_bh(&hash->list_locks[bucket]);
12321240

12331241
*idx_s = 0;
12341242
return 0;
@@ -1248,7 +1256,6 @@ int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb)
12481256
struct batadv_priv *bat_priv;
12491257
struct batadv_hard_iface *primary_if = NULL;
12501258
struct batadv_hashtable *hash;
1251-
struct hlist_head *head;
12521259
int ret;
12531260
int ifindex;
12541261
int bucket = cb->args[0];
@@ -1276,10 +1283,8 @@ int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb)
12761283
hash = bat_priv->tt.local_hash;
12771284

12781285
while (bucket < hash->size) {
1279-
head = &hash->table[bucket];
1280-
1281-
if (batadv_tt_local_dump_bucket(msg, portid, cb->nlh->nlmsg_seq,
1282-
bat_priv, head, &idx))
1286+
if (batadv_tt_local_dump_bucket(msg, portid, cb, bat_priv,
1287+
hash, bucket, &idx))
12831288
break;
12841289

12851290
bucket++;

0 commit comments

Comments
 (0)