Commit 46acabae authored by Maksim Krasnyanskiy's avatar Maksim Krasnyanskiy

[Bluetooth] Improved RFCOMM TTY TX buffer management.

Don't buffer more data than we have credits for.

Patch from David Woodhouse <dwmw2@infradead.org>
parent bba207eb
...@@ -72,7 +72,6 @@ struct rfcomm_dev { ...@@ -72,7 +72,6 @@ struct rfcomm_dev {
struct tasklet_struct wakeup_task; struct tasklet_struct wakeup_task;
atomic_t wmem_alloc; atomic_t wmem_alloc;
unsigned int sndbuf;
}; };
static LIST_HEAD(rfcomm_dev_list); static LIST_HEAD(rfcomm_dev_list);
...@@ -200,8 +199,6 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) ...@@ -200,8 +199,6 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
dev->flags = req->flags & dev->flags = req->flags &
((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC)); ((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
dev->sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
init_waitqueue_head(&dev->wait); init_waitqueue_head(&dev->wait);
tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev); tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
...@@ -238,6 +235,13 @@ static void rfcomm_dev_del(struct rfcomm_dev *dev) ...@@ -238,6 +235,13 @@ static void rfcomm_dev_del(struct rfcomm_dev *dev)
} }
/* ---- Send buffer ---- */ /* ---- Send buffer ---- */
static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc)
{
/* We can't let it be zero, because we don't get a callback
when tx_credits becomes nonzero, hence we'd never wake up */
return dlc->mtu * (dlc->tx_credits?:1);
}
static void rfcomm_wfree(struct sk_buff *skb) static void rfcomm_wfree(struct sk_buff *skb)
{ {
struct rfcomm_dev *dev = (void *) skb->sk; struct rfcomm_dev *dev = (void *) skb->sk;
...@@ -257,7 +261,7 @@ static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *de ...@@ -257,7 +261,7 @@ static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *de
static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int priority) static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int priority)
{ {
if (atomic_read(&dev->wmem_alloc) < dev->sndbuf) { if (atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) {
struct sk_buff *skb = alloc_skb(size, priority); struct sk_buff *skb = alloc_skb(size, priority);
if (skb) { if (skb) {
rfcomm_set_owner_w(skb, dev); rfcomm_set_owner_w(skb, dev);
...@@ -651,11 +655,14 @@ static int rfcomm_tty_write(struct tty_struct *tty, int from_user, const unsigne ...@@ -651,11 +655,14 @@ static int rfcomm_tty_write(struct tty_struct *tty, int from_user, const unsigne
static int rfcomm_tty_write_room(struct tty_struct *tty) static int rfcomm_tty_write_room(struct tty_struct *tty)
{ {
struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
struct rfcomm_dlc *dlc = dev->dlc; int room;
BT_DBG("tty %p", tty); BT_DBG("tty %p", tty);
return dlc->mtu * (dlc->tx_credits ? : 10); room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc);
if (room < 0)
room = 0;
return room;
} }
static int rfcomm_tty_set_modem_status(uint cmd, struct rfcomm_dlc *dlc, uint status) static int rfcomm_tty_set_modem_status(uint cmd, struct rfcomm_dlc *dlc, uint status)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment