aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2011-11-21 06:11:33 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2012-01-06 23:20:13 -0500
commit8e8b87964bc8dc5c14b6543fc933b7725f07d3ac (patch)
tree9a14c135741f3a8ba960ff97f060a58597604a6d /fs
parent7ada4db88634429f4da690ad1c4eb73c93085f0c (diff)
vfs: prevent remount read-only if pending removes
If there are any inodes on the super block that have been unlinked (i_nlink == 0) but have not yet been deleted then prevent the remounting the super block read-only. Reported-by: Toshiyuki Okajima <toshi.okajima@jp.fujitsu.com> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Tested-by: Toshiyuki Okajima <toshi.okajima@jp.fujitsu.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/file_table.c23
-rw-r--r--fs/namespace.c7
-rw-r--r--fs/super.c4
3 files changed, 7 insertions, 27 deletions
diff --git a/fs/file_table.c b/fs/file_table.c
index c322794f7360..20002e39754d 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -474,29 +474,6 @@ void file_sb_list_del(struct file *file)
474 474
475#endif 475#endif
476 476
477int fs_may_remount_ro(struct super_block *sb)
478{
479 struct file *file;
480 /* Check that no files are currently opened for writing. */
481 lg_global_lock(files_lglock);
482 do_file_list_for_each_entry(sb, file) {
483 struct inode *inode = file->f_path.dentry->d_inode;
484
485 /* File with pending delete? */
486 if (inode->i_nlink == 0)
487 goto too_bad;
488
489 /* Writeable file? */
490 if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE))
491 goto too_bad;
492 } while_file_list_for_each_entry;
493 lg_global_unlock(files_lglock);
494 return 1; /* Tis' cool bro. */
495too_bad:
496 lg_global_unlock(files_lglock);
497 return 0;
498}
499
500/** 477/**
501 * mark_files_ro - mark all files read-only 478 * mark_files_ro - mark all files read-only
502 * @sb: superblock in question 479 * @sb: superblock in question
diff --git a/fs/namespace.c b/fs/namespace.c
index 98ebc78b21ab..7e6f2c9dc7c4 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -449,6 +449,10 @@ int sb_prepare_remount_readonly(struct super_block *sb)
449 struct mount *mnt; 449 struct mount *mnt;
450 int err = 0; 450 int err = 0;
451 451
452 /* Racy optimization. Recheck the counter under MNT_WRITE_HOLD */
453 if (atomic_long_read(&sb->s_remove_count))
454 return -EBUSY;
455
452 br_write_lock(vfsmount_lock); 456 br_write_lock(vfsmount_lock);
453 list_for_each_entry(mnt, &sb->s_mounts, mnt_instance) { 457 list_for_each_entry(mnt, &sb->s_mounts, mnt_instance) {
454 if (!(mnt->mnt.mnt_flags & MNT_READONLY)) { 458 if (!(mnt->mnt.mnt_flags & MNT_READONLY)) {
@@ -460,6 +464,9 @@ int sb_prepare_remount_readonly(struct super_block *sb)
460 } 464 }
461 } 465 }
462 } 466 }
467 if (!err && atomic_long_read(&sb->s_remove_count))
468 err = -EBUSY;
469
463 if (!err) { 470 if (!err) {
464 sb->s_readonly_remount = 1; 471 sb->s_readonly_remount = 1;
465 smp_wmb(); 472 smp_wmb();
diff --git a/fs/super.c b/fs/super.c
index 6acc02237e3e..de41e1e46f09 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -729,10 +729,6 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
729 retval = sb_prepare_remount_readonly(sb); 729 retval = sb_prepare_remount_readonly(sb);
730 if (retval) 730 if (retval)
731 return retval; 731 return retval;
732
733 retval = -EBUSY;
734 if (!fs_may_remount_ro(sb))
735 goto cancel_readonly;
736 } 732 }
737 } 733 }
738 734