Commit 38b04ed7 authored by Qingfang Deng's avatar Qingfang Deng Committed by Paolo Abeni
Browse files

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: default avatar <syzbot+5fd749c74105b0e1b302@syzkaller.appspotmail.com>
Closes: https://lore.kernel.org/all/68c858b0.050a0220.3c6139.0d1c.GAE@google.com/


Signed-off-by: default avatarQingfang Deng <dqfext@gmail.com>
Reviewed-by: default avatarDan Carpenter <dan.carpenter@linaro.org>
Link: https://patch.msgid.link/20250925051059.26876-1-dqfext@gmail.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 7bd80ed8
Loading
Loading
Loading
Loading
+5 −52
Original line number Diff line number Diff line
@@ -115,8 +115,6 @@ struct sixpack {

	struct timer_list	tx_t;
	struct timer_list	resync_t;
	refcount_t		refcnt;
	struct completion	dead;
	spinlock_t		lock;
};

@@ -353,42 +351,13 @@ static void sp_bump(struct sixpack *sp, char cmd)

/* ----------------------------------------------------------------------- */

/*
 * We have a potential race on dereferencing tty->disc_data, because the tty
 * layer provides no locking at all - thus one cpu could be running
 * sixpack_receive_buf while another calls sixpack_close, which zeroes
 * tty->disc_data and frees the memory that sixpack_receive_buf is using.  The
 * best way to fix this is to use a rwlock in the tty struct, but for now we
 * use a single global rwlock for all ttys in ppp line discipline.
 */
static DEFINE_RWLOCK(disc_data_lock);
                                                                                
static struct sixpack *sp_get(struct tty_struct *tty)
{
	struct sixpack *sp;

	read_lock(&disc_data_lock);
	sp = tty->disc_data;
	if (sp)
		refcount_inc(&sp->refcnt);
	read_unlock(&disc_data_lock);

	return sp;
}

static void sp_put(struct sixpack *sp)
{
	if (refcount_dec_and_test(&sp->refcnt))
		complete(&sp->dead);
}

/*
 * Called by the TTY driver when there's room for more data.  If we have
 * more packets to send, we send them here.
 */
static void sixpack_write_wakeup(struct tty_struct *tty)
{
	struct sixpack *sp = sp_get(tty);
	struct sixpack *sp = tty->disc_data;
	int actual;

	if (!sp)
@@ -400,7 +369,7 @@ static void sixpack_write_wakeup(struct tty_struct *tty)
		clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
		sp->tx_enable = 0;
		netif_wake_queue(sp->dev);
		goto out;
		return;
	}

	if (sp->tx_enable) {
@@ -408,9 +377,6 @@ static void sixpack_write_wakeup(struct tty_struct *tty)
		sp->xleft -= actual;
		sp->xhead += actual;
	}

out:
	sp_put(sp);
}

/* ----------------------------------------------------------------------- */
@@ -430,7 +396,7 @@ static void sixpack_receive_buf(struct tty_struct *tty, const u8 *cp,
	if (!count)
		return;

	sp = sp_get(tty);
	sp = tty->disc_data;
	if (!sp)
		return;

@@ -446,7 +412,6 @@ static void sixpack_receive_buf(struct tty_struct *tty, const u8 *cp,
	}
	sixpack_decode(sp, cp, count1);

	sp_put(sp);
	tty_unthrottle(tty);
}

@@ -561,8 +526,6 @@ static int sixpack_open(struct tty_struct *tty)

	spin_lock_init(&sp->lock);
	spin_lock_init(&sp->rxlock);
	refcount_set(&sp->refcnt, 1);
	init_completion(&sp->dead);

	/* !!! length of the buffers. MTU is IP MTU, not PACLEN!  */

@@ -638,19 +601,11 @@ static void sixpack_close(struct tty_struct *tty)
{
	struct sixpack *sp;

	write_lock_irq(&disc_data_lock);
	sp = tty->disc_data;
	tty->disc_data = NULL;
	write_unlock_irq(&disc_data_lock);
	if (!sp)
		return;

	/*
	 * We have now ensured that nobody can start using ap from now on, but
	 * we have to wait for all existing users to finish.
	 */
	if (!refcount_dec_and_test(&sp->refcnt))
		wait_for_completion(&sp->dead);
	tty->disc_data = NULL;

	/* We must stop the queue to avoid potentially scribbling
	 * on the free buffers. The sp->dead completion is not sufficient
@@ -673,7 +628,7 @@ static void sixpack_close(struct tty_struct *tty)
static int sixpack_ioctl(struct tty_struct *tty, unsigned int cmd,
		unsigned long arg)
{
	struct sixpack *sp = sp_get(tty);
	struct sixpack *sp = tty->disc_data;
	struct net_device *dev;
	unsigned int tmp, err;

@@ -725,8 +680,6 @@ static int sixpack_ioctl(struct tty_struct *tty, unsigned int cmd,
		err = tty_mode_ioctl(tty, cmd, arg);
	}

	sp_put(sp);

	return err;
}