fs: implement Dynamic FSync 2.0 (thx andip71)

This commit is contained in:
googyanas 2018-07-18 23:41:35 +02:00 committed by BlackMesa123
parent 7295c7e958
commit 40c33a5cc2
5 changed files with 321 additions and 0 deletions

View File

@ -12,6 +12,12 @@ config INTERRUPTIBLE_SYNC
bool "Support interruptible sync for Samsung Mobile Device"
default y
config DYNAMIC_FSYNC
bool "dynamic file sync control"
default n
help
An experimental file sync control using new power_suspend driver
if BLOCK
source "fs/ext2/Kconfig"

View File

@ -128,3 +128,4 @@ obj-y += exofs/ # Multiple modules
obj-$(CONFIG_CEPH_FS) += ceph/
obj-$(CONFIG_PSTORE) += pstore/
obj-$(CONFIG_EFIVAR_FS) += efivarfs/
obj-$(CONFIG_DYNAMIC_FSYNC) += dyn_sync_cntrl.o

257
fs/dyn_sync_cntrl.c Normal file
View File

@ -0,0 +1,257 @@
/*
* Dynamic sync control driver V2
*
* by andip71 (alias Lord Boeffla)
*
* All credits for original implemenation to faux123
*
*/
#include <linux/module.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/writeback.h>
#include <linux/dyn_sync_cntrl.h>
#include <linux/lcd_notify.h>
// fsync_mutex protects dyn_fsync_active during suspend / late resume transitions
static DEFINE_MUTEX(fsync_mutex);
// Declarations
bool suspend_active __read_mostly = false;
bool dyn_fsync_active __read_mostly = DYN_FSYNC_ACTIVE_DEFAULT;
static struct notifier_block lcd_notif;
extern void sync_filesystems(int wait);
// Functions
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: dynamic 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\n",
DYN_FSYNC_VERSION_MAJOR,
DYN_FSYNC_VERSION_MINOR);
}
static ssize_t dyn_fsync_suspend_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "suspend active: %u\n", suspend_active);
}
static void dyn_fsync_force_flush(void)
{
sync_filesystems(0);
sync_filesystems(1);
}
static int dyn_fsync_panic_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
suspend_active = false;
dyn_fsync_force_flush();
pr_warn("dynamic fsync: panic - force flush!\n");
return NOTIFY_DONE;
}
static int dyn_fsync_notify_sys(struct notifier_block *this, unsigned long code,
void *unused)
{
if (code == SYS_DOWN || code == SYS_HALT)
{
suspend_active = false;
dyn_fsync_force_flush();
pr_warn("dynamic fsync: reboot - force flush!\n");
}
return NOTIFY_DONE;
}
static int lcd_notifier_callback(struct notifier_block *this,
unsigned long event, void *data)
{
switch (event)
{
case LCD_EVENT_OFF_START:
mutex_lock(&fsync_mutex);
suspend_active = false;
if (dyn_fsync_active)
{
dyn_fsync_force_flush();
}
mutex_unlock(&fsync_mutex);
break;
case LCD_EVENT_ON_END:
mutex_lock(&fsync_mutex);
suspend_active = true;
mutex_unlock(&fsync_mutex);
break;
default:
break;
}
return 0;
}
// Module structures
static struct notifier_block dyn_fsync_notifier =
{
.notifier_call = dyn_fsync_notify_sys,
};
static struct kobj_attribute dyn_fsync_active_attribute =
__ATTR(Dyn_fsync_active, 0660,
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_suspend_attribute =
__ATTR(Dyn_fsync_suspend, 0444, dyn_fsync_suspend_show, NULL);
static struct attribute *dyn_fsync_active_attrs[] =
{
&dyn_fsync_active_attribute.attr,
&dyn_fsync_version_attribute.attr,
&dyn_fsync_suspend_attribute.attr,
NULL,
};
static struct attribute_group dyn_fsync_active_attr_group =
{
.attrs = dyn_fsync_active_attrs,
};
static struct notifier_block dyn_fsync_panic_block =
{
.notifier_call = dyn_fsync_panic_event,
.priority = INT_MAX,
};
static struct kobject *dyn_fsync_kobj;
// Module init/exit
static int dyn_fsync_init(void)
{
int sysfs_result;
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_kobj create failed!\n", __FUNCTION__);
return -ENOMEM;
}
sysfs_result = sysfs_create_group(dyn_fsync_kobj,
&dyn_fsync_active_attr_group);
if (sysfs_result)
{
pr_err("%s dyn_fsync sysfs create failed!\n", __FUNCTION__);
kobject_put(dyn_fsync_kobj);
}
lcd_notif.notifier_call = lcd_notifier_callback;
if (lcd_register_client(&lcd_notif) != 0)
{
pr_err("%s: Failed to register lcd callback\n", __func__);
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);
return -EFAULT;
}
pr_info("%s dynamic fsync initialisation complete\n", __FUNCTION__);
return sysfs_result;
}
static void dyn_fsync_exit(void)
{
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);
lcd_unregister_client(&lcd_notif);
pr_info("%s dynamic fsync unregistration complete\n", __FUNCTION__);
}
module_init(dyn_fsync_init);
module_exit(dyn_fsync_exit);
MODULE_AUTHOR("andip71");
MODULE_DESCRIPTION("dynamic fsync - automatic fs sync optimization for msm8974");
MODULE_LICENSE("GPL v2");

