Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

8021q: use RCU for egress QoS mappings

The TX fast path and reporting paths walk egress QoS mappings without
RTNL. Convert the mapping lists to RCU-protected pointers, use RCU
reader annotations in readers, and defer freeing mapping nodes with an
embedded rcu_head.

This prepares the egress QoS mapping code for safe removal of mapping
nodes in a follow-up change while preserving the current behavior.

Co-developed-by: Yuan Tan <yuantan098@gmail.com>
Signed-off-by: Yuan Tan <yuantan098@gmail.com>
Signed-off-by: Longxuan Yu <ylong030@ucr.edu>
Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
Link: https://patch.msgid.link/9136768189f8c6d3f824f476c62d2fa1111688e8.1776647968.git.yuantan098@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Longxuan Yu and committed by
Paolo Abeni
fc69decc 5a5db99c

+46 -32
+16 -9
include/linux/if_vlan.h
··· 147 147 * @priority: skb priority 148 148 * @vlan_qos: vlan priority: (skb->priority << 13) & 0xE000 149 149 * @next: pointer to next struct 150 + * @rcu: used for deferred freeing of mapping nodes 150 151 */ 151 152 struct vlan_priority_tci_mapping { 152 153 u32 priority; 153 154 u16 vlan_qos; 154 - struct vlan_priority_tci_mapping *next; 155 + struct vlan_priority_tci_mapping __rcu *next; 156 + struct rcu_head rcu; 155 157 }; 156 158 157 159 struct proc_dir_entry; ··· 179 177 unsigned int nr_ingress_mappings; 180 178 u32 ingress_priority_map[8]; 181 179 unsigned int nr_egress_mappings; 182 - struct vlan_priority_tci_mapping *egress_priority_map[16]; 180 + struct vlan_priority_tci_mapping __rcu *egress_priority_map[16]; 183 181 184 182 __be16 vlan_proto; 185 183 u16 vlan_id; ··· 211 209 vlan_dev_get_egress_qos_mask(struct net_device *dev, u32 skprio) 212 210 { 213 211 struct vlan_priority_tci_mapping *mp; 212 + u16 vlan_qos = 0; 214 213 215 - smp_rmb(); /* coupled with smp_wmb() in vlan_dev_set_egress_priority() */ 214 + rcu_read_lock(); 216 215 217 - mp = vlan_dev_priv(dev)->egress_priority_map[(skprio & 0xF)]; 216 + mp = rcu_dereference(vlan_dev_priv(dev)->egress_priority_map[skprio & 0xF]); 218 217 while (mp) { 219 218 if (mp->priority == skprio) { 220 - return mp->vlan_qos; /* This should already be shifted 221 - * to mask correctly with the 222 - * VLAN's TCI */ 219 + vlan_qos = READ_ONCE(mp->vlan_qos); 220 + break; 223 221 } 224 - mp = mp->next; 222 + mp = rcu_dereference(mp->next); 225 223 } 226 - return 0; 224 + rcu_read_unlock(); 225 + 226 + /* This should already be shifted to mask correctly with 227 + * the VLAN's TCI. 228 + */ 229 + return vlan_qos; 227 230 } 228 231 229 232 extern bool vlan_do_receive(struct sk_buff **skb);
+16 -15
net/8021q/vlan_dev.c
··· 172 172 u32 skb_prio, u16 vlan_prio) 173 173 { 174 174 struct vlan_dev_priv *vlan = vlan_dev_priv(dev); 175 - struct vlan_priority_tci_mapping *mp = NULL; 175 + struct vlan_priority_tci_mapping *mp; 176 176 struct vlan_priority_tci_mapping *np; 177 + u32 bucket = skb_prio & 0xF; 177 178 u32 vlan_qos = (vlan_prio << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK; 178 179 179 180 /* See if a priority mapping exists.. */ 180 - mp = vlan->egress_priority_map[skb_prio & 0xF]; 181 + mp = rtnl_dereference(vlan->egress_priority_map[bucket]); 181 182 while (mp) { 182 183 if (mp->priority == skb_prio) { 183 184 if (mp->vlan_qos && !vlan_qos) 184 185 vlan->nr_egress_mappings--; 185 186 else if (!mp->vlan_qos && vlan_qos) 186 187 vlan->nr_egress_mappings++; 187 - mp->vlan_qos = vlan_qos; 188 + WRITE_ONCE(mp->vlan_qos, vlan_qos); 188 189 return 0; 189 190 } 190 - mp = mp->next; 191 + mp = rtnl_dereference(mp->next); 191 192 } 192 193 193 194 /* Create a new mapping then. */ 194 - mp = vlan->egress_priority_map[skb_prio & 0xF]; 195 195 np = kmalloc_obj(struct vlan_priority_tci_mapping); 196 196 if (!np) 197 197 return -ENOBUFS; 198 198 199 - np->next = mp; 200 199 np->priority = skb_prio; 201 200 np->vlan_qos = vlan_qos; 202 - /* Before inserting this element in hash table, make sure all its fields 203 - * are committed to memory. 204 - * coupled with smp_rmb() in vlan_dev_get_egress_qos_mask() 205 - */ 206 - smp_wmb(); 207 - vlan->egress_priority_map[skb_prio & 0xF] = np; 201 + RCU_INIT_POINTER(np->next, rtnl_dereference(vlan->egress_priority_map[bucket])); 202 + rcu_assign_pointer(vlan->egress_priority_map[bucket], np); 208 203 if (vlan_qos) 209 204 vlan->nr_egress_mappings++; 210 205 return 0; ··· 599 604 int i; 600 605 601 606 for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) { 602 - while ((pm = vlan->egress_priority_map[i]) != NULL) { 603 - vlan->egress_priority_map[i] = pm->next; 604 - kfree(pm); 607 + pm = rtnl_dereference(vlan->egress_priority_map[i]); 608 + RCU_INIT_POINTER(vlan->egress_priority_map[i], NULL); 609 + while (pm) { 610 + struct vlan_priority_tci_mapping *next; 611 + 612 + next = rtnl_dereference(pm->next); 613 + kfree_rcu(pm, rcu); 614 + pm = next; 605 615 } 606 616 } 617 + vlan->nr_egress_mappings = 0; 607 618 } 608 619 609 620 static void vlan_dev_uninit(struct net_device *dev)
+6 -4
net/8021q/vlan_netlink.c
··· 260 260 goto nla_put_failure; 261 261 262 262 for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) { 263 - for (pm = vlan->egress_priority_map[i]; pm; 264 - pm = pm->next) { 265 - if (!pm->vlan_qos) 263 + for (pm = rcu_dereference_rtnl(vlan->egress_priority_map[i]); pm; 264 + pm = rcu_dereference_rtnl(pm->next)) { 265 + u16 vlan_qos = READ_ONCE(pm->vlan_qos); 266 + 267 + if (!vlan_qos) 266 268 continue; 267 269 268 270 m.from = pm->priority; 269 - m.to = (pm->vlan_qos >> 13) & 0x7; 271 + m.to = (vlan_qos >> 13) & 0x7; 270 272 if (nla_put(skb, IFLA_VLAN_QOS_MAPPING, 271 273 sizeof(m), &m)) 272 274 goto nla_put_failure;
+8 -4
net/8021q/vlanproc.c
··· 262 262 vlan->ingress_priority_map[7]); 263 263 264 264 seq_printf(seq, " EGRESS priority mappings: "); 265 + rcu_read_lock(); 265 266 for (i = 0; i < 16; i++) { 266 - const struct vlan_priority_tci_mapping *mp 267 - = vlan->egress_priority_map[i]; 267 + const struct vlan_priority_tci_mapping *mp = 268 + rcu_dereference(vlan->egress_priority_map[i]); 268 269 while (mp) { 270 + u16 vlan_qos = READ_ONCE(mp->vlan_qos); 271 + 269 272 seq_printf(seq, "%u:%d ", 270 - mp->priority, ((mp->vlan_qos >> 13) & 0x7)); 271 - mp = mp->next; 273 + mp->priority, ((vlan_qos >> 13) & 0x7)); 274 + mp = rcu_dereference(mp->next); 272 275 } 273 276 } 277 + rcu_read_unlock(); 274 278 seq_puts(seq, "\n"); 275 279 276 280 return 0;