Change-Id: Ia97972540645d4b40cffaafd92189546a7be2805 Signed-off-by: Pranaya Deomani <pranayadeomani@protonmail.com>
122 lines
3.2 KiB
C
Executable File
122 lines
3.2 KiB
C
Executable File
/***********************************************************
|
|
** Copyright (C), 2008-2019, OPPO Mobile Comm Corp., Ltd.
|
|
** VENDOR_EDIT
|
|
** File: - panic_flush.c
|
|
** Description: code to flush device cache in panic
|
|
**
|
|
** Version: 1.0
|
|
** Date : 2019/08/27
|
|
** Author: yanwu@TECH.Storage.FS, add code to flush device cache in panic
|
|
**
|
|
** ------------------ Revision History:------------------------
|
|
** <author> <data> <version > <desc>
|
|
** yanwu 2019/08/27 1.0 add the file
|
|
****************************************************************/
|
|
|
|
#define DEBUG
|
|
#include <linux/wait.h>
|
|
#include <linux/module.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/blkdev.h>
|
|
#include <linux/kthread.h>
|
|
|
|
#define PANIC_FLUSH_POLL_MS (10)
|
|
struct panic_flush_control {
|
|
struct task_struct *flush_thread;
|
|
wait_queue_head_t flush_wq;
|
|
atomic_t flush_issuing;
|
|
atomic_t flush_issued;
|
|
};
|
|
|
|
static struct panic_flush_control *pfc;
|
|
static void panic_issue_flush(struct super_block *sb ,void *arg)
|
|
{
|
|
int ret = -1;
|
|
int *flush_count = (int *)arg;
|
|
if (!(sb->s_flags & MS_RDONLY) && NULL != sb->s_bdev) {
|
|
ret = blkdev_issue_flush(sb->s_bdev, GFP_KERNEL, NULL);
|
|
}
|
|
if (!ret) {
|
|
(*flush_count)++;
|
|
pr_emerg("blkdev_issue_flush before panic return %d\n", *flush_count);
|
|
}
|
|
}
|
|
|
|
static int panic_flush_thread(void *data)
|
|
{
|
|
int flush_count = 0;
|
|
repeat:
|
|
if (kthread_should_stop())
|
|
return 0;
|
|
|
|
wait_event(pfc->flush_wq, kthread_should_stop() || atomic_read(&pfc->flush_issuing) > 0);
|
|
if (atomic_read(&pfc->flush_issuing) > 0) {
|
|
iterate_supers(panic_issue_flush, &flush_count);
|
|
pr_emerg("Up to now, total %d panic_issue_flush_count\n", flush_count);
|
|
atomic_inc(&pfc->flush_issued);
|
|
atomic_dec(&pfc->flush_issuing);
|
|
}
|
|
goto repeat;
|
|
}
|
|
|
|
extern int sysctl_ext4_fsync_enable;
|
|
int panic_flush_device_cache(int timeout)
|
|
{
|
|
pr_emerg("%s\n", __func__);
|
|
if (!pfc || !sysctl_ext4_fsync_enable) {
|
|
pr_emerg("%s: skip flush device cache\n", __func__);
|
|
return timeout;
|
|
}
|
|
|
|
if (atomic_inc_return(&pfc->flush_issuing) == 1 &&
|
|
waitqueue_active(&pfc->flush_wq)) {
|
|
pr_emerg("%s: flush device cache\n", __func__);
|
|
atomic_set(&pfc->flush_issued, 0);
|
|
wake_up(&pfc->flush_wq);
|
|
while (timeout > 0 && atomic_read(&pfc->flush_issued) == 0) {
|
|
mdelay(PANIC_FLUSH_POLL_MS);
|
|
timeout -= PANIC_FLUSH_POLL_MS;
|
|
}
|
|
pr_emerg("%s: remaining timeout = %d\n", __func__, timeout);
|
|
}
|
|
return timeout;
|
|
}
|
|
|
|
static int __init create_panic_flush_control(void)
|
|
{
|
|
int err = 0;
|
|
pr_debug("%s\n", __func__);
|
|
pfc = kzalloc(sizeof(*pfc), GFP_KERNEL);
|
|
if (!pfc) {
|
|
pr_err("%s: fail to allocate memory\n", __func__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
init_waitqueue_head(&pfc->flush_wq);
|
|
atomic_set(&pfc->flush_issuing, 0);
|
|
atomic_set(&pfc->flush_issued, 0);
|
|
pfc->flush_thread = kthread_run(panic_flush_thread, pfc, "panic_flush");
|
|
if (IS_ERR(pfc->flush_thread)) {
|
|
err = PTR_ERR(pfc->flush_thread);
|
|
kfree(pfc);
|
|
pfc = NULL;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
static void __exit destroy_panic_flush_control(void)
|
|
{
|
|
pr_debug("%s\n", __func__);
|
|
if (pfc && pfc->flush_thread) {
|
|
pr_debug("%s: stop panic_flush thread\n", __func__);
|
|
kthread_stop(pfc->flush_thread);
|
|
kfree(pfc);
|
|
pfc = NULL;
|
|
}
|
|
}
|
|
module_init(create_panic_flush_control);
|
|
module_exit(destroy_panic_flush_control);
|
|
MODULE_DESCRIPTION("OPPO panic flush control");
|
|
MODULE_LICENSE("GPL v2");
|
|
|