aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorPaul Reioux <reioux@gmail.com>2015-03-29 14:52:41 -0400
committerMoyster <oysterized@gmail.com>2016-08-26 16:09:52 +0200
commitd2cdb4e1ce3df4e28b0e51807455ddf424ff2e71 (patch)
tree6d71460d5c5f1da06e3c94aa317af430fdecefba /fs
parent595adec881c2eaead1bd81ce21864407f50b136e (diff)
Dynamic Fsync Control
Diffstat (limited to 'fs')
-rw-r--r--fs/Kconfig6
-rw-r--r--fs/Makefile1
-rw-r--r--fs/dyn_sync_cntrl.c209
-rw-r--r--fs/sync.c48
4 files changed, 264 insertions, 0 deletions
diff --git a/fs/Kconfig b/fs/Kconfig
index 62282418e..d90a607ba 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -269,4 +269,10 @@ source "fs/nls/Kconfig"
source "fs/dlm/Kconfig"
source "fs/rawfs/Kconfig"
+config DYNAMIC_FSYNC
+ bool "dynamic file sync control"
+ default n
+ help
+ An experimental file sync control using new power_suspend driver
+
endmenu
diff --git a/fs/Makefile b/fs/Makefile
index 5547e2d96..74068e859 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -127,3 +127,4 @@ obj-$(CONFIG_CEPH_FS) += ceph/
obj-$(CONFIG_PSTORE) += pstore/
obj-$(CONFIG_EFIVAR_FS) += efivarfs/
obj-$(CONFIG_RAWFS_FS) += rawfs/
+obj-$(CONFIG_DYNAMIC_FSYNC) += dyn_sync_cntrl.o
diff --git a/fs/dyn_sync_cntrl.c b/fs/dyn_sync_cntrl.c
new file mode 100644
index 000000000..229029956
--- /dev/null
+++ b/fs/dyn_sync_cntrl.c
@@ -0,0 +1,209 @@
+/*
+ * Author: Paul Reioux aka Faux123 <reioux@gmail.com>
+ *
+ * Copyright 2013 Paul Reioux
+ * Copyright 2012 Paul Reioux
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/earlysuspend.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/writeback.h>
+
+#define DYN_FSYNC_VERSION_MAJOR 1
+#define DYN_FSYNC_VERSION_MINOR 5
+
+/*
+ * fsync_mutex protects dyn_fsync_active during early suspend / late resume
+ * transitions
+ */
+static DEFINE_MUTEX(fsync_mutex);
+
+bool early_suspend_active __read_mostly = false;
+bool dyn_fsync_active __read_mostly = true;
+
+static ssize_t dyn_fsync_active_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", (dyn_fsync_active ? 1 : 0));
+}
+
+static ssize_t dyn_fsync_active_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ unsigned int data;
+
+ if(sscanf(buf, "%u\n", &data) == 1) {
+ if (data == 1) {
+ pr_info("%s: dynamic fsync enabled\n", __FUNCTION__);
+ dyn_fsync_active = true;
+ }
+ else if (data == 0) {
+ pr_info("%s: dyanamic fsync disabled\n", __FUNCTION__);
+ dyn_fsync_active = false;
+ }
+ else
+ pr_info("%s: bad value: %u\n", __FUNCTION__, data);
+ } else
+ pr_info("%s: unknown input!\n", __FUNCTION__);
+
+ return count;
+}
+
+static ssize_t dyn_fsync_version_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf, "version: %u.%u by faux123\n",
+ DYN_FSYNC_VERSION_MAJOR,
+ DYN_FSYNC_VERSION_MINOR);
+}
+
+static ssize_t dyn_fsync_earlysuspend_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf, "early suspend active: %u\n", early_suspend_active);
+}
+
+static struct kobj_attribute dyn_fsync_active_attribute =
+ __ATTR(Dyn_fsync_active, 0666,
+ dyn_fsync_active_show,
+ dyn_fsync_active_store);
+
+static struct kobj_attribute dyn_fsync_version_attribute =
+ __ATTR(Dyn_fsync_version, 0444, dyn_fsync_version_show, NULL);
+
+static struct kobj_attribute dyn_fsync_earlysuspend_attribute =
+ __ATTR(Dyn_fsync_earlysuspend, 0444, dyn_fsync_earlysuspend_show, NULL);
+
+static struct attribute *dyn_fsync_active_attrs[] =
+ {
+ &dyn_fsync_active_attribute.attr,
+ &dyn_fsync_version_attribute.attr,
+ &dyn_fsync_earlysuspend_attribute.attr,
+ NULL,
+ };
+
+static struct attribute_group dyn_fsync_active_attr_group =
+ {
+ .attrs = dyn_fsync_active_attrs,
+ };
+
+static struct kobject *dyn_fsync_kobj;
+
+extern void sync_filesystems(int wait);
+static void dyn_fsync_force_flush(void)
+{
+ sync_filesystems(0);
+ sync_filesystems(1);
+}
+
+static void dyn_fsync_suspend(struct early_suspend *p)
+{
+ mutex_lock(&fsync_mutex);
+ if (dyn_fsync_active) {
+ early_suspend_active = true;
+ dyn_fsync_force_flush();
+ }
+ mutex_unlock(&fsync_mutex);
+}
+
+static void dyn_fsync_resume(struct early_suspend *p)
+{
+ mutex_lock(&fsync_mutex);
+ early_suspend_active = false;
+ mutex_unlock(&fsync_mutex);
+}
+
+static struct early_suspend dyn_fsync_early_suspend_handler =
+ {
+ .suspend = dyn_fsync_suspend,
+ .resume = dyn_fsync_resume,
+ };
+
+static int dyn_fsync_panic_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ early_suspend_active = true;
+ dyn_fsync_force_flush();
+ //pr_warn("dyn fsync: panic: force flush!\n");
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block dyn_fsync_panic_block = {
+ .notifier_call = dyn_fsync_panic_event,
+ .priority = INT_MAX,
+};
+
+static int dyn_fsync_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ if (code == SYS_DOWN || code == SYS_HALT) {
+ early_suspend_active = true;
+ dyn_fsync_force_flush();
+ //pr_warn("dyn fsync: reboot: force flush!\n");
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block dyn_fsync_notifier = {
+ .notifier_call = dyn_fsync_notify_sys,
+};
+
+static int dyn_fsync_init(void)
+{
+ int sysfs_result;
+
+ register_early_suspend(&dyn_fsync_early_suspend_handler);
+ register_reboot_notifier(&dyn_fsync_notifier);
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &dyn_fsync_panic_block);
+
+ dyn_fsync_kobj = kobject_create_and_add("dyn_fsync", kernel_kobj);
+ if (!dyn_fsync_kobj) {
+ pr_err("%s dyn_fsync kobject create failed!\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+
+ sysfs_result = sysfs_create_group(dyn_fsync_kobj,
+ &dyn_fsync_active_attr_group);
+
+ if (sysfs_result) {
+ pr_info("%s dyn_fsync sysfs create failed!\n", __FUNCTION__);
+ kobject_put(dyn_fsync_kobj);
+ }
+ return sysfs_result;
+}
+
+static void dyn_fsync_exit(void)
+{
+ unregister_early_suspend(&dyn_fsync_early_suspend_handler);
+ unregister_reboot_notifier(&dyn_fsync_notifier);
+ atomic_notifier_chain_unregister(&panic_notifier_list,
+ &dyn_fsync_panic_block);
+
+ if (dyn_fsync_kobj != NULL)
+ kobject_put(dyn_fsync_kobj);
+}
+
+module_init(dyn_fsync_init);
+module_exit(dyn_fsync_exit);
+
+MODULE_AUTHOR("Paul Reioux <reioux@gmail.com>");
+MODULE_DESCRIPTION("dynamic fsync - automatic fs sync optimizaition using"
+ "early_suspend driver!");
+MODULE_LICENSE("GPL v2");
diff --git a/fs/sync.c b/fs/sync.c
index 905f3f6b3..686996e50 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -17,6 +17,11 @@
#include <linux/backing-dev.h>
#include "internal.h"
+#ifdef CONFIG_DYNAMIC_FSYNC
+extern bool early_suspend_active;
+extern bool dyn_fsync_active;
+#endif
+
#define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \
SYNC_FILE_RANGE_WAIT_AFTER)
@@ -89,6 +94,17 @@ static void fdatawait_one_bdev(struct block_device *bdev, void *arg)
filemap_fdatawait(bdev->bd_inode->i_mapping);
}
+#ifndef CONFIG_DYNAMIC_FSYNC
+static
+#endif
+void sync_filesystems(int wait)
+{
+ iterate_supers(sync_fs_one_sb, &wait);
+}
+#ifdef CONFIG_DYNAMIC_FSYNC
+EXPORT_SYMBOL_GPL(sync_filesystems);
+#endif
+
/*
* Sync everything. We start by waking flusher threads so that most of
* writeback runs on all devices in parallel. Then we sync all inodes reliably
@@ -193,7 +209,15 @@ EXPORT_SYMBOL(vfs_fsync_range);
*/
int vfs_fsync(struct file *file, int datasync)
{
+#ifdef CONFIG_DYNAMIC_FSYNC
+ if (likely(dyn_fsync_active && !early_suspend_active))
+ return 0;
+ else {
+#endif
return vfs_fsync_range(file, 0, LLONG_MAX, datasync);
+#ifdef CONFIG_DYNAMIC_FSYNC
+ }
+#endif
}
EXPORT_SYMBOL(vfs_fsync);
@@ -211,11 +235,21 @@ static int do_fsync(unsigned int fd, int datasync)
SYSCALL_DEFINE1(fsync, unsigned int, fd)
{
+#ifdef CONFIG_DYNAMIC_FSYNC
+ if (likely(dyn_fsync_active && !early_suspend_active))
+ return 0;
+ else
+#endif
return do_fsync(fd, 0);
}
SYSCALL_DEFINE1(fdatasync, unsigned int, fd)
{
+#if 0
+ if (likely(dyn_fsync_active && !early_suspend_active))
+ return 0;
+ else
+#endif
return do_fsync(fd, 1);
}
@@ -286,6 +320,12 @@ EXPORT_SYMBOL(generic_write_sync);
SYSCALL_DEFINE4(sync_file_range, int, fd, loff_t, offset, loff_t, nbytes,
unsigned int, flags)
{
+#ifdef CONFIG_DYNAMIC_FSYNC
+if (likely(dyn_fsync_active && !early_suspend_active))
+return 0;
+else {
+#endif
+
int ret;
struct fd f;
struct address_space *mapping;
@@ -364,6 +404,9 @@ out_put:
fdput(f);
out:
return ret;
+#ifdef CONFIG_DYNAMIC_FSYNC
+ }
+#endif
}
/* It would be nice if people remember that not all the world's an i386
@@ -371,5 +414,10 @@ out:
SYSCALL_DEFINE4(sync_file_range2, int, fd, unsigned int, flags,
loff_t, offset, loff_t, nbytes)
{
+#ifdef CONFIG_DYNAMIC_FSYNC
+ if (likely(dyn_fsync_active && !early_suspend_active))
+ return 0;
+ else
+#endif
return sys_sync_file_range(fd, offset, nbytes, flags);
}