Git基本概念

在一个普通的文件夹下使用git init命令就会创建一个.git文件夹,原来的文件夹就变成了一个git repository。关于repository所有的变动都记录在这个.git文件夹中,所以.git文件夹就是git repository和普通文件夹的唯一区别。把它删除了,git repository也就变成了普通文件夹。

git中,提交一次操作进版本库的包含两个步骤:stagingcommitting。如下图所示:

1-1

(1)Staginggit add操作。修改后的文件只是进入了staging区域,还没有进入最后的版本库。Staging中的修改会在下一次git commit操作中提交进版本库。Staging中的文件状态也被称作snapshotStaging可以使用户把相关的改动保存在一个snapshot中,这样保证每次commit都是有关联,有意义的。

(2)Committinggit commit操作。把staging区域中的snapshot提交进版本库。

另外,git status命令显示当前repository中所有文件的状态,比如哪些文件处于staging区域,git log则会显示已经进入版本库的revision history。如下图所示:

1-2

参考资料:
The Basics

Linux kernel 笔记 (13)——“magic SysRq key”简介

Magic SysRq key”是一种组合键(例如在X86平台,是ALT-SysRq-<command key>),除非kernel被完全锁定(连中断都无法处理),否则就会响应这个组合键。这是一个很好的调试kernel方法。

要使用“magic SysRq key”功能,编译kernelCONFIG_MAGIC_SYSRQ要选择yes:“make menuconfig”->“Kernel hacking”->“Magic SysRq key”。当“magic SysRq key”功能编译进kernel后,可以通过/proc/sys/kernel/sysrq文件控制“magic SysRq key”键的功能。这个文件里的默认值是CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE这个配置项的值。例如:

0:关闭所有“`magic SysRq key`”功能
1:开启所有“`magic SysRq key`”功能
......

要注意/proc/sys/kernel/sysrq只能影响通过键盘使用“magic SysRq key”键的功能。而通过访问/proc/sysrq-trigger使用“magic SysRq key”键的功能则总是允许的。

常用的命令包括:

重启系统 (在系统hung住时特别管用):
echo b > /proc/sysrq-trigger

让系统crash:
echo c > /proc/sysrq-trigger

......

具体请参考kernel文档。

参考资料:
(1)magic sysrq: a linux system debugging technique
(2)sysrq.txt

Lua笔记(12)——注释

Lua中单行注释是以“--”开头,多行注释以“--[[”开头,以“]]”结尾。举例如下:

-- your code goes here
--[[
print("Hello")
--]]

