| 1 | commit d7d3d8f1ee4435e32bc6c93187798b7e2e3170a9 |
| 2 | Author: David Woodhouse <David.Woodhouse@intel.com> |
| 3 | Date: Thu Nov 29 23:28:30 2012 +0000 |
| 4 | |
| 5 | solos-pci: remove list_vccs() debugging function |
| 6 | |
| 7 | No idea why we've gone so long dumping a list of VCCs with vci==0 on |
| 8 | every ->open() call... |
| 9 | |
| 10 | Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> |
| 11 | |
| 12 | commit c93967bfd3a3dffa759a3f28370167bf3cdbc3d0 |
| 13 | Author: David Woodhouse <David.Woodhouse@intel.com> |
| 14 | Date: Thu Nov 29 23:27:20 2012 +0000 |
| 15 | |
| 16 | solos-pci: use GFP_KERNEL where possible, not GFP_ATOMIC |
| 17 | |
| 18 | Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> |
| 19 | |
| 20 | commit ad6999e17ae4f7b99f6d28f425ae970acb115347 |
| 21 | Author: David Woodhouse <David.Woodhouse@intel.com> |
| 22 | Date: Thu Nov 29 23:15:30 2012 +0000 |
| 23 | |
| 24 | solos-pci: clean up pclose() function |
| 25 | |
| 26 | - Flush pending TX skbs from the queue rather than waiting for them all to |
| 27 | complete (suggested by Krzysztof Mazur <krzysiek@podlesie.net>). |
| 28 | - Clear ATM_VF_ADDR only when the PKT_PCLOSE packet has been submitted. |
| 29 | - Don't clear ATM_VF_READY at all — vcc_destroy_socket() does that for us. |
| 30 | |
| 31 | Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> |
| 32 | |
| 33 | commit 2547e97f29d6d69d567947d5ef90b6b4fbcaf565 |
| 34 | Author: David Woodhouse <David.Woodhouse@intel.com> |
| 35 | Date: Wed Nov 28 10:15:05 2012 +0000 |
| 36 | |
| 37 | pppoatm: optimise PPP channel wakeups after sock_owned_by_user() |
| 38 | |
| 39 | We don't need to schedule the wakeup tasklet on *every* unlock; only if we |
| 40 | actually blocked the channel in the first place. |
| 41 | |
| 42 | Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> |
| 43 | Acked-by: Krzysztof Mazur <krzysiek@podlesie.net> |
| 44 | |
| 45 | commit 990b0884a2e9668c08e9daa4d70a54d65329cb6f |
| 46 | Author: Krzysztof Mazur <krzysiek@podlesie.net> |
| 47 | Date: Wed Nov 28 09:08:04 2012 +0100 |
| 48 | |
| 49 | br2684: allow assign only on a connected socket |
| 50 | |
| 51 | The br2684 does not check if used vcc is in connected state, |
| 52 | causing potential Oops in pppoatm_send() when vcc->send() is called |
| 53 | on not fully connected socket. |
| 54 | |
| 55 | Now br2684 can be assigned only on connected sockets; otherwise |
| 56 | -EINVAL error is returned. |
| 57 | |
| 58 | Signed-off-by: Krzysztof Mazur <krzysiek@podlesie.net> |
| 59 | Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> |
| 60 | |
| 61 | commit f49b6da01f0abebb17f6241473d53018d923f6b0 |
| 62 | Author: Nathan Williams <nathan@traverse.com.au> |
| 63 | Date: Tue Nov 27 17:34:09 2012 +1100 |
| 64 | |
| 65 | solos-pci: Fix leak of skb received for unknown vcc |
| 66 | |
| 67 | ... and ensure that the next skb is set up for RX in the DMA case. |
| 68 | |
| 69 | Signed-off-by: Nathan Williams <nathan@traverse.com.au> |
| 70 | Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> |
| 71 | |
| 72 | commit a61d37ff4a555886c4ebe31d2c6d893afb6f4d3c |
| 73 | Author: David Woodhouse <David.Woodhouse@intel.com> |
| 74 | Date: Wed Nov 28 00:46:45 2012 +0000 |
| 75 | |
| 76 | br2684: fix module_put() race |
| 77 | |
| 78 | The br2684 code used module_put() during unassignment from vcc with |
| 79 | hope that we have BKL. This assumption is no longer true. |
| 80 | |
| 81 | Now owner field in atmvcc is used to move this module_put() |
| 82 | to vcc_destroy_socket(). |
| 83 | |
| 84 | Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> |
| 85 | Acked-by: Krzysztof Mazur <krzysiek@podlesie.net> |
| 86 | |
| 87 | commit c52f40629884ddc62c7af445fd5d620fdb466fb2 |
| 88 | Author: David Woodhouse <David.Woodhouse@intel.com> |
| 89 | Date: Wed Nov 28 00:05:52 2012 +0000 |
| 90 | |
| 91 | pppoatm: fix missing wakeup in pppoatm_send() |
| 92 | |
| 93 | Now that we can return zero from pppoatm_send() for reasons *other* than |
| 94 | the queue being full, that means we can't depend on a subsequent call to |
| 95 | pppoatm_pop() waking the queue, and we might leave it stalled |
| 96 | indefinitely. |
| 97 | |
| 98 | Use the ->release_cb() callback to wake the queue after the sock is |
| 99 | unlocked. |
| 100 | |
| 101 | Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> |
| 102 | Acked-by: Krzysztof Mazur <krzysiek@podlesie.net> |
| 103 | |
| 104 | commit 35826e7372fe39b7db7930eda0267c82d68d1a4c |
| 105 | Author: David Woodhouse <dwmw2@infradead.org> |
| 106 | Date: Tue Nov 27 23:28:36 2012 +0000 |
| 107 | |
| 108 | br2684: don't send frames on not-ready vcc |
| 109 | |
| 110 | Avoid submitting packets to a vcc which is being closed. Things go badly |
| 111 | wrong when the ->pop method gets later called after everything's been |
| 112 | torn down. |
| 113 | |
| 114 | Use the ATM socket lock for synchronisation with vcc_destroy_socket(), |
| 115 | which clears the ATM_VF_READY bit under the same lock. Otherwise, we |
| 116 | could end up submitting a packet to the device driver even after its |
| 117 | ->ops->close method has been called. And it could call the vcc's ->pop |
| 118 | method after the protocol has been shut down. Which leads to a panic. |
| 119 | |
| 120 | Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> |
| 121 | Acked-by: Krzysztof Mazur <krzysiek@podlesie.net> |
| 122 | |
| 123 | commit 7f940dde65de4a707f3dd723bb6ce9de90ca1eab |
| 124 | Author: David Woodhouse <David.Woodhouse@intel.com> |
| 125 | Date: Wed Nov 28 00:03:11 2012 +0000 |
| 126 | |
| 127 | atm: add release_cb() callback to vcc |
| 128 | |
| 129 | The immediate use case for this is that it will allow us to ensure that a |
| 130 | pppoatm queue is woken after it has to drop a packet due to the sock being |
| 131 | locked. |
| 132 | |
| 133 | Note that 'release_cb' is called when the socket is *unlocked*. This is |
| 134 | not to be confused with vcc_release() — which probably ought to be called |
| 135 | vcc_close(). |
| 136 | |
| 137 | Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> |
| 138 | Acked-by: Krzysztof Mazur <krzysiek@podlesie.net> |
| 139 | |
| 140 | commit def1b2f9083f84d0a77730e537c76429914d17c1 |
| 141 | Author: David Woodhouse <David.Woodhouse@intel.com> |
| 142 | Date: Tue Nov 27 23:49:24 2012 +0000 |
| 143 | |
| 144 | solos-pci: wait for pending TX to complete when releasing vcc |
| 145 | |
| 146 | We should no longer be calling the old pop routine for the vcc, after |
| 147 | vcc_release() has completed. Make sure we wait for any pending TX skbs |
| 148 | to complete, by waiting for our own PKT_PCLOSE control skb to be sent. |
| 149 | |
| 150 | Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> |
| 151 | |
| 152 | commit 397ff16dce53888ec693b3718640be2560204751 |
| 153 | Author: Krzysztof Mazur <krzysiek@podlesie.net> |
| 154 | Date: Tue Nov 6 23:17:02 2012 +0100 |
| 155 | |
| 156 | pppoatm: do not inline pppoatm_may_send() |
| 157 | |
| 158 | The pppoatm_may_send() is quite heavy and it's called three times |
| 159 | in pppoatm_send() and inlining costs more than 200 bytes of code |
| 160 | (more than 10% of total pppoatm driver code size). |
| 161 | |
| 162 | add/remove: 1/0 grow/shrink: 0/1 up/down: 132/-367 (-235) |
| 163 | function old new delta |
| 164 | pppoatm_may_send - 132 +132 |
| 165 | pppoatm_send 900 533 -367 |
| 166 | |
| 167 | Signed-off-by: Krzysztof Mazur <krzysiek@podlesie.net> |
| 168 | Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> |
| 169 | |
| 170 | commit 071d93931a75dc1f82f0baa9959613af81c5a032 |
| 171 | Author: Krzysztof Mazur <krzysiek@podlesie.net> |
| 172 | Date: Sat Nov 10 23:33:19 2012 +0100 |
| 173 | |
| 174 | pppoatm: drop frames to not-ready vcc |
| 175 | |
| 176 | The vcc_destroy_socket() closes vcc before the protocol is detached |
| 177 | from vcc by calling vcc->push() with NULL skb. This leaves some time |
| 178 | window, where the protocol may call vcc->send() on closed vcc |
| 179 | and crash. |
| 180 | |
| 181 | Now pppoatm_send(), like vcc_sendmsg(), checks for vcc flags that |
| 182 | indicate that vcc is not ready. If the vcc is not ready we just |
| 183 | drop frame. Queueing frames is much more complicated because we |
| 184 | don't have callbacks that inform us about vcc flags changes. |
| 185 | |
| 186 | Signed-off-by: Krzysztof Mazur <krzysiek@podlesie.net> |
| 187 | Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> |
| 188 | |
| 189 | commit 3ac108006fd7f20cb8fc8ea2287f1497bcda00a1 |
| 190 | Author: Krzysztof Mazur <krzysiek@podlesie.net> |
| 191 | Date: Tue Nov 6 23:17:00 2012 +0100 |
| 192 | |
| 193 | pppoatm: take ATM socket lock in pppoatm_send() |
| 194 | |
| 195 | The pppoatm_send() does not take any lock that will prevent concurrent |
| 196 | vcc_sendmsg(). This causes two problems: |
| 197 | |
| 198 | - there is no locking between checking the send queue size |
| 199 | with atm_may_send() and incrementing sk_wmem_alloc, |
| 200 | and the real queue size can be a little higher than sk_sndbuf |
| 201 | |
| 202 | - the vcc->sendmsg() can be called concurrently. I'm not sure |
| 203 | if it's allowed. Some drivers (eni, nicstar, ...) seem |
| 204 | to assume it will never happen. |
| 205 | |
| 206 | Now pppoatm_send() takes ATM socket lock, the same that is used |
| 207 | in vcc_sendmsg() and other ATM socket functions. The pppoatm_send() |
| 208 | is called with BH disabled, so bh_lock_sock() is used instead |
| 209 | of lock_sock(). |
| 210 | |
| 211 | Signed-off-by: Krzysztof Mazur <krzysiek@podlesie.net> |
| 212 | Cc: Chas Williams - CONTRACTOR <chas@cmf.nrl.navy.mil> |
| 213 | Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> |
| 214 | |
| 215 | commit e41faed9cde1acce657f75a0b19a1787e9850d3f |
| 216 | Author: Krzysztof Mazur <krzysiek@podlesie.net> |
| 217 | Date: Tue Nov 6 23:16:59 2012 +0100 |
| 218 | |
| 219 | pppoatm: fix module_put() race |
| 220 | |
| 221 | The pppoatm used module_put() during unassignment from vcc with |
| 222 | hope that we have BKL. This assumption is no longer true. |
| 223 | |
| 224 | Now owner field in atmvcc is used to move this module_put() |
| 225 | to vcc_destroy_socket(). |
| 226 | |
| 227 | Signed-off-by: Krzysztof Mazur <krzysiek@podlesie.net> |
| 228 | Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> |
| 229 | |
| 230 | commit 3b1a914595f3f9beb9e38ff3ddc7bdafa092ba22 |
| 231 | Author: Krzysztof Mazur <krzysiek@podlesie.net> |
| 232 | Date: Tue Nov 6 23:16:58 2012 +0100 |
| 233 | |
| 234 | pppoatm: allow assign only on a connected socket |
| 235 | |
| 236 | The pppoatm does not check if used vcc is in connected state, |
| 237 | causing an Oops in pppoatm_send() when vcc->send() is called |
| 238 | on not fully connected socket. |
| 239 | |
| 240 | Now pppoatm can be assigned only on connected sockets; otherwise |
| 241 | -EINVAL error is returned. |
| 242 | |
| 243 | Signed-off-by: Krzysztof Mazur <krzysiek@podlesie.net> |
| 244 | Cc: Chas Williams - CONTRACTOR <chas@cmf.nrl.navy.mil> |
| 245 | Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> |
| 246 | |
| 247 | commit ec809bd817dfa1905283468e4c813684ed4efe78 |
| 248 | Author: Krzysztof Mazur <krzysiek@podlesie.net> |
| 249 | Date: Tue Nov 6 23:16:57 2012 +0100 |
| 250 | |
| 251 | atm: add owner of push() callback to atmvcc |
| 252 | |
| 253 | The atm is using atmvcc->push(vcc, NULL) callback to notify protocol |
| 254 | that vcc will be closed and protocol must detach from it. This callback |
| 255 | is usually used by protocol to decrement module usage count by module_put(), |
| 256 | but it leaves small window then module is still used after module_put(). |
| 257 | |
| 258 | Now the owner of push() callback is kept in atmvcc and |
| 259 | module_put(atmvcc->owner) is called after the protocol is detached from vcc. |
| 260 | |
| 261 | Signed-off-by: Krzysztof Mazur <krzysiek@podlesie.net> |
| 262 | Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> |
| 263 | Acked-by: Chas Williams <chas@cmf.nrl.navy.mil> |
| 264 | |
| 265 | commit ae088d663beebb3cad0e7abaac67ee61a7c578d5 |
| 266 | Author: David Woodhouse <dwmw2@infradead.org> |
| 267 | Date: Sun Nov 25 12:06:52 2012 +0000 |
| 268 | |
| 269 | atm: br2684: Fix excessive queue bloat |
| 270 | |
| 271 | There's really no excuse for an additional wmem_default of buffering |
| 272 | between the netdev queue and the ATM device. Two packets (one in-flight, |
| 273 | and one ready to send) ought to be fine. It's not as if it should take |
| 274 | long to get another from the netdev queue when we need it. |
| 275 | |
| 276 | If necessary we can make the queue space configurable later, but I don't |
| 277 | think it's likely to be necessary. |
| 278 | |
| 279 | cf. commit 9d02daf754238adac48fa075ee79e7edd3d79ed3 (pppoatm: Fix |
| 280 | excessive queue bloat) which did something very similar for PPPoATM. |
| 281 | |
| 282 | Note that there is a tremendously unlikely race condition which may |
| 283 | result in qspace temporarily going negative. If a CPU running the |
| 284 | br2684_pop() function goes off into the weeds for a long period of time |
| 285 | after incrementing qspace to 1, but before calling netdev_wake_queue()... |
| 286 | and another CPU ends up calling br2684_start_xmit() and *stopping* the |
| 287 | queue again before the first CPU comes back, the netdev queue could |
| 288 | end up being woken when qspace has already reached zero. |
| 289 | |
| 290 | An alternative approach to coping with this race would be to check in |
| 291 | br2684_start_xmit() for qspace==0 and return NETDEV_TX_BUSY, but just |
| 292 | using '> 0' and '< 1' for comparison instead of '== 0' and '!= 0' is |
| 293 | simpler. It just warranted a mention of *why* we do it that way... |
| 294 | |
| 295 | Move the call to atmvcc->send() to happen *after* the accounting and |
| 296 | potentially stopping the netdev queue, in br2684_xmit_vcc(). This matters |
| 297 | if the ->send() call suffers an immediate failure, because it'll call |
| 298 | br2684_pop() with the offending skb before returning. We want that to |
| 299 | happen *after* we've done the initial accounting for the packet in |
| 300 | question. Also make it return an appropriate success/failure indication |
| 301 | while we're at it. |
| 302 | |
| 303 | Tested by running 'ping -l 1000 bottomless.aaisp.net.uk' from within my |
| 304 | network, with only a single PPPoE-over-BR2684 link running. And after |
| 305 | setting txqueuelen on the nas0 interface to something low (5, in fact). |
| 306 | Before the patch, we'd see about 15 packets being queued and a resulting |
| 307 | latency of ~56ms being reached. After the patch, we see only about 8, |
| 308 | which is fairly much what we expect. And a max latency of ~36ms. On this |
| 309 | OpenWRT box, wmem_default is 163840. |
| 310 | |
| 311 | Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> |
| 312 | Reviewed-by: Krzysztof Mazur <krzysiek@podlesie.net> |
| 313 | Signed-off-by: David S. Miller <davem@davemloft.net> |
| 314 | |
| 315 | --- a/drivers/atm/solos-pci.c |
| 316 | +++ b/drivers/atm/solos-pci.c |
| 317 | @@ -92,6 +92,7 @@ struct pkt_hdr { |
| 318 | }; |
| 319 | |
| 320 | struct solos_skb_cb { |
| 321 | + struct completion c; |
| 322 | struct atm_vcc *vcc; |
| 323 | uint32_t dma_addr; |
| 324 | }; |
| 325 | @@ -164,7 +165,6 @@ static void fpga_queue(struct solos_card |
| 326 | static uint32_t fpga_tx(struct solos_card *); |
| 327 | static irqreturn_t solos_irq(int irq, void *dev_id); |
| 328 | static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci); |
| 329 | -static int list_vccs(int vci); |
| 330 | static int atm_init(struct solos_card *, struct device *); |
| 331 | static void atm_remove(struct solos_card *); |
| 332 | static int send_command(struct solos_card *card, int dev, const char *buf, size_t size); |
| 333 | @@ -710,7 +710,8 @@ void solos_bh(unsigned long card_arg) |
| 334 | dev_warn(&card->dev->dev, "Received packet for unknown VPI.VCI %d.%d on port %d\n", |
| 335 | le16_to_cpu(header->vpi), le16_to_cpu(header->vci), |
| 336 | port); |
| 337 | - continue; |
| 338 | + dev_kfree_skb_any(skb); |
| 339 | + break; |
| 340 | } |
| 341 | atm_charge(vcc, skb->truesize); |
| 342 | vcc->push(vcc, skb); |
| 343 | @@ -790,44 +791,6 @@ static struct atm_vcc *find_vcc(struct a |
| 344 | return vcc; |
| 345 | } |
| 346 | |
| 347 | -static int list_vccs(int vci) |
| 348 | -{ |
| 349 | - struct hlist_head *head; |
| 350 | - struct atm_vcc *vcc; |
| 351 | - struct hlist_node *node; |
| 352 | - struct sock *s; |
| 353 | - int num_found = 0; |
| 354 | - int i; |
| 355 | - |
| 356 | - read_lock(&vcc_sklist_lock); |
| 357 | - if (vci != 0){ |
| 358 | - head = &vcc_hash[vci & (VCC_HTABLE_SIZE -1)]; |
| 359 | - sk_for_each(s, node, head) { |
| 360 | - num_found ++; |
| 361 | - vcc = atm_sk(s); |
| 362 | - printk(KERN_DEBUG "Device: %d Vpi: %d Vci: %d\n", |
| 363 | - vcc->dev->number, |
| 364 | - vcc->vpi, |
| 365 | - vcc->vci); |
| 366 | - } |
| 367 | - } else { |
| 368 | - for(i = 0; i < VCC_HTABLE_SIZE; i++){ |
| 369 | - head = &vcc_hash[i]; |
| 370 | - sk_for_each(s, node, head) { |
| 371 | - num_found ++; |
| 372 | - vcc = atm_sk(s); |
| 373 | - printk(KERN_DEBUG "Device: %d Vpi: %d Vci: %d\n", |
| 374 | - vcc->dev->number, |
| 375 | - vcc->vpi, |
| 376 | - vcc->vci); |
| 377 | - } |
| 378 | - } |
| 379 | - } |
| 380 | - read_unlock(&vcc_sklist_lock); |
| 381 | - return num_found; |
| 382 | -} |
| 383 | - |
| 384 | - |
| 385 | static int popen(struct atm_vcc *vcc) |
| 386 | { |
| 387 | struct solos_card *card = vcc->dev->dev_data; |
| 388 | @@ -840,7 +803,7 @@ static int popen(struct atm_vcc *vcc) |
| 389 | return -EINVAL; |
| 390 | } |
| 391 | |
| 392 | - skb = alloc_skb(sizeof(*header), GFP_ATOMIC); |
| 393 | + skb = alloc_skb(sizeof(*header), GFP_KERNEL); |
| 394 | if (!skb) { |
| 395 | if (net_ratelimit()) |
| 396 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n"); |
| 397 | @@ -857,8 +820,6 @@ static int popen(struct atm_vcc *vcc) |
| 398 | |
| 399 | set_bit(ATM_VF_ADDR, &vcc->flags); |
| 400 | set_bit(ATM_VF_READY, &vcc->flags); |
| 401 | - list_vccs(0); |
| 402 | - |
| 403 | |
| 404 | return 0; |
| 405 | } |
| 406 | @@ -866,10 +827,21 @@ static int popen(struct atm_vcc *vcc) |
| 407 | static void pclose(struct atm_vcc *vcc) |
| 408 | { |
| 409 | struct solos_card *card = vcc->dev->dev_data; |
| 410 | - struct sk_buff *skb; |
| 411 | + unsigned char port = SOLOS_CHAN(vcc->dev); |
| 412 | + struct sk_buff *skb, *tmpskb; |
| 413 | struct pkt_hdr *header; |
| 414 | |
| 415 | - skb = alloc_skb(sizeof(*header), GFP_ATOMIC); |
| 416 | + /* Remove any yet-to-be-transmitted packets from the pending queue */ |
| 417 | + spin_lock(&card->tx_queue_lock); |
| 418 | + skb_queue_walk_safe(&card->tx_queue[port], skb, tmpskb) { |
| 419 | + if (SKB_CB(skb)->vcc == vcc) { |
| 420 | + skb_unlink(skb, &card->tx_queue[port]); |
| 421 | + solos_pop(vcc, skb); |
| 422 | + } |
| 423 | + } |
| 424 | + spin_unlock(&card->tx_queue_lock); |
| 425 | + |
| 426 | + skb = alloc_skb(sizeof(*header), GFP_KERNEL); |
| 427 | if (!skb) { |
| 428 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in pclose()\n"); |
| 429 | return; |
| 430 | @@ -881,15 +853,21 @@ static void pclose(struct atm_vcc *vcc) |
| 431 | header->vci = cpu_to_le16(vcc->vci); |
| 432 | header->type = cpu_to_le16(PKT_PCLOSE); |
| 433 | |
| 434 | - fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL); |
| 435 | + init_completion(&SKB_CB(skb)->c); |
| 436 | |
| 437 | - clear_bit(ATM_VF_ADDR, &vcc->flags); |
| 438 | - clear_bit(ATM_VF_READY, &vcc->flags); |
| 439 | + fpga_queue(card, port, skb, NULL); |
| 440 | + |
| 441 | + if (!wait_for_completion_timeout(&SKB_CB(skb)->c, 5 * HZ)) |
| 442 | + dev_warn(&card->dev->dev, "Timeout waiting for VCC close on port %d\n", |
| 443 | + port); |
| 444 | |
| 445 | /* Hold up vcc_destroy_socket() (our caller) until solos_bh() in the |
| 446 | tasklet has finished processing any incoming packets (and, more to |
| 447 | the point, using the vcc pointer). */ |
| 448 | tasklet_unlock_wait(&card->tlet); |
| 449 | + |
| 450 | + clear_bit(ATM_VF_ADDR, &vcc->flags); |
| 451 | + |
| 452 | return; |
| 453 | } |
| 454 | |
| 455 | @@ -1011,9 +989,12 @@ static uint32_t fpga_tx(struct solos_car |
| 456 | if (vcc) { |
| 457 | atomic_inc(&vcc->stats->tx); |
| 458 | solos_pop(vcc, oldskb); |
| 459 | - } else |
| 460 | + } else { |
| 461 | + struct pkt_hdr *header = (void *)oldskb->data; |
| 462 | + if (le16_to_cpu(header->type) == PKT_PCLOSE) |
| 463 | + complete(&SKB_CB(oldskb)->c); |
| 464 | dev_kfree_skb_irq(oldskb); |
| 465 | - |
| 466 | + } |
| 467 | } |
| 468 | } |
| 469 | /* For non-DMA TX, write the 'TX start' bit for all four ports simultaneously */ |
| 470 | @@ -1248,7 +1229,7 @@ static int atm_init(struct solos_card *c |
| 471 | card->atmdev[i]->phy_data = (void *)(unsigned long)i; |
| 472 | atm_dev_signal_change(card->atmdev[i], ATM_PHY_SIG_FOUND); |
| 473 | |
| 474 | - skb = alloc_skb(sizeof(*header), GFP_ATOMIC); |
| 475 | + skb = alloc_skb(sizeof(*header), GFP_KERNEL); |
| 476 | if (!skb) { |
| 477 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in atm_init()\n"); |
| 478 | continue; |
| 479 | @@ -1345,6 +1326,8 @@ static struct pci_driver fpga_driver = { |
| 480 | |
| 481 | static int __init solos_pci_init(void) |
| 482 | { |
| 483 | + BUILD_BUG_ON(sizeof(struct solos_skb_cb) > sizeof(((struct sk_buff *)0)->cb)); |
| 484 | + |
| 485 | printk(KERN_INFO "Solos PCI Driver Version %s\n", VERSION); |
| 486 | return pci_register_driver(&fpga_driver); |
| 487 | } |
| 488 | --- a/include/linux/atmdev.h |
| 489 | +++ b/include/linux/atmdev.h |
| 490 | @@ -308,6 +308,7 @@ struct atm_vcc { |
| 491 | struct atm_dev *dev; /* device back pointer */ |
| 492 | struct atm_qos qos; /* QOS */ |
| 493 | struct atm_sap sap; /* SAP */ |
| 494 | + void (*release_cb)(struct atm_vcc *vcc); /* release_sock callback */ |
| 495 | void (*push)(struct atm_vcc *vcc,struct sk_buff *skb); |
| 496 | void (*pop)(struct atm_vcc *vcc,struct sk_buff *skb); /* optional */ |
| 497 | int (*push_oam)(struct atm_vcc *vcc,void *cell); |
| 498 | @@ -315,6 +316,7 @@ struct atm_vcc { |
| 499 | void *dev_data; /* per-device data */ |
| 500 | void *proto_data; /* per-protocol data */ |
| 501 | struct k_atm_aal_stats *stats; /* pointer to AAL stats group */ |
| 502 | + struct module *owner; /* owner of ->push function */ |
| 503 | /* SVC part --- may move later ------------------------------------- */ |
| 504 | short itf; /* interface number */ |
| 505 | struct sockaddr_atmsvc local; |
| 506 | --- a/net/atm/br2684.c |
| 507 | +++ b/net/atm/br2684.c |
| 508 | @@ -68,12 +68,15 @@ struct br2684_vcc { |
| 509 | /* keep old push, pop functions for chaining */ |
| 510 | void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb); |
| 511 | void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb); |
| 512 | + void (*old_release_cb)(struct atm_vcc *vcc); |
| 513 | + struct module *old_owner; |
| 514 | enum br2684_encaps encaps; |
| 515 | struct list_head brvccs; |
| 516 | #ifdef CONFIG_ATM_BR2684_IPFILTER |
| 517 | struct br2684_filter filter; |
| 518 | #endif /* CONFIG_ATM_BR2684_IPFILTER */ |
| 519 | unsigned int copies_needed, copies_failed; |
| 520 | + atomic_t qspace; |
| 521 | }; |
| 522 | |
| 523 | struct br2684_dev { |
| 524 | @@ -181,18 +184,15 @@ static struct notifier_block atm_dev_not |
| 525 | static void br2684_pop(struct atm_vcc *vcc, struct sk_buff *skb) |
| 526 | { |
| 527 | struct br2684_vcc *brvcc = BR2684_VCC(vcc); |
| 528 | - struct net_device *net_dev = skb->dev; |
| 529 | |
| 530 | - pr_debug("(vcc %p ; net_dev %p )\n", vcc, net_dev); |
| 531 | + pr_debug("(vcc %p ; net_dev %p )\n", vcc, brvcc->device); |
| 532 | brvcc->old_pop(vcc, skb); |
| 533 | |
| 534 | - if (!net_dev) |
| 535 | - return; |
| 536 | - |
| 537 | - if (atm_may_send(vcc, 0)) |
| 538 | - netif_wake_queue(net_dev); |
| 539 | - |
| 540 | + /* If the queue space just went up from zero, wake */ |
| 541 | + if (atomic_inc_return(&brvcc->qspace) == 1) |
| 542 | + netif_wake_queue(brvcc->device); |
| 543 | } |
| 544 | + |
| 545 | /* |
| 546 | * Send a packet out a particular vcc. Not to useful right now, but paves |
| 547 | * the way for multiple vcc's per itf. Returns true if we can send, |
| 548 | @@ -256,16 +256,30 @@ static int br2684_xmit_vcc(struct sk_buf |
| 549 | ATM_SKB(skb)->atm_options = atmvcc->atm_options; |
| 550 | dev->stats.tx_packets++; |
| 551 | dev->stats.tx_bytes += skb->len; |
| 552 | - atmvcc->send(atmvcc, skb); |
| 553 | |
| 554 | - if (!atm_may_send(atmvcc, 0)) { |
| 555 | + if (atomic_dec_return(&brvcc->qspace) < 1) { |
| 556 | + /* No more please! */ |
| 557 | netif_stop_queue(brvcc->device); |
| 558 | - /*check for race with br2684_pop*/ |
| 559 | - if (atm_may_send(atmvcc, 0)) |
| 560 | - netif_start_queue(brvcc->device); |
| 561 | + /* We might have raced with br2684_pop() */ |
| 562 | + if (unlikely(atomic_read(&brvcc->qspace) > 0)) |
| 563 | + netif_wake_queue(brvcc->device); |
| 564 | } |
| 565 | |
| 566 | - return 1; |
| 567 | + /* If this fails immediately, the skb will be freed and br2684_pop() |
| 568 | + will wake the queue if appropriate. Just return an error so that |
| 569 | + the stats are updated correctly */ |
| 570 | + return !atmvcc->send(atmvcc, skb); |
| 571 | +} |
| 572 | + |
| 573 | +static void br2684_release_cb(struct atm_vcc *atmvcc) |
| 574 | +{ |
| 575 | + struct br2684_vcc *brvcc = BR2684_VCC(atmvcc); |
| 576 | + |
| 577 | + if (atomic_read(&brvcc->qspace) > 0) |
| 578 | + netif_wake_queue(brvcc->device); |
| 579 | + |
| 580 | + if (brvcc->old_release_cb) |
| 581 | + brvcc->old_release_cb(atmvcc); |
| 582 | } |
| 583 | |
| 584 | static inline struct br2684_vcc *pick_outgoing_vcc(const struct sk_buff *skb, |
| 585 | @@ -279,6 +293,8 @@ static netdev_tx_t br2684_start_xmit(str |
| 586 | { |
| 587 | struct br2684_dev *brdev = BRPRIV(dev); |
| 588 | struct br2684_vcc *brvcc; |
| 589 | + struct atm_vcc *atmvcc; |
| 590 | + netdev_tx_t ret = NETDEV_TX_OK; |
| 591 | |
| 592 | pr_debug("skb_dst(skb)=%p\n", skb_dst(skb)); |
| 593 | read_lock(&devs_lock); |
| 594 | @@ -289,9 +305,26 @@ static netdev_tx_t br2684_start_xmit(str |
| 595 | dev->stats.tx_carrier_errors++; |
| 596 | /* netif_stop_queue(dev); */ |
| 597 | dev_kfree_skb(skb); |
| 598 | - read_unlock(&devs_lock); |
| 599 | - return NETDEV_TX_OK; |
| 600 | + goto out_devs; |
| 601 | } |
| 602 | + atmvcc = brvcc->atmvcc; |
| 603 | + |
| 604 | + bh_lock_sock(sk_atm(atmvcc)); |
| 605 | + |
| 606 | + if (test_bit(ATM_VF_RELEASED, &atmvcc->flags) || |
| 607 | + test_bit(ATM_VF_CLOSE, &atmvcc->flags) || |
| 608 | + !test_bit(ATM_VF_READY, &atmvcc->flags)) { |
| 609 | + dev->stats.tx_dropped++; |
| 610 | + dev_kfree_skb(skb); |
| 611 | + goto out; |
| 612 | + } |
| 613 | + |
| 614 | + if (sock_owned_by_user(sk_atm(atmvcc))) { |
| 615 | + netif_stop_queue(brvcc->device); |
| 616 | + ret = NETDEV_TX_BUSY; |
| 617 | + goto out; |
| 618 | + } |
| 619 | + |
| 620 | if (!br2684_xmit_vcc(skb, dev, brvcc)) { |
| 621 | /* |
| 622 | * We should probably use netif_*_queue() here, but that |
| 623 | @@ -303,8 +336,11 @@ static netdev_tx_t br2684_start_xmit(str |
| 624 | dev->stats.tx_errors++; |
| 625 | dev->stats.tx_fifo_errors++; |
| 626 | } |
| 627 | + out: |
| 628 | + bh_unlock_sock(sk_atm(atmvcc)); |
| 629 | + out_devs: |
| 630 | read_unlock(&devs_lock); |
| 631 | - return NETDEV_TX_OK; |
| 632 | + return ret; |
| 633 | } |
| 634 | |
| 635 | /* |
| 636 | @@ -377,9 +413,10 @@ static void br2684_close_vcc(struct br26 |
| 637 | list_del(&brvcc->brvccs); |
| 638 | write_unlock_irq(&devs_lock); |
| 639 | brvcc->atmvcc->user_back = NULL; /* what about vcc->recvq ??? */ |
| 640 | + brvcc->atmvcc->release_cb = brvcc->old_release_cb; |
| 641 | brvcc->old_push(brvcc->atmvcc, NULL); /* pass on the bad news */ |
| 642 | + module_put(brvcc->old_owner); |
| 643 | kfree(brvcc); |
| 644 | - module_put(THIS_MODULE); |
| 645 | } |
| 646 | |
| 647 | /* when AAL5 PDU comes in: */ |
| 648 | @@ -504,6 +541,13 @@ static int br2684_regvcc(struct atm_vcc |
| 649 | brvcc = kzalloc(sizeof(struct br2684_vcc), GFP_KERNEL); |
| 650 | if (!brvcc) |
| 651 | return -ENOMEM; |
| 652 | + /* |
| 653 | + * Allow two packets in the ATM queue. One actually being sent, and one |
| 654 | + * for the ATM 'TX done' handler to send. It shouldn't take long to get |
| 655 | + * the next one from the netdev queue, when we need it. More than that |
| 656 | + * would be bufferbloat. |
| 657 | + */ |
| 658 | + atomic_set(&brvcc->qspace, 2); |
| 659 | write_lock_irq(&devs_lock); |
| 660 | net_dev = br2684_find_dev(&be.ifspec); |
| 661 | if (net_dev == NULL) { |
| 662 | @@ -546,9 +590,13 @@ static int br2684_regvcc(struct atm_vcc |
| 663 | brvcc->encaps = (enum br2684_encaps)be.encaps; |
| 664 | brvcc->old_push = atmvcc->push; |
| 665 | brvcc->old_pop = atmvcc->pop; |
| 666 | + brvcc->old_release_cb = atmvcc->release_cb; |
| 667 | + brvcc->old_owner = atmvcc->owner; |
| 668 | barrier(); |
| 669 | atmvcc->push = br2684_push; |
| 670 | atmvcc->pop = br2684_pop; |
| 671 | + atmvcc->release_cb = br2684_release_cb; |
| 672 | + atmvcc->owner = THIS_MODULE; |
| 673 | |
| 674 | /* initialize netdev carrier state */ |
| 675 | if (atmvcc->dev->signal == ATM_PHY_SIG_LOST) |
| 676 | @@ -687,10 +735,13 @@ static int br2684_ioctl(struct socket *s |
| 677 | return -ENOIOCTLCMD; |
| 678 | if (!capable(CAP_NET_ADMIN)) |
| 679 | return -EPERM; |
| 680 | - if (cmd == ATM_SETBACKEND) |
| 681 | + if (cmd == ATM_SETBACKEND) { |
| 682 | + if (sock->state != SS_CONNECTED) |
| 683 | + return -EINVAL; |
| 684 | return br2684_regvcc(atmvcc, argp); |
| 685 | - else |
| 686 | + } else { |
| 687 | return br2684_create(argp); |
| 688 | + } |
| 689 | #ifdef CONFIG_ATM_BR2684_IPFILTER |
| 690 | case BR2684_SETFILT: |
| 691 | if (atmvcc->push != br2684_push) |
| 692 | --- a/net/atm/common.c |
| 693 | +++ b/net/atm/common.c |
| 694 | @@ -126,10 +126,19 @@ static void vcc_write_space(struct sock |
| 695 | rcu_read_unlock(); |
| 696 | } |
| 697 | |
| 698 | +static void vcc_release_cb(struct sock *sk) |
| 699 | +{ |
| 700 | + struct atm_vcc *vcc = atm_sk(sk); |
| 701 | + |
| 702 | + if (vcc->release_cb) |
| 703 | + vcc->release_cb(vcc); |
| 704 | +} |
| 705 | + |
| 706 | static struct proto vcc_proto = { |
| 707 | .name = "VCC", |
| 708 | .owner = THIS_MODULE, |
| 709 | .obj_size = sizeof(struct atm_vcc), |
| 710 | + .release_cb = vcc_release_cb, |
| 711 | }; |
| 712 | |
| 713 | int vcc_create(struct net *net, struct socket *sock, int protocol, int family) |
| 714 | @@ -156,7 +165,9 @@ int vcc_create(struct net *net, struct s |
| 715 | atomic_set(&sk->sk_rmem_alloc, 0); |
| 716 | vcc->push = NULL; |
| 717 | vcc->pop = NULL; |
| 718 | + vcc->owner = NULL; |
| 719 | vcc->push_oam = NULL; |
| 720 | + vcc->release_cb = NULL; |
| 721 | vcc->vpi = vcc->vci = 0; /* no VCI/VPI yet */ |
| 722 | vcc->atm_options = vcc->aal_options = 0; |
| 723 | sk->sk_destruct = vcc_sock_destruct; |
| 724 | @@ -175,6 +186,7 @@ static void vcc_destroy_socket(struct so |
| 725 | vcc->dev->ops->close(vcc); |
| 726 | if (vcc->push) |
| 727 | vcc->push(vcc, NULL); /* atmarpd has no push */ |
| 728 | + module_put(vcc->owner); |
| 729 | |
| 730 | while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { |
| 731 | atm_return(vcc, skb->truesize); |
| 732 | --- a/net/atm/pppoatm.c |
| 733 | +++ b/net/atm/pppoatm.c |
| 734 | @@ -60,6 +60,8 @@ struct pppoatm_vcc { |
| 735 | struct atm_vcc *atmvcc; /* VCC descriptor */ |
| 736 | void (*old_push)(struct atm_vcc *, struct sk_buff *); |
| 737 | void (*old_pop)(struct atm_vcc *, struct sk_buff *); |
| 738 | + void (*old_release_cb)(struct atm_vcc *); |
| 739 | + struct module *old_owner; |
| 740 | /* keep old push/pop for detaching */ |
| 741 | enum pppoatm_encaps encaps; |
| 742 | atomic_t inflight; |
| 743 | @@ -107,6 +109,24 @@ static void pppoatm_wakeup_sender(unsign |
| 744 | ppp_output_wakeup((struct ppp_channel *) arg); |
| 745 | } |
| 746 | |
| 747 | +static void pppoatm_release_cb(struct atm_vcc *atmvcc) |
| 748 | +{ |
| 749 | + struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc); |
| 750 | + |
| 751 | + /* |
| 752 | + * As in pppoatm_pop(), it's safe to clear the BLOCKED bit here because |
| 753 | + * the wakeup *can't* race with pppoatm_send(). They both hold the PPP |
| 754 | + * channel's ->downl lock. And the potential race with *setting* it, |
| 755 | + * which leads to the double-check dance in pppoatm_may_send(), doesn't |
| 756 | + * exist here. In the sock_owned_by_user() case in pppoatm_send(), we |
| 757 | + * set the BLOCKED bit while the socket is still locked. We know that |
| 758 | + * ->release_cb() can't be called until that's done. |
| 759 | + */ |
| 760 | + if (test_and_clear_bit(BLOCKED, &pvcc->blocked)) |
| 761 | + tasklet_schedule(&pvcc->wakeup_tasklet); |
| 762 | + if (pvcc->old_release_cb) |
| 763 | + pvcc->old_release_cb(atmvcc); |
| 764 | +} |
| 765 | /* |
| 766 | * This gets called every time the ATM card has finished sending our |
| 767 | * skb. The ->old_pop will take care up normal atm flow control, |
| 768 | @@ -151,12 +171,11 @@ static void pppoatm_unassign_vcc(struct |
| 769 | pvcc = atmvcc_to_pvcc(atmvcc); |
| 770 | atmvcc->push = pvcc->old_push; |
| 771 | atmvcc->pop = pvcc->old_pop; |
| 772 | + atmvcc->release_cb = pvcc->old_release_cb; |
| 773 | tasklet_kill(&pvcc->wakeup_tasklet); |
| 774 | ppp_unregister_channel(&pvcc->chan); |
| 775 | atmvcc->user_back = NULL; |
| 776 | kfree(pvcc); |
| 777 | - /* Gee, I hope we have the big kernel lock here... */ |
| 778 | - module_put(THIS_MODULE); |
| 779 | } |
| 780 | |
| 781 | /* Called when an AAL5 PDU comes in */ |
| 782 | @@ -165,9 +184,13 @@ static void pppoatm_push(struct atm_vcc |
| 783 | struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc); |
| 784 | pr_debug("\n"); |
| 785 | if (skb == NULL) { /* VCC was closed */ |
| 786 | + struct module *module; |
| 787 | + |
| 788 | pr_debug("removing ATMPPP VCC %p\n", pvcc); |
| 789 | + module = pvcc->old_owner; |
| 790 | pppoatm_unassign_vcc(atmvcc); |
| 791 | atmvcc->push(atmvcc, NULL); /* Pass along bad news */ |
| 792 | + module_put(module); |
| 793 | return; |
| 794 | } |
| 795 | atm_return(atmvcc, skb->truesize); |
| 796 | @@ -211,7 +234,7 @@ error: |
| 797 | ppp_input_error(&pvcc->chan, 0); |
| 798 | } |
| 799 | |
| 800 | -static inline int pppoatm_may_send(struct pppoatm_vcc *pvcc, int size) |
| 801 | +static int pppoatm_may_send(struct pppoatm_vcc *pvcc, int size) |
| 802 | { |
| 803 | /* |
| 804 | * It's not clear that we need to bother with using atm_may_send() |
| 805 | @@ -269,10 +292,33 @@ static inline int pppoatm_may_send(struc |
| 806 | static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) |
| 807 | { |
| 808 | struct pppoatm_vcc *pvcc = chan_to_pvcc(chan); |
| 809 | + struct atm_vcc *vcc; |
| 810 | + int ret; |
| 811 | + |
| 812 | ATM_SKB(skb)->vcc = pvcc->atmvcc; |
| 813 | pr_debug("(skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc); |
| 814 | if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT)) |
| 815 | (void) skb_pull(skb, 1); |
| 816 | + |
| 817 | + vcc = ATM_SKB(skb)->vcc; |
| 818 | + bh_lock_sock(sk_atm(vcc)); |
| 819 | + if (sock_owned_by_user(sk_atm(vcc))) { |
| 820 | + /* |
| 821 | + * Needs to happen (and be flushed, hence test_and_) before we unlock |
| 822 | + * the socket. It needs to be seen by the time our ->release_cb gets |
| 823 | + * called. |
| 824 | + */ |
| 825 | + test_and_set_bit(BLOCKED, &pvcc->blocked); |
| 826 | + goto nospace; |
| 827 | + } |
| 828 | + if (test_bit(ATM_VF_RELEASED, &vcc->flags) || |
| 829 | + test_bit(ATM_VF_CLOSE, &vcc->flags) || |
| 830 | + !test_bit(ATM_VF_READY, &vcc->flags)) { |
| 831 | + bh_unlock_sock(sk_atm(vcc)); |
| 832 | + kfree_skb(skb); |
| 833 | + return DROP_PACKET; |
| 834 | + } |
| 835 | + |
| 836 | switch (pvcc->encaps) { /* LLC encapsulation needed */ |
| 837 | case e_llc: |
| 838 | if (skb_headroom(skb) < LLC_LEN) { |
| 839 | @@ -285,8 +331,10 @@ static int pppoatm_send(struct ppp_chann |
| 840 | } |
| 841 | consume_skb(skb); |
| 842 | skb = n; |
| 843 | - if (skb == NULL) |
| 844 | + if (skb == NULL) { |
| 845 | + bh_unlock_sock(sk_atm(vcc)); |
| 846 | return DROP_PACKET; |
| 847 | + } |
| 848 | } else if (!pppoatm_may_send(pvcc, skb->truesize)) |
| 849 | goto nospace; |
| 850 | memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN); |
| 851 | @@ -296,6 +344,7 @@ static int pppoatm_send(struct ppp_chann |
| 852 | goto nospace; |
| 853 | break; |
| 854 | case e_autodetect: |
| 855 | + bh_unlock_sock(sk_atm(vcc)); |
| 856 | pr_debug("Trying to send without setting encaps!\n"); |
| 857 | kfree_skb(skb); |
| 858 | return 1; |
| 859 | @@ -305,9 +354,12 @@ static int pppoatm_send(struct ppp_chann |
| 860 | ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options; |
| 861 | pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", |
| 862 | skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev); |
| 863 | - return ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb) |
| 864 | + ret = ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb) |
| 865 | ? DROP_PACKET : 1; |
| 866 | + bh_unlock_sock(sk_atm(vcc)); |
| 867 | + return ret; |
| 868 | nospace: |
| 869 | + bh_unlock_sock(sk_atm(vcc)); |
| 870 | /* |
| 871 | * We don't have space to send this SKB now, but we might have |
| 872 | * already applied SC_COMP_PROT compression, so may need to undo |
| 873 | @@ -362,6 +414,8 @@ static int pppoatm_assign_vcc(struct atm |
| 874 | atomic_set(&pvcc->inflight, NONE_INFLIGHT); |
| 875 | pvcc->old_push = atmvcc->push; |
| 876 | pvcc->old_pop = atmvcc->pop; |
| 877 | + pvcc->old_owner = atmvcc->owner; |
| 878 | + pvcc->old_release_cb = atmvcc->release_cb; |
| 879 | pvcc->encaps = (enum pppoatm_encaps) be.encaps; |
| 880 | pvcc->chan.private = pvcc; |
| 881 | pvcc->chan.ops = &pppoatm_ops; |
| 882 | @@ -377,7 +431,9 @@ static int pppoatm_assign_vcc(struct atm |
| 883 | atmvcc->user_back = pvcc; |
| 884 | atmvcc->push = pppoatm_push; |
| 885 | atmvcc->pop = pppoatm_pop; |
| 886 | + atmvcc->release_cb = pppoatm_release_cb; |
| 887 | __module_get(THIS_MODULE); |
| 888 | + atmvcc->owner = THIS_MODULE; |
| 889 | |
| 890 | /* re-process everything received between connection setup and |
| 891 | backend setup */ |
| 892 | @@ -406,6 +462,8 @@ static int pppoatm_ioctl(struct socket * |
| 893 | return -ENOIOCTLCMD; |
| 894 | if (!capable(CAP_NET_ADMIN)) |
| 895 | return -EPERM; |
| 896 | + if (sock->state != SS_CONNECTED) |
| 897 | + return -EINVAL; |
| 898 | return pppoatm_assign_vcc(atmvcc, argp); |
| 899 | } |
| 900 | case PPPIOCGCHAN: |
| 901 | |