View File

@ -18,6 +18,10 @@
#include <linux/backing-dev.h>
#include "internal.h"
#ifdef CONFIG_DYNAMIC_FSYNC
#include <linux/dyn_sync_cntrl.h>
#endif
bool fsync_enabled = true;
module_param(fsync_enabled, bool, 0755);
@ -348,6 +352,21 @@ static void fdatawait_one_bdev(struct block_device *bdev, void *arg)
filemap_fdatawait_keep_errors(bdev->bd_inode->i_mapping);
}
#ifdef CONFIG_DYNAMIC_FSYNC
/*
* Sync all the data for all the filesystems (called by sys_sync() and
* emergency sync)
*/
void sync_filesystems(int wait)
{
iterate_supers(sync_inodes_one_sb, NULL);
iterate_supers(sync_fs_one_sb, &wait);
iterate_supers(sync_fs_one_sb, &wait);
iterate_bdevs(fdatawrite_one_bdev, NULL);
iterate_bdevs(fdatawait_one_bdev, NULL);
}
#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
@ -500,6 +519,11 @@ int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync)
if (!fsync_enabled)
return 0;
#ifdef CONFIG_DYNAMIC_FSYNC
if (likely(dyn_fsync_active && suspend_active))
return 0;
#endif
if (!file->f_op->fsync)
return -EINVAL;
if (!datasync && (inode->i_state & I_DIRTY_TIME)) {
@ -552,6 +576,11 @@ SYSCALL_DEFINE1(fsync, unsigned int, fd)
if (!fsync_enabled)
return 0;
#ifdef CONFIG_DYNAMIC_FSYNC
if (likely(dyn_fsync_active && suspend_active))
return 0;
#endif
return do_fsync(fd, 0);
}
@ -560,6 +589,11 @@ SYSCALL_DEFINE1(fdatasync, unsigned int, fd)
if (!fsync_enabled)
return 0;
#ifdef CONFIG_DYNAMIC_FSYNC
if (likely(dyn_fsync_active && suspend_active))
return 0;
#endif
return do_fsync(fd, 1);
}
@ -622,6 +656,11 @@ SYSCALL_DEFINE4(sync_file_range, int, fd, loff_t, offset, loff_t, nbytes,
if (!fsync_enabled)
return 0;
#ifdef CONFIG_DYNAMIC_FSYNC
if (likely(dyn_fsync_active && suspend_active))
return 0;
#endif
ret = -EINVAL;
if (flags & ~VALID_FLAGS)
goto out;
@ -702,5 +741,9 @@ 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 && suspend_active))
return 0;
#endif
return sys_sync_file_range(fd, offset, nbytes, flags);
}

View File

@ -0,0 +1,14 @@
/*
* Dynamic sync control driver definitions (V2)
*
* by andip71 (alias Lord Boeffla)
*
*/
#define DYN_FSYNC_ACTIVE_DEFAULT true
#define DYN_FSYNC_VERSION_MAJOR 2
#define DYN_FSYNC_VERSION_MINOR 0
extern bool suspend_active;
extern bool dyn_fsync_active;