This patch adds debugger log flushing support in kernel via .fsync()
callback. The in-kernel flushing is more efficient, because it reduces
useless log IOs by bypassing log user_read/kern_write during the flush
period.

Signed-off-by: Lv Zheng <lv.zh...@intel.com>
---
 drivers/acpi/acpi_dbg.c |   94 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 90 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
index dee8692..90d6922 100644
--- a/drivers/acpi/acpi_dbg.c
+++ b/drivers/acpi/acpi_dbg.c
@@ -46,6 +46,8 @@
 #define ACPI_AML_KERN          (ACPI_AML_IN_KERN | ACPI_AML_OUT_KERN)
 #define ACPI_AML_BUSY          (ACPI_AML_USER | ACPI_AML_KERN)
 #define ACPI_AML_OPEN          (ACPI_AML_OPENED | ACPI_AML_CLOSED)
+#define ACPI_AML_FLUSHING_LOG  0x0040 /* flushing log output */
+#define ACPI_AML_WAITING_CMD   0x0080 /* waiting for cmd input */
 
 struct acpi_aml_io {
        wait_queue_head_t wait;
@@ -120,6 +122,20 @@ static inline bool __acpi_aml_busy(void)
        return false;
 }
 
+static inline bool __acpi_aml_waiting_cmd(void)
+{
+       if (acpi_aml_io.flags & ACPI_AML_WAITING_CMD)
+               return true;
+       return false;
+}
+
+static inline bool __acpi_aml_flushing_log(void)
+{
+       if (acpi_aml_io.flags & ACPI_AML_FLUSHING_LOG)
+               return true;
+       return false;
+}
+
 static inline bool __acpi_aml_opened(void)
 {
        if (acpi_aml_io.flags & ACPI_AML_OPEN)
@@ -152,6 +168,26 @@ static bool acpi_aml_busy(void)
        return ret;
 }
 
+static inline bool acpi_aml_waiting_cmd(void)
+{
+       bool ret;
+
+       mutex_lock(&acpi_aml_io.lock);
+       ret = __acpi_aml_waiting_cmd();
+       mutex_unlock(&acpi_aml_io.lock);
+       return ret;
+}
+
+static inline bool acpi_aml_flushing_log(void)
+{
+       bool ret;
+
+       mutex_lock(&acpi_aml_io.lock);
+       ret = __acpi_aml_flushing_log();
+       mutex_unlock(&acpi_aml_io.lock);
+       return ret;
+}
+
 static bool acpi_aml_used(void)
 {
        bool ret;
@@ -183,7 +219,8 @@ static bool acpi_aml_kern_writable(void)
 
        mutex_lock(&acpi_aml_io.lock);
        ret = !__acpi_aml_access_ok(ACPI_AML_OUT_KERN) ||
-             __acpi_aml_writable(&acpi_aml_io.out_crc, ACPI_AML_OUT_KERN);
+             __acpi_aml_writable(&acpi_aml_io.out_crc, ACPI_AML_OUT_KERN) ||
+             __acpi_aml_flushing_log();
        mutex_unlock(&acpi_aml_io.lock);
        return ret;
 }
@@ -264,6 +301,9 @@ static int acpi_aml_write_kern(const char *buf, int len)
        int n;
        char *p;
 
+       if (acpi_aml_flushing_log())
+               return len;
+
        ret = acpi_aml_lock_write(crc, ACPI_AML_OUT_KERN);
        if (ret < 0)
                return ret;
@@ -458,9 +498,18 @@ static int acpi_aml_wait_command_ready(bool single_step,
        else
                acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
 
+       mutex_lock(&acpi_aml_io.lock);
+       acpi_aml_io.flags |= ACPI_AML_WAITING_CMD;
+       wake_up_interruptible(&acpi_aml_io.wait);
+       mutex_unlock(&acpi_aml_io.lock);
+
        status = acpi_os_get_line(buffer, length, NULL);
        if (ACPI_FAILURE(status))
                return -EINVAL;
+
+       mutex_lock(&acpi_aml_io.lock);
+       acpi_aml_io.flags &= ~ACPI_AML_WAITING_CMD;
+       mutex_unlock(&acpi_aml_io.lock);
        return 0;
 }
 
@@ -593,9 +642,11 @@ static int acpi_aml_read_user(char __user *buf, int len)
        smp_rmb();
        p = &crc->buf[crc->tail];
        n = min(len, circ_count_to_end(crc));
-       if (copy_to_user(buf, p, n)) {
-               ret = -EFAULT;
-               goto out;
+       if (!acpi_aml_flushing_log()) {
+               if (copy_to_user(buf, p, n)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
        }
        /* sync tail after removing logs */
        smp_mb();
@@ -731,10 +782,45 @@ static unsigned int acpi_aml_poll(struct file *file, 
poll_table *wait)
        return masks;
 }
 
+static int acpi_aml_flush(void)
+{
+       int ret;
+
+       /*
+        * Discard output buffer and put the driver into a state waiting
+        * for the new user input.
+        */
+       mutex_lock(&acpi_aml_io.lock);
+       acpi_aml_io.flags |= ACPI_AML_FLUSHING_LOG;
+       mutex_unlock(&acpi_aml_io.lock);
+
+       ret = wait_event_interruptible(acpi_aml_io.wait,
+               acpi_aml_waiting_cmd());
+       (void)acpi_aml_read_user(NULL, ACPI_AML_BUF_SIZE);
+
+       mutex_lock(&acpi_aml_io.lock);
+       acpi_aml_io.flags &= ~ACPI_AML_FLUSHING_LOG;
+       mutex_unlock(&acpi_aml_io.lock);
+       return ret;
+}
+
+static int acpi_aml_fsync(struct file *file,
+                         loff_t start, loff_t end, int datasync)
+{
+       struct inode *inode = file_inode(file);
+       int ret;
+
+       inode_lock(inode);
+       ret = acpi_aml_flush();
+       inode_unlock(inode);
+       return ret;
+}
+
 static const struct file_operations acpi_aml_operations = {
        .read           = acpi_aml_read,
        .write          = acpi_aml_write,
        .poll           = acpi_aml_poll,
+       .fsync          = acpi_aml_fsync,
        .open           = acpi_aml_open,
        .release        = acpi_aml_release,
        .llseek         = generic_file_llseek,
-- 
1.7.10

Reply via email to