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

6pack: drop redundant locking and refcounting

The TTY layer already serializes line discipline operations with
tty->ldisc_sem, so the extra disc_data_lock and refcnt in 6pack
are unnecessary.

Removing them simplifies the code and also resolves a lockdep warning
reported by syzbot. The warning did not indicate a real deadlock, since
the write-side lock was only taken in process context with hardirqs
disabled.

Reported-by: syzbot+5fd749c74105b0e1b302@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/all/68c858b0.050a0220.3c6139.0d1c.GAE@google.com/
Signed-off-by: Qingfang Deng <dqfext@gmail.com>
Reviewed-by: Dan Carpenter <dan.carpenter@linaro.org>
Link: https://patch.msgid.link/20250925051059.26876-1-dqfext@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Qingfang Deng and committed by
Paolo Abeni
38b04ed7 7bd80ed8

+5 -52
+5 -52
drivers/net/hamradio/6pack.c
··· 115 115 116 116 struct timer_list tx_t; 117 117 struct timer_list resync_t; 118 - refcount_t refcnt; 119 - struct completion dead; 120 118 spinlock_t lock; 121 119 }; 122 120 ··· 352 354 /* ----------------------------------------------------------------------- */ 353 355 354 356 /* 355 - * We have a potential race on dereferencing tty->disc_data, because the tty 356 - * layer provides no locking at all - thus one cpu could be running 357 - * sixpack_receive_buf while another calls sixpack_close, which zeroes 358 - * tty->disc_data and frees the memory that sixpack_receive_buf is using. The 359 - * best way to fix this is to use a rwlock in the tty struct, but for now we 360 - * use a single global rwlock for all ttys in ppp line discipline. 361 - */ 362 - static DEFINE_RWLOCK(disc_data_lock); 363 - 364 - static struct sixpack *sp_get(struct tty_struct *tty) 365 - { 366 - struct sixpack *sp; 367 - 368 - read_lock(&disc_data_lock); 369 - sp = tty->disc_data; 370 - if (sp) 371 - refcount_inc(&sp->refcnt); 372 - read_unlock(&disc_data_lock); 373 - 374 - return sp; 375 - } 376 - 377 - static void sp_put(struct sixpack *sp) 378 - { 379 - if (refcount_dec_and_test(&sp->refcnt)) 380 - complete(&sp->dead); 381 - } 382 - 383 - /* 384 357 * Called by the TTY driver when there's room for more data. If we have 385 358 * more packets to send, we send them here. 386 359 */ 387 360 static void sixpack_write_wakeup(struct tty_struct *tty) 388 361 { 389 - struct sixpack *sp = sp_get(tty); 362 + struct sixpack *sp = tty->disc_data; 390 363 int actual; 391 364 392 365 if (!sp) ··· 369 400 clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 370 401 sp->tx_enable = 0; 371 402 netif_wake_queue(sp->dev); 372 - goto out; 403 + return; 373 404 } 374 405 375 406 if (sp->tx_enable) { ··· 377 408 sp->xleft -= actual; 378 409 sp->xhead += actual; 379 410 } 380 - 381 - out: 382 - sp_put(sp); 383 411 } 384 412 385 413 /* ----------------------------------------------------------------------- */ ··· 396 430 if (!count) 397 431 return; 398 432 399 - sp = sp_get(tty); 433 + sp = tty->disc_data; 400 434 if (!sp) 401 435 return; 402 436 ··· 412 446 } 413 447 sixpack_decode(sp, cp, count1); 414 448 415 - sp_put(sp); 416 449 tty_unthrottle(tty); 417 450 } 418 451 ··· 526 561 527 562 spin_lock_init(&sp->lock); 528 563 spin_lock_init(&sp->rxlock); 529 - refcount_set(&sp->refcnt, 1); 530 - init_completion(&sp->dead); 531 564 532 565 /* !!! length of the buffers. MTU is IP MTU, not PACLEN! */ 533 566 ··· 601 638 { 602 639 struct sixpack *sp; 603 640 604 - write_lock_irq(&disc_data_lock); 605 641 sp = tty->disc_data; 606 - tty->disc_data = NULL; 607 - write_unlock_irq(&disc_data_lock); 608 642 if (!sp) 609 643 return; 610 644 611 - /* 612 - * We have now ensured that nobody can start using ap from now on, but 613 - * we have to wait for all existing users to finish. 614 - */ 615 - if (!refcount_dec_and_test(&sp->refcnt)) 616 - wait_for_completion(&sp->dead); 645 + tty->disc_data = NULL; 617 646 618 647 /* We must stop the queue to avoid potentially scribbling 619 648 * on the free buffers. The sp->dead completion is not sufficient ··· 628 673 static int sixpack_ioctl(struct tty_struct *tty, unsigned int cmd, 629 674 unsigned long arg) 630 675 { 631 - struct sixpack *sp = sp_get(tty); 676 + struct sixpack *sp = tty->disc_data; 632 677 struct net_device *dev; 633 678 unsigned int tmp, err; 634 679 ··· 679 724 default: 680 725 err = tty_mode_ioctl(tty, cmd, arg); 681 726 } 682 - 683 - sp_put(sp); 684 727 685 728 return err; 686 729 }