diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 2d2efb877975..ec9a7cc8afc7 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -49,7 +49,7 @@ const char vlan_version[] = DRV_VERSION; static int vlan_group_prealloc_vid(struct vlan_group *vg, __be16 vlan_proto, u16 vlan_id) { - struct net_device **array; + struct net_device __rcu **array; unsigned int vidx; unsigned int size; int pidx; @@ -70,10 +70,8 @@ static int vlan_group_prealloc_vid(struct vlan_group *vg, if (array == NULL) return -ENOBUFS; - /* paired with smp_rmb() in __vlan_group_get_device() */ - smp_wmb(); - - vg->vlan_devices_arrays[pidx][vidx] = array; + /* paired with smp_load_acquire() in __vlan_group_get_device() */ + smp_store_release(&vg->vlan_devices_arrays[pidx][vidx], array); return 0; } diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index c41caaf94095..d874ab323d32 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -22,8 +22,8 @@ enum vlan_protos { struct vlan_group { unsigned int nr_vlan_devs; struct hlist_node hlist; /* linked list */ - struct net_device **vlan_devices_arrays[VLAN_PROTO_NUM] - [VLAN_GROUP_ARRAY_SPLIT_PARTS]; + struct net_device __rcu **vlan_devices_arrays[VLAN_PROTO_NUM] + [VLAN_GROUP_ARRAY_SPLIT_PARTS]; }; struct vlan_info { @@ -54,15 +54,13 @@ static inline struct net_device *__vlan_group_get_device(struct vlan_group *vg, unsigned int pidx, u16 vlan_id) { - struct net_device **array; + struct net_device __rcu **array; - array = vg->vlan_devices_arrays[pidx] - [vlan_id / VLAN_GROUP_ARRAY_PART_LEN]; + /* Pairs with smp_store_release() in vlan_group_prealloc_vid() */ + array = smp_load_acquire(&vg->vlan_devices_arrays[pidx] + [vlan_id / VLAN_GROUP_ARRAY_PART_LEN]); - /* paired with smp_wmb() in vlan_group_prealloc_vid() */ - smp_rmb(); - - return array ? array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] : NULL; + return array ? rcu_dereference_raw(array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN]) : NULL; } static inline struct net_device *vlan_group_get_device(struct vlan_group *vg, @@ -82,13 +80,13 @@ static inline void vlan_group_set_device(struct vlan_group *vg, struct net_device *dev) { int pidx = vlan_proto_idx(vlan_proto); - struct net_device **array; + struct net_device __rcu **array; if (!vg || pidx < 0) return; array = vg->vlan_devices_arrays[pidx] [vlan_id / VLAN_GROUP_ARRAY_PART_LEN]; - array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev; + rcu_assign_pointer(array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN], dev); } /* Must be invoked with rcu_read_lock or with RTNL. */