mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	tty_lock: Localise the lock
In each remaining case the tty_lock is associated with a specific tty. This means we can now lock on a per tty basis. We do need tty_lock_pair() for the pty case. Uglier but still a step in the right direction. [fixed up calls in 3 missing drivers - gregkh] Signed-off-by: Alan Cox <alan@linux.intel.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
		
							parent
							
								
									d739e65bb2
								
							
						
					
					
						commit
						d29f3ef39b
					
				
					 15 changed files with 155 additions and 103 deletions
				
			
		| 
						 | 
					@ -1859,9 +1859,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
 | 
				
			||||||
		printk("block_til_ready blocking: ttys%d, count = %d\n",
 | 
							printk("block_til_ready blocking: ttys%d, count = %d\n",
 | 
				
			||||||
		       info->line, state->count);
 | 
							       info->line, state->count);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
		tty_unlock();
 | 
							tty_unlock(tty);
 | 
				
			||||||
		schedule();
 | 
							schedule();
 | 
				
			||||||
		tty_lock();
 | 
							tty_lock(tty);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	current->state = TASK_RUNNING;
 | 
						current->state = TASK_RUNNING;
 | 
				
			||||||
	remove_wait_queue(&info->open_wait, &wait);
 | 
						remove_wait_queue(&info->open_wait, &wait);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1033,7 +1033,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
 | 
				
			||||||
	if (!retinfo)
 | 
						if (!retinfo)
 | 
				
			||||||
		return -EFAULT;
 | 
							return -EFAULT;
 | 
				
			||||||
	memset(&tmp, 0, sizeof(tmp));
 | 
						memset(&tmp, 0, sizeof(tmp));
 | 
				
			||||||
	tty_lock();
 | 
						tty_lock(tty);
 | 
				
			||||||
	tmp.line = tty->index;
 | 
						tmp.line = tty->index;
 | 
				
			||||||
	tmp.port = state->port;
 | 
						tmp.port = state->port;
 | 
				
			||||||
	tmp.flags = state->tport.flags;
 | 
						tmp.flags = state->tport.flags;
 | 
				
			||||||
