[PATCH v1 3/3] fat: self-manage own fsinfo block

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

 



From: Artem Bityutskiy <artem.bityutskiy@xxxxxxxxxxxxxxx>

This is the final patch of the series which makes FAT independent of the
VFS '->write_super' method which was used for writing out the FSINFO block
(which contains various non-essential counters like the next free cluster).

Now we just submit a delayed work when the FSINFO block is marked as dirty.
A spinlock is used to make sure we submit only one work at a time. On unmount
or '->sync_fs()', we just flush the workqueue which should make sure the
FSINFO block is written out.

We use the generic 'system_long_wq' for these purposes because it seem to fit
the task well. Indeed, own workqueue would be an overkill and waste of
resources.

The FSINFO write-out delay is the same as before:
'/proc/sys/vm/dirty_expire_centisecs'.

Reminder: this exercises is being done in order to kill the global VFS
'sync_supers()' thread which wakes up the system every 5 seconds no matter
what.

Signed-off-by: Artem Bityutskiy <artem.bityutskiy@xxxxxxxxxxxxxxx>
---
 fs/fat/fat.h    |    7 ++++++-
 fs/fat/fatent.c |   14 +++++++++++++-
 fs/fat/inode.c  |   47 ++++++++++++++++++++++++++++++-----------------
 3 files changed, 49 insertions(+), 19 deletions(-)

diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index 66994f3..4f08ee0 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -7,6 +7,7 @@
 #include <linux/fs.h>
 #include <linux/mutex.h>
 #include <linux/ratelimit.h>
+#include <linux/workqueue.h>
 #include <linux/msdos_fs.h>
 
 /*
@@ -75,7 +76,7 @@ struct msdos_sb_info {
 	struct fat_mount_options options;
 	struct nls_table *nls_disk;  /* Codepage used on disk */
 	struct nls_table *nls_io;    /* Charset used for input and display */
-	const void *dir_ops;		     /* Opaque; default directory operations */
+	const void *dir_ops;         /* Opaque; default directory operations */
 	int dir_per_block;	     /* dir entries per block */
 	int dir_per_block_bits;	     /* log2(dir_per_block) */
 
@@ -87,6 +88,10 @@ struct msdos_sb_info {
 
 	spinlock_t inode_hash_lock;
 	struct hlist_head inode_hashtable[FAT_HASH_SIZE];
+
+	struct delayed_work fsinfo_work; /* FSINFO block write-out work */
+	int fsinfo_dirty; /* non-zero if the FSINFO block should be synced */
+	spinlock_t fsinfo_lock; /* protects fsinfo_* fields */
 };
 
 #define FAT_CACHE_VALID	0	/* special case for valid cache */
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c
index 8e778ef..8d31994 100644
--- a/fs/fat/fatent.c
+++ b/fs/fat/fatent.c
@@ -310,7 +310,19 @@ void fat_ent_access_init(struct super_block *sb)
 
 static void fat_mark_fsinfo_dirty(struct super_block *sb)
 {
-	sb->s_dirt = 1;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	unsigned long delay;
+
+	if (sb->s_flags & MS_RDONLY || sbi->fat_bits != 32)
+		return;
+
+	spin_lock(&sbi->fsinfo_lock);
+	if (!sbi->fsinfo_dirty) {
+		delay = msecs_to_jiffies(dirty_writeback_interval * 10);
+		queue_delayed_work(system_long_wq, &sbi->fsinfo_work, delay);
+		sbi->fsinfo_dirty = 1;
+	}
+	spin_unlock(&sbi->fsinfo_lock);
 }
 
 static inline int fat_ent_update_ptr(struct super_block *sb,
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 21687e3..ca544b1 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -459,37 +459,49 @@ static void fat_evict_inode(struct inode *inode)
 	fat_detach(inode);
 }
 
-static void fat_write_super(struct super_block *sb)
+static struct msdos_sb_info *work_to_sb(struct work_struct *work)
 {
-	lock_super(sb);
-	sb->s_dirt = 0;
+	struct delayed_work *dwork;
+
+	dwork = container_of(work, struct delayed_work, work);
+	return container_of(dwork, struct msdos_sb_info, fsinfo_work);
+}
+
+static void write_super(struct work_struct *work)
+{
+	struct msdos_sb_info *sbi = work_to_sb(work);
+	struct super_block *sb = sbi->fat_inode->i_sb;
+
+	spin_lock(&sbi->fsinfo_lock);
+	if (!sbi->fsinfo_dirty) {
+		spin_unlock(&sbi->fsinfo_lock);
+		return;
+	}
+	sbi->fsinfo_dirty = 0;
+	spin_unlock(&sbi->fsinfo_lock);
 
-	if (!(sb->s_flags & MS_RDONLY))
-		fat_clusters_flush(sb);
+	lock_super(sb);
+	fat_clusters_flush(sb);
 	unlock_super(sb);
 }
 
 static int fat_sync_fs(struct super_block *sb, int wait)
 {
-	int err = 0;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 
-	if (sb->s_dirt) {
-		lock_super(sb);
-		sb->s_dirt = 0;
-		err = fat_clusters_flush(sb);
-		unlock_super(sb);
-	}
+	if (wait)
+		flush_delayed_work_sync(&sbi->fsinfo_work);
+	else
+		flush_delayed_work(&sbi->fsinfo_work);
 
-	return err;
+	return 0;
 }
 
 static void fat_put_super(struct super_block *sb)
 {
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 
-	if (sb->s_dirt)
-		fat_write_super(sb);
-
+	flush_delayed_work_sync(&sbi->fsinfo_work);
 	iput(sbi->fat_inode);
 
 	unload_nls(sbi->nls_disk);
@@ -678,7 +690,6 @@ static const struct super_operations fat_sops = {
 	.write_inode	= fat_write_inode,
 	.evict_inode	= fat_evict_inode,
 	.put_super	= fat_put_super,
-	.write_super	= fat_write_super,
 	.sync_fs	= fat_sync_fs,
 	.statfs		= fat_statfs,
 	.remount_fs	= fat_remount,
@@ -1271,6 +1282,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 	sb->s_export_op = &fat_export_ops;
 	ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL,
 			     DEFAULT_RATELIMIT_BURST);
+	INIT_DELAYED_WORK_DEFERRABLE(&sbi->fsinfo_work, write_super);
+	spin_lock_init(&sbi->fsinfo_lock);
 
 	error = parse_options(sb, data, isvfat, silent, &debug, &sbi->options);
 	if (error)
-- 
1.7.7.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