mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	pipe: take allocation and freeing of pipe_inode_info out of ->i_mutex
* new field - pipe->files; number of struct file over that pipe (all sharing the same inode, of course); protected by inode->i_lock. * pipe_release() decrements pipe->files, clears inode->i_pipe when if the counter has reached 0 (all under ->i_lock) and, in that case, frees pipe after having done pipe_unlock() * fifo_open() starts with grabbing ->i_lock, and either bumps pipe->files if ->i_pipe was non-NULL or allocates a new pipe (dropping and regaining ->i_lock) and rechecks ->i_pipe; if it's still NULL, inserts new pipe there, otherwise bumps ->i_pipe->files and frees the one we'd allocated. At that point we know that ->i_pipe is non-NULL and won't go away, so we can do pipe_lock() on it and proceed as we used to. If we end up failing, decrement pipe->files and if it reaches 0 clear ->i_pipe and free the sucker after pipe_unlock(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									18c03cfd40
								
							
						
					
					
						commit
						ba5bb14733
					
				
					 2 changed files with 53 additions and 21 deletions
				
			
		
							
								
								
									
										72
									
								
								fs/pipe.c
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								fs/pipe.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -718,23 +718,30 @@ pipe_poll(struct file *filp, poll_table *wait)
 | 
			
		|||
static int
 | 
			
		||||