| 
						 | 
					@ -1042,7 +1042,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
 | 
				
			||||||
	tmp.close_delay = state->tport.close_delay;
 | 
						tmp.close_delay = state->tport.close_delay;
 | 
				
			||||||
	tmp.closing_wait = state->tport.closing_wait;
 | 
						tmp.closing_wait = state->tport.closing_wait;
 | 
				
			||||||
	tmp.custom_divisor = state->custom_divisor;
 | 
						tmp.custom_divisor = state->custom_divisor;
 | 
				
			||||||
	tty_unlock();
 | 
						tty_unlock(tty);
 | 
				
			||||||
	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
 | 
						if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
 | 
				
			||||||
		return -EFAULT;
 | 
							return -EFAULT;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -1059,12 +1059,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
 | 
				
			||||||
	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
 | 
						if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
 | 
				
			||||||
		return -EFAULT;
 | 
							return -EFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tty_lock();
 | 
						tty_lock(tty);
 | 
				
			||||||
	change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) ||
 | 
						change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) ||
 | 
				
			||||||
		new_serial.custom_divisor != state->custom_divisor;
 | 
							new_serial.custom_divisor != state->custom_divisor;
 | 
				
			||||||
	if (new_serial.irq || new_serial.port != state->port ||
 | 
						if (new_serial.irq || new_serial.port != state->port ||
 | 
				
			||||||
			new_serial.xmit_fifo_size != state->xmit_fifo_size) {
 | 
								new_serial.xmit_fifo_size != state->xmit_fifo_size) {
 | 
				
			||||||
		tty_unlock();
 | 
							tty_unlock(tty);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
| 
						 | 
					@ -1084,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (new_serial.baud_base < 9600) {
 | 
						if (new_serial.baud_base < 9600) {
 | 
				
			||||||
		tty_unlock();
 | 
							tty_unlock(tty);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1116,7 +1116,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
		retval = startup(tty, state);
 | 
							retval = startup(tty, state);
 | 
				
			||||||
	tty_unlock();
 | 
						tty_unlock(tty);
 | 
				
			||||||
	return retval;
 | 
						return retval;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1599,7 +1599,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
 | 
				
			||||||
	 * If the port is the middle of closing, bail out now
 | 
						 * If the port is the middle of closing, bail out now
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
 | 
						if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
 | 
				
			||||||
		wait_event_interruptible_tty(info->port.close_wait,
 | 
							wait_event_interruptible_tty(tty, info->port.close_wait,
 | 
				
			||||||
				!(info->port.flags & ASYNC_CLOSING));
 | 
									!(info->port.flags & ASYNC_CLOSING));
 | 
				
			||||||
		return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
 | 
							return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1065,7 +1065,8 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	TRACE_L("read()");
 | 
						TRACE_L("read()");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tty_lock();
 | 
						/* FIXME: should use a private lock */
 | 
				
			||||||
 | 
						tty_lock(tty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pClient = findClient(pInfo, task_pid(current));
 | 
						pClient = findClient(pInfo, task_pid(current));
 | 
				
			||||||
	if (pClient) {
 | 
						if (pClient) {
 | 
				
			||||||
| 
						 | 
					@ -1077,7 +1078,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
 | 
				
			||||||
				goto unlock;
 | 
									goto unlock;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			/* block until there is a message: */
 | 
								/* block until there is a message: */
 | 
				
			||||||
			wait_event_interruptible_tty(pInfo->read_wait,
 | 
								wait_event_interruptible_tty(tty, pInfo->read_wait,
 | 
				
			||||||
					(pMsg = remove_msg(pInfo, pClient)));
 | 
										(pMsg = remove_msg(pInfo, pClient)));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1107,7 +1108,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ret = -EPERM;
 | 
						ret = -EPERM;
 | 
				
			||||||
unlock:
 | 
					unlock:
 | 
				
			||||||
	tty_unlock();
 | 
						tty_unlock(tty);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1156,7 +1157,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
 | 
				
			||||||
	pHeader->locks = 0;
 | 
						pHeader->locks = 0;
 | 
				
			||||||
	pHeader->owner = NULL;
 | 
						pHeader->owner = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tty_lock();
 | 
						tty_lock(tty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pClient = findClient(pInfo, task_pid(current));
 | 
						pClient = findClient(pInfo, task_pid(current));
 | 
				
			||||||
	if (pClient) {
 | 
						if (pClient) {
 | 
				
			||||||
| 
						 | 
					@ -1175,7 +1176,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
 | 
				
			||||||
	add_tx_queue(pInfo, pHeader);
 | 
						add_tx_queue(pInfo, pHeader);
 | 
				
			||||||
	trigger_transmit(pInfo);
 | 
						trigger_transmit(pInfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tty_unlock();
 | 
						tty_unlock(tty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,6 +47,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
 | 
				
			||||||
	wake_up_interruptible(&tty->read_wait);
 | 
						wake_up_interruptible(&tty->read_wait);
 | 
				
			||||||
	wake_up_interruptible(&tty->write_wait);
 | 
						wake_up_interruptible(&tty->write_wait);
 | 
				
			||||||
	tty->packet = 0;
 | 
						tty->packet = 0;
 | 
				
			||||||
 | 
						/* Review - krefs on tty_link ?? */
 | 
				
			||||||
	if (!tty->link)
 | 
						if (!tty->link)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	tty->link->packet = 0;
 | 
						tty->link->packet = 0;
 | 
				
			||||||
| 
						 | 
					@ -62,9 +63,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
 | 
				
			||||||
		        mutex_unlock(&devpts_mutex);
 | 
							        mutex_unlock(&devpts_mutex);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
		tty_unlock();
 | 
					 | 
				
			||||||
		tty_vhangup(tty->link);
 | 
							tty_vhangup(tty->link);
 | 
				
			||||||
		tty_lock();
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -622,26 +621,29 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 | 
				
			||||||
		return retval;
 | 
							return retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* find a device that is not in use. */
 | 
						/* find a device that is not in use. */
 | 
				
			||||||
	tty_lock();
 | 
						mutex_lock(&devpts_mutex);
 | 
				
			||||||
	index = devpts_new_index(inode);
 | 
						index = devpts_new_index(inode);
 | 
				
			||||||
	tty_unlock();
 | 
					 | 
				
			||||||
	if (index < 0) {
 | 
						if (index < 0) {
 | 
				
			||||||
		retval = index;
 | 
							retval = index;
 | 
				
			||||||
		goto err_file;
 | 
							goto err_file;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_unlock(&devpts_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&tty_mutex);
 | 
						mutex_lock(&tty_mutex);
 | 
				
			||||||
	mutex_lock(&devpts_mutex);
 | 
						mutex_lock(&devpts_mutex);
 | 
				
			||||||
	tty = tty_init_dev(ptm_driver, index);
 | 
						tty = tty_init_dev(ptm_driver, index);
 | 
				
			||||||
	mutex_unlock(&devpts_mutex);
 | 
					 | 
				
			||||||
	tty_lock();
 | 
					 | 
				
			||||||
	mutex_unlock(&tty_mutex);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (IS_ERR(tty)) {
 | 
						if (IS_ERR(tty)) {
 | 
				
			||||||
		retval = PTR_ERR(tty);
 | 
							retval = PTR_ERR(tty);
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* The tty returned here is locked so we can safely
 | 
				
			||||||
 | 
						   drop the mutex */
 | 
				
			||||||
 | 
						mutex_unlock(&devpts_mutex);
 | 
				
			||||||
 | 
						mutex_unlock(&tty_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
 | 
						set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tty_add_file(tty, filp);
 | 
						tty_add_file(tty, filp);
 | 
				
			||||||
| 
						 | 
					@ -654,16 +656,17 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 | 
				
			||||||
	if (retval)
 | 
						if (retval)
 | 
				
			||||||
		goto err_release;
 | 
							goto err_release;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tty_unlock();
 | 
						tty_unlock(tty);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
err_release:
 | 
					err_release:
 | 
				
			||||||
	tty_unlock();
 | 
						tty_unlock(tty);
 | 
				
			||||||
	tty_release(inode, filp);
 | 
						tty_release(inode, filp);
 | 
				
			||||||
	return retval;
 | 
						return retval;
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
 | 
						mutex_unlock(&tty_mutex);
 | 
				
			||||||
	devpts_kill_index(inode, index);
 | 
						devpts_kill_index(inode, index);
 | 
				
			||||||
	tty_unlock();
 | 
					 | 
				
			||||||
err_file:
 | 
					err_file:
 | 
				
			||||||
 | 
					        mutex_unlock(&devpts_mutex);
 | 
				
			||||||
	tty_free_file(filp);
 | 
						tty_free_file(filp);
 | 
				
			||||||
	return retval;
 | 
						return retval;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4052,9 +4052,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
 | 
				
			||||||
		printk("block_til_ready blocking: ttyS%d, count = %d\n",
 | 
							printk("block_til_ready blocking: ttyS%d, count = %d\n",
 | 
				
			||||||
		       info->line, info->count);
 | 
							       info->line, info->count);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
		tty_unlock();
 | 
							tty_unlock(tty);
 | 
				
			||||||
		schedule();
 | 
							schedule();
 | 
				
			||||||
		tty_lock();
 | 
							tty_lock(tty);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	set_current_state(TASK_RUNNING);
 | 
						set_current_state(TASK_RUNNING);
 | 
				
			||||||
	remove_wait_queue(&info->open_wait, &wait);
 | 
						remove_wait_queue(&info->open_wait, &wait);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3338,9 +3338,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
 | 
				
			||||||
			printk("%s(%d):block_til_ready blocking on %s count=%d\n",
 | 
								printk("%s(%d):block_til_ready blocking on %s count=%d\n",
 | 
				
			||||||
				 __FILE__,__LINE__, tty->driver->name, port->count );
 | 
									 __FILE__,__LINE__, tty->driver->name, port->count );
 | 
				
			||||||
				 
 | 
									 
 | 
				
			||||||
		tty_unlock();
 | 
							tty_unlock(tty);
 | 
				
			||||||
		schedule();
 | 
							schedule();
 | 
				
			||||||
		tty_lock();
 | 
							tty_lock(tty);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	set_current_state(TASK_RUNNING);
 | 
						set_current_state(TASK_RUNNING);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3336,9 +3336,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		DBGINFO(("%s block_til_ready wait\n", tty->driver->name));
 | 
							DBGINFO(("%s block_til_ready wait\n", tty->driver->name));
 | 
				
			||||||
		tty_unlock();
 | 
							tty_unlock(tty);
 | 
				
			||||||
		schedule();
 | 
							schedule();
 | 
				
			||||||
		tty_lock();
 | 
							tty_lock(tty);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set_current_state(TASK_RUNNING);
 | 
						set_current_state(TASK_RUNNING);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3357,9 +3357,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
 | 
				
			||||||
			printk("%s(%d):%s block_til_ready() count=%d\n",
 | 
								printk("%s(%d):%s block_til_ready() count=%d\n",
 | 
				
			||||||
				 __FILE__,__LINE__, tty->driver->name, port->count );
 | 
									 __FILE__,__LINE__, tty->driver->name, port->count );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		tty_unlock();
 | 
							tty_unlock(tty);
 | 
				
			||||||
		schedule();
 | 
							schedule();
 | 
				
			||||||
		tty_lock();
 | 
							tty_lock(tty);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set_current_state(TASK_RUNNING);
 | 
						set_current_state(TASK_RUNNING);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -185,6 +185,7 @@ void free_tty_struct(struct tty_struct *tty)
 | 
				
			||||||
		put_device(tty->dev);
 | 
							put_device(tty->dev);
 | 
				
			||||||
	kfree(tty->write_buf);
 | 
						kfree(tty->write_buf);
 | 
				
			||||||
	tty_buffer_free_all(tty);
 | 
						tty_buffer_free_all(tty);
 | 
				
			||||||
 | 
						tty->magic = 0xDEADDEAD;
 | 
				
			||||||
	kfree(tty);
 | 
						kfree(tty);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -573,7 +574,7 @@ void __tty_hangup(struct tty_struct *tty)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	spin_unlock(&redirect_lock);
 | 
						spin_unlock(&redirect_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tty_lock();
 | 
						tty_lock(tty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* some functions below drop BTM, so we need this bit */
 | 
						/* some functions below drop BTM, so we need this bit */
 | 
				
			||||||
	set_bit(TTY_HUPPING, &tty->flags);
 | 
						set_bit(TTY_HUPPING, &tty->flags);
 | 
				
			||||||
| 
						 | 
					@ -666,7 +667,7 @@ void __tty_hangup(struct tty_struct *tty)
 | 
				
			||||||
	clear_bit(TTY_HUPPING, &tty->flags);
 | 
						clear_bit(TTY_HUPPING, &tty->flags);
 | 
				
			||||||
	tty_ldisc_enable(tty);
 | 
						tty_ldisc_enable(tty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tty_unlock();
 | 
						tty_unlock(tty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (f)
 | 
						if (f)
 | 
				
			||||||
		fput(f);
 | 
							fput(f);
 | 
				
			||||||
| 
						 | 
					@ -1103,12 +1104,12 @@ void tty_write_message(struct tty_struct *tty, char *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (tty) {
 | 
						if (tty) {
 | 
				
			||||||
		mutex_lock(&tty->atomic_write_lock);
 | 
							mutex_lock(&tty->atomic_write_lock);
 | 
				
			||||||
		tty_lock();
 | 
							tty_lock(tty);
 | 
				
			||||||
		if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
 | 
							if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
 | 
				
			||||||
			tty_unlock();
 | 
								tty_unlock(tty);
 | 
				
			||||||
			tty->ops->write(tty, msg, strlen(msg));
 | 
								tty->ops->write(tty, msg, strlen(msg));
 | 
				
			||||||
		} else
 | 
							} else
 | 
				
			||||||
			tty_unlock();
 | 
								tty_unlock(tty);
 | 
				
			||||||
		tty_write_unlock(tty);
 | 
							tty_write_unlock(tty);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return;
 | 
						return;
 | 
				
			||||||
| 
						 | 
					@ -1403,6 +1404,7 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	initialize_tty_struct(tty, driver, idx);
 | 
						initialize_tty_struct(tty, driver, idx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tty_lock(tty);
 | 
				
			||||||
	retval = tty_driver_install_tty(driver, tty);
 | 
						retval = tty_driver_install_tty(driver, tty);
 | 
				
			||||||
	if (retval < 0)
 | 
						if (retval < 0)
 | 
				
			||||||
		goto err_deinit_tty;
 | 
							goto err_deinit_tty;
 | 
				
			||||||
| 
						 | 
					@ -1415,9 +1417,11 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
 | 
				
			||||||
	retval = tty_ldisc_setup(tty, tty->link);
 | 
						retval = tty_ldisc_setup(tty, tty->link);
 | 
				
			||||||
	if (retval)
 | 
						if (retval)
 | 
				
			||||||
		goto err_release_tty;
 | 
							goto err_release_tty;
 | 
				
			||||||
 | 
						/* Return the tty locked so that it cannot vanish under the caller */
 | 
				
			||||||
	return tty;
 | 
						return tty;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_deinit_tty:
 | 
					err_deinit_tty:
 | 
				
			||||||
 | 
						tty_unlock(tty);
 | 
				
			||||||
	deinitialize_tty_struct(tty);
 | 
						deinitialize_tty_struct(tty);
 | 
				
			||||||
	free_tty_struct(tty);
 | 
						free_tty_struct(tty);
 | 
				
			||||||
err_module_put:
 | 
					err_module_put:
 | 
				
			||||||
| 
						 | 
					@ -1426,6 +1430,7 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* call the tty release_tty routine to clean out this slot */
 | 
						/* call the tty release_tty routine to clean out this slot */
 | 
				
			||||||
err_release_tty:
 | 
					err_release_tty:
 | 
				
			||||||
 | 
						tty_unlock(tty);
 | 
				
			||||||
	printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, "
 | 
						printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, "
 | 
				
			||||||
				 "clearing slot %d\n", idx);
 | 
									 "clearing slot %d\n", idx);
 | 
				
			||||||
	release_tty(tty, idx);
 | 
						release_tty(tty, idx);
 | 
				
			||||||
| 
						 | 
					@ -1628,7 +1633,7 @@ int tty_release(struct inode *inode, struct file *filp)
 | 
				
			||||||
	if (tty_paranoia_check(tty, inode, __func__))
 | 
						if (tty_paranoia_check(tty, inode, __func__))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tty_lock();
 | 
						tty_lock(tty);
 | 
				
			||||||
	check_tty_count(tty, __func__);
 | 
						check_tty_count(tty, __func__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__tty_fasync(-1, filp, 0);
 | 
						__tty_fasync(-1, filp, 0);
 | 
				
			||||||
| 
						 | 
					@ -1637,10 +1642,11 @@ int tty_release(struct inode *inode, struct file *filp)
 | 
				
			||||||
	pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
 | 
						pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
 | 
				
			||||||
		      tty->driver->subtype == PTY_TYPE_MASTER);
 | 
							      tty->driver->subtype == PTY_TYPE_MASTER);
 | 
				
			||||||
	devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
 | 
						devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
 | 
				
			||||||
 | 
						/* Review: parallel close */
 | 
				
			||||||
	o_tty = tty->link;
 | 
						o_tty = tty->link;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (tty_release_checks(tty, o_tty, idx)) {
 | 
						if (tty_release_checks(tty, o_tty, idx)) {
 | 
				
			||||||
		tty_unlock();
 | 
							tty_unlock(tty);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1652,7 +1658,7 @@ int tty_release(struct inode *inode, struct file *filp)
 | 
				
			||||||
	if (tty->ops->close)
 | 
						if (tty->ops->close)
 | 
				
			||||||
		tty->ops->close(tty, filp);
 | 
							tty->ops->close(tty, filp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tty_unlock();
 | 
						tty_unlock(tty);
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Sanity check: if tty->count is going to zero, there shouldn't be
 | 
						 * Sanity check: if tty->count is going to zero, there shouldn't be
 | 
				
			||||||
	 * any waiters on tty->read_wait or tty->write_wait.  We test the
 | 
						 * any waiters on tty->read_wait or tty->write_wait.  We test the
 | 
				
			||||||
| 
						 | 
					@ -1675,7 +1681,7 @@ int tty_release(struct inode *inode, struct file *filp)
 | 
				
			||||||
		   opens on /dev/tty */
 | 
							   opens on /dev/tty */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mutex_lock(&tty_mutex);
 | 
							mutex_lock(&tty_mutex);
 | 
				
			||||||
		tty_lock();
 | 
							tty_lock_pair(tty, o_tty);
 | 
				
			||||||
		tty_closing = tty->count <= 1;
 | 
							tty_closing = tty->count <= 1;
 | 
				
			||||||
		o_tty_closing = o_tty &&
 | 
							o_tty_closing = o_tty &&
 | 
				
			||||||
			(o_tty->count <= (pty_master ? 1 : 0));
 | 
								(o_tty->count <= (pty_master ? 1 : 0));
 | 
				
			||||||
| 
						 | 
					@ -1706,7 +1712,7 @@ int tty_release(struct inode *inode, struct file *filp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",
 | 
							printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",
 | 
				
			||||||
				__func__, tty_name(tty, buf));
 | 
									__func__, tty_name(tty, buf));
 | 
				
			||||||
		tty_unlock();
 | 
							tty_unlock_pair(tty, o_tty);
 | 
				
			||||||
		mutex_unlock(&tty_mutex);
 | 
							mutex_unlock(&tty_mutex);
 | 
				
			||||||
		schedule();
 | 
							schedule();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1769,7 +1775,7 @@ int tty_release(struct inode *inode, struct file *filp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* check whether both sides are closing ... */
 | 
						/* check whether both sides are closing ... */
 | 
				
			||||||
	if (!tty_closing || (o_tty && !o_tty_closing)) {
 | 
						if (!tty_closing || (o_tty && !o_tty_closing)) {
 | 
				
			||||||
		tty_unlock();
 | 
							tty_unlock_pair(tty, o_tty);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1782,14 +1788,16 @@ int tty_release(struct inode *inode, struct file *filp)
 | 
				
			||||||
	tty_ldisc_release(tty, o_tty);
 | 
						tty_ldisc_release(tty, o_tty);
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The release_tty function takes care of the details of clearing
 | 
						 * The release_tty function takes care of the details of clearing
 | 
				
			||||||
	 * the slots and preserving the termios structure.
 | 
						 * the slots and preserving the termios structure. The tty_unlock_pair
 | 
				
			||||||
 | 
						 * should be safe as we keep a kref while the tty is locked (so the
 | 
				
			||||||
 | 
						 * unlock never unlocks a freed tty).
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	release_tty(tty, idx);
 | 
						release_tty(tty, idx);
 | 
				
			||||||
 | 
						tty_unlock_pair(tty, o_tty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Make this pty number available for reallocation */
 | 
						/* Make this pty number available for reallocation */
 | 
				
			||||||
	if (devpts)
 | 
						if (devpts)
 | 
				
			||||||
		devpts_kill_index(inode, idx);
 | 
							devpts_kill_index(inode, idx);
 | 
				
			||||||
	tty_unlock();
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1893,6 +1901,9 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
 | 
				
			||||||
 *	Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev.
 | 
					 *	Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev.
 | 
				
			||||||
 *		 tty->count should protect the rest.
 | 
					 *		 tty->count should protect the rest.
 | 
				
			||||||
 *		 ->siglock protects ->signal/->sighand
 | 
					 *		 ->siglock protects ->signal/->sighand
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	Note: the tty_unlock/lock cases without a ref are only safe due to
 | 
				
			||||||
 | 
					 *	tty_mutex
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int tty_open(struct inode *inode, struct file *filp)
 | 
					static int tty_open(struct inode *inode, struct file *filp)
 | 
				
			||||||
| 
						 | 
					@ -1916,8 +1927,7 @@ static int tty_open(struct inode *inode, struct file *filp)
 | 
				
			||||||
	retval = 0;
 | 
						retval = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&tty_mutex);
 | 
						mutex_lock(&tty_mutex);
 | 
				
			||||||
	tty_lock();
 | 
						/* This is protected by the tty_mutex */
 | 
				
			||||||
 | 
					 | 
				
			||||||
	tty = tty_open_current_tty(device, filp);
 | 
						tty = tty_open_current_tty(device, filp);
 | 
				
			||||||
	if (IS_ERR(tty)) {
 | 
						if (IS_ERR(tty)) {
 | 
				
			||||||
		retval = PTR_ERR(tty);
 | 
							retval = PTR_ERR(tty);
 | 
				
			||||||
| 
						 | 
					@ -1938,17 +1948,19 @@ static int tty_open(struct inode *inode, struct file *filp)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (tty) {
 | 
						if (tty) {
 | 
				
			||||||
 | 
							tty_lock(tty);
 | 
				
			||||||
		retval = tty_reopen(tty);
 | 
							retval = tty_reopen(tty);
 | 
				
			||||||
		if (retval)
 | 
							if (retval < 0) {
 | 
				
			||||||
 | 
								tty_unlock(tty);
 | 
				
			||||||
			tty = ERR_PTR(retval);
 | 
								tty = ERR_PTR(retval);
 | 
				
			||||||
	} else
 | 
							}
 | 
				
			||||||
 | 
						} else	/* Returns with the tty_lock held for now */
 | 
				
			||||||
		tty = tty_init_dev(driver, index);
 | 
							tty = tty_init_dev(driver, index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_unlock(&tty_mutex);
 | 
						mutex_unlock(&tty_mutex);
 | 
				
			||||||
	if (driver)
 | 
						if (driver)
 | 
				
			||||||
		tty_driver_kref_put(driver);
 | 
							tty_driver_kref_put(driver);
 | 
				
			||||||
	if (IS_ERR(tty)) {
 | 
						if (IS_ERR(tty)) {
 | 
				
			||||||
		tty_unlock();
 | 
					 | 
				
			||||||
		retval = PTR_ERR(tty);
 | 
							retval = PTR_ERR(tty);
 | 
				
			||||||
		goto err_file;
 | 
							goto err_file;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1977,7 +1989,7 @@ static int tty_open(struct inode *inode, struct file *filp)
 | 
				
			||||||
		printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__,
 | 
							printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__,
 | 
				
			||||||
				retval, tty->name);
 | 
									retval, tty->name);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
		tty_unlock(); /* need to call tty_release without BTM */
 | 
							tty_unlock(tty); /* need to call tty_release without BTM */
 | 
				
			||||||
		tty_release(inode, filp);
 | 
							tty_release(inode, filp);
 | 
				
			||||||
		if (retval != -ERESTARTSYS)
 | 
							if (retval != -ERESTARTSYS)
 | 
				
			||||||
			return retval;
 | 
								return retval;
 | 
				
			||||||
| 
						 | 
					@ -1989,17 +2001,15 @@ static int tty_open(struct inode *inode, struct file *filp)
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * Need to reset f_op in case a hangup happened.
 | 
							 * Need to reset f_op in case a hangup happened.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		tty_lock();
 | 
					 | 
				
			||||||
		if (filp->f_op == &hung_up_tty_fops)
 | 
							if (filp->f_op == &hung_up_tty_fops)
 | 
				
			||||||
			filp->f_op = &tty_fops;
 | 
								filp->f_op = &tty_fops;
 | 
				
			||||||
		tty_unlock();
 | 
					 | 
				
			||||||
		goto retry_open;
 | 
							goto retry_open;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tty_unlock();
 | 
						tty_unlock(tty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&tty_mutex);
 | 
						mutex_lock(&tty_mutex);
 | 
				
			||||||
	tty_lock();
 | 
						tty_lock(tty);
 | 
				
			||||||
	spin_lock_irq(¤t->sighand->siglock);
 | 
						spin_lock_irq(¤t->sighand->siglock);
 | 
				
			||||||
	if (!noctty &&
 | 
						if (!noctty &&
 | 
				
			||||||
	    current->signal->leader &&
 | 
						    current->signal->leader &&
 | 
				
			||||||
| 
						 | 
					@ -2007,11 +2017,10 @@ static int tty_open(struct inode *inode, struct file *filp)
 | 
				
			||||||
	    tty->session == NULL)
 | 
						    tty->session == NULL)
 | 
				
			||||||
		__proc_set_tty(current, tty);
 | 
							__proc_set_tty(current, tty);
 | 
				
			||||||
	spin_unlock_irq(¤t->sighand->siglock);
 | 
						spin_unlock_irq(¤t->sighand->siglock);
 | 
				
			||||||
	tty_unlock();
 | 
						tty_unlock(tty);
 | 
				
			||||||
	mutex_unlock(&tty_mutex);
 | 
						mutex_unlock(&tty_mutex);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
err_unlock:
 | 
					err_unlock:
 | 
				
			||||||
	tty_unlock();
 | 
					 | 
				
			||||||
	mutex_unlock(&tty_mutex);
 | 
						mutex_unlock(&tty_mutex);
 | 
				
			||||||
	/* after locks to avoid deadlock */
 | 
						/* after locks to avoid deadlock */
 | 
				
			||||||
	if (!IS_ERR_OR_NULL(driver))
 | 
						if (!IS_ERR_OR_NULL(driver))
 | 
				
			||||||
| 
						 | 
					@ -2094,10 +2103,13 @@ static int __tty_fasync(int fd, struct file *filp, int on)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int tty_fasync(int fd, struct file *filp, int on)
 | 
					static int tty_fasync(int fd, struct file *filp, int on)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct tty_struct *tty = file_tty(filp);
 | 
				
			||||||
	int retval;
 | 
						int retval;
 | 
				
			||||||
	tty_lock();
 | 
					
 | 
				
			||||||
 | 
						tty_lock(tty);
 | 
				
			||||||
	retval = __tty_fasync(fd, filp, on);
 | 
						retval = __tty_fasync(fd, filp, on);
 | 
				
			||||||
	tty_unlock();
 | 
						tty_unlock(tty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return retval;
 | 
						return retval;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2934,6 +2946,7 @@ void initialize_tty_struct(struct tty_struct *tty,
 | 
				
			||||||
	tty->pgrp = NULL;
 | 
						tty->pgrp = NULL;
 | 
				
			||||||
	tty->overrun_time = jiffies;
 | 
						tty->overrun_time = jiffies;
 | 
				
			||||||
	tty_buffer_init(tty);
 | 
						tty_buffer_init(tty);
 | 
				
			||||||
 | 
						mutex_init(&tty->legacy_mutex);
 | 
				
			||||||
	mutex_init(&tty->termios_mutex);
 | 
						mutex_init(&tty->termios_mutex);
 | 
				
			||||||
	mutex_init(&tty->ldisc_mutex);
 | 
						mutex_init(&tty->ldisc_mutex);
 | 
				
			||||||
	init_waitqueue_head(&tty->write_wait);
 | 
						init_waitqueue_head(&tty->write_wait);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -567,7 +567,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 | 
				
			||||||
	if (IS_ERR(new_ldisc))
 | 
						if (IS_ERR(new_ldisc))
 | 
				
			||||||
		return PTR_ERR(new_ldisc);
 | 
							return PTR_ERR(new_ldisc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tty_lock();
 | 
						tty_lock(tty);
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 *	We need to look at the tty locking here for pty/tty pairs
 | 
						 *	We need to look at the tty locking here for pty/tty pairs
 | 
				
			||||||
	 *	when both sides try to change in parallel.
 | 
						 *	when both sides try to change in parallel.
 | 
				
			||||||
| 
						 | 
					@ -581,12 +581,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (tty->ldisc->ops->num == ldisc) {
 | 
						if (tty->ldisc->ops->num == ldisc) {
 | 
				
			||||||
		tty_unlock();
 | 
							tty_unlock(tty);
 | 
				
			||||||
		tty_ldisc_put(new_ldisc);
 | 
							tty_ldisc_put(new_ldisc);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tty_unlock();
 | 
						tty_unlock(tty);
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 *	Problem: What do we do if this blocks ?
 | 
						 *	Problem: What do we do if this blocks ?
 | 
				
			||||||
	 *	We could deadlock here
 | 
						 *	We could deadlock here
 | 
				
			||||||
| 
						 | 
					@ -594,7 +594,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tty_wait_until_sent(tty, 0);
 | 
						tty_wait_until_sent(tty, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tty_lock();
 | 
						tty_lock(tty);
 | 
				
			||||||
	mutex_lock(&tty->ldisc_mutex);
 | 
						mutex_lock(&tty->ldisc_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -604,10 +604,10 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
 | 
						while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
 | 
				
			||||||
		mutex_unlock(&tty->ldisc_mutex);
 | 
							mutex_unlock(&tty->ldisc_mutex);
 | 
				
			||||||
		tty_unlock();
 | 
							tty_unlock(tty);
 | 
				
			||||||
		wait_event(tty_ldisc_wait,
 | 
							wait_event(tty_ldisc_wait,
 | 
				
			||||||
			test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
 | 
								test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
 | 
				
			||||||
		tty_lock();
 | 
							tty_lock(tty);
 | 
				
			||||||
		mutex_lock(&tty->ldisc_mutex);
 | 
							mutex_lock(&tty->ldisc_mutex);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -622,7 +622,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	o_ldisc = tty->ldisc;
 | 
						o_ldisc = tty->ldisc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tty_unlock();
 | 
						tty_unlock(tty);
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 *	Make sure we don't change while someone holds a
 | 
						 *	Make sure we don't change while someone holds a
 | 
				
			||||||
	 *	reference to the line discipline. The TTY_LDISC bit
 | 
						 *	reference to the line discipline. The TTY_LDISC bit
 | 
				
			||||||
| 
						 | 
					@ -649,7 +649,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	retval = tty_ldisc_wait_idle(tty, 5 * HZ);
 | 
						retval = tty_ldisc_wait_idle(tty, 5 * HZ);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tty_lock();
 | 
						tty_lock(tty);
 | 
				
			||||||
	mutex_lock(&tty->ldisc_mutex);
 | 
						mutex_lock(&tty->ldisc_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* handle wait idle failure locked */
 | 
						/* handle wait idle failure locked */
 | 
				
			||||||
| 
						 | 
					@ -664,7 +664,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 | 
				
			||||||
		clear_bit(TTY_LDISC_CHANGING, &tty->flags);
 | 
							clear_bit(TTY_LDISC_CHANGING, &tty->flags);
 | 
				
			||||||
		mutex_unlock(&tty->ldisc_mutex);
 | 
							mutex_unlock(&tty->ldisc_mutex);
 | 
				
			||||||
		tty_ldisc_put(new_ldisc);
 | 
							tty_ldisc_put(new_ldisc);
 | 
				
			||||||
		tty_unlock();
 | 
							tty_unlock(tty);
 | 
				
			||||||
		return -EIO;
 | 
							return -EIO;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -707,7 +707,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 | 
				
			||||||
	if (o_work)
 | 
						if (o_work)
 | 
				
			||||||
		schedule_work(&o_tty->buf.work);
 | 
							schedule_work(&o_tty->buf.work);
 | 
				
			||||||
	mutex_unlock(&tty->ldisc_mutex);
 | 
						mutex_unlock(&tty->ldisc_mutex);
 | 
				
			||||||
	tty_unlock();
 | 
						tty_unlock(tty);
 | 
				
			||||||
	return retval;
 | 
						return retval;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -815,11 +815,11 @@ void tty_ldisc_hangup(struct tty_struct *tty)
 | 
				
			||||||
	 * need to wait for another function taking the BTM
 | 
						 * need to wait for another function taking the BTM
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	clear_bit(TTY_LDISC, &tty->flags);
 | 
						clear_bit(TTY_LDISC, &tty->flags);
 | 
				
			||||||
	tty_unlock();
 | 
						tty_unlock(tty);
 | 
				
			||||||
	cancel_work_sync(&tty->buf.work);
 | 
						cancel_work_sync(&tty->buf.work);
 | 
				
			||||||
	mutex_unlock(&tty->ldisc_mutex);
 | 
						mutex_unlock(&tty->ldisc_mutex);
 | 
				
			||||||
retry:
 | 
					retry:
 | 
				
			||||||
	tty_lock();
 | 
						tty_lock(tty);
 | 
				
			||||||
	mutex_lock(&tty->ldisc_mutex);
 | 
						mutex_lock(&tty->ldisc_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* At this point we have a closed ldisc and we want to
 | 
						/* At this point we have a closed ldisc and we want to
 | 
				
			||||||
| 
						 | 
					@ -830,7 +830,7 @@ void tty_ldisc_hangup(struct tty_struct *tty)
 | 
				
			||||||
		if (atomic_read(&tty->ldisc->users) != 1) {
 | 
							if (atomic_read(&tty->ldisc->users) != 1) {
 | 
				
			||||||
			char cur_n[TASK_COMM_LEN], tty_n[64];
 | 
								char cur_n[TASK_COMM_LEN], tty_n[64];
 | 
				
			||||||
			long timeout = 3 * HZ;
 | 
								long timeout = 3 * HZ;
 | 
				
			||||||
			tty_unlock();
 | 
								tty_unlock(tty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
 | 
								while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
 | 
				
			||||||
				timeout = MAX_SCHEDULE_TIMEOUT;
 | 
									timeout = MAX_SCHEDULE_TIMEOUT;
 | 
				
			||||||
| 
						 | 
					@ -911,10 +911,10 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
 | 
				
			||||||
	 * race with the set_ldisc code path.
 | 
						 * race with the set_ldisc code path.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tty_unlock();
 | 
						tty_unlock(tty);
 | 
				
			||||||
	tty_ldisc_halt(tty);
 | 
						tty_ldisc_halt(tty);
 | 
				
			||||||
	tty_ldisc_flush_works(tty);
 | 
						tty_ldisc_flush_works(tty);
 | 
				
			||||||
	tty_lock();
 | 
						tty_lock(tty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&tty->ldisc_mutex);
 | 
						mutex_lock(&tty->ldisc_mutex);
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,29 +4,59 @@
 | 
				
			||||||
#include <linux/semaphore.h>
 | 
					#include <linux/semaphore.h>
 | 
				
			||||||
#include <linux/sched.h>
 | 
					#include <linux/sched.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/* Legacy tty mutex glue */
 | 
				
			||||||
 * The 'big tty mutex'
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This mutex is taken and released by tty_lock() and tty_unlock(),
 | 
					 | 
				
			||||||
 * replacing the older big kernel lock.
 | 
					 | 
				
			||||||
 * It can no longer be taken recursively, and does not get
 | 
					 | 
				
			||||||
 * released implicitly while sleeping.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Don't use in new code.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static DEFINE_MUTEX(big_tty_mutex);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Getting the big tty mutex.
 | 
					 * Getting the big tty mutex.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void __lockfunc tty_lock(void)
 | 
					
 | 
				
			||||||
 | 
					void __lockfunc tty_lock(struct tty_struct *tty)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	mutex_lock(&big_tty_mutex);
 | 
						if (tty->magic != TTY_MAGIC) {
 | 
				
			||||||
 | 
							printk(KERN_ERR "L Bad %p\n", tty);
 | 
				
			||||||
 | 
							WARN_ON(1);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						tty_kref_get(tty);
 | 
				
			||||||
 | 
						mutex_lock(&tty->legacy_mutex);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(tty_lock);
 | 
					EXPORT_SYMBOL(tty_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void __lockfunc tty_unlock(void)
 | 
					void __lockfunc tty_unlock(struct tty_struct *tty)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	mutex_unlock(&big_tty_mutex);
 | 
						if (tty->magic != TTY_MAGIC) {
 | 
				
			||||||
 | 
							printk(KERN_ERR "U Bad %p\n", tty);
 | 
				
			||||||
 | 
							WARN_ON(1);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mutex_unlock(&tty->legacy_mutex);
 | 
				
			||||||
 | 
						tty_kref_put(tty);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(tty_unlock);
 | 
					EXPORT_SYMBOL(tty_unlock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Getting the big tty mutex for a pair of ttys with lock ordering
 | 
				
			||||||
 | 
					 * On a non pty/tty pair tty2 can be NULL which is just fine.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void __lockfunc tty_lock_pair(struct tty_struct *tty,
 | 
				
			||||||
 | 
										struct tty_struct *tty2)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (tty < tty2) {
 | 
				
			||||||
 | 
							tty_lock(tty);
 | 
				
			||||||
 | 
							tty_lock(tty2);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if (tty2 && tty2 != tty)
 | 
				
			||||||
 | 
								tty_lock(tty2);
 | 
				
			||||||
 | 
							tty_lock(tty);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(tty_lock_pair);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void __lockfunc tty_unlock_pair(struct tty_struct *tty,
 | 
				
			||||||
 | 
											struct tty_struct *tty2)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						tty_unlock(tty);
 | 
				
			||||||
 | 
						if (tty2 && tty2 != tty)
 | 
				
			||||||
 | 
							tty_unlock(tty2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(tty_unlock_pair);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -230,7 +230,7 @@ int tty_port_block_til_ready(struct tty_port *port,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* block if port is in the process of being closed */
 | 
						/* block if port is in the process of being closed */
 | 
				
			||||||
	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
 | 
						if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
 | 
				
			||||||
		wait_event_interruptible_tty(port->close_wait,
 | 
							wait_event_interruptible_tty(tty, port->close_wait,
 | 
				
			||||||
				!(port->flags & ASYNC_CLOSING));
 | 
									!(port->flags & ASYNC_CLOSING));
 | 
				
			||||||
		if (port->flags & ASYNC_HUP_NOTIFY)
 | 
							if (port->flags & ASYNC_HUP_NOTIFY)
 | 
				
			||||||
			return -EAGAIN;
 | 
								return -EAGAIN;
 | 
				
			||||||
| 
						 | 
					@ -296,9 +296,9 @@ int tty_port_block_til_ready(struct tty_port *port,
 | 
				
			||||||
			retval = -ERESTARTSYS;
 | 
								retval = -ERESTARTSYS;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		tty_unlock();
 | 
							tty_unlock(tty);
 | 
				
			||||||
		schedule();
 | 
							schedule();
 | 
				
			||||||
		tty_lock();
 | 
							tty_lock(tty);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	finish_wait(&port->open_wait, &wait);
 | 
						finish_wait(&port->open_wait, &wait);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -268,6 +268,7 @@ struct tty_struct {
 | 
				
			||||||
	struct mutex ldisc_mutex;
 | 
						struct mutex ldisc_mutex;
 | 
				
			||||||
	struct tty_ldisc *ldisc;
 | 
						struct tty_ldisc *ldisc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct mutex legacy_mutex;
 | 
				
			||||||
	struct mutex termios_mutex;
 | 
						struct mutex termios_mutex;
 | 
				
			||||||
	spinlock_t ctrl_lock;
 | 
						spinlock_t ctrl_lock;
 | 
				
			||||||
	/* Termios values are protected by the termios mutex */
 | 
						/* Termios values are protected by the termios mutex */
 | 
				
			||||||
| 
						 | 
					@ -605,8 +606,12 @@ extern long vt_compat_ioctl(struct tty_struct *tty,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* tty_mutex.c */
 | 
					/* tty_mutex.c */
 | 
				
			||||||
/* functions for preparation of BKL removal */
 | 
					/* functions for preparation of BKL removal */
 | 
				
			||||||
extern void __lockfunc tty_lock(void) __acquires(tty_lock);
 | 
					extern void __lockfunc tty_lock(struct tty_struct *tty);
 | 
				
			||||||
extern void __lockfunc tty_unlock(void) __releases(tty_lock);
 | 
					extern void __lockfunc tty_unlock(struct tty_struct *tty);
 | 
				
			||||||
 | 
					extern void __lockfunc tty_lock_pair(struct tty_struct *tty,
 | 
				
			||||||
 | 
									struct tty_struct *tty2);
 | 
				
			||||||
 | 
					extern void __lockfunc tty_unlock_pair(struct tty_struct *tty,
 | 
				
			||||||
 | 
									struct tty_struct *tty2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * this shall be called only from where BTM is held (like close)
 | 
					 * this shall be called only from where BTM is held (like close)
 | 
				
			||||||
| 
						 | 
					@ -621,9 +626,9 @@ extern void __lockfunc tty_unlock(void) __releases(tty_lock);
 | 
				
			||||||
static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
 | 
					static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
 | 
				
			||||||
		long timeout)
 | 
							long timeout)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	tty_unlock(); /* tty->ops->close holds the BTM, drop it while waiting */
 | 
						tty_unlock(tty); /* tty->ops->close holds the BTM, drop it while waiting */
 | 
				
			||||||
	tty_wait_until_sent(tty, timeout);
 | 
						tty_wait_until_sent(tty, timeout);
 | 
				
			||||||
	tty_lock();
 | 
						tty_lock(tty);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -638,16 +643,16 @@ static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Do not use in new code.
 | 
					 * Do not use in new code.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define wait_event_interruptible_tty(wq, condition)			\
 | 
					#define wait_event_interruptible_tty(tty, wq, condition)		\
 | 
				
			||||||
({									\
 | 
					({									\
 | 
				
			||||||
	int __ret = 0;							\
 | 
						int __ret = 0;							\
 | 
				
			||||||
	if (!(condition)) {						\
 | 
						if (!(condition)) {						\
 | 
				
			||||||
		__wait_event_interruptible_tty(wq, condition, __ret);	\
 | 
							__wait_event_interruptible_tty(tty, wq, condition, __ret);	\
 | 
				
			||||||
	}								\
 | 
						}								\
 | 
				
			||||||
	__ret;								\
 | 
						__ret;								\
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define __wait_event_interruptible_tty(wq, condition, ret)		\
 | 
					#define __wait_event_interruptible_tty(tty, wq, condition, ret)		\
 | 
				
			||||||
do {									\
 | 
					do {									\
 | 
				
			||||||
	DEFINE_WAIT(__wait);						\
 | 
						DEFINE_WAIT(__wait);						\
 | 
				
			||||||
									\
 | 
														\
 | 
				
			||||||
| 
						 | 
					@ -656,9 +661,9 @@ do {									\
 | 
				
			||||||
		if (condition)						\
 | 
							if (condition)						\
 | 
				
			||||||
			break;						\
 | 
								break;						\
 | 
				
			||||||
		if (!signal_pending(current)) {				\
 | 
							if (!signal_pending(current)) {				\
 | 
				
			||||||
			tty_unlock();					\
 | 
								tty_unlock(tty);					\
 | 
				
			||||||
			schedule();					\
 | 
								schedule();					\
 | 
				
			||||||
			tty_lock();					\
 | 
								tty_lock(tty);					\
 | 
				
			||||||
			continue;					\
 | 
								continue;					\
 | 
				
			||||||
		}							\
 | 
							}							\
 | 
				
			||||||
		ret = -ERESTARTSYS;					\
 | 
							ret = -ERESTARTSYS;					\
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -710,9 +710,9 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		tty_unlock();
 | 
							tty_unlock(tty);
 | 
				
			||||||
		schedule();
 | 
							schedule();
 | 
				
			||||||
		tty_lock();
 | 
							tty_lock(tty);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	set_current_state(TASK_RUNNING);
 | 
						set_current_state(TASK_RUNNING);
 | 
				
			||||||
	remove_wait_queue(&dev->wait, &wait);
 | 
						remove_wait_queue(&dev->wait, &wait);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue