[PATCH 2/3] vfs: per-sb write count preparation stage

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Current fs_may_remount_ro() implementation is suboptimal.
Sane implementation must have some sort of per-sb dirty counter.
We may implement it exactly like mnt write counter. But this
introduce additional code on fast path. Let do not reinvent the
weel. And just caclulate sb write count as sum of write_count
of it's vfsmnts.
To achieve this task we have to link vfsmnt in to per-sb list.

Later patch introduce actual dirty write counter implementation.

NOTE: The problem with per-sb list is than external modules may
not know about this new logic. Module may just forget to insert
mnt in to sb's list. This condition is hard to guard by some sort
of BUG_ON. So it's list will be empty and write_count will result
incorrect result.

Signed-off-by: Dmitry Monakhov <dmonakhov@xxxxxxxxxx>
---
 fs/btrfs/super.c      |    2 +-
 fs/gfs2/ops_fstype.c  |    4 ++--
 fs/namespace.c        |   23 +++++++++++++++++++++--
 fs/nfs/super.c        |   12 ++++++------
 fs/super.c            |    1 +
 include/linux/fs.h    |    3 +++
 include/linux/mount.h |    1 +
 7 files changed, 35 insertions(+), 11 deletions(-)

diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 8a1ea6e..f82b0ad 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -567,7 +567,7 @@ static int btrfs_get_sb(struct file_system_type *fs_type, int flags,
 		}
 	}
 
-	mnt->mnt_sb = s;
+	super_add_mnt(s, mnt);
 	mnt->mnt_root = root;
 
 	kfree(subvol_name);
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index 8a102f7..f0d71a0 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -1361,7 +1361,7 @@ static int gfs2_get_sb(struct file_system_type *fs_type, int flags,
 	}
 
 	sdp = s->s_fs_info;
-	mnt->mnt_sb = s;
+	super_add_mnt(sb, mnt);
 	if (args.ar_meta)
 		mnt->mnt_root = dget(sdp->sd_master_dir);
 	else
@@ -1406,7 +1406,7 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags,
 		return -EBUSY;
 	}
 	sdp = s->s_fs_info;
-	mnt->mnt_sb = s;
+	super_add_mnt(s, mnt);
 	mnt->mnt_root = dget(sdp->sd_master_dir);
 	return 0;
 }
diff --git a/fs/namespace.c b/fs/namespace.c
index ffa3843..e816097 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -145,6 +145,7 @@ struct vfsmount *alloc_vfsmnt(const char *name)
 		INIT_LIST_HEAD(&mnt->mnt_hash);
 		INIT_LIST_HEAD(&mnt->mnt_child);
 		INIT_LIST_HEAD(&mnt->mnt_mounts);
+		INIT_LIST_HEAD(&mnt->mnt_sb_list);
 		INIT_LIST_HEAD(&mnt->mnt_list);
 		INIT_LIST_HEAD(&mnt->mnt_expire);
 		INIT_LIST_HEAD(&mnt->mnt_share);
@@ -389,9 +390,26 @@ static void __mnt_unmake_readonly(struct vfsmount *mnt)
 	spin_unlock(&vfsmount_lock);
 }
 
-void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb)
+void super_add_mnt(struct super_block *sb, struct vfsmount *mnt)
 {
+	spin_lock(&vfsmount_lock);
+	list_add(&sb->s_vfsmount, &mnt->mnt_sb_list);
 	mnt->mnt_sb = sb;
+	spin_unlock(&vfsmount_lock);
+}
+EXPORT_SYMBOL(super_add_mnt);
+
+void super_del_mnt(struct vfsmount *mnt)
+{
+	spin_lock(&vfsmount_lock);
+	list_del_init(&mnt->mnt_sb_list);
+	spin_unlock(&vfsmount_lock);
+}
+EXPORT_SYMBOL(super_del_mnt);
+
+void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb)
+{
+	super_add_mnt(sb, mnt);
 	mnt->mnt_root = dget(sb->s_root);
 }
 
@@ -563,7 +581,7 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
 
 		mnt->mnt_flags = old->mnt_flags;
 		atomic_inc(&sb->s_active);
-		mnt->mnt_sb = sb;
+		super_add_mnt(sb, mnt);
 		mnt->mnt_root = dget(root);
 		mnt->mnt_mountpoint = mnt->mnt_root;
 		mnt->mnt_parent = mnt;
@@ -997,6 +1015,7 @@ void release_mounts(struct list_head *head)
 	while (!list_empty(head)) {
 		mnt = list_first_entry(head, struct vfsmount, mnt_hash);
 		list_del_init(&mnt->mnt_hash);
+		super_del_mnt(mnt);
 		if (mnt->mnt_parent != mnt) {
 			struct dentry *dentry;
 			struct vfsmount *m;
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index f1afee4..3470201 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2235,7 +2235,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
 		goto error_splat_root;
 
 	s->s_flags |= MS_ACTIVE;
-	mnt->mnt_sb = s;
+	super_add_mnt(s, mnt);
 	mnt->mnt_root = mntroot;
 	error = 0;
 
@@ -2347,7 +2347,7 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags,
 	}
 
 	s->s_flags |= MS_ACTIVE;
-	mnt->mnt_sb = s;
+	super_add_mnt(s, mnt);
 	mnt->mnt_root = mntroot;
 
 	/* clone any lsm security options from the parent to the new sb */
@@ -2599,7 +2599,7 @@ static int nfs4_remote_get_sb(struct file_system_type *fs_type,
 		goto error_splat_root;
 
 	s->s_flags |= MS_ACTIVE;
-	mnt->mnt_sb = s;
+	super_add_mnt(s, mnt);
 	mnt->mnt_root = mntroot;
 	error = 0;
 
@@ -2681,7 +2681,7 @@ static int nfs_follow_remote_path(struct vfsmount *root_mnt,
 
 	s = nd.path.mnt->mnt_sb;
 	atomic_inc(&s->s_active);
-	mnt_target->mnt_sb = s;
+	super_add_mnt(s, mnt);
 	mnt_target->mnt_root = dget(nd.path.dentry);
 
 	/* Correct the device pathname */
@@ -2832,7 +2832,7 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags,
 	}
 
 	s->s_flags |= MS_ACTIVE;
-	mnt->mnt_sb = s;
+	super_add_mnt(s, mnt);
 	mnt->mnt_root = mntroot;
 
 	security_sb_clone_mnt_opts(data->sb, s);
@@ -2914,7 +2914,7 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type,
 	}
 
 	s->s_flags |= MS_ACTIVE;
-	mnt->mnt_sb = s;
+	super_add_mnt(s, mnt);
 	mnt->mnt_root = mntroot;
 
 	security_sb_clone_mnt_opts(data->sb, s);
diff --git a/fs/super.c b/fs/super.c
index f35ac60..d3e0083 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -151,6 +151,7 @@ int __put_super_and_need_restart(struct super_block *sb)
 {
 	/* check for race with generic_shutdown_super() */
 	if (list_empty(&sb->s_list)) {
+		WARN_ON(!list_empty(&sb->s_vfsmount));
 		/* super block is removed, need to restart... */
 		__put_super(sb);
 		return 1;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 66369f6..75f057d 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1339,6 +1339,7 @@ struct super_block {
 #endif
 	struct xattr_handler	**s_xattr;
 
+	struct list_head	s_vfsmount;	/* All vfsmounts */
 	struct list_head	s_inodes;	/* all inodes */
 	struct hlist_head	s_anon;		/* anonymous dentries for (nfs) exporting */
 	struct list_head	s_files;
@@ -1779,6 +1780,8 @@ extern int get_sb_pseudo(struct file_system_type *, char *,
 	const struct super_operations *ops, unsigned long,
 	struct vfsmount *mnt);
 extern void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb);
+extern void super_add_mnt(struct super_block *sb, struct vfsmount *mnt);
+extern void super_del_mnt(struct vfsmount *mnt);
 int __put_super_and_need_restart(struct super_block *sb);
 void put_super(struct super_block *sb);
 
diff --git a/include/linux/mount.h b/include/linux/mount.h
index ca726eb..751784c 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -59,6 +59,7 @@ struct vfsmount {
 	/* 4 bytes hole on 64bits arches */
 	const char *mnt_devname;	/* Name of device e.g. /dev/dsk/hda1 */
 	struct list_head mnt_list;
+	struct list_head mnt_sb_list;	/* link sb-speciffic mounts */
 	struct list_head mnt_expire;	/* link in fs-specific expiry list */
 	struct list_head mnt_share;	/* circular list of shared mounts */
 	struct list_head mnt_slave_list;/* list of slave mounts */
-- 
1.6.6

--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux