--- tags: linux2022 --- # 2022q1 Homework6 (ktcp) contributed by < `SmallHanley` > > [作業說明](https://hackmd.io/@sysprog/linux2022-ktcp) > [GitHub: kecho](https://github.com/SmallHanley/kecho) > [CS:APP CH11 Note](https://hackmd.io/@SmallHanley/csapp-ch11) ## 開發環境 ```shell $ cat /proc/version Linux version 5.13.0-40-generic (buildd@ubuntu) (gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0, GNU ld (GNU Binutils for Ubuntu) 2.34) #45~20.04.1-Ubuntu SMP Mon Apr 4 09:38:31 UTC 2022 $ lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian Address sizes: 39 bits physical, 48 bits virtual CPU(s): 8 On-line CPU(s) list: 0-7 Thread(s) per core: 2 Core(s) per socket: 4 Socket(s): 1 NUMA node(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 142 Model name: Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz Stepping: 10 CPU MHz: 1800.000 CPU max MHz: 3400.0000 CPU min MHz: 400.0000 BogoMIPS: 3600.00 Virtualisation: VT-x L1d cache: 128 KiB L1i cache: 128 KiB L2 cache: 1 MiB L3 cache: 6 MiB NUMA node0 CPU(s): 0-7 ``` ___ ## 自我檢查清單 ### Q1 :::success 參照 [Linux 核心模組掛載機制](https://hackmd.io/@sysprog/linux-kernel-module),解釋 `$ sudo insmod khttpd.ko port=1999` 這命令是如何讓 `port=1999` 傳遞到核心,作為核心模組初始化的參數呢? > 過程中也會參照到 [你所不知道的 C 語言:連結器和執行檔資訊](https://hackmd.io/@sysprog/c-linker-loader) ::: 參考 [lkmpg 4.5 Passing Command Line Arguments to a Module](https://sysprog21.github.io/lkmpg/?fbclid=IwAR18Okz1l1yBkzaz4z6DjJUxvwcqmp1q9Vs6gleiIGL8bGLdY1dQewsF7S0#passing-command-line-arguments-to-a-module),我們可以從 command line 傳入參數到核心模組。將欲接收傳入值的變數宣告成全域變數,並使用 `module_param()` macro (另外還有 `module_param_array()`、`module_param_string()`)。而 `module_param()` macro 是宣告在 [include/linux/moduleparam.h](https://elixir.bootlin.com/linux/latest/source/include/linux/moduleparam.h#L126): ```c #define module_param(name, type, perm) \ module_param_named(name, name, type, perm) #define module_param_named(name, value, type, perm) \ param_check_##type(name, &(value)); \ module_param_cb(name, &param_ops_##type, &value, perm); \ __MODULE_PARM_TYPE(name, #type) ``` 其中 `param_check_##type()` 會根據 `type` 展開成以下獨一無二名字的函式: ```c /* All the helper functions */ /* The macros to do compile-time type checking stolen from Jakub Jelinek, who IIRC came up with this idea for the 2.4 module init code. */ #define __param_check(name, p, type) \ static inline type __always_unused *__check_##name(void) { return(p); } ``` 而 `__always_unused` include 至 [include/linux/compiler_attributes.h](https://elixir.bootlin.com/linux/latest/source/include/linux/compiler_attributes.h#L285),展開後是 `__attribute__((__unused__))`,參考 [Common-Function-Attributes](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes) 的 `unused` attribute。 > This attribute, attached to a function, means that the function is meant to be possibly unused. GCC does not produce a warning for this function. 使得程式可以在編譯時期檢查 type 是否為規範的 type。 接著,以下是 `module_param_cb()` 的展開: ```c /** * module_param_cb - general callback for a module/cmdline parameter * @name: a valid C identifier which is the parameter name. * @ops: the set & get operations for this parameter. * @arg: args for @ops * @perm: visibility in sysfs. * * The ops can have NULL set or get functions. */ #define module_param_cb(name, ops, arg, perm) \ __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, -1, 0) /* This is the fundamental function for registering boot/module parameters. */ #define __module_param_call(prefix, name, ops, arg, perm, level, flags) \ /* Default value instead of permissions? */ \ static const char __param_str_##name[] = prefix #name; \ static struct kernel_param __moduleparam_const __param_##name \ __used __section("__param") \ __aligned(__alignof__(struct kernel_param)) \ = { __param_str_##name, THIS_MODULE, ops, \ VERIFY_OCTAL_PERMISSIONS(perm), level, flags, { arg } } ``` 如果要方便觀察展開內容,可以使用 gcc toolchain 讓 gcc 命令執行到前置處理器結束,尚未進入編譯階段 (使用 `-E` flag): ```bash $ TREE=/usr/src/linux-headers-`uname -r` $ gcc -E test.c \ -I$TREE/include \ -I$TREE/arch/x86/include \ -I$TREE/arch/x86/include/generated \ -I$TREE/include/uapi \ > tmp ``` ==TODO== 參考 [Linux 核心模組掛載機制](https://hackmd.io/@sysprog/linux-kernel-module#Linux-%E6%A0%B8%E5%BF%83%E6%A8%A1%E7%B5%84%E6%8E%9B%E8%BC%89%E6%A9%9F%E5%88%B6),使用 `strace` 追蹤 `insmod` 的系統呼叫: ```bash $ sudo strace -o tmp insmod kecho.ko port=1999 $ grep '1999' tmp execve("/usr/sbin/insmod", ["insmod", "kecho.ko", "port=1999"], 0x7ffd2fb17f10 /* 26 vars */) = 0 finit_module(3, "port=1999", 0) = 0 ``` 若是傳入多個參數: ```bash $ sudo strace insmod kecho.ko port=12345 backlog=128 bench=0 ... finit_module(3, "port=12345 backlog=128 bench=0", 0) = 0 ... ``` ### Q2 :::success 參照 [CS:APP 第 11 章](https://hackmd.io/s/ByPlLNaTG),給定的 kHTTPd 和書中的 web 伺服器有哪些流程是一致?又有什麼是你認為 kHTTPd 可改進的部分? ::: ### Q3 :::success `htstress.c` 用到 [epoll](http://man7.org/linux/man-pages/man7/epoll.7.html) 系統呼叫,其作用為何?這樣的 HTTP 效能分析工具原理為何? ::: ### Q4 :::success 給定的 `kecho` 已使用 CMWQ,請陳述其優勢和用法 ::: ### Q5 :::success 核心文件 [Concurrency Managed Workqueue (cmwq)](https://www.kernel.org/doc/html/latest/core-api/workqueue.html) 提到 "The original create_`*`workqueue() functions are deprecated and scheduled for removal",請參閱 Linux 核心的 git log (不要用 Google 搜尋!),揣摩 Linux 核心開發者的考量 ::: ### Q6 :::success 解釋 `user-echo-server` 運作原理,特別是 [epoll](http://man7.org/linux/man-pages/man7/epoll.7.html) 系統呼叫的使用 ::: ### Q7 :::success 是否理解 `bench` 原理,能否比較 `kecho` 和 `user-echo-server` 表現?佐以製圖 ::: ### Q8 :::success 解釋 `drop-tcp-socket` 核心模組運作原理。`TIME-WAIT` sockets 又是什麼? :::