Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

Al Viro dd20908a 44ba8406

+9 -21
+2 -2
fs/file_table.c
··· 209 209 struct dentry *dentry = file->f_path.dentry; 210 210 struct inode *inode = dentry->d_inode; 211 211 212 - put_write_access(inode); 213 - 214 212 if (special_file(inode->i_mode)) 215 213 return; 214 + 215 + put_write_access(inode); 216 216 if (file_check_writeable(file) != 0) 217 217 return; 218 218 __mnt_drop_write(mnt);
+7 -19
fs/open.c
··· 641 641 static inline int __get_file_write_access(struct inode *inode, 642 642 struct vfsmount *mnt) 643 643 { 644 - int error; 645 - error = get_write_access(inode); 644 + int error = get_write_access(inode); 646 645 if (error) 647 646 return error; 648 - /* 649 - * Do not take mount writer counts on 650 - * special files since no writes to 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 - } 647 + error = __mnt_want_write(mnt); 648 + if (error) 649 + put_write_access(inode); 661 650 return error; 662 651 } 663 652 ··· 679 690 680 691 path_get(&f->f_path); 681 692 inode = f->f_inode = f->f_path.dentry->d_inode; 682 - if (f->f_mode & FMODE_WRITE) { 693 + if (f->f_mode & FMODE_WRITE && !special_file(inode->i_mode)) { 683 694 error = __get_file_write_access(inode, f->f_path.mnt); 684 695 if (error) 685 696 goto cleanup_file; 686 - if (!special_file(inode->i_mode)) 687 - file_take_write(f); 697 + file_take_write(f); 688 698 } 689 699 690 700 f->f_mapping = inode->i_mapping; ··· 730 742 cleanup_all: 731 743 fops_put(f->f_op); 732 744 if (f->f_mode & FMODE_WRITE) { 733 - put_write_access(inode); 734 745 if (!special_file(inode->i_mode)) { 735 746 /* 736 747 * We don't consider this a real ··· 737 750 * because it all happenend right 738 751 * here, so just reset the state. 739 752 */ 753 + put_write_access(inode); 740 754 file_reset_write(f); 741 755 __mnt_drop_write(f->f_path.mnt); 742 756 }