lkml.org 
[lkml]   [2020]   [May]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[RFC v4][PATCH part-3 09/14] asidrv: Add ioctls to manage ASI page faults
    Date
    Add ioctls to list and clear ASI page faults. Also add an ioctl to display
    or not stack trace on ASI page fault.

    Signed-off-by: Alexandre Chartre <alexandre.chartre@oracle.com>
    ---
    drivers/staging/asi/asidrv.c | 88 ++++++++++++++++++++++++++++++++++++
    drivers/staging/asi/asidrv.h | 32 +++++++++++++
    2 files changed, 120 insertions(+)

    diff --git a/drivers/staging/asi/asidrv.c b/drivers/staging/asi/asidrv.c
    index 9ca17e0b654e..e6edfbe5acea 100644
    --- a/drivers/staging/asi/asidrv.c
    +++ b/drivers/staging/asi/asidrv.c
    @@ -4,6 +4,7 @@
    */

    #include <linux/fs.h>
    +#include <linux/kallsyms.h>
    #include <linux/kthread.h>
    #include <linux/miscdevice.h>
    #include <linux/module.h>
    @@ -790,12 +791,99 @@ static int asidrv_ioctl_run_sequence(struct asidrv_test *test,
    return 0;
    }

    +/*
    + * ASI fault ioctls
    + */
    +
    +static int asidrv_ioctl_list_fault(struct asi *asi, unsigned long arg)
    +{
    + struct asidrv_fault_list __user *uflist;
    + struct asidrv_fault_list *flist;
    + size_t flist_size;
    + __u32 uflist_len;
    + int i;
    +
    + uflist = (struct asidrv_fault_list __user *)arg;
    + if (copy_from_user(&uflist_len, &uflist->length, sizeof(uflist_len)))
    + return -EFAULT;
    +
    + uflist_len = min_t(unsigned int, uflist_len, ASI_FAULT_LOG_SIZE);
    +
    + flist_size = sizeof(*flist) + sizeof(struct asidrv_fault) * uflist_len;
    + flist = kzalloc(flist_size, GFP_KERNEL);
    + if (!flist)
    + return -ENOMEM;
    +
    + for (i = 0; i < ASI_FAULT_LOG_SIZE; i++) {
    + if (!asi->fault_log[i].address)
    + break;
    + if (i < uflist_len) {
    + flist->fault[i].addr = asi->fault_log[i].address;
    + flist->fault[i].count = asi->fault_log[i].count;
    + sprint_symbol(flist->fault[i].symbol,
    + asi->fault_log[i].address);
    + }
    + }
    + flist->length = i;
    +
    + if (copy_to_user(uflist, flist, flist_size)) {
    + kfree(flist);
    + return -EFAULT;
    + }
    +
    + if (i >= ASI_FAULT_LOG_SIZE)
    + pr_warn("ASI %p: fault log buffer is full [%d]\n", asi, i);
    +
    + kfree(flist);
    +
    + return 0;
    +}
    +
    +static int asidrv_ioctl_clear_fault(struct asi *asi)
    +{
    + int i;
    +
    + for (i = 0; i < ASI_FAULT_LOG_SIZE; i++) {
    + if (!asi->fault_log[i].address)
    + break;
    + asi->fault_log[i].address = 0;
    + }
    +
    + pr_debug("ASI %p: faults cleared\n", asi);
    + return 0;
    +}
    +
    +static int asidrv_ioctl_log_fault_stack(struct asi *asi, bool log_stack)
    +{
    + if (log_stack) {
    + asi->fault_log_policy |= ASI_FAULT_LOG_STACK;
    + pr_debug("ASI %p: setting fault stack\n", asi);
    + } else {
    + asi->fault_log_policy &= ~ASI_FAULT_LOG_STACK;
    + pr_debug("ASI %p: clearing fault stack\n", asi);
    + }
    +
    + return 0;
    +}
    +
    static long asidrv_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
    {
    struct asidrv_test *test = asidrv_test;
    + struct asi *asi = test->asi;

    switch (cmd) {

    + /* ASI fault ioctls */
    +
    + case ASIDRV_IOCTL_LIST_FAULT:
    + return asidrv_ioctl_list_fault(asi, arg);
    +
    + case ASIDRV_IOCTL_CLEAR_FAULT:
    + return asidrv_ioctl_clear_fault(asi);
    +
    + case ASIDRV_IOCTL_LOG_FAULT_STACK:
    + return asidrv_ioctl_log_fault_stack(asi, arg);
    +
    /* Test ioctls */

    case ASIDRV_IOCTL_RUN_SEQUENCE:
    diff --git a/drivers/staging/asi/asidrv.h b/drivers/staging/asi/asidrv.h
    index 9f540b119883..99ab9843e36b 100644
    --- a/drivers/staging/asi/asidrv.h
    +++ b/drivers/staging/asi/asidrv.h
    @@ -36,9 +36,41 @@ enum asidrv_run_error {

    #define ASIDRV_IOCTL_RUN_SEQUENCE _IOWR('a', 1, struct asidrv_run_param)

    +/*
    + * ASIDRV_IOCTL_LIST_FAULT: return the list of ASI faults.
    + *
    + * User should set 'length' with the number of entries available in the
    + * 'fault' array. On return, 'length' is set to the number of ASI faults
    + * (which can be larger than the original 'length' value), and the 'fault'
    + * array is filled with the ASI faults.
    + */
    +#define ASIDRV_IOCTL_LIST_FAULT _IOWR('a', 2, struct asidrv_fault_list)
    +#define ASIDRV_IOCTL_CLEAR_FAULT _IO('a', 3)
    +#define ASIDRV_IOCTL_LOG_FAULT_STACK _IO('a', 4)
    +
    +#define ASIDRV_KSYM_NAME_LEN 128
    +/*
    + * We need KSYM_SYMBOL_LEN to lookup symbol. However it's not part of
    + * userland include. So we use a reasonably large value (KSYM_SYMBOL_LEN
    + * is around 310).
    + */
    +#define ASIDRV_KSYM_SYMBOL_LEN 512
    +
    struct asidrv_run_param {
    __u32 sequence; /* sequence to run */
    __u32 run_error; /* result error after run */
    __u32 asi_active; /* ASI is active after run? */
    };
    +
    +struct asidrv_fault {
    + __u64 addr;
    + char symbol[ASIDRV_KSYM_SYMBOL_LEN];
    + __u32 count;
    +};
    +
    +struct asidrv_fault_list {
    + __u32 length;
    + struct asidrv_fault fault[0];
    +};
    +
    #endif
    --
    2.18.2
    \
     
     \ /
      Last update: 2020-05-04 17:07    [W:4.922 / U:0.284 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site