--- /dev/null
+From 84950cf0ba02fd6a5defe2511bc41f9aa2237632 Mon Sep 17 00:00:00 2001
+From: Mikko Rapeli <mikko.rapeli@iki.fi>
+Date: Wed, 11 Jul 2007 09:18:15 +0200
+Subject: [PATCH] [Bluetooth] Hangup TTY before releasing rfcomm_dev
+
+From: Mikko Rapeli <mikko.rapeli@iki.fi>
+
+The core problem is that RFCOMM socket layer ioctl can release
+rfcomm_dev struct while RFCOMM TTY layer is still actively using
+it. Calling tty_vhangup() is needed for a synchronous hangup before
+rfcomm_dev is freed.
+
+Addresses the oops at http://bugzilla.kernel.org/show_bug.cgi?id=7509
+
+Acked-by: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/bluetooth/rfcomm/tty.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/net/bluetooth/rfcomm/tty.c
++++ b/net/bluetooth/rfcomm/tty.c
+@@ -383,6 +383,10 @@ static int rfcomm_release_dev(void __use
+ if (req.flags & (1 << RFCOMM_HANGUP_NOW))
+ rfcomm_dlc_close(dev->dlc, 0);
+
++ /* Shut down TTY synchronously before freeing rfcomm_dev */
++ if (dev->tty)
++ tty_vhangup(dev->tty);
++
+ rfcomm_dev_del(dev);
+ rfcomm_dev_put(dev);
+ return 0;
--- /dev/null
+From 8de0a15483b357d0f0b821330ec84d1660cadc4e Mon Sep 17 00:00:00 2001
+From: Ville Tervo <ville.tervo@nokia.com>
+Date: Wed, 11 Jul 2007 09:23:41 +0200
+Subject: [PATCH] [Bluetooth] Keep rfcomm_dev on the list until it is freed
+
+From: Ville Tervo <ville.tervo@nokia.com>
+
+This patch changes the RFCOMM TTY release process so that the TTY is kept
+on the list until it is really freed. A new device flag is used to keep
+track of released TTYs.
+
+Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
+Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/net/bluetooth/rfcomm.h | 1 +
+ net/bluetooth/rfcomm/tty.c | 30 ++++++++++++++++++++++--------
+ 2 files changed, 23 insertions(+), 8 deletions(-)
+
+--- a/include/net/bluetooth/rfcomm.h
++++ b/include/net/bluetooth/rfcomm.h
+@@ -323,6 +323,7 @@ int rfcomm_connect_ind(struct rfcomm_se
+ #define RFCOMM_RELEASE_ONHUP 1
+ #define RFCOMM_HANGUP_NOW 2
+ #define RFCOMM_TTY_ATTACHED 3
++#define RFCOMM_TTY_RELEASED 4
+
+ struct rfcomm_dev_req {
+ s16 dev_id;
+--- a/net/bluetooth/rfcomm/tty.c
++++ b/net/bluetooth/rfcomm/tty.c
+@@ -95,6 +95,10 @@ static void rfcomm_dev_destruct(struct r
+
+ BT_DBG("dev %p dlc %p", dev, dlc);
+
++ write_lock_bh(&rfcomm_dev_lock);
++ list_del_init(&dev->list);
++ write_unlock_bh(&rfcomm_dev_lock);
++
+ rfcomm_dlc_lock(dlc);
+ /* Detach DLC if it's owned by this dev */
+ if (dlc->owner == dev)
+@@ -156,8 +160,13 @@ static inline struct rfcomm_dev *rfcomm_
+ read_lock(&rfcomm_dev_lock);
+
+ dev = __rfcomm_dev_get(id);
+- if (dev)
+- rfcomm_dev_hold(dev);
++
++ if (dev) {
++ if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
++ dev = NULL;
++ else
++ rfcomm_dev_hold(dev);
++ }
+
+ read_unlock(&rfcomm_dev_lock);
+
+@@ -265,6 +274,12 @@ out:
+
+ dev->tty_dev = tty_register_device(rfcomm_tty_driver, dev->id, NULL);
+
++ if (IS_ERR(dev->tty_dev)) {
++ list_del(&dev->list);
++ kfree(dev);
++ return PTR_ERR(dev->tty_dev);
++ }
++
+ return dev->id;
+ }
+
+@@ -272,10 +287,7 @@ static void rfcomm_dev_del(struct rfcomm
+ {
+ BT_DBG("dev %p", dev);
+
+- write_lock_bh(&rfcomm_dev_lock);
+- list_del_init(&dev->list);
+- write_unlock_bh(&rfcomm_dev_lock);
+-
++ set_bit(RFCOMM_TTY_RELEASED, &dev->flags);
+ rfcomm_dev_put(dev);
+ }
+
+@@ -329,7 +341,7 @@ static int rfcomm_create_dev(struct sock
+ if (copy_from_user(&req, arg, sizeof(req)))
+ return -EFAULT;
+
+- BT_DBG("sk %p dev_id %id flags 0x%x", sk, req.dev_id, req.flags);
++ BT_DBG("sk %p dev_id %d flags 0x%x", sk, req.dev_id, req.flags);
+
+ if (req.flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN))
+ return -EPERM;
+@@ -370,7 +382,7 @@ static int rfcomm_release_dev(void __use
+ if (copy_from_user(&req, arg, sizeof(req)))
+ return -EFAULT;
+
+- BT_DBG("dev_id %id flags 0x%x", req.dev_id, req.flags);
++ BT_DBG("dev_id %d flags 0x%x", req.dev_id, req.flags);
+
+ if (!(dev = rfcomm_dev_get(req.dev_id)))
+ return -ENODEV;
+@@ -419,6 +431,8 @@ static int rfcomm_get_dev_list(void __us
+
+ list_for_each(p, &rfcomm_dev_list) {
+ struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list);
++ if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
++ continue;
+ (di + n)->id = dev->id;
+ (di + n)->flags = dev->flags;
+ (di + n)->state = dev->dlc->state;