Bluetooth: don't release the port in rfcomm_dev_state_change()
When the dlc is closed, rfcomm_dev_state_change() tries to release the
port in the case it cannot get a reference to the tty. However this is
racy and not even needed.
Infact as Peter Hurley points out:
1. Only consider dlcs that are 'stolen' from a connected socket, ie.
   reused. Allocated dlcs cannot have been closed prior to port
   activate and so for these dlcs a tty reference will always be avail
   in rfcomm_dev_state_change() -- except for the conditions covered by
   #2b below.
2. If a tty was at some point previously created for this rfcomm, then
   either
   (a) the tty reference is still avail, so rfcomm_dev_state_change()
       will perform a hangup. So nothing to do, or,
   (b) the tty reference is no longer avail, and the tty_port will be
       destroyed by the last tty_port_put() in rfcomm_tty_cleanup.
       Again, no action required.
3. Prior to obtaining the dlc lock in rfcomm_dev_add(),
   rfcomm_dev_state_change() will not 'see' a rfcomm_dev so nothing to
   do here.
4. After releasing the dlc lock in rfcomm_dev_add(),
   rfcomm_dev_state_change() will 'see' an incomplete rfcomm_dev if a
   tty reference could not be obtained. Again, the best thing to do here
   is nothing. Any future attempted open() will block on
   rfcomm_dev_carrier_raised(). The unconnected device will exist until
   released by ioctl(RFCOMMRELEASEDEV).
The patch removes the aforementioned code and uses the
tty_port_tty_hangup() helper to hangup the tty.
Signed-off-by: Gianluca Anzolin <gianluca@sottospazio.it>
Reviewed-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
	
	
This commit is contained in:
		
					parent
					
						
							
								bf5430360e
							
						
					
				
			
			
				commit
				
					
						29cd718beb
					
				
			
		
					 1 changed files with 2 additions and 33 deletions
				
			
		|  | @ -569,7 +569,6 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb) | ||||||
| static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) | static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) | ||||||
| { | { | ||||||
| 	struct rfcomm_dev *dev = dlc->owner; | 	struct rfcomm_dev *dev = dlc->owner; | ||||||
| 	struct tty_struct *tty; |  | ||||||
| 	if (!dev) | 	if (!dev) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
|  | @ -581,38 +580,8 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) | ||||||
| 			    DPM_ORDER_DEV_AFTER_PARENT); | 			    DPM_ORDER_DEV_AFTER_PARENT); | ||||||
| 
 | 
 | ||||||
| 		wake_up_interruptible(&dev->port.open_wait); | 		wake_up_interruptible(&dev->port.open_wait); | ||||||
| 	} else if (dlc->state == BT_CLOSED) { | 	} else if (dlc->state == BT_CLOSED) | ||||||
| 		tty = tty_port_tty_get(&dev->port); | 		tty_port_tty_hangup(&dev->port, false); | ||||||
| 		if (!tty) { |  | ||||||
| 			if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) { |  | ||||||
| 				/* Drop DLC lock here to avoid deadlock
 |  | ||||||
| 				 * 1. rfcomm_dev_get will take rfcomm_dev_lock |  | ||||||
| 				 *    but in rfcomm_dev_add there's lock order: |  | ||||||
| 				 *    rfcomm_dev_lock -> dlc lock |  | ||||||
| 				 * 2. tty_port_put will deadlock if it's |  | ||||||
| 				 *    the last reference |  | ||||||
| 				 * |  | ||||||
| 				 * FIXME: when we release the lock anything |  | ||||||
| 				 * could happen to dev, even its destruction |  | ||||||
| 				 */ |  | ||||||
| 				rfcomm_dlc_unlock(dlc); |  | ||||||
| 				if (rfcomm_dev_get(dev->id) == NULL) { |  | ||||||
| 					rfcomm_dlc_lock(dlc); |  | ||||||
| 					return; |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				if (!test_and_set_bit(RFCOMM_TTY_RELEASED, |  | ||||||
| 						      &dev->flags)) |  | ||||||
| 					tty_port_put(&dev->port); |  | ||||||
| 
 |  | ||||||
| 				tty_port_put(&dev->port); |  | ||||||
| 				rfcomm_dlc_lock(dlc); |  | ||||||
| 			} |  | ||||||
| 		} else { |  | ||||||
| 			tty_hangup(tty); |  | ||||||
| 			tty_kref_put(tty); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig) | static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Gianluca Anzolin
				Gianluca Anzolin