|
@@ -273,6 +273,15 @@ static unsigned int mnt_get_writers(struct mount *mnt)
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
+static int mnt_is_readonly(struct vfsmount *mnt)
|
|
|
+{
|
|
|
+ if (mnt->mnt_sb->s_readonly_remount)
|
|
|
+ return 1;
|
|
|
+ /* Order wrt setting s_flags/s_readonly_remount in do_remount() */
|
|
|
+ smp_rmb();
|
|
|
+ return __mnt_is_readonly(mnt);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Most r/o checks on a fs are for operations that take
|
|
|
* discrete amounts of time, like a write() or unlink().
|
|
@@ -312,7 +321,7 @@ int mnt_want_write(struct vfsmount *m)
|
|
|
* MNT_WRITE_HOLD is cleared.
|
|
|
*/
|
|
|
smp_rmb();
|
|
|
- if (__mnt_is_readonly(m)) {
|
|
|
+ if (mnt_is_readonly(m)) {
|
|
|
mnt_dec_writers(mnt);
|
|
|
ret = -EROFS;
|
|
|
goto out;
|
|
@@ -435,6 +444,35 @@ static void __mnt_unmake_readonly(struct mount *mnt)
|
|
|
br_write_unlock(vfsmount_lock);
|
|
|
}
|
|
|
|
|
|
+int sb_prepare_remount_readonly(struct super_block *sb)
|
|
|
+{
|
|
|
+ struct mount *mnt;
|
|
|
+ int err = 0;
|
|
|
+
|
|
|
+ br_write_lock(vfsmount_lock);
|
|
|
+ list_for_each_entry(mnt, &sb->s_mounts, mnt_instance) {
|
|
|
+ if (!(mnt->mnt.mnt_flags & MNT_READONLY)) {
|
|
|
+ mnt->mnt.mnt_flags |= MNT_WRITE_HOLD;
|
|
|
+ smp_mb();
|
|
|
+ if (mnt_get_writers(mnt) > 0) {
|
|
|
+ err = -EBUSY;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!err) {
|
|
|
+ sb->s_readonly_remount = 1;
|
|
|
+ smp_wmb();
|
|
|
+ }
|
|
|
+ list_for_each_entry(mnt, &sb->s_mounts, mnt_instance) {
|
|
|
+ if (mnt->mnt.mnt_flags & MNT_WRITE_HOLD)
|
|
|
+ mnt->mnt.mnt_flags &= ~MNT_WRITE_HOLD;
|
|
|
+ }
|
|
|
+ br_write_unlock(vfsmount_lock);
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
static void free_vfsmnt(struct mount *mnt)
|
|
|
{
|
|
|
kfree(mnt->mnt_devname);
|