Commit ba5bb147 authored by Al Viro's avatar Al Viro

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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 18c03cfd
...@@ -718,23 +718,30 @@ pipe_poll(struct file *filp, poll_table *wait) ...@@ -718,23 +718,30 @@ pipe_poll(struct file *filp, poll_table *wait)
static int static int
pipe_release(struct inode *inode, struct file *file) 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_lock(pipe);
pipe = inode->i_pipe;
if (file->f_mode & FMODE_READ) if (file->f_mode & FMODE_READ)
pipe->readers--; pipe->readers--;
if (file->f_mode & FMODE_WRITE) if (file->f_mode & FMODE_WRITE)
pipe->writers--; pipe->writers--;
if (!pipe->readers && !pipe->writers) { if (pipe->readers || pipe->writers) {
free_pipe_info(inode);
} else {
wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM | POLLERR | POLLHUP); 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_readers, SIGIO, POLL_IN);
kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); 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; return 0;
} }
...@@ -827,8 +834,9 @@ static struct inode * get_pipe_inode(void) ...@@ -827,8 +834,9 @@ static struct inode * get_pipe_inode(void)
pipe = alloc_pipe_info(inode); pipe = alloc_pipe_info(inode);
if (!pipe) if (!pipe)
goto fail_iput; goto fail_iput;
inode->i_pipe = pipe;
inode->i_pipe = pipe;
pipe->files = 2;
pipe->readers = pipe->writers = 1; pipe->readers = pipe->writers = 1;
inode->i_fop = &pipefifo_fops; inode->i_fop = &pipefifo_fops;
...@@ -999,18 +1007,36 @@ static int fifo_open(struct inode *inode, struct file *filp) ...@@ -999,18 +1007,36 @@ static int fifo_open(struct inode *inode, struct file *filp)
{ {
struct pipe_inode_info *pipe; struct pipe_inode_info *pipe;
bool is_pipe = inode->i_sb->s_magic == PIPEFS_MAGIC; bool is_pipe = inode->i_sb->s_magic == PIPEFS_MAGIC;
int kill = 0;
int ret; int ret;
mutex_lock(&inode->i_mutex); filp->f_version = 0;
pipe = inode->i_pipe;
if (!pipe) { spin_lock(&inode->i_lock);
ret = -ENOMEM; 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); pipe = alloc_pipe_info(inode);
if (!pipe) if (!pipe)
goto err_nocleanup; return -ENOMEM;
inode->i_pipe = pipe; 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 */ /* We can only do regular read/write on fifos */
filp->f_mode &= (FMODE_READ | FMODE_WRITE); filp->f_mode &= (FMODE_READ | FMODE_WRITE);
...@@ -1080,7 +1106,7 @@ static int fifo_open(struct inode *inode, struct file *filp) ...@@ -1080,7 +1106,7 @@ static int fifo_open(struct inode *inode, struct file *filp)
} }
/* Ok! */ /* Ok! */
mutex_unlock(&inode->i_mutex); pipe_unlock(pipe);
return 0; return 0;
err_rd: err_rd:
...@@ -1096,11 +1122,15 @@ static int fifo_open(struct inode *inode, struct file *filp) ...@@ -1096,11 +1122,15 @@ static int fifo_open(struct inode *inode, struct file *filp)
goto err; goto err;
err: err:
if (!pipe->readers && !pipe->writers) spin_lock(&inode->i_lock);
free_pipe_info(inode); if (!--pipe->files) {
inode->i_pipe = NULL;
err_nocleanup: kill = 1;
mutex_unlock(&inode->i_mutex); }
spin_unlock(&inode->i_lock);
pipe_unlock(pipe);
if (kill)
__free_pipe_info(pipe);
return ret; return ret;
} }
......
...@@ -34,6 +34,7 @@ struct pipe_buffer { ...@@ -34,6 +34,7 @@ struct pipe_buffer {
* @tmp_page: cached released page * @tmp_page: cached released page
* @readers: number of current readers of this pipe * @readers: number of current readers of this pipe
* @writers: number of current writers 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 * @waiting_writers: number of writers blocked waiting for room
* @r_counter: reader counter * @r_counter: reader counter
* @w_counter: writer counter * @w_counter: writer counter
...@@ -47,6 +48,7 @@ struct pipe_inode_info { ...@@ -47,6 +48,7 @@ struct pipe_inode_info {
unsigned int nrbufs, curbuf, buffers; unsigned int nrbufs, curbuf, buffers;
unsigned int readers; unsigned int readers;
unsigned int writers; unsigned int writers;
unsigned int files;
unsigned int waiting_writers; unsigned int waiting_writers;
unsigned int r_counter; unsigned int r_counter;
unsigned int w_counter; unsigned int w_counter;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment