Try   HackMD

2019q1 第 15 週測驗題


測驗 1

以下 Linux 核心模組程式碼嘗試模仿 Android Logging System,提供一個特製的裝置驅動程式,允許 userspace 透過 VFS 寫入日誌和紀錄追蹤。已知可在 Linux v4.15 運作。

  • Makefile
ccflags-y += -std=gnu99
obj-m := log.o

KERNELDIR ?= /lib/modules/`uname -r`/build

default:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) module
  • log.c
#include <linux/fs.h>                     
#include <linux/miscdevice.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/slab.h>

#define LOG_LINE_BUF_SIZE 256
#define LOG_BUF_OUTPUT_BUF_SIZE (LOG_LINE_BUF_SIZE * 4 * 4 * 32)

struct mylog {
    void *buff;
    ssize_t buf_write_size;
};

static struct mylog *mylog = NULL;

static int mylog_open(struct inode *inode, struct file *file) {
    file->private_data = mylog;
    printk("client: %s (%d)\n", current->comm, current->pid);

    return 0;
}

static int mylog_release(struct inode *inode, struct file *file) {
    struct mylog *mylog = file->private_data;

    ClearPageReserved(virt_to_page(mylog->buff));
    kfree(mylog->buff);
    kfree(mylog);

    return 0;
}

static int mylog_mmap(struct file *file, struct vm_area_struct *vma) {
    struct mylog *mylog = AAA;
    unsigned long pfn_start =
        (virt_to_phys(mylog->buff) >> BBB) + CCC;
    unsigned long size = vma->vm_end - vma->vm_start;
    
    return remap_pfn_range(vma, vma->vm_start, pfn_start, size,
                           vma->vm_page_prot);
}

static const struct file_operations mylog_fops = {
    .owner = THIS_MODULE,
    .open = mylog_open,
    .release = mylog_release,
    .mmap = mylog_mmap,
};

static struct miscdevice mylog_misc = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "mylog",
    .fops = &mylog_fops,
};

static int __init mylog_init(void) {
    int ret = 0;

    mylog = kzalloc(sizeof(struct mylog), GFP_KERNEL);
    if (!mylog) {
        ret = -ENOMEM;
        goto err_mylog;
    }

    mylog->buff = kzalloc(LOG_BUF_OUTPUT_BUF_SIZE, GFP_KERNEL);
    if (!mylog->buff) {
        ret = -ENOMEM;
        goto err_buff;
    }

    SetPageReserved(virt_to_page(mylog->buff));

    ret = misc_register(&mylog_misc);
    if (unlikely(ret)) {
        pr_err("failed to register misc device!\n");
        goto err_register;
    }

    return 0;

err_register:
    kfree(mylog->buff);
err_buff:
    kfree(mylog);
err_mylog:
    return ret;
}

static void __exit mylog_exit(void) {
    misc_deregister(&mylog_misc);
}

module_init(mylog_init);
module_exit(mylog_exit);
MODULE_LICENSE("GPL");

參考資訊:

請補完程式碼。

作答區

AAA = ?

  • (a) NULL
  • (b) file->f_security
  • (c) file->f_mapping
  • (d) file->private_data

BBB = ?

  • (a) PAGE_SHIFT
  • (b) 1
  • (c) 2
  • (d) PAGE_SIZE

CCC = ?

  • (a) 1
  • (b) vma->vm_start
  • (c) vma->vm_end
  • (d) vma->vm_raend
  • (e) vma->m_private_data
  • (f) vma->vm_pgoff