diff options
Diffstat (limited to 'fs/super.c')
-rw-r--r-- | fs/super.c | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/fs/super.c b/fs/super.c index 09008dbd264e..1f8f05ede437 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/idr.h> | 37 | #include <linux/idr.h> |
38 | #include <linux/kobject.h> | 38 | #include <linux/kobject.h> |
39 | #include <linux/mutex.h> | 39 | #include <linux/mutex.h> |
40 | #include <linux/file.h> | ||
40 | #include <asm/uaccess.h> | 41 | #include <asm/uaccess.h> |
41 | 42 | ||
42 | 43 | ||
@@ -567,10 +568,29 @@ static void mark_files_ro(struct super_block *sb) | |||
567 | { | 568 | { |
568 | struct file *f; | 569 | struct file *f; |
569 | 570 | ||
571 | retry: | ||
570 | file_list_lock(); | 572 | file_list_lock(); |
571 | list_for_each_entry(f, &sb->s_files, f_u.fu_list) { | 573 | list_for_each_entry(f, &sb->s_files, f_u.fu_list) { |
572 | if (S_ISREG(f->f_path.dentry->d_inode->i_mode) && file_count(f)) | 574 | struct vfsmount *mnt; |
573 | f->f_mode &= ~FMODE_WRITE; | 575 | if (!S_ISREG(f->f_path.dentry->d_inode->i_mode)) |
576 | continue; | ||
577 | if (!file_count(f)) | ||
578 | continue; | ||
579 | if (!(f->f_mode & FMODE_WRITE)) | ||
580 | continue; | ||
581 | f->f_mode &= ~FMODE_WRITE; | ||
582 | if (file_check_writeable(f) != 0) | ||
583 | continue; | ||
584 | file_release_write(f); | ||
585 | mnt = mntget(f->f_path.mnt); | ||
586 | file_list_unlock(); | ||
587 | /* | ||
588 | * This can sleep, so we can't hold | ||
589 | * the file_list_lock() spinlock. | ||
590 | */ | ||
591 | mnt_drop_write(mnt); | ||
592 | mntput(mnt); | ||
593 | goto retry; | ||
574 | } | 594 | } |
575 | file_list_unlock(); | 595 | file_list_unlock(); |
576 | } | 596 | } |