From: Chad Goodman Date: Sun, 25 Nov 2012 07:42:10 +0000 (-0800) Subject: FILESYSTEM: dynamic f/sync X-Git-Url: https://ziggy471.com/git/gitweb.cgi?p=ziggy471-sgs3-jb.git;a=commitdiff;h=a4ce669b711b1db61c39192014ce243fb9cf23c7 FILESYSTEM: dynamic f/sync Signed-off-by: Ziggy --- --- 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 +#include +#include +#include +#include + +#include + +#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 "); +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 #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;