diff options
| author | Paul Reioux <reioux@gmail.com> | 2015-03-29 14:52:41 -0400 |
|---|---|---|
| committer | Moyster <oysterized@gmail.com> | 2016-08-26 16:09:52 +0200 |
| commit | d2cdb4e1ce3df4e28b0e51807455ddf424ff2e71 (patch) | |
| tree | 6d71460d5c5f1da06e3c94aa317af430fdecefba /fs | |
| parent | 595adec881c2eaead1bd81ce21864407f50b136e (diff) | |
Dynamic Fsync Control
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/Kconfig | 6 | ||||
| -rw-r--r-- | fs/Makefile | 1 | ||||
| -rw-r--r-- | fs/dyn_sync_cntrl.c | 209 | ||||
| -rw-r--r-- | fs/sync.c | 48 |
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"); @@ -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); } |
