fs: implement Dynamic FSync 2.0 (thx andip71)
This commit is contained in:
parent
7295c7e958
commit
40c33a5cc2
|
@ -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"
|
||||
|
|
|
@ -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
257
fs/dyn_sync_cntrl.c
Normal 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");
|
43
fs/sync.c
43
fs/sync.c
|
@ -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);
|
||||
}
|
||||
|
|
14
include/linux/dyn_sync_cntrl.h
Normal file
14
include/linux/dyn_sync_cntrl.h
Normal 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;
|
||||
|
Loading…
Reference in New Issue
Block a user