--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -274,4 +274,10 @@ endif
source "fs/nls/Kconfig"
source "fs/dlm/Kconfig"
+config DYNAMIC_FSYNC
+ bool "dynamic file sync control"
+ default y
+ help
+ An experimental file sync control using Android's early suspend / late resume drivers
+
endmenu
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -127,3 +127,4 @@ obj-$(CONFIG_PSTORE) += pstore/
# Patched by YAFFS
obj-$(CONFIG_YAFFS_FS) += yaffs2/
+obj-$(CONFIG_DYNAMIC_FSYNC) += dyn_sync_cntrl.o
--- /dev/null
+++ b/fs/dyn_sync_cntrl.c
@@ -0,0 +1,158 @@
+/*
+ * Base from Chad Goodman, chad.goodman@gmail.com
+ * modifications to base from faux123
+ * Copyright 2012 Chad Goodman
+ *
+ * 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/writeback.h>
+
+#define DYN_FSYNC_VERSION 2
+
+/*
+ * fsync_mutex protects dyn_fsync_active during early suspend / lat resume transitions
+ */
+static DEFINE_MUTEX(fsync_mutex);
+
+bool early_suspend_active = false;
+static bool dyn_fsync_active = 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\n", DYN_FSYNC_VERSION);
+}
+
+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;
+
+static void dyn_fsync_early_suspend(struct early_suspend *h)
+{
+ mutex_lock(&fsync_mutex);
+ if (dyn_fsync_active) {
+ early_suspend_active = true;
+#if 1
+ /* flush all outstanding buffers */
+ wakeup_flusher_threads(0);
+ sync_filesystems(0);
+ sync_filesystems(1);
+#endif
+ }
+ mutex_unlock(&fsync_mutex);
+}
+
+static void dyn_fsync_late_resume(struct early_suspend *h)
+{
+ mutex_lock(&fsync_mutex);
+ early_suspend_active = false;
+ mutex_unlock(&fsync_mutex);
+}
+
+static struct early_suspend dyn_fsync_early_suspend_handler =
+ {
+ .level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN,
+ .suspend = dyn_fsync_early_suspend,
+ .resume = dyn_fsync_late_resume,
+ };
+
+static int dyn_fsync_init(void)
+{
+ int sysfs_result;
+
+ register_early_suspend(&dyn_fsync_early_suspend_handler);
+
+ 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);
+
+ if (dyn_fsync_kobj != NULL)
+ kobject_put(dyn_fsync_kobj);
+}
+
+module_init(dyn_fsync_init);
+module_exit(dyn_fsync_exit);
+
+MODULE_AUTHOR("Chad Goodman <chad.goodman@gmail.com>");
+MODULE_DESCRIPTION("F/Sync Control");
+MODULE_LICENSE("GPL");
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -163,7 +163,7 @@ do_mpage_readpage(struct bio *bio, struc
sector_t block_in_file;
sector_t last_block;
sector_t last_block_in_file;
- sector_t blocks[MAX_BUF_PER_PAGE];
+ sector_t blocks[MAX_BUF_PER_PAGE] = { 0 };
unsigned page_block;
unsigned first_hole = blocks_per_page;
struct block_device *bdev = NULL;
@@ -456,7 +456,7 @@ static int __mpage_writepage(struct page
const unsigned blocks_per_page = PAGE_CACHE_SIZE >> blkbits;
sector_t last_block;
sector_t block_in_file;
- sector_t blocks[MAX_BUF_PER_PAGE];
+ sector_t blocks[MAX_BUF_PER_PAGE] = { 0 };
unsigned page_block;
unsigned first_unmapped = blocks_per_page;
struct block_device *bdev = NULL;
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -18,6 +18,10 @@
#include <linux/backing-dev.h>
#include "internal.h"
+#ifdef CONFIG_DYNAMIC_FSYNC
+extern bool early_suspend_active;
+#endif
+
#define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \
SYNC_FILE_RANGE_WAIT_AFTER)
@@ -87,7 +91,7 @@ static void sync_one_sb(struct super_blo
* Sync all the data for all the filesystems (called by sys_sync() and
* emergency sync)
*/
-static void sync_filesystems(int wait)
+void sync_filesystems(int wait)
{
iterate_supers(sync_one_sb, &wait);
}
@@ -165,6 +169,12 @@ SYSCALL_DEFINE1(syncfs, int, fd)
*/
int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync)
{
+#ifdef CONFIG_DYNAMIC_FSYNC
+ if (!early_suspend_active)
+ return 0;
+ else {
+#endif
+
struct address_space *mapping = file->f_mapping;
int err, ret;
@@ -187,6 +197,9 @@ int vfs_fsync_range(struct file *file, l
out:
return ret;
+#ifdef CONFIG_DYNAMIC_FSYNC
+ }
+#endif
}
EXPORT_SYMBOL(vfs_fsync_range);
@@ -219,11 +232,21 @@ static int do_fsync(unsigned int fd, int
SYSCALL_DEFINE1(fsync, unsigned int, fd)
{
+#ifdef CONFIG_DYNAMIC_FSYNC
+ if (!early_suspend_active)
+ return 0;
+ else
+#endif
return do_fsync(fd, 0);
}
SYSCALL_DEFINE1(fdatasync, unsigned int, fd)
{
+#ifdef CONFIG_DYNAMIC_FSYNC
+ if (!early_suspend_active)
+ return 0;
+ else
+#endif
return do_fsync(fd, 1);
}
@@ -294,6 +317,12 @@ EXPORT_SYMBOL(generic_write_sync);
SYSCALL_DEFINE(sync_file_range)(int fd, loff_t offset, loff_t nbytes,
unsigned int flags)
{
+#ifdef CONFIG_DYNAMIC_FSYNC
+ if (!early_suspend_active)
+ return 0;
+ else {
+#endif
+
int ret;
struct file *file;
struct address_space *mapping;
@@ -373,6 +402,9 @@ out_put:
fput_light(file, fput_needed);
out:
return ret;
+#ifdef CONFIG_DYNAMIC_FSYNC
+ }
+#endif
}
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
asmlinkage long SyS_sync_file_range(long fd, loff_t offset, loff_t nbytes,
@@ -389,6 +421,11 @@ SYSCALL_ALIAS(sys_sync_file_range, SyS_s
SYSCALL_DEFINE(sync_file_range2)(int fd, unsigned int flags,
loff_t offset, loff_t nbytes)
{
+#ifdef CONFIG_DYNAMIC_FSYNC
+ if (!early_suspend_active)
+ return 0;
+ else
+#endif
return sys_sync_file_range(fd, offset, nbytes, flags);
}
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2054,6 +2054,7 @@ static inline int thaw_bdev(struct block
}
#endif
extern int sync_filesystem(struct super_block *);
+extern void sync_filesystems(int wait);
extern const struct file_operations def_blk_fops;
extern const struct file_operations def_chr_fops;
extern const struct file_operations bad_sock_fops;