diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-03-14 10:56:20 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-04-01 23:19:11 -0400 |
commit | dd20908a8a06b22c171f6c3fcdbdbd65bed07505 (patch) | |
tree | 447e2df881b2f056608098d3b24ab6d9734ce992 /fs/open.c | |
parent | 44ba8406d0005400e56c6b6a279a669eb761d1b8 (diff) |
don't bother with {get,put}_write_access() on non-regular files
it's pointless and actually leads to wrong behaviour in at least one
moderately convoluted case (pipe(), close one end, try to get to
another via /proc/*/fd and run into ETXTBUSY).
Cc: stable@vger.kernel.org
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/open.c')
-rw-r--r-- | fs/open.c | 26 |
1 files changed, 7 insertions, 19 deletions
@@ -641,23 +641,12 @@ out: | |||
641 | static inline int __get_file_write_access(struct inode *inode, | 641 | static inline int __get_file_write_access(struct inode *inode, |
642 | struct vfsmount *mnt) | 642 | struct vfsmount *mnt) |
643 | { | 643 | { |
644 | int error; | 644 | int error = get_write_access(inode); |
645 | error = get_write_access(inode); | ||
646 | if (error) | 645 | if (error) |
647 | return error; | 646 | return error; |
648 | /* | 647 | error = __mnt_want_write(mnt); |
649 | * Do not take mount writer counts on | 648 | if (error) |
650 | * special files since no writes to | 649 | put_write_access(inode); |
651 | * the mount itself will occur. | ||
652 | */ | ||
653 | if (!special_file(inode->i_mode)) { | ||
654 | /* | ||
655 | * Balanced in __fput() | ||
656 | */ | ||
657 | error = __mnt_want_write(mnt); | ||
658 | if (error) | ||
659 | put_write_access(inode); | ||
660 | } | ||
661 | return error; | 650 | return error; |
662 | } | 651 | } |
663 | 652 | ||
@@ -690,12 +679,11 @@ static int do_dentry_open(struct file *f, | |||
690 | 679 | ||
691 | path_get(&f->f_path); | 680 | path_get(&f->f_path); |
692 | inode = f->f_inode = f->f_path.dentry->d_inode; | 681 | inode = f->f_inode = f->f_path.dentry->d_inode; |
693 | if (f->f_mode & FMODE_WRITE) { | 682 | if (f->f_mode & FMODE_WRITE && !special_file(inode->i_mode)) { |
694 | error = __get_file_write_access(inode, f->f_path.mnt); | 683 | error = __get_file_write_access(inode, f->f_path.mnt); |
695 | if (error) | 684 | if (error) |
696 | goto cleanup_file; | 685 | goto cleanup_file; |
697 | if (!special_file(inode->i_mode)) | 686 | file_take_write(f); |
698 | file_take_write(f); | ||
699 | } | 687 | } |
700 | 688 | ||
701 | f->f_mapping = inode->i_mapping; | 689 | f->f_mapping = inode->i_mapping; |
@@ -742,7 +730,6 @@ static int do_dentry_open(struct file *f, | |||
742 | cleanup_all: | 730 | cleanup_all: |
743 | fops_put(f->f_op); | 731 | fops_put(f->f_op); |
744 | if (f->f_mode & FMODE_WRITE) { | 732 | if (f->f_mode & FMODE_WRITE) { |
745 | put_write_access(inode); | ||
746 | if (!special_file(inode->i_mode)) { | 733 | if (!special_file(inode->i_mode)) { |
747 | /* | 734 | /* |
748 | * We don't consider this a real | 735 | * We don't consider this a real |
@@ -750,6 +737,7 @@ cleanup_all: | |||
750 | * because it all happenend right | 737 | * because it all happenend right |
751 | * here, so just reset the state. | 738 | * here, so just reset the state. |
752 | */ | 739 | */ |
740 | put_write_access(inode); | ||
753 | file_reset_write(f); | 741 | file_reset_write(f); |
754 | __mnt_drop_write(f->f_path.mnt); | 742 | __mnt_drop_write(f->f_path.mnt); |
755 | } | 743 | } |