258 lines
5.4 KiB
C
258 lines
5.4 KiB
C
/*
|
|
* 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/state_notifier.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 STATE_NOTIFIER_ACTIVE:
|
|
mutex_lock(&fsync_mutex);
|
|
|
|
suspend_active = false;
|
|
|
|
if (dyn_fsync_active)
|
|
{
|
|
dyn_fsync_force_flush();
|
|
}
|
|
|
|
mutex_unlock(&fsync_mutex);
|
|
break;
|
|
|
|
case STATE_NOTIFIER_SUSPEND:
|
|
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 (state_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);
|
|
|
|
state_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");
|