上面以“--[[”开头,“--]]”结尾注释代码是一个小技巧。一旦想使这段被注释的代码生效,只要把“--[[”改成“---[[”即可。这样就变成了两个单行注释:

-- your code goes here
---[[
print("Hello")
--]]

运行如下:

Hello

Linux kernel 笔记 (12)——如何删除内核?

本文介绍如何删除自己编译安装的内核:

(1)在/boot文件夹下删除相关文件:

/boot/vmlinuz*KERNEL-VERSION*
/boot/initrd*KERNEL-VERSION*
/boot/System-map*KERNEL-VERSION*
/boot/config-*KERNEL-VERSION*(如果存在)

(2)删除和这个kernel相关的module文件夹。默认是在/lib/modules这个目录下:

/lib/modules/*KERNEL-VERSION*/

(3)修改grub启动文件:删除相应的menuentry,并记得修改default值。

参考资料:
How to: Linux delete or remove kernel

Linux kernel IOMMU代码分析笔记(5)——Interrupt Remapping初始化相关部分

irq_remap_ops定义在drivers\iommu\irq_remapping.h中:

struct irq_remap_ops {
    /* Check whether Interrupt Remapping is supported */
    int (*supported)(void);

    /* Initializes hardware and makes it ready for remapping interrupts */
    int  (*prepare)(void);

    /* Enables the remapping hardware */
    int  (*enable)(void);

    /* Disables the remapping hardware */
    void (*disable)(void);

    /* Reenables the remapping hardware */
    int  (*reenable)(int);

    /* Enable fault handling */
    int  (*enable_faulting)(void);

    /* IO-APIC setup routine */
    int (*setup_ioapic_entry)(int irq, struct IO_APIC_route_entry *,
                  unsigned int, int,
                  struct io_apic_irq_attr *);

    /* Set the CPU affinity of a remapped interrupt */
    int (*set_affinity)(struct irq_data *data, const struct cpumask *mask,
                bool force);

    /* Free an IRQ */
    int (*free_irq)(int);

    /* Create MSI msg to use for interrupt remapping */
    void (*compose_msi_msg)(struct pci_dev *,
                unsigned int, unsigned int,
                struct msi_msg *, u8);

    /* Allocate remapping resources for MSI */
    int (*msi_alloc_irq)(struct pci_dev *, int, int);

    /* Setup the remapped MSI irq */
    int (*msi_setup_irq)(struct pci_dev *, unsigned int, int, int);

    /* Setup interrupt remapping for an HPET MSI */
    int (*setup_hpet_msi)(unsigned int, unsigned int);
};

extern struct irq_remap_ops intel_irq_remap_ops;
extern struct irq_remap_ops amd_iommu_irq_ops;

可以看到,在结构体中定义了一系列的函数指针,每个函数的作用都写得很清楚。

针对intel处理器的结构体定义在drivers\iommu\intel_irq_remapping.c

struct irq_remap_ops intel_irq_remap_ops = {
    .supported      = intel_irq_remapping_supported,
    .prepare        = dmar_table_init,
    .enable         = intel_enable_irq_remapping,
    .disable        = disable_irq_remapping,
    .reenable       = reenable_irq_remapping,
    .enable_faulting    = enable_drhd_fault_handling,
    .setup_ioapic_entry = intel_setup_ioapic_entry,
    .set_affinity       = intel_ioapic_set_affinity,
    .free_irq       = free_irte,
    .compose_msi_msg    = intel_compose_msi_msg,
    .msi_alloc_irq      = intel_msi_alloc_irq,
    .msi_setup_irq      = intel_msi_setup_irq,
    .setup_hpet_msi     = intel_setup_hpet_msi,
};

AMD相关的暂不讨论。

enable_IR_x2apic函数(arch\x86\kernel\apic)中,包含着irq_remap_ops中初始化相关函数的调用:

void __init enable_IR_x2apic(void)
{
    ......
    /* Make sure irq_remap_ops are initialized */
    setup_irq_remapping_ops();

    hardware_init_ret = irq_remapping_prepare();
    if (hardware_init_ret && !x2apic_supported())
        return;

    ......   
    if (hardware_init_ret)
        ret = -1;
    else
        ret = enable_IR();

    ......
}

(1)

void __init setup_irq_remapping_ops(void)
{
    remap_ops = &intel_irq_remap_ops;

#ifdef CONFIG_AMD_IOMMU
    if (amd_iommu_irq_ops.prepare() == 0)
        remap_ops = &amd_iommu_irq_ops;
#endif
}

这个函数会让全局变量remap_ops这个指针指向intel_irq_remap_opsamd_iommu_irq_ops

(2)

int __init irq_remapping_prepare(void)
{
    if (!remap_ops || !remap_ops->prepare)
        return -ENODEV;

    return remap_ops->prepare();
}

irq_remapping_prepare会调用prepare函数(Intel平台即dmar_table_init)。

(3)

int __init enable_IR(void)
{
#ifdef CONFIG_IRQ_REMAP
    if (!irq_remapping_supported()) {
        pr_debug("intr-remapping not supported\n");
        return -1;
    }

    if (!x2apic_preenabled && skip_ioapic_setup) {
        pr_info("Skipped enabling intr-remap because of skipping "
            "io-apic setup\n");
        return -1;
    }

    return irq_remapping_enable();
#endif
    return -1;
}

enable_IR中会调用irq_remapping_supportedirq_remapping_enable

int irq_remapping_supported(void)
{
    if (disable_irq_remap)
        return 0;

    if (!remap_ops || !remap_ops->supported)
        return 0;

    return remap_ops->supported();
}

int __init irq_remapping_enable(void)
{
    int ret;

    if (!remap_ops || !remap_ops->enable)
        return -ENODEV;

    ret = remap_ops->enable();

    if (irq_remapping_enabled)
        irq_remapping_modify_x86_ops();

    return ret;
}

会先后调用supportedIntel平台即为intel_irq_remapping_supported)和enable函数(Intel平台即为intel_enable_irq_remapping)。

irq_remapping_modify_x86_ops会把其它函数赋值给相应的全局函数指针:

static void __init irq_remapping_modify_x86_ops(void)
{
    x86_io_apic_ops.disable     = irq_remapping_disable_io_apic;
    x86_io_apic_ops.set_affinity    = set_remapped_irq_affinity;
    x86_io_apic_ops.setup_entry = setup_ioapic_remapped_entry;
    x86_io_apic_ops.eoi_ioapic_pin  = eoi_ioapic_pin_remapped;
    x86_msi.setup_msi_irqs      = irq_remapping_setup_msi_irqs;
    x86_msi.setup_hpet_msi      = setup_hpet_msi_remapped;
    x86_msi.compose_msi_msg     = compose_remapped_msi_msg;
}

Shark代码分析笔记(2)——main函数

看一下main函数:

int main(int argc, char **argv)
{
    int ret = EXIT_FAILURE;
    int flags = 0, script;
    int base;

    if (argv[0] && argv[0][0]) progname = argv[0];

    lua_State *ls = lua_open();
    if (!ls) {
        l_message(progname, "cannot create state: not enough memory");
        return ret;
    }

    g_ls = ls;

    script = collectargs(argv, &flags);
    if (script <= 0) {  /* invalid args? */
        print_usage();
        return 0;
    }

    if (flags & FLAGS_VERSION)
        print_version();

    luaL_openlibs(ls);  /* open libraries */

    // Get package.preload so we can store builtins in it.
    lua_getglobal(ls, "package");
    lua_getfield(ls, -1, "preload");
    lua_remove(ls, -2); // Remove package

    // Store uv module definition at preload.uv
    lua_pushcfunction(ls, luaopen_luv);
    lua_setfield(ls, -2, "uv");

    luaL_openlib(ls, "shark", ll_shark, 0);

    lua_getglobal(ls, "shark");
    lua_pushboolean(ls, shark_verbose);
    lua_setfield(ls, -2, "verbose");
    lua_pop(ls, 1);

    int narg = getargs(ls, argv, script);  /* collect arguments */
    lua_setglobal(ls, "arg");

#include "shark_init.h"
    luaL_loadbuffer(ls, luaJIT_BC_shark_init, luaJIT_BC_shark_init_SIZE,
            NULL);
    if((ret = lua_pcall(ls, 0, 0, 0))) {
        ret = lua_report(ls, ret);
        goto out;
    }

    g_event_loop = luv_loop(ls);

    if((ret = luaL_loadfile(ls, argv[script]))) {
        ret = lua_report(ls, ret);
        goto out;
    }

    base = lua_gettop(ls) - 1;
    lua_pushcfunction(ls, lua_traceback);
    lua_insert(ls, base);

    if (lua_pcall(ls, 0, 0, base)) {
        fprintf(stderr, "%s\n", lua_tostring(ls, -1));
        exit(EXIT_FAILURE);
    }

    lua_pop(ls, 1);

    //TODO: move to lua init code
    uv_run(g_event_loop, UV_RUN_DEFAULT);

    ret = 0;
 out:
    lua_close(ls);
    return ret;
}  

(1)

if (argv[0] && argv[0][0]) progname = argv[0];

progname存的是运行程序名字:/path/to/shark

(2)

    lua_State *ls = lua_open();
    if (!ls) {
        l_message(progname, "cannot create state: not enough memory");
        return ret;
    }

    g_ls = ls;

创建一个新的Lua运行环境,为了后续使用。

(3)

script = collectargs(argv, &flags);
if (script <= 0) {  /* invalid args? */
    print_usage();
    return 0;
}

if (flags & FLAGS_VERSION)
    print_version();

先看一下print_version

static void print_version(void)
{
    fputs(SHARK_VERSION " -- " SHARK_COPYRIGHT ". " SHARK_URL "\n", stdout);
    exit(0);
}

比较简单,打印出版本就退出了。

再看一下print_usage

static void print_usage(void)
{
    fprintf(stderr,
    "usage: shark [options]... [script [args]...].\n"
    "Available options are:\n"
    "  -v        Show version information.\n");
    fflush(stderr);
}

可以看到shark的使用方法:

shark [options]... [script [args]...]

shark程序后面跟着可选参数,还有执行脚本。

(4)

luaL_openlibs(ls);  /* open libraries */

加载Luajit提供的函数库。

(5)

// Get package.preload so we can store builtins in it.
lua_getglobal(ls, "package");
lua_getfield(ls, -1, "preload");
lua_remove(ls, -2); // Remove package

lua_getglobal(ls, "package");用来把package这个table压入堆栈:

 ___________________________
|____ package(类型:table)___|  (-1)

lua_getfield(ls, -1, "preload");用来从index-1处取出keypreload值,也就是:package.preload这个table,并压入堆栈:

 ___________________________
|package.preload(类型:table)|  (-1)
|____ package(类型:table)___|  (-2)

lua_remove(ls, -2);package从堆栈中移除:

 ___________________________
|package.preload(类型:table)|  (-1)

(6)

// Store uv module definition at preload.uv
lua_pushcfunction(ls, luaopen_luv);
lua_setfield(ls, -2, "uv");

lua_pushcfunction(ls, luaopen_luv);luaopen_luv函数压入堆栈:

 ___________________________
|__luaopen_luv(类型:函数)___|  (-1)
|package.preload(类型:table)|  (-2)

lua_setfield(ls, -2, "uv");执行效果是:package.preload.uv = luaopen_luv,然后把luaopen_luv弹出堆栈:

 ____________________________________________
|package.preload(类型:table,uv = luaopen_luv)|  (-1)

(7)

luaL_openlib(ls, "shark", ll_shark, 0);

ll_shark数组定义如下:

static const struct luaL_reg ll_shark[] = {
        {"debuginfo_set", &shark_api_debuginfo_set},
        {"lua_ref", &shark_api_lua_ref},
        {"get_ref", &shark_api_get_ref},
        {"stats", &shark_api_stats},
        {"set_binary", &shark_api_set_binary},
        {"exec", &shark_api_exec},
//TODO: move to sock library
#ifndef BPF_DISABLE
        {"open_raw_sock", &shark_api_open_raw_sock},
        {"sock_attach_bpf", &shark_api_sock_attach_bpf},
        {"iptos", &shark_api_iptos},
#endif
    {NULL, NULL}
};

luaL_openlib(ls, "shark", ll_shark, 0);函数的作用是创建一个table然后将这个table赋给package.loaded[shark]和全局变量shark,并将ll_shark数组中的函数注册到这个table,最后把table压入堆栈:

 ————————————————————————————————————————————
|___一个注册ll_shark函数数组的table___________|  (-1)
|package.preload(类型:table,uv = luaopen_luv)|  (-2)

(8)

    lua_getglobal(ls, "shark");
    lua_pushboolean(ls, shark_verbose);
    lua_setfield(ls, -2, "verbose");
    lua_pop(ls, 1);

lua_getglobal(ls, "shark");shark table压入堆栈:

 ____________________________________________
|       shark(类型:table)                    |  (-1)
 ————————————————————————————————————————————
|___一个注册ll_shark函数数组的table___________|  (-2)
|package.preload(类型:table,uv = luaopen_luv)|  (-3)

lua_pushboolean(ls, shark_verbose);shark_verbose这个布尔值压入堆栈:

_____________________________________________
| ______shark_verbose(类型:bool)_____________|  (-1)
|       shark(类型:table)                    |  (-2)
 ————————————————————————————————————————————
|___一个注册ll_shark函数数组的table___________|  (-3)
|package.preload(类型:table,uv = luaopen_luv)|  (-4)

lua_setfield(ls, -2, "verbose");执行效果是:shark.verbose = shark_verbose,然后把shark_verbose弹出堆栈:

 ____________________________________________
| shark(类型:table, verbose = shark_verbose) |  (-1)
 ————————————————————————————————————————————
|___一个注册ll_shark函数数组的table___________|  (-2)
|package.preload(类型:table,uv = luaopen_luv)|  (-3)

lua_pop(ls, 1);把栈顶元素弹出堆栈:

 ————————————————————————————————————————————
|___一个注册ll_shark函数数组的table___________|  (-1)
|package.preload(类型:table,uv = luaopen_luv)|  (-2)

(9)

int narg = getargs(ls, argv, script);  /* collect arguments */
lua_setglobal(ls, "arg");

getargs函数实现如下:

static int getargs(lua_State *ls, char **argv, int n)
{
    int narg;
    int i;
    int argc = 0;

    while (argv[argc])
        argc++;  /* count total number of arguments */

    narg = argc - (n + 1);  /* number of arguments to the script */
    luaL_checkstack(ls, narg + 3, "too many arguments to script");

    for (i = n + 1; i < argc; i++)
        lua_pushstring(ls, argv[i]);

    lua_createtable(ls, narg, n + 1);

    for (i = 0; i < argc; i++) {
        lua_pushstring(ls, argv[i]);
        lua_rawseti(ls, -2, i - n);
    }

    return narg;
}

getargs函数中,传入参数nLua脚本在命令行参数的索引,而narg则是脚本的参数。举个例子:

/root/shark/shark trace.lua 1 2

argc4n1narg2

luaL_checkstack(ls, narg + 3, "too many arguments to script");检查堆栈是否有足够的空间。

    for (i = n + 1; i < argc; i++)
        lua_pushstring(ls, argv[i]);

把参数12压入堆栈:

 ___________________________________________
|__________参数: 2__________________________|  (-1)
|          参数: 1                          |  (-2)
|———————————————————————————————————————————
|___一个注册ll_shark函数数组的table___________|  (-3)
|package.preload(类型:table,uv = luaopen_luv)|  (-4)  

lua_createtable(ls, narg, n + 1);创建一个table(包含narg数组元素,n + 1非数组元素)并压入堆栈:

 ———————————————————————————————————————————
|______table________________________________|  (-1)
|__________参数: 2__________________________|  (-2)
|          参数: 1                          |  (-3)
|———————————————————————————————————————————
|___一个注册ll_shark函数数组的table___________|  (-4)
|package.preload(类型:table,uv = luaopen_luv)|  (-5)  

看最后一个循环:

    for (i = 0; i < argc; i++) {
        lua_pushstring(ls, argv[i]);
        lua_rawseti(ls, -2, i - n);
    }

lua_pushstring(ls, argv[i]);依次把参数压入堆栈,lua_rawseti(ls, -2, i - n);则是把参数传入table

 —————————————————————————————————————————————————
|_table(index:value->1:shark;0:trace.lua;1:1;2:2_|  (-1)
|__________参数: 2_______________________________|  (-2)
|          参数: 1                               |  (-3)
|————————————————————————————————————————|
|___一个注册ll_shark函数数组的table________________|  (-4)
|package.preload(类型:table,uv = luaopen_luv)     |  (-5)  

lua_setglobal(ls, "arg");作用是把栈顶table弹出,并赋值给arg。所以arg就指向了这个tableindex:value->1:shark;0:trace.lua;1:1;2:2)。堆栈变为:

____________________________________________
|__________参数: 2__________________________|  (-1)
|          参数: 1                          |  (-2)
|———————————————————————————————————————————
|___一个注册ll_shark函数数组的table___________|  (-3)
|package.preload(类型:table,uv = luaopen_luv)|  (-4) 

(10)

#include "shark_init.h"
luaL_loadbuffer(ls, luaJIT_BC_shark_init, luaJIT_BC_shark_init_SIZE,
        NULL);

shark_init.h是由shark_init.lua生成的(以后再详细介绍shark_init.lua),luaJIT_BC_shark_initluaJIT_BC_shark_init_SIZE也定义在shark_init.h文件中。

luaL_loadbuffer(ls, luaJIT_BC_shark_init, luaJIT_BC_shark_init_SIZE, NULL);luaJIT_BC_shark_init这个chunk压入堆栈:

____________________________________________
|_luaJIT_BC_shark_init chunk(类型:函数)______| (-1)
|__________参数: 2__________________________|  (-2)
|          参数: 1                          |  (-3)
|———————————————————————————————————————————
|___一个注册ll_shark函数数组的table___________|  (-4)
|package.preload(类型:table,uv = luaopen_luv)|  (-5)  

(11)

if((ret = lua_pcall(ls, 0, 0, 0))) {
        ret = lua_report(ls, ret);
        goto out;
}

接下来lua_pcall(ls, 0, 0, 0)会运行luaJIT_BC_shark_init这个chunk。运行完后,把chunk弹出堆栈:

————————————————————————————————————————————
|__________参数: 2__________________________|  (-1)
|          参数: 1                          |  (-2)
|———————————————————————————————————————————
|___一个注册ll_shark函数数组的table___________|  (-3)
|package.preload(类型:table,uv = luaopen_luv)|  (-4)  

lua_report比较简单,就是如果出错的话,就从栈顶取出错误信息,打印完以后再弹栈:

int lua_report(lua_State *ls, int status)
{
    if (status && !lua_isnil(ls, -1)) {
        const char *msg = lua_tostring(ls, -1);
        if (msg == NULL)
            msg = "(error object is not a string)";
        l_message(progname, msg);
        lua_pop(ls, 1);
    }
    return status;
}  

(12)

    g_event_loop = luv_loop(ls);

    if((ret = luaL_loadfile(ls, argv[script]))) {
        ret = lua_report(ls, ret);
        goto out;
    }

    base = lua_gettop(ls) - 1;
    lua_pushcfunction(ls, lua_traceback);
    lua_insert(ls, base);

    if (lua_pcall(ls, 0, 0, base)) {
        fprintf(stderr, "%s\n", lua_tostring(ls, -1));
        exit(EXIT_FAILURE);
    }

    lua_pop(ls, 1);

    //TODO: move to lua init code
    uv_run(g_event_loop, UV_RUN_DEFAULT);

    ret = 0;
 out:
    lua_close(ls);
    return ret;

剩下这段代码就是运行脚本,其中lua_traceback是脚本出错时的处理函数。个人觉得细节上还有些问题,需要和作者沟通一下,这块代码暂时留个小尾巴。

Linux kernel 笔记 (11)——pr_fmt

kernel代码中,很多.c文件开头都会有pr_fmt的定义,例如drivers\iommu\dmar.c

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt /* has to precede printk.h */

这个pr_fmt是针对这个特定的模块定义的。看一下include\linux\printk.h

#ifndef pr_fmt
#define pr_fmt(fmt) fmt
#endif

可以看到,如果这个模块没有定义自己的pr_fmt,那么就会使用默认的fmt。自己定义pr_fmt的好处是可以更清晰地打印这个模块的相关log,便于以后调试。

Shark代码分析笔记(1)——Makefile

Shark项目的Makefile

#Define BPF_ENABLE if Linux kernel is 4.0+
#BPF_DISABLE=1

CFLAGS=-I. -I core/ -I core/libuv/include -I core/luajit/src/ -I bpf/libbpf/

CORE_LIB=core/luajit/src/libluajit.a core/libuv/.libs/libuv.a

PERF_LIBS= perf/libperf.a perf/libtraceevent.a perf/libapikfs.a
LIB=$(CORE_LIB) $(PERF_LIBS) -lm -ldl -lelf -lc -lpthread

OBJS=core/shark.o core/luv/luv.o perf/perf.o

BUILTIN_LUA_OBJS = perf/perf_builtin_lua.o
OBJS += $(BUILTIN_LUA_OBJS)

ifndef BPF_DISABLE
OBJS += bpf/bpf.o bpf/libbpf/bpf_load.o bpf/libbpf/libbpf.o
BUILTIN_LUA_OBJS += bpf/bpf_builtin_lua.o
else
CFLAGS += -DBPF_DISABLE
endif

TARGET=shark

#ffi need to call some functions in library, so add -rdynamic option
$(TARGET) : core/luajit/src/libluajit.a core/libuv/.libs/libuv.a core/shark_init.h $(OBJS) force
    $(CC) -o $(TARGET) -rdynamic $(OBJS) $(LIB)

core/luajit/src/libluajit.a:
    @cd core/luajit; make

core/libuv/.libs/libuv.a:
    @cd core/libuv; ./autogen.sh; ./configure; make


DEPS := $(OBJS:.o=.d)
-include $(DEPS)

%.o : %.c
    $(CC) -MD -g -c $(CFLAGS) $< -o $@

LUAJIT_BIN=core/luajit/src/luajit

core/shark_init.h : core/shark_init.lua
    cd core/luajit/src; ./luajit -b ../../shark_init.lua ../../shark_init.h

bpf/bpf_builtin_lua.o : bpf/bpf.lua
    cd core/luajit/src; ./luajit -b ../../../bpf/bpf.lua ../../../bpf/bpf_builtin_lua.o

perf/perf_builtin_lua.o : perf/perf.lua
    cd core/luajit/src; ./luajit -b ../../../perf/perf.lua ../../../perf/perf_builtin_lua.o

force:
    true

clean:
    @rm -rf $(TARGET) *.d *.o core/*.d core/*.o bpf/*.d bpf/*.o perf/*.d perf/*.o core/shark_builtin.h bpf/bpf_builtin_lua.h perf/perf_builtin_lua.h

(1)因为有些BPF的选项只在比较高版本的Linux kernel上才支持,所以加了一个编译开关BPF_DISABLE,可以用来关闭BPF功能( 关闭BPF编译:make BPF_DISABLE=1 )。

(2)

PERF_LIBS= perf/libperf.a perf/libtraceevent.a perf/libapikfs.a

core/luajit/src/libluajit.a:
    @cd core/luajit; make

core/libuv/.libs/libuv.a:
    @cd core/libuv; ./autogen.sh; ./configure; make

使用了三个从Linux kernel生成的perf相关的库:perf/libperf.aperf/libtraceevent.aperf/libapikfs.a

还有三个第三方库:luajit(core/luajit)libuv(core/libuv))luv(core/luv)

(3)

core/shark_init.h : core/shark_init.lua
    cd core/luajit/src; ./luajit -b ../../shark_init.lua ../../shark_init.h

bpf/bpf_builtin_lua.o : bpf/bpf.lua
    cd core/luajit/src; ./luajit -b ../../../bpf/bpf.lua ../../../bpf/bpf_builtin_lua.o

perf/perf_builtin_lua.o : perf/perf.lua
    cd core/luajit/src; ./luajit -b ../../../perf/perf.lua ../../../perf/perf_builtin_lua.o

core/shark_init.lua用来生成core/shark_init.hbpf/bpf.luaperf/perf.lua分别用来生成bpf/bpf_builtin_lua.operf/perf_builtin_lua.o

(4)

DEPS := $(OBJS:.o=.d)
    -include $(DEPS)

%.o : %.c
    $(CC) -MD -g -c $(CFLAGS) $< -o $@

编译生成object文件,并会生成依赖文件。

(5)

TARGET=shark

#ffi need to call some functions in library, so add -rdynamic option
$(TARGET) : core/luajit/src/libluajit.a core/libuv/.libs/libuv.a core/shark_init.h $(OBJS) force
    $(CC) -o $(TARGET) -rdynamic $(OBJS) $(LIB)

最终编译生成一个可执行文件:shark

git patch简介

本文简单介绍一下git patch

首先创建包含git的工作目录:

git init git_repo

接着在这个文件夹下创建一个文本文件(a.txt):

aaaa
bbbb
cccc
dddd
eeee
ffff

把这个文件加到git版本控制:

git add a.txt
git commit -m "Initialize a.txt"

接着再开出一个patch分支,剩下的操作都在这个分支上进行:

git checkout -b patch

然后把a.txt文件第二行的bbbb改成bb11

aaaa
bb11
cccc
dddd
eeee
ffff

提交:

git commit -a -m "Modify a.txt"

接下来生成相对于master分支的patch

[root@localhost git_repo]# git format-patch master
0001-Modify-a.txt.patch

看一下0001-Modify-a.txt.patch这个patch文件:

From 9512ec20468586e0632ece9e97e4e89b3a68c40e Mon Sep 17 00:00:00 2001
From: root <root@localhost.localdomain>
Date: Thu, 30 Jul 2015 02:30:45 -0400
Subject: [PATCH 1/3] Modify a.txt

---
 a.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/a.txt b/a.txt
index 1707b56..1ba3da1 100644
--- a/a.txt
+++ b/a.txt
@@ -1,5 +1,5 @@
 aaaa
-bbbb
+bb11
 cccc
 dddd
 eeee
--
2.4.3

重点看一下@@ -1,5 +1,5 @@-1,5表示原来的文件,+1,5表示修改后的文件。1表示起始行号,5表示从起始行号算起,一共包含多少行。下面的-bbbb表示删除原来文件的内容,而+bb11表示修改后文件的内容。

下面切换回master分支:

[root@localhost git_repo]# git checkout master
Switched to branch 'master'

看一下master分支的a.txt

[root@localhost git_repo]# cat a.txt
aaaa
bbbb
cccc
dddd
eeee
ffff

没有任何变化。

接下来merge patch

[root@localhost git_repo]# git am < 0001-Modify-a.txt.patch
Applying: Modify a.txt

再次查看a.txt

[root@localhost git_repo]# cat a.txt
aaaa
bb11
cccc
dddd
eeee
ffff

可以看到patch已经成功地merge进了a.txt

Linux kernel IOMMU代码分析笔记(4)——fault处理函数

dmar_fault是发生DMA remapping faultinterrupt remapping fault时的处理函数。代码如下:

irqreturn_t dmar_fault(int irq, void *dev_id)
{
    struct intel_iommu *iommu = dev_id;
    int reg, fault_index;
    u32 fault_status;
    unsigned long flag;

    raw_spin_lock_irqsave(&iommu->register_lock, flag);
    fault_status = readl(iommu->reg + DMAR_FSTS_REG);
    if (fault_status)
        pr_err("DRHD: handling fault status reg %x\n", fault_status);

    /* TBD: ignore advanced fault log currently */
    if (!(fault_status & DMA_FSTS_PPF))
        goto unlock_exit;

    fault_index = dma_fsts_fault_record_index(fault_status);
    reg = cap_fault_reg_offset(iommu->cap);
    while (1) {
        u8 fault_reason;
        u16 source_id;
        u64 guest_addr;
        int type;
        u32 data;

        /* highest 32 bits */
        data = readl(iommu->reg + reg +
                fault_index * PRIMARY_FAULT_REG_LEN + 12);
        if (!(data & DMA_FRCD_F))
            break;

        fault_reason = dma_frcd_fault_reason(data);
        type = dma_frcd_type(data);

        data = readl(iommu->reg + reg +
                fault_index * PRIMARY_FAULT_REG_LEN + 8);
        source_id = dma_frcd_source_id(data);

        guest_addr = dmar_readq(iommu->reg + reg +
                fault_index * PRIMARY_FAULT_REG_LEN);
        guest_addr = dma_frcd_page_addr(guest_addr);
        /* clear the fault */
        writel(DMA_FRCD_F, iommu->reg + reg +
            fault_index * PRIMARY_FAULT_REG_LEN + 12);

        raw_spin_unlock_irqrestore(&iommu->register_lock, flag);

        dmar_fault_do_one(iommu, type, fault_reason,
                source_id, guest_addr);

        fault_index++;
        if (fault_index >= cap_num_fault_regs(iommu->cap))
            fault_index = 0;
        raw_spin_lock_irqsave(&iommu->register_lock, flag);
    }

    writel(DMA_FSTS_PFO | DMA_FSTS_PPF, iommu->reg + DMAR_FSTS_REG);

unlock_exit:
    raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
    return IRQ_HANDLED;
}  

分析一下这段代码:

(1)

fault_status = readl(iommu->reg + DMAR_FSTS_REG);
if (fault_status)
    pr_err("DRHD: handling fault status reg %x\n", fault_status);

/* TBD: ignore advanced fault log currently */
if (!(fault_status & DMA_FSTS_PPF))
    goto unlock_exit;

fault_index = dma_fsts_fault_record_index(fault_status);

DMAR_FSTS_REGFault Status Register,其中PPFPrimary Pending Fault)是否置位表明fault recording registers是否还有fault信息。而fault_index则是第一个含有fault信息的fault recording registers的索引。

(2)

reg = cap_fault_reg_offset(iommu->cap);

计算fault recording registers的地址偏移量。

(3)接下来的while循环会读取包含fault信息的fault recording registers

(4)

    data = readl(iommu->reg + reg +
            fault_index * PRIMARY_FAULT_REG_LEN + 12);
    if (!(data & DMA_FRCD_F))
        break;

    fault_reason = dma_frcd_fault_reason(data);
    type = dma_frcd_type(data);

    data = readl(iommu->reg + reg +
            fault_index * PRIMARY_FAULT_REG_LEN + 8);
    source_id = dma_frcd_source_id(data);

    guest_addr = dmar_readq(iommu->reg + reg +
            fault_index * PRIMARY_FAULT_REG_LEN);
    guest_addr = dma_frcd_page_addr(guest_addr);
    /* clear the fault */
    writel(DMA_FRCD_F, iommu->reg + reg +
        fault_index * PRIMARY_FAULT_REG_LEN + 12);

fault recording registers读取fault信息。需要注意的是,由于X86平台是小端模式,所以寄存器的高位内容会位于内存的高地址空间。另外,每读取完一个fault recording register信息,要把DMA_FRCD_F写回寄存器,用来表明软件已经读完了。

(5)dmar_fault_do_one是格式化打印的fault信息,其代码如下:

static int dmar_fault_do_one(struct intel_iommu *iommu, int type,
        u8 fault_reason, u16 source_id, unsigned long long addr)
{
    const char *reason;
    int fault_type;

    reason = dmar_get_fault_reason(fault_reason, &fault_type);

    if (fault_type == INTR_REMAP)
        pr_err("INTR-REMAP: Request device [[%02x:%02x.%d] "
               "fault index %llx\n"
            "INTR-REMAP:[fault reason %02d] %s\n",
            (source_id >> 8), PCI_SLOT(source_id & 0xFF),
            PCI_FUNC(source_id & 0xFF), addr >> 48,
            fault_reason, reason);
    else
        pr_err("DMAR:[%s] Request device [%02x:%02x.%d] "
               "fault addr %llx \n"
               "DMAR:[fault reason %02d] %s\n",
               (type ? "DMA Read" : "DMA Write"),
               (source_id >> 8), PCI_SLOT(source_id & 0xFF),
               PCI_FUNC(source_id & 0xFF), addr, fault_reason, reason);
    return 0;
}

(6)

writel(DMA_FSTS_PFO | DMA_FSTS_PPF, iommu->reg + DMAR_FSTS_REG);

最后表明软件已处理完所有的fault信息。