aboutsummaryrefslogtreecommitdiffstats
path: root/fs/pipe.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2013-03-21 02:21:19 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2013-04-09 14:12:59 -0400
commitba5bb147330a8737b6b5a812cc774c79c070704b (patch)
tree3043bd880634f47275a2083c53ed98ce2c1c70bc /fs/pipe.c
parent18c03cfd403b88852f75f200206983ee6df28423 (diff)
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>
Diffstat (limited to 'fs/pipe.c')
-rw-r--r--fs/pipe.c72
1 files changed, 51 insertions, 21 deletions
diff --git a/fs/pipe.c b/fs/pipe.c
index 357471db890d..abaa9234d27b 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -718,23 +718,30 @@ pipe_poll(struct file *filp, poll_table *wait)
718static int 718static int
719pipe_release(struct inode *inode, struct file *file) 719pipe_release(struct inode *inode, struct file *file)
720{ 720{
721 struct pipe_inode_info *pipe; 721 struct pipe_inode_info *pipe = inode->i_pipe;
722 int kill = 0;
722 723
723 mutex_lock(&inode->i_mutex); 724 pipe_lock(pipe);
724 pipe = inode->i_pipe;
725 if (file->f_mode & FMODE_READ) 725 if (file->f_mode & FMODE_READ)
726 pipe->readers--; 726 pipe->readers--;
727 if (file->f_mode & FMODE_WRITE) 727 if (file->f_mode & FMODE_WRITE)
728 pipe->writers--; 728 pipe->writers--;
729 729
730 if (!pipe->readers && !pipe->writers) { 730 if (pipe->readers || pipe->writers) {
731 free_pipe_info(inode);
732 } else {
733 wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM | POLLERR | POLLHUP); 731 wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM | POLLERR | POLLHUP);
734 kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); 732 kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
735 kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); 733 kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
736 } 734 }
737 mutex_unlock(&inode->i_mutex); 735 spin_lock(&inode->i_lock);
736 if (!--pipe->files) {
737 inode->i_pipe = NULL;
738 kill = 1;
739 }
740 spin_unlock(&inode->i_lock);
741 pipe_unlock(pipe);
742
743 if (kill)
744 __free_pipe_info(pipe);
738 745
739 return 0; 746 return 0;
740} 747}
@@ -827,8 +834,9 @@ static struct inode * get_pipe_inode(void)
827 pipe = alloc_pipe_info(inode); 834 pipe = alloc_pipe_info(inode);
828 if (!pipe) 835 if (!pipe)
829 goto fail_iput; 836 goto fail_iput;
830 inode->i_pipe = pipe;
831 837
838 inode->i_pipe = pipe;
839 pipe->files = 2;
832 pipe->readers = pipe->writers = 1; 840 pipe->readers = pipe->writers = 1;
833 inode->i_fop = &pipefifo_fops; 841 inode->i_fop = &pipefifo_fops;
834 842
@@ -999,18 +1007,36 @@ static int fifo_open(struct inode *inode, struct file *filp)
999{ 1007{
1000 struct pipe_inode_info *pipe; 1008 struct pipe_inode_info *pipe;
1001 bool is_pipe = inode->i_sb->s_magic == PIPEFS_MAGIC; 1009 bool is_pipe = inode->i_sb->s_magic == PIPEFS_MAGIC;
1010 int kill = 0;
1002 int ret; 1011 int ret;
1003 1012
1004 mutex_lock(&inode->i_mutex); 1013 filp->f_version = 0;
1005 pipe = inode->i_pipe; 1014
1006 if (!pipe) { 1015 spin_lock(&inode->i_lock);
1007 ret = -ENOMEM; 1016 if (inode->i_pipe) {
1017 pipe = inode->i_pipe;
1018 pipe->files++;
1019 spin_unlock(&inode->i_lock);
1020 } else {
1021 spin_unlock(&inode->i_lock);
1008 pipe = alloc_pipe_info(inode); 1022 pipe = alloc_pipe_info(inode);
1009 if (!pipe) 1023 if (!pipe)
1010 goto err_nocleanup; 1024 return -ENOMEM;
1011 inode->i_pipe = pipe; 1025 pipe->files = 1;
1026 spin_lock(&inode->i_lock);
1027 if (unlikely(inode->i_pipe)) {
1028 inode->i_pipe->files++;
1029 spin_unlock(&inode->i_lock);
1030 __free_pipe_info(pipe);
1031 pipe = inode->i_pipe;
1032 } else {
1033 inode->i_pipe = pipe;
1034 spin_unlock(&inode->i_lock);
1035 }
1012 } 1036 }
1013 filp->f_version = 0; 1037 /* OK, we have a pipe and it's pinned down */
1038
1039 pipe_lock(pipe);
1014 1040
1015 /* We can only do regular read/write on fifos */ 1041 /* We can only do regular read/write on fifos */
1016 filp->f_mode &= (FMODE_READ | FMODE_WRITE); 1042 filp->f_mode &= (FMODE_READ | FMODE_WRITE);
@@ -1080,7 +1106,7 @@ static int fifo_open(struct inode *inode, struct file *filp)
1080 } 1106 }
1081 1107
1082 /* Ok! */ 1108 /* Ok! */
1083 mutex_unlock(&inode->i_mutex); 1109 pipe_unlock(pipe);
1084 return 0; 1110 return 0;
1085 1111
1086err_rd: 1112err_rd:
@@ -1096,11 +1122,15 @@ err_wr:
1096 goto err; 1122 goto err;
1097 1123
1098err: 1124err:
1099 if (!pipe->readers && !pipe->writers) 1125 spin_lock(&inode->i_lock);
1100 free_pipe_info(inode); 1126 if (!--pipe->files) {
1101 1127 inode->i_pipe = NULL;
1102err_nocleanup: 1128 kill = 1;
1103 mutex_unlock(&inode->i_mutex); 1129 }
1130 spin_unlock(&inode->i_lock);
1131 pipe_unlock(pipe);
1132 if (kill)
1133 __free_pipe_info(pipe);
1104 return ret; 1134 return ret;
1105} 1135}
1106 1136