diff options
Diffstat (limited to 'fs/open.c')
-rw-r--r-- | fs/open.c | 68 |
1 files changed, 16 insertions, 52 deletions
@@ -655,35 +655,6 @@ out: | |||
655 | return error; | 655 | return error; |
656 | } | 656 | } |
657 | 657 | ||
658 | /* | ||
659 | * You have to be very careful that these write | ||
660 | * counts get cleaned up in error cases and | ||
661 | * upon __fput(). This should probably never | ||
662 | * be called outside of __dentry_open(). | ||
663 | */ | ||
664 | static inline int __get_file_write_access(struct inode *inode, | ||
665 | struct vfsmount *mnt) | ||
666 | { | ||
667 | int error; | ||
668 | error = get_write_access(inode); | ||
669 | if (error) | ||
670 | return error; | ||
671 | /* | ||
672 | * Do not take mount writer counts on | ||
673 | * special files since no writes to | ||
674 | * the mount itself will occur. | ||
675 | */ | ||
676 | if (!special_file(inode->i_mode)) { | ||
677 | /* | ||
678 | * Balanced in __fput() | ||
679 | */ | ||
680 | error = __mnt_want_write(mnt); | ||
681 | if (error) | ||
682 | put_write_access(inode); | ||
683 | } | ||
684 | return error; | ||
685 | } | ||
686 | |||
687 | int open_check_o_direct(struct file *f) | 658 | int open_check_o_direct(struct file *f) |
688 | { | 659 | { |
689 | /* NB: we're sure to have correct a_ops only after f_op->open */ | 660 | /* NB: we're sure to have correct a_ops only after f_op->open */ |
@@ -708,26 +679,28 @@ static int do_dentry_open(struct file *f, | |||
708 | f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | | 679 | f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | |
709 | FMODE_PREAD | FMODE_PWRITE; | 680 | FMODE_PREAD | FMODE_PWRITE; |
710 | 681 | ||
711 | if (unlikely(f->f_flags & O_PATH)) | ||
712 | f->f_mode = FMODE_PATH; | ||
713 | |||
714 | path_get(&f->f_path); | 682 | path_get(&f->f_path); |
715 | inode = f->f_inode = f->f_path.dentry->d_inode; | 683 | inode = f->f_inode = f->f_path.dentry->d_inode; |
716 | if (f->f_mode & FMODE_WRITE) { | ||
717 | error = __get_file_write_access(inode, f->f_path.mnt); | ||
718 | if (error) | ||
719 | goto cleanup_file; | ||
720 | if (!special_file(inode->i_mode)) | ||
721 | file_take_write(f); | ||
722 | } | ||
723 | |||
724 | f->f_mapping = inode->i_mapping; | 684 | f->f_mapping = inode->i_mapping; |
725 | 685 | ||
726 | if (unlikely(f->f_mode & FMODE_PATH)) { | 686 | if (unlikely(f->f_flags & O_PATH)) { |
687 | f->f_mode = FMODE_PATH; | ||
727 | f->f_op = &empty_fops; | 688 | f->f_op = &empty_fops; |
728 | return 0; | 689 | return 0; |
729 | } | 690 | } |
730 | 691 | ||
692 | if (f->f_mode & FMODE_WRITE && !special_file(inode->i_mode)) { | ||
693 | error = get_write_access(inode); | ||
694 | if (unlikely(error)) | ||
695 | goto cleanup_file; | ||
696 | error = __mnt_want_write(f->f_path.mnt); | ||
697 | if (unlikely(error)) { | ||
698 | put_write_access(inode); | ||
699 | goto cleanup_file; | ||
700 | } | ||
701 | f->f_mode |= FMODE_WRITER; | ||
702 | } | ||
703 | |||
731 | /* POSIX.1-2008/SUSv4 Section XSI 2.9.7 */ | 704 | /* POSIX.1-2008/SUSv4 Section XSI 2.9.7 */ |
732 | if (S_ISREG(inode->i_mode)) | 705 | if (S_ISREG(inode->i_mode)) |
733 | f->f_mode |= FMODE_ATOMIC_POS; | 706 | f->f_mode |= FMODE_ATOMIC_POS; |
@@ -764,18 +737,9 @@ static int do_dentry_open(struct file *f, | |||
764 | 737 | ||
765 | cleanup_all: | 738 | cleanup_all: |
766 | fops_put(f->f_op); | 739 | fops_put(f->f_op); |
767 | if (f->f_mode & FMODE_WRITE) { | 740 | if (f->f_mode & FMODE_WRITER) { |
768 | put_write_access(inode); | 741 | put_write_access(inode); |
769 | if (!special_file(inode->i_mode)) { | 742 | __mnt_drop_write(f->f_path.mnt); |
770 | /* | ||
771 | * We don't consider this a real | ||
772 | * mnt_want/drop_write() pair | ||
773 | * because it all happenend right | ||
774 | * here, so just reset the state. | ||
775 | */ | ||
776 | file_reset_write(f); | ||
777 | __mnt_drop_write(f->f_path.mnt); | ||
778 | } | ||
779 | } | 743 | } |
780 | cleanup_file: | 744 | cleanup_file: |
781 | path_put(&f->f_path); | 745 | path_put(&f->f_path); |