summaryrefslogtreecommitdiff
path: root/recipes-kernel/linux/linux-3.12.27/linux-3.12-release-rfcomm-port-fix.patch
blob: 70c41d25d486d28823ab08a188334229ce8ec24e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
commit 5b899241874dcc1a2b932a668731c80a3a869575
Author: Gianluca Anzolin <gianluca@sottospazio.it>
Date:   Mon Jan 6 21:23:50 2014 +0100

    Bluetooth: Release RFCOMM port when the last user closes the TTY
    
    This patch fixes a userspace regression introduced by the commit
    29cd718b.
    
    If the rfcomm device was created with the flag RFCOMM_RELEASE_ONHUP the
    user space expects that the tty_port is released as soon as the last
    process closes the tty.
    
    The current code attempts to release the port in the function
    rfcomm_dev_state_change(). However it won't get a reference to the
    relevant tty to send a HUP: at that point the tty is already destroyed
    and therefore NULL.
    
    This patch fixes the regression by taking over the tty refcount in the
    tty install method(). This way the tty_port is automatically released as
    soon as the tty is destroyed.
    
    As a consequence the check for RFCOMM_RELEASE_ONHUP flag in the hangup()
    method is now redundant. Instead we have to be careful with the reference
    counting in the rfcomm_release_dev() function.
    
    Signed-off-by: Gianluca Anzolin <gianluca@sottospazio.it>
    Reported-by: Alexander Holler <holler@ahsoftware.de>
    Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 84fcf9f..a535ef1 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -437,7 +437,8 @@ static int rfcomm_release_dev(void __user *arg)
 		tty_kref_put(tty);
 	}
 
-	if (!test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags))
+	if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) &&
+	    !test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags))
 		tty_port_put(&dev->port);
 
 	tty_port_put(&dev->port);
@@ -670,10 +671,20 @@ static int rfcomm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
 
 	/* install the tty_port */
 	err = tty_port_install(&dev->port, driver, tty);
-	if (err)
+	if (err) {
 		rfcomm_tty_cleanup(tty);
+		return err;
+	}
 
-	return err;
+	/* take over the tty_port reference if the port was created with the
+	 * flag RFCOMM_RELEASE_ONHUP. This will force the release of the port
+	 * when the last process closes the tty. The behaviour is expected by
+	 * userspace.
+	 */
+	if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
+		tty_port_put(&dev->port);
+
+	return 0;
 }
 
 static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
@@ -1010,10 +1021,6 @@ static void rfcomm_tty_hangup(struct tty_struct *tty)
 	BT_DBG("tty %p dev %p", tty, dev);
 
 	tty_port_hangup(&dev->port);
-
-	if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) &&
-	    !test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags))
-		tty_port_put(&dev->port);
 }
 
 static int rfcomm_tty_tiocmget(struct tty_struct *tty)