diff options
-rw-r--r-- | fs/pipe.c | 72 | ||||
-rw-r--r-- | include/linux/pipe_fs_i.h | 2 |
2 files changed, 53 insertions, 21 deletions
@@ -718,23 +718,30 @@ pipe_poll(struct file *filp, poll_table *wait) | |||
718 | static int | 718 | static int |
719 | pipe_release(struct inode *inode, struct file *file) | 719 | pipe_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 | ||
1086 | err_rd: | 1112 | err_rd: |
@@ -1096,11 +1122,15 @@ err_wr: | |||
1096 | goto err; | 1122 | goto err; |
1097 | 1123 | ||
1098 | err: | 1124 | err: |
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; | |
1102 | err_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 | ||
diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index ad1a427b5267..59778e1c9c08 100644 --- a/include/linux/pipe_fs_i.h +++ b/include/linux/pipe_fs_i.h | |||
@@ -34,6 +34,7 @@ struct pipe_buffer { | |||
34 | * @tmp_page: cached released page | 34 | * @tmp_page: cached released page |
35 | * @readers: number of current readers of this pipe | 35 | * @readers: number of current readers of this pipe |
36 | * @writers: number of current writers of this pipe | 36 | * @writers: number of current writers of this pipe |
37 | * @files: number of struct file refering this pipe (protected by ->i_lock) | ||
37 | * @waiting_writers: number of writers blocked waiting for room | 38 | * @waiting_writers: number of writers blocked waiting for room |
38 | * @r_counter: reader counter | 39 | * @r_counter: reader counter |
39 | * @w_counter: writer counter | 40 | * @w_counter: writer counter |
@@ -47,6 +48,7 @@ struct pipe_inode_info { | |||
47 | unsigned int nrbufs, curbuf, buffers; | 48 | unsigned int nrbufs, curbuf, buffers; |
48 | unsigned int readers; | 49 | unsigned int readers; |
49 | unsigned int writers; | 50 | unsigned int writers; |
51 | unsigned int files; | ||
50 | unsigned int waiting_writers; | 52 | unsigned int waiting_writers; |
51 | unsigned int r_counter; | 53 | unsigned int r_counter; |
52 | unsigned int w_counter; | 54 | unsigned int w_counter; |