aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/macvtap.c
diff options
context:
space:
mode:
authorJason Wang <jasowang@redhat.com>2013-06-05 19:54:38 -0400
committerDavid S. Miller <davem@davemloft.net>2013-06-08 02:49:09 -0400
commit376b1aabe1f53aad80615d05ddb8c43670be6a5c (patch)
tree95c266af703da4637da900c972c841f68948b0de /drivers/net/macvtap.c
parentf0afce01aa639e5164cf73f063b81a8b95619c3a (diff)
macvtap: eliminate linear search
Linear search were used in both get_slot() and macvtap_get_queue(), this is because: - macvtap didn't reshuffle the array of taps when create or destroy a queue, so when adding a new queue, macvtap must do linear search to find a location for the new queue. This will also complicate the TUNSETQUEUE implementation for multiqueue API. - the queue itself didn't track the queue index, so the we must do a linear search in the array to find the location of a existed queue. The solution is straightforward: reshuffle the array and introduce a queue_index to macvtap_queue. Signed-off-by: Jason Wang <jasowang@redhat.com> Acked-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/macvtap.c')
-rw-r--r--drivers/net/macvtap.c64
1 files changed, 20 insertions, 44 deletions
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index d18130b3fe0d..5ccba99b15f4 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -44,6 +44,7 @@ struct macvtap_queue {
44 struct macvlan_dev __rcu *vlan; 44 struct macvlan_dev __rcu *vlan;
45 struct file *file; 45 struct file *file;
46 unsigned int flags; 46 unsigned int flags;
47 u16 queue_index;
47}; 48};
48 49
49static struct proto macvtap_proto = { 50static struct proto macvtap_proto = {
@@ -84,30 +85,10 @@ static const struct proto_ops macvtap_socket_ops;
84 */ 85 */
85static DEFINE_SPINLOCK(macvtap_lock); 86static DEFINE_SPINLOCK(macvtap_lock);
86 87
87/*
88 * get_slot: return a [unused/occupied] slot in vlan->taps[]:
89 * - if 'q' is NULL, return the first empty slot;
90 * - otherwise, return the slot this pointer occupies.
91 */
92static int get_slot(struct macvlan_dev *vlan, struct macvtap_queue *q)
93{
94 int i;
95
96 for (i = 0; i < MAX_MACVTAP_QUEUES; i++) {
97 if (rcu_dereference_protected(vlan->taps[i],
98 lockdep_is_held(&macvtap_lock)) == q)
99 return i;
100 }
101
102 /* Should never happen */
103 BUG_ON(1);
104}
105
106static int macvtap_set_queue(struct net_device *dev, struct file *file, 88static int macvtap_set_queue(struct net_device *dev, struct file *file,
107 struct macvtap_queue *q) 89 struct macvtap_queue *q)
108{ 90{
109 struct macvlan_dev *vlan = netdev_priv(dev); 91 struct macvlan_dev *vlan = netdev_priv(dev);
110 int index;
111 int err = -EBUSY; 92 int err = -EBUSY;
112 93
113 spin_lock(&macvtap_lock); 94 spin_lock(&macvtap_lock);
@@ -115,12 +96,12 @@ static int macvtap_set_queue(struct net_device *dev, struct file *file,
115 goto out; 96 goto out;
116 97
117 err = 0; 98 err = 0;
118 index = get_slot(vlan, NULL);
119 rcu_assign_pointer(q->vlan, vlan); 99 rcu_assign_pointer(q->vlan, vlan);
120 rcu_assign_pointer(vlan->taps[index], q); 100 rcu_assign_pointer(vlan->taps[vlan->numvtaps], q);
121 sock_hold(&q->sk); 101 sock_hold(&q->sk);
122 102
123 q->file = file; 103 q->file = file;
104 q->queue_index = vlan->numvtaps;
124 file->private_data = q; 105 file->private_data = q;
125 106
126 vlan->numvtaps++; 107 vlan->numvtaps++;
@@ -140,15 +121,22 @@ out:
140 */ 121 */
141static void macvtap_put_queue(struct macvtap_queue *q) 122static void macvtap_put_queue(struct macvtap_queue *q)
142{ 123{
124 struct macvtap_queue *nq;
143 struct macvlan_dev *vlan; 125 struct macvlan_dev *vlan;
144 126
145 spin_lock(&macvtap_lock); 127 spin_lock(&macvtap_lock);
146 vlan = rcu_dereference_protected(q->vlan, 128 vlan = rcu_dereference_protected(q->vlan,
147 lockdep_is_held(&macvtap_lock)); 129 lockdep_is_held(&macvtap_lock));
148 if (vlan) { 130 if (vlan) {
149 int index = get_slot(vlan, q); 131 int index = q->queue_index;
132 BUG_ON(index >= vlan->numvtaps);
133
134 nq = rcu_dereference_protected(vlan->taps[vlan->numvtaps - 1],
135 lockdep_is_held(&macvtap_lock));
136 rcu_assign_pointer(vlan->taps[index], nq);
137 nq->queue_index = index;
150 138
151 RCU_INIT_POINTER(vlan->taps[index], NULL); 139 RCU_INIT_POINTER(vlan->taps[vlan->numvtaps - 1], NULL);
152 RCU_INIT_POINTER(q->vlan, NULL); 140 RCU_INIT_POINTER(q->vlan, NULL);
153 sock_put(&q->sk); 141 sock_put(&q->sk);
154 --vlan->numvtaps; 142 --vlan->numvtaps;
@@ -182,8 +170,7 @@ static struct macvtap_queue *macvtap_get_queue(struct net_device *dev,
182 rxq = skb_get_rxhash(skb); 170 rxq = skb_get_rxhash(skb);
183 if (rxq) { 171 if (rxq) {
184 tap = rcu_dereference(vlan->taps[rxq % numvtaps]); 172 tap = rcu_dereference(vlan->taps[rxq % numvtaps]);
185 if (tap) 173 goto out;
186 goto out;
187 } 174 }
188 175
189 if (likely(skb_rx_queue_recorded(skb))) { 176 if (likely(skb_rx_queue_recorded(skb))) {
@@ -193,17 +180,10 @@ static struct macvtap_queue *macvtap_get_queue(struct net_device *dev,
193 rxq -= numvtaps; 180 rxq -= numvtaps;
194 181
195 tap = rcu_dereference(vlan->taps[rxq]); 182 tap = rcu_dereference(vlan->taps[rxq]);
196 if (tap) 183 goto out;
197 goto out;
198 }
199
200 /* Everything failed - find first available queue */
201 for (rxq = 0; rxq < MAX_MACVTAP_QUEUES; rxq++) {
202 tap = rcu_dereference(vlan->taps[rxq]);
203 if (tap)
204 break;
205 } 184 }
206 185
186 tap = rcu_dereference(vlan->taps[0]);
207out: 187out:
208 return tap; 188 return tap;
209} 189}
@@ -219,19 +199,15 @@ static void macvtap_del_queues(struct net_device *dev)
219 struct macvtap_queue *q, *qlist[MAX_MACVTAP_QUEUES]; 199 struct macvtap_queue *q, *qlist[MAX_MACVTAP_QUEUES];
220 int i, j = 0; 200 int i, j = 0;
221 201
222 /* macvtap_put_queue can free some slots, so go through all slots */
223 spin_lock(&macvtap_lock); 202 spin_lock(&macvtap_lock);
224 for (i = 0; i < MAX_MACVTAP_QUEUES && vlan->numvtaps; i++) { 203 for (i = 0; i < vlan->numvtaps; i++) {
225 q = rcu_dereference_protected(vlan->taps[i], 204 q = rcu_dereference_protected(vlan->taps[i],
226 lockdep_is_held(&macvtap_lock)); 205 lockdep_is_held(&macvtap_lock));
227 if (q) { 206 BUG_ON(q == NULL);
228 qlist[j++] = q; 207 qlist[j++] = q;
229 RCU_INIT_POINTER(vlan->taps[i], NULL); 208 RCU_INIT_POINTER(vlan->taps[i], NULL);
230 RCU_INIT_POINTER(q->vlan, NULL); 209 RCU_INIT_POINTER(q->vlan, NULL);
231 vlan->numvtaps--;
232 }
233 } 210 }
234 BUG_ON(vlan->numvtaps != 0);
235 /* guarantee that any future macvtap_set_queue will fail */ 211 /* guarantee that any future macvtap_set_queue will fail */
236 vlan->numvtaps = MAX_MACVTAP_QUEUES; 212 vlan->numvtaps = MAX_MACVTAP_QUEUES;
237 spin_unlock(&macvtap_lock); 213 spin_unlock(&macvtap_lock);