pipe_release(struct inode *inode, struct file *file)
 | 
			
		||||
{
 | 
			
		||||
	struct pipe_inode_info *pipe;
 | 
			
		||||
	struct pipe_inode_info *pipe = inode->i_pipe;
 | 
			
		||||
	int kill = 0;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&inode->i_mutex);
 | 
			
		||||
	pipe = inode->i_pipe;
 | 
			
		||||
	pipe_lock(pipe);
 | 
			
		||||
	if (file->f_mode & FMODE_READ)
 | 
			
		||||
		pipe->readers--;
 | 
			
		||||
	if (file->f_mode & FMODE_WRITE)
 | 
			
		||||
		pipe->writers--;
 | 
			
		||||
 | 
			
		||||
	if (!pipe->readers && !pipe->writers) {
 | 
			
		||||
		free_pipe_info(inode);
 | 
			
		||||
	} else {
 | 
			
		||||
	if (pipe->readers || pipe->writers) {
 | 
			
		||||
		wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM | POLLERR | POLLHUP);
 | 
			
		||||
		kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
 | 
			
		||||
		kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
 | 
			
		||||
	}
 | 
			
		||||
	mutex_unlock(&inode->i_mutex);
 | 
			
		||||
	spin_lock(&inode->i_lock);
 | 
			
		||||
	if (!--pipe->files) {
 | 
			
		||||
		inode->i_pipe = NULL;
 | 
			
		||||
		kill = 1;
 | 
			
		||||
	}
 | 
			
		||||
	spin_unlock(&inode->i_lock);
 | 
			
		||||
	pipe_unlock(pipe);
 | 
			
		||||
 | 
			
		||||
	if (kill)
 | 
			
		||||
		__free_pipe_info(pipe);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -827,8 +834,9 @@ static struct inode * get_pipe_inode(void)
 | 
			
		|||
	pipe = alloc_pipe_info(inode);
 | 
			
		||||
	if (!pipe)
 | 
			
		||||
		goto fail_iput;
 | 
			
		||||
	inode->i_pipe = pipe;
 | 
			
		||||
 | 
			
		||||
	inode->i_pipe = pipe;
 | 
			
		||||
	pipe->files = 2;
 | 
			
		||||
	pipe->readers = pipe->writers = 1;
 | 
			
		||||
	inode->i_fop = &pipefifo_fops;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -999,18 +1007,36 @@ static int fifo_open(struct inode *inode, struct file *filp)
 | 
			
		|||
{
 | 
			
		||||
	struct pipe_inode_info *pipe;
 | 
			
		||||
	bool is_pipe = inode->i_sb->s_magic == PIPEFS_MAGIC;
 | 
			
		||||
	int kill = 0;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&inode->i_mutex);
 | 
			
		||||
	pipe = inode->i_pipe;
 | 
			
		||||
	if (!pipe) {
 | 
			
		||||
		ret = -ENOMEM;
 | 
			
		||||
	filp->f_version = 0;
 | 
			
		||||
 | 
			
		||||
	spin_lock(&inode->i_lock);
 | 
			
		||||
	if (inode->i_pipe) {
 | 
			
		||||
		pipe = inode->i_pipe;
 | 
			
		||||
		pipe->files++;
 | 
			
		||||
		spin_unlock(&inode->i_lock);
 | 
			
		||||
	} else {
 | 
			
		||||
		spin_unlock(&inode->i_lock);
 | 
			
		||||
		pipe = alloc_pipe_info(inode);
 | 
			
		||||
		if (!pipe)
 | 
			
		||||
			goto err_nocleanup;
 | 
			
		||||
		inode->i_pipe = pipe;
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
		pipe->files = 1;
 | 
			
		||||
		spin_lock(&inode->i_lock);
 | 
			
		||||
		if (unlikely(inode->i_pipe)) {
 | 
			
		||||
			inode->i_pipe->files++;
 | 
			
		||||
			spin_unlock(&inode->i_lock);
 | 
			
		||||
			__free_pipe_info(pipe);
 | 
			
		||||
			pipe = inode->i_pipe;
 | 
			
		||||
		} else {
 | 
			
		||||
			inode->i_pipe = pipe;
 | 
			
		||||
			spin_unlock(&inode->i_lock);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	filp->f_version = 0;
 | 
			
		||||
	/* OK, we have a pipe and it's pinned down */
 | 
			
		||||
 | 
			
		||||
	pipe_lock(pipe);
 | 
			
		||||
 | 
			
		||||
	/* We can only do regular read/write on fifos */
 | 
			
		||||
	filp->f_mode &= (FMODE_READ | FMODE_WRITE);
 | 
			
		||||
| 
						 | 
				
			
			@ -1080,7 +1106,7 @@ static int fifo_open(struct inode *inode, struct file *filp)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	/* Ok! */
 | 
			
		||||
	mutex_unlock(&inode->i_mutex);
 | 
			
		||||
	pipe_unlock(pipe);
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_rd:
 | 
			
		||||
| 
						 | 
				
			
			@ -1096,11 +1122,15 @@ static int fifo_open(struct inode *inode, struct file *filp)
 | 
			
		|||
	goto err;
 | 
			
		||||
 | 
			
		||||
err:
 | 
			
		||||
	if (!pipe->readers && !pipe->writers)
 | 
			
		||||
		free_pipe_info(inode);
 | 
			
		||||
 | 
			
		||||
err_nocleanup:
 | 
			
		||||
	mutex_unlock(&inode->i_mutex);
 | 
			
		||||
	spin_lock(&inode->i_lock);
 | 
			
		||||
	if (!--pipe->files) {
 | 
			
		||||
		inode->i_pipe = NULL;
 | 
			
		||||
		kill = 1;
 | 
			
		||||
	}
 | 
			
		||||
	spin_unlock(&inode->i_lock);
 | 
			
		||||
	pipe_unlock(pipe);
 | 
			
		||||
	if (kill)
 | 
			
		||||
		__free_pipe_info(pipe);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,7 @@ struct pipe_buffer {
 | 
			
		|||
 *	@tmp_page: cached released page
 | 
			
		||||
 *	@readers: number of current readers of this pipe
 | 
			
		||||
 *	@writers: number of current writers of this pipe
 | 
			
		||||
 *	@files: number of struct file refering this pipe (protected by ->i_lock)
 | 
			
		||||
 *	@waiting_writers: number of writers blocked waiting for room
 | 
			
		||||
 *	@r_counter: reader counter
 | 
			
		||||
 *	@w_counter: writer counter
 | 
			
		||||
| 
						 | 
				
			
			@ -47,6 +48,7 @@ struct pipe_inode_info {
 | 
			
		|||
	unsigned int nrbufs, curbuf, buffers;
 | 
			
		||||
	unsigned int readers;
 | 
			
		||||
	unsigned int writers;
 | 
			
		||||
	unsigned int files;
 | 
			
		||||
	unsigned int waiting_writers;
 | 
			
		||||
	unsigned int r_counter;
 | 
			
		||||
	unsigned int w_counter;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue