[Feature][T108][bug-view-1989] add ext4 file write async for ota files P2

Change-Id: Ifde9601d9963aba991475e2c27f3ee1902ac8a25
diff --git a/config/defconfig_asr1806p301 b/config/defconfig_asr1806p301
index 1b33184..46b16b6 100755
--- a/config/defconfig_asr1806p301
+++ b/config/defconfig_asr1806p301
@@ -3783,6 +3783,7 @@
 # CONFIG_PACKAGE_kmod-tpm-i2c-atmel is not set
 # CONFIG_PACKAGE_kmod-tpm-i2c-infineon is not set
 CONFIG_PACKAGE_kmod-zram=y
+CONFIG_PACKAGE_kmod-opt-cmd-36=y
 # end of Other modules
 
 #
diff --git a/package/kernel/opt-cmd-36/Makefile b/package/kernel/opt-cmd-36/Makefile
new file mode 100755
index 0000000..71b3101
--- /dev/null
+++ b/package/kernel/opt-cmd-36/Makefile
@@ -0,0 +1,68 @@
+#
+# Copyright (C) 2007 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=opt-cmd-36
+PKG_VERSION:=1
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
+PREBUILT_DIR:=$(CURDIR)/files
+
+PKG_MAINTAINER:=<you.chen@mobiletek.cn>
+
+include $(INCLUDE_DIR)/package.mk
+
+define KernelPackage/opt-cmd-36
+  TITLE:=Mbtk Optimize command 36
+  DEPENDS:=@TARGET_mmp
+  FILES:=$(PKG_BUILD_DIR)/opt_cmd_36.ko
+  VERSION:=$(LINUX_VERSION)+$(PKG_NAME)-$(PKG_VERSION)
+endef
+
+define KernelPackage/opt_cmd_36/description
+  Kernel support for Optimize command 36
+endef
+
+EXTRA_CFLAGS:= \
+
+
+MAKE_CMD:=$(MAKE) $(PKG_JOBS) -C "$(LINUX_DIR)" \
+			ARCH="$(LINUX_KARCH)" \
+			CROSS_COMPILE="$(TARGET_CROSS)" \
+			M="$(PKG_BUILD_DIR)" \
+			cmd_ar='rm -f $$$$@; $(TARGET_CROSS)ar cDrs $$$$@ $$$$(real-prereqs)' \
+			EXTRA_CFLAGS="$(EXTRA_CFLAGS)"
+
+
+CLEAN_CMD:=rm -rf $(PKG_BUILD_DIR)/{*.o,*.mod.*,modules.order,Module.symvers,ipkg-*,*.ko,*.a,ipkg-*} \
+			rm -rf $(MRVLDIR)/fastpath/{*.o,*.mod.*,modules.order,Module.symvers,ipkg-*,*.ko,*.a,ipkg-*}
+
+define Build/Prepare/Prebuilt
+	@rm -rf $(PKG_BUILD_DIR)
+endef
+
+$(STAMP_PREPARED): FORCE
+
+define Build/Prepare
+	@mkdir -p $(PKG_BUILD_DIR)
+	@cp -rf $(PREBUILT_DIR)/* $(PKG_BUILD_DIR)
+endef
+
+define Build/Compile
+	$(MAKE_CMD) modules
+	mkdir -p $(BIN_DIR)/symbol/modules
+	cp -rf $(PKG_BUILD_DIR)/opt_cmd_36.o $(BIN_DIR)/symbol/modules/
+endef
+
+define Build/Clean
+	$(if $(wildcard $(USE_SOURCE_DIR)), $(CLEAN_CMD),)
+endef
+
+$(eval $(call KernelPackage,opt-cmd-36))
diff --git a/package/kernel/opt-cmd-36/files/Kconfig b/package/kernel/opt-cmd-36/files/Kconfig
new file mode 100755
index 0000000..4ea775f
--- /dev/null
+++ b/package/kernel/opt-cmd-36/files/Kconfig
@@ -0,0 +1,20 @@
+
+config MRVL_FASTPATH
+	tristate "Marvell Fastpath"
+	default m
+	depends on NF_CT_NETLINK && NF_CONNTRACK_FASTPATH
+	select NETIF_RX_FASTPATH_HOOK
+	help
+		Enable marvell fastpath in the application processor
+
+if !NF_CT_NETLINK || !NF_CONNTRACK_FASTPATH
+
+comment "Fastpath support disabled"
+
+comment "NF_CT_NETLINK disabled"
+	depends on !NF_CT_NETLINK
+
+comment "NF_CONNTRACK_FASTPATH disabled"
+	depends on !NF_CONNTRACK_FASTPATH
+	
+endif
diff --git a/package/kernel/opt-cmd-36/files/Makefile b/package/kernel/opt-cmd-36/files/Makefile
new file mode 100755
index 0000000..64de5a5
--- /dev/null
+++ b/package/kernel/opt-cmd-36/files/Makefile
@@ -0,0 +1,20 @@
+ifneq ($(KERNELRELEASE),)
+
+obj-m := opt_cmd_36.o
+
+opt_cmd_36-y :=	hook_ext4.o
+
+else
+
+all:
+	@echo
+	@echo "usage:"
+	@echo "      make -C <kernel_build_dir> M=\`pwd\` ARCH=arm CROSS_COMPILE=<...> modules"
+	@echo
+	$(error)
+clean:
+	rm -f *.o .*.cmd modules.order Module.symvers mfp.ko mfp.mod.c
+	rm -rf .tmp_versions
+
+endif
+
diff --git a/package/kernel/opt-cmd-36/files/hook_ext4.c b/package/kernel/opt-cmd-36/files/hook_ext4.c
new file mode 100755
index 0000000..f71adc1
--- /dev/null
+++ b/package/kernel/opt-cmd-36/files/hook_ext4.c
@@ -0,0 +1,680 @@
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/uio.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/interrupt.h>
+
+extern char *d_path(const struct path *, char *, int);
+static struct file_operations org_operations;
+static struct file_operations hooked_operations;
+static struct inode_operations org_inode_operations;
+static struct file_operations *p_curr_file_operations;
+
+static char opt_file_name[256] = {0};
+static char * hooked_files[32] = {
+	"/media/download/mdm.download",
+	"/media/download/sbl.download",
+	"/media/download/mcu_a.download",
+	"/media/download/mcu_b.download",
+	"/media/download/ble.download",
+	"/media/download/file.download",
+	"/media/download/runtime_file",
+	"/media/download/swk1",
+	"/media/download/swk2",
+	0,
+};
+static int g_hooked_file_cnt = 0;
+static spinlock_t my_lock;
+static struct work_struct my_work;
+static struct work_struct rename_file_work;
+static loff_t g_next_pos;
+static loff_t g_ki_pos;
+static bool g_scheduled = false;
+static struct file * g_hooked_file_filp;
+static const char * g_hooked_file_name;
+static char g_hooked_tmp_file[256];
+static bool g_hooked_tmp_file_writen;
+static char * g_last_hook_file = NULL;
+
+struct cached_items_type
+{
+	struct file * filp;
+	void * cached_buffer;
+	int cached_buffer_len;
+	loff_t curr_offset;
+	void * allocate_ptr;
+};
+
+struct cached_buffer_type
+{
+	void * cached_buffer;
+	void * ptr;
+};
+
+#define BUF_CNT_MASK 0xff
+#define ITEM_CNT_MASK 0xfff
+static struct cached_items_type cached_items[ITEM_CNT_MASK + 1] = {0};
+static struct cached_buffer_type g_buffers[BUF_CNT_MASK+1] = {0};
+static int head_pos = 0;
+static int tail_pos = 0;
+static int max_cnt = 0;
+
+static int buffer_head_pos = 0;
+static int buffer_tail_pos = BUF_CNT_MASK;
+
+static size_t init_and_push_item(struct file *filp, struct kiocb *iocb, struct iov_iter *from)
+{
+	unsigned long flags;
+	int index = (tail_pos) & ITEM_CNT_MASK;
+	int ret, buffer_index;
+	loff_t local_pos = 0;
+	size_t cnt = 0;
+	//if (iocb != NULL)
+	if (g_next_pos != -1)
+	{
+		if (g_next_pos != g_ki_pos)
+			printk("cy: next pos %ld current :%ld\n", g_next_pos);
+		local_pos = g_next_pos;
+		g_next_pos = -1;
+		// if (local_pos != 0 && g_ki_pos != local_pos) {
+		// 	printk("cy: got pos %ld, curr %ld\n", local_pos, g_ki_pos);
+		// }
+	}
+	else
+	{
+		local_pos = g_ki_pos;
+	}
+
+	cnt = iov_iter_count(from);
+	if (buffer_head_pos >= buffer_tail_pos || cnt > 16*PAGE_SIZE)
+	{
+		cached_items[index].allocate_ptr = kmalloc((cnt/PAGE_SIZE + 2)*PAGE_SIZE, GFP_KERNEL);
+		if (cached_items[index].allocate_ptr == NULL)
+			return 0;
+		cached_items[index].cached_buffer = (char*)((((long long)cached_items[index].allocate_ptr)/PAGE_SIZE + 1)*PAGE_SIZE);
+	}
+	else
+	{
+		buffer_index = (buffer_head_pos++ & BUF_CNT_MASK);
+		cached_items[index].allocate_ptr = NULL;
+		cached_items[index].cached_buffer = g_buffers[buffer_index].cached_buffer;
+	}
+
+	cached_items[index].filp = filp;
+	ret = copy_from_iter(cached_items[index].cached_buffer, cnt, from);
+	cached_items[index].cached_buffer_len = cnt;
+	cached_items[index].curr_offset = local_pos;
+	g_ki_pos = local_pos + cnt;
+
+	tail_pos++;
+	if (!g_scheduled)
+	{
+		g_scheduled = true;
+		schedule_work(&my_work);
+	}
+	return cnt;
+}
+
+struct cached_items_type * get_head_item(void)
+{
+	if (head_pos >= tail_pos)
+		return NULL;
+	return &cached_items[head_pos++ & ITEM_CNT_MASK];
+}
+
+static int my_ext4_file_open(struct inode * inode, struct file * filp)
+{
+	int i, j, ret, found;
+	unsigned long flags;
+	struct file * local_file;
+	char buff[256];
+	ret = org_operations.open(inode, filp);
+	//ret = 0;
+	if (ret == 0)
+	{
+		found = 0;
+		for(i=0; i<32 && found < g_hooked_file_cnt; i++) {
+			if (hooked_files[i] != NULL && strcmp(hooked_files[i], file_path(filp, buff, 256)) == 0)
+			{
+				printk("found hooked file11, %s write ptr %p private_data %p\n", hooked_files[i], filp->f_op->write, filp->private_data);
+
+				for(j=0;j<5;j++) {
+					if (g_hooked_file_filp != NULL)
+						usleep_range(2000,2100);
+					else
+						break;
+				}
+				if (g_hooked_file_filp != NULL)
+				{
+					if (g_last_hook_file == NULL || strcmp(hooked_files[i], g_last_hook_file) != 0)
+						break;
+					
+					for(j=0;j<100;j++) {
+						if (g_hooked_file_filp != NULL)
+							usleep_range(20000,21000);
+						else
+							break;
+					}
+				}
+
+				spin_lock_irqsave(&my_lock, flags);
+				head_pos = 0;
+				tail_pos = 0;
+				max_cnt = 0;
+				g_ki_pos = 0;
+				buffer_head_pos = 0;
+				buffer_tail_pos = BUF_CNT_MASK;
+				g_last_hook_file = hooked_files[i];
+				p_curr_file_operations->open = org_operations.open;
+				spin_unlock_irqrestore(&my_lock, flags);
+
+				g_hooked_tmp_file_writen = false;
+				g_hooked_file_name = hooked_files[i];
+				sprintf(g_hooked_tmp_file, "%s.dl", hooked_files[i]);
+				printk("cy: after name is %s\n", g_hooked_tmp_file);
+				local_file = filp_open(g_hooked_tmp_file, O_RDWR | O_CREAT | O_TRUNC, 0644);
+
+				spin_lock_irqsave(&my_lock, flags);
+				if (!IS_ERR(local_file))
+				{
+					g_hooked_file_filp = local_file;
+					filp->private_data = local_file;
+					filp->f_op = &hooked_operations;
+				}
+				else
+				{
+					g_hooked_file_filp = NULL;
+				}
+				p_curr_file_operations->open = my_ext4_file_open;
+				spin_unlock_irqrestore(&my_lock, flags);
+				break;
+			}
+			else if (hooked_files[i] != NULL) {
+				found++;
+			}
+		}
+		//dump_stack();
+	}
+	return ret;
+}
+
+static loff_t my_ext4_llseek(struct file *file, loff_t offset, int whence)
+{
+	//printk("cy: %s, %ld, %d\n", __func__, offset, whence);
+	if (whence == SEEK_SET) {
+		g_next_pos = offset;
+		if (g_hooked_tmp_file_writen)
+			return offset;
+		else
+			return org_operations.llseek(file, offset, whence);
+	}
+	else
+	{
+		printk("unhandle %d\n", whence);
+		return org_operations.llseek(file, offset, whence);
+	}
+}
+
+static ssize_t my_ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
+{	
+	printk("cy: %s\n", __func__);
+	return org_operations.read_iter(iocb, to);
+}
+
+static ssize_t my_ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
+{
+
+	int i, ret;
+	int left_cnt, waited = 0;
+	loff_t write_cnt=0;
+	for (i=0; i<40;i++)
+	{
+		left_cnt = tail_pos - head_pos;
+		if ( left_cnt> max_cnt){
+			max_cnt = left_cnt;
+			if ((max_cnt & 0x1f) == 0)
+				printk("cy: got max %d", max_cnt);
+		}
+		if (left_cnt < ITEM_CNT_MASK)
+		{
+			break;
+		}
+		if (!g_scheduled)
+		{
+			g_scheduled = true;
+			schedule_work(&my_work);
+		}
+		waited = 1;
+		usleep_range(1000,1100);
+	}
+
+	if (i >= 40) {
+		printk("cy: write fail\n");
+		return -1;
+	}
+	else if (i > 1){
+		printk("cy: got full\n");
+	}
+
+	//printk("cy: my_ext4_file_write_iter %p\n", iocb->ki_filp->private_data);
+	if (iocb->ki_filp->private_data != NULL)
+	{
+		write_cnt = init_and_push_item(iocb->ki_filp->private_data, iocb, from);
+		g_hooked_tmp_file_writen = true;
+	}
+
+	// if (left_cnt > 64)
+	// 	usleep_range(7000,7100);
+	// else if (left_cnt > 32)
+	// 	usleep_range(5000,5100);
+	// else if (left_cnt > 8)
+	// 	usleep_range(3000,3100);
+	// else if (left_cnt > 1 && !waited)
+	//	usleep_range(500,600);
+	return write_cnt;
+}
+
+static int my_ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
+{
+	printk("cy: %s\n", __func__);
+	return org_operations.fsync(file, start, end, datasync);
+}
+
+static int my_ext4_release_file(struct inode *inode, struct file *filp)
+{
+	int i, ret;
+	// struct file *local_filp=NULL;
+	char buff[256];
+	char buff2[256];
+	char * file_name;
+	//printk("cy: %s\n", __func__);
+	if (filp == NULL)
+		return -1;
+	// dump_stack();
+	for (i=0; i<40;i++)
+	{
+		if (tail_pos == head_pos)
+			break;
+		usleep_range(300,350);
+	}
+
+	//printk("cy: close file wait count %d\n", i);
+	if (filp->private_data != NULL)
+	{
+		filp->private_data = 0;
+	}
+	ret = org_operations.release(inode, filp);
+	if (g_hooked_file_filp != NULL)
+	{
+		schedule_work(&rename_file_work);
+	}
+	return ret;
+}
+
+static void my_callback(struct work_struct *work)
+{
+	ssize_t ret;
+	loff_t local_pos = 0;
+	struct cached_items_type * p;
+	p = get_head_item();
+	// if (p != NULL)
+	// 	usleep_range(200,250);
+	
+	while(p != NULL) {
+		local_pos = p->curr_offset;
+		ret = __kernel_write(p->filp, p->cached_buffer, p->cached_buffer_len, &local_pos);
+		//g_ki_pos = p->curr_offset + p->cached_buffer_len;
+		if (p->allocate_ptr)
+		{
+			kfree(p->allocate_ptr);
+			p->allocate_ptr = NULL;
+			p->cached_buffer = NULL;
+		}
+		else
+		{
+			buffer_tail_pos++;
+			p->cached_buffer = NULL;
+		}
+		p = get_head_item();
+	}
+	g_scheduled = false;
+}
+
+static void rename_file_callback(struct work_struct *work)
+{
+	int ret, i;
+	struct path old_path, new_path;
+    struct dentry *old_dentry, *new_dentry;
+	if (g_hooked_file_filp == NULL)
+		return;
+	printk("cy4: close ld file finish\n");
+	if (!g_hooked_tmp_file_writen)
+	{
+		ret = filp_close(g_hooked_file_filp, 0);
+		g_hooked_file_filp = NULL;
+		return;
+	}
+	printk("cy: head pos %d, tail pos %d\n", head_pos, tail_pos);
+	if (!g_scheduled) // write thread not running, check again
+	{
+		printk("cy: not g_scheduled\n");
+		my_callback(&my_work);
+	}
+	for (i=0; i<5000;i++)
+	{
+		if (head_pos == tail_pos)
+		{
+			break;
+		}
+		if (!g_scheduled)
+		{
+			printk("cy: not g_scheduled 2\n");
+			my_callback(&my_work);
+			break;
+		}
+		usleep_range(1000,1100);
+		if ((i & 0x3ff) == 0 )
+			printk("cy: wait file write done, sleep again\n");
+	}
+	printk("cy: wait times %d\n", i);
+	ret = filp_close(g_hooked_file_filp, 0);
+	g_hooked_file_filp = NULL;
+	ret = kern_path(g_hooked_tmp_file, LOOKUP_PARENT, &old_path);
+	if (ret != 0)
+		goto out2;
+	ret = kern_path(g_hooked_file_name, LOOKUP_PARENT, &new_path);
+	if (ret != 0)
+		goto out1;
+
+	old_dentry = old_path.dentry;
+	new_dentry = new_path.dentry;
+	if (old_dentry != NULL && new_dentry != NULL && old_path.dentry->d_parent != NULL && new_path.dentry->d_parent != NULL)
+	{
+		ret = vfs_rename(old_path.dentry->d_parent->d_inode, old_dentry, new_path.dentry->d_parent->d_inode, new_dentry, NULL, RENAME_EXCHANGE);
+	}
+	else
+	{
+		printk("cy: got null ptr\n");
+	}
+	path_put(&new_path);
+out1:
+	path_put(&old_path);
+out2:
+	g_hooked_tmp_file_writen = false;
+	printk("cy:rename file finish\n");
+}
+
+#define DEBUGFS_READ_FUNC(name)                                         \
+    static ssize_t asr_dbgfs_##name##_read(struct file *file,          \
+                                            char __user *user_buf,      \
+                                            size_t count, loff_t *ppos);
+
+#define DEBUGFS_WRITE_FUNC(name)                                         \
+    static ssize_t asr_dbgfs_##name##_write(struct file *file,          \
+                                             const char __user *user_buf,\
+                                             size_t count, loff_t *ppos);
+
+
+#define DEBUGFS_ADD_FILE(name, parent, mode) do {               \
+    if (!debugfs_create_file(#name, mode, parent, NULL,      \
+                &asr_dbgfs_##name##_ops))                      \
+    goto err;                                                   \
+} while (0)
+
+#define DEBUGFS_WRITE_FILE_OPS(name)                            \
+    DEBUGFS_WRITE_FUNC(name);                                   \
+static const struct file_operations asr_dbgfs_##name##_ops = { \
+    .write  = asr_dbgfs_##name##_write,                        \
+    .open   = simple_open,                                      \
+    .llseek = generic_file_llseek,                              \
+};
+
+#define DEBUGFS_READ_FILE_OPS(name)                             \
+    DEBUGFS_READ_FUNC(name);                                    \
+static const struct file_operations asr_dbgfs_##name##_ops = { \
+    .read   = asr_dbgfs_##name##_read,                         \
+    .open   = simple_open,                                      \
+    .llseek = generic_file_llseek,                              \
+};
+
+static void strip_enter(char * buf, int len){
+	int i;
+	for(i=0;i<len;i++) {
+		if (buf[i] == '\r' || buf[i] == '\n' || buf[i]=='\0') {
+			buf[i] = '\0';
+			return;
+		}
+	}
+}
+
+static ssize_t asr_dbgfs_add_hook_write(struct file *file,
+                                          const char __user *user_buf,
+                                          size_t count, loff_t *ppos)
+{
+	int i;
+	char buf[256]={0};
+	size_t len = min_t(size_t, sizeof(buf) - 1, count);
+	printk("cy: add hook count %d\n", count);
+	if (copy_from_user(buf, user_buf, len))
+        return -EFAULT;
+	strip_enter(buf, 256);
+	printk("cy: add hook buf %s\n", buf);
+	for(i=0;i<32;i++) {
+		if (hooked_files[i] == NULL) {
+			hooked_files[i] = kmalloc(count+1, GFP_KERNEL);
+			strcpy(hooked_files[i], buf);
+			g_hooked_file_cnt++;
+			break;
+		}
+	}
+	if (i >= 32)
+		return  -EFAULT;
+	return count;
+}
+DEBUGFS_WRITE_FILE_OPS(add_hook);
+
+static ssize_t asr_dbgfs_del_hook_write(struct file *file,
+                                          const char __user *user_buf,
+                                          size_t count, loff_t *ppos)
+{
+	int i;
+	char buf[256]={0};
+	size_t len = min_t(size_t, sizeof(buf) - 1, count);
+	printk("cy: del hook count %d\n", count);
+	if (copy_from_user(buf, user_buf, len))
+        return -EFAULT;
+
+	strip_enter(buf, 256);
+	printk("cy: del hook buf %s\n", buf);
+	for(i=0;i<32;i++) {
+		if (hooked_files[i] != NULL && strcmp(hooked_files[i], buf) == 0) {
+			hooked_files[i] = NULL;
+			g_hooked_file_cnt--;
+			break;
+		}
+	}
+	if (i >= 32)
+		return  -EFAULT;
+	return count;
+}
+DEBUGFS_WRITE_FILE_OPS(del_hook);
+
+static ssize_t asr_dbgfs_show_all_read(struct file *file,
+                                        char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+	int i, found, ret, read;
+	char *buf;
+	int bufsz = 256 * g_hooked_file_cnt;
+	buf = kmalloc(bufsz, GFP_ATOMIC);
+    if (buf == NULL)
+        return 0;
+	found = 0;
+	ret = 0;
+	for(i=0;i<32 && found < g_hooked_file_cnt;i++) {
+		if (hooked_files[i] != NULL) {
+			found++;
+			ret += scnprintf(&buf[ret], 258, "%s\n", hooked_files[i]);
+		}
+	}
+	read = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+    kfree(buf);
+
+    return read;
+}
+DEBUGFS_READ_FILE_OPS(show_all);
+
+static struct dentry * hook_root=NULL;
+
+static int asr_dbgfs_register(void)
+{
+	if (!(hook_root = debugfs_create_dir("opt_cmd_36",NULL)))
+		return -1;
+	DEBUGFS_ADD_FILE(add_hook, hook_root, S_IWUSR | S_IRUSR);
+	DEBUGFS_ADD_FILE(del_hook, hook_root, S_IWUSR | S_IRUSR);
+	DEBUGFS_ADD_FILE(show_all, hook_root, S_IRUSR);
+	return 0;
+err:
+	debugfs_remove_recursive(hook_root);
+	return -1;
+}
+
+static void asr_dbgfs_unregister(void)
+{
+	if (hook_root != NULL)
+	{
+		debugfs_remove_recursive(hook_root);
+		hook_root = NULL;
+	}
+}
+
+static int __init opt_cmd_36_init(void)
+{
+	int ret, i;
+	unsigned long flags;
+	struct file *filp;
+	char * ptr;
+    char *filename = "/media/.test_create";
+	g_hooked_file_filp = NULL;
+	g_hooked_tmp_file_writen = false;
+
+	for(i=0; i<32;i++) {
+		if (hooked_files[i] != NULL) {
+			printk("cy: got %s\n", hooked_files[i]);
+			g_hooked_file_cnt++;
+		}
+		else if (strlen(opt_file_name) > 0)
+		{
+			hooked_files[i] = opt_file_name;
+			g_hooked_file_cnt++;
+			break;
+		}
+	}
+	filp = filp_open(filename, O_RDONLY | O_CREAT, 0644);
+    if (IS_ERR(filp) || filp->f_op == NULL) {
+        printk(KERN_ERR "Failed to open file: %ld\n", PTR_ERR(filp));
+		return -1;
+    }
+
+	printk("cy11: opt_cmd_36_init param [%s]\n", opt_file_name);
+	INIT_WORK(&my_work, my_callback);
+	INIT_WORK(&rename_file_work, rename_file_callback);
+
+	for(i=0;i<=BUF_CNT_MASK;i++)
+	{
+		g_buffers[i].ptr = kmalloc(32*PAGE_SIZE, GFP_KERNEL);
+		ptr = (char*)((((long long)g_buffers[i].ptr)/PAGE_SIZE + 1)*PAGE_SIZE);
+		g_buffers[i].cached_buffer = ptr;
+		//cached_items[i].org_ptr = kmalloc(32*PAGE_SIZE, GFP_KERNEL);
+		//ptr = (char*)((((long long)cached_items[i].org_ptr)/PAGE_SIZE + 1)*PAGE_SIZE);
+		//cached_items[i].cached_buffer = ptr;
+	}
+
+	spin_lock_irqsave(&my_lock, flags);
+	p_curr_file_operations = filp->f_op;
+
+    org_operations.llseek = p_curr_file_operations->llseek;
+    org_operations.read_iter      = p_curr_file_operations->read_iter;
+    org_operations.write_iter     = p_curr_file_operations->write_iter;
+    org_operations.unlocked_ioctl = p_curr_file_operations->unlocked_ioctl;
+#ifdef CONFIG_COMPAT
+    org_operations.compat_ioctl   = p_curr_file_operations->compat_ioctl;
+#endif
+    org_operations.mmap           = p_curr_file_operations->mmap;
+    org_operations.mmap_supported_flags = p_curr_file_operations->mmap_supported_flags;
+    org_operations.open           = p_curr_file_operations->open;
+    org_operations.release        = p_curr_file_operations->release;
+    org_operations.fsync          = p_curr_file_operations->fsync;
+    org_operations.get_unmapped_area = p_curr_file_operations->get_unmapped_area;
+    org_operations.splice_read    = p_curr_file_operations->splice_read;
+    org_operations.splice_write   = p_curr_file_operations->splice_write;
+    org_operations.fallocate      = p_curr_file_operations->fallocate;
+
+    hooked_operations.llseek = my_ext4_llseek;
+	//hooked_operations.write = hooked_write;
+    //hooked_operations.read_iter      = my_ext4_file_read_iter;
+	hooked_operations.read_iter      = p_curr_file_operations->read_iter;
+    hooked_operations.write_iter     = my_ext4_file_write_iter;
+	//hooked_operations.write_iter     = p_curr_file_operations->write_iter;
+    hooked_operations.unlocked_ioctl = p_curr_file_operations->unlocked_ioctl;
+#ifdef CONFIG_COMPAT
+    hooked_operations.compat_ioctl   = p_curr_file_operations->compat_ioctl;
+#endif
+    hooked_operations.mmap           = p_curr_file_operations->mmap;
+    hooked_operations.mmap_supported_flags = p_curr_file_operations->mmap_supported_flags;
+    hooked_operations.open           = p_curr_file_operations->open;
+    //hooked_operations.release        = p_curr_file_operations->release;
+	hooked_operations.release        = my_ext4_release_file;
+    //hooked_operations.fsync          = p_curr_file_operations->fsync;	
+    hooked_operations.fsync          = my_ext4_sync_file;
+    hooked_operations.get_unmapped_area = p_curr_file_operations->get_unmapped_area;
+    hooked_operations.splice_read    = p_curr_file_operations->splice_read;
+    hooked_operations.splice_write   = p_curr_file_operations->splice_write;
+    hooked_operations.fallocate      = p_curr_file_operations->fallocate;
+
+	p_curr_file_operations->open = my_ext4_file_open;
+	spin_unlock_irqrestore(&my_lock, flags);
+
+	ret = filp_close(filp, 0);
+
+	asr_dbgfs_register();
+
+	pr_debug("init done\n");
+	return 0;
+
+}
+
+
+static void __exit opt_cmd_36_exit(void)
+{
+	int i;
+	unsigned long flags;
+	spin_lock_irqsave(&my_lock, flags);
+	p_curr_file_operations->open = org_operations.open;
+	spin_unlock_irqrestore(&my_lock, flags);
+	
+	for(i=0;i<=BUF_CNT_MASK;i++)
+	{
+		// if (cached_items[i].org_ptr != NULL)
+		// 	kfree(cached_items[i].org_ptr);
+		if (g_buffers[i].ptr != NULL)
+			kfree(g_buffers[i].ptr);
+	}
+
+	asr_dbgfs_unregister();
+
+	pr_debug("exit done\n");
+}
+
+module_param_string(opt_file_name, opt_file_name, 256, 0);
+
+module_init(opt_cmd_36_init)
+module_exit(opt_cmd_36_exit)
+
+MODULE_LICENSE("GPL");