Try   HackMD

2019q1 Homework2 (fibdrv)

contributed by < TsundereChen >

tags: sysprog TsundereChen

Report

make check command

  • When compiling, using different compiler will prompt different kinds of message
    • Using clang v6.0.0-1ubuntu2 won't have error messages related to code
    • Using gcc v8.2.1 would have warning message below
      ​​​​​​​​make[1]: Entering directory '/usr/lib/modules/5.0.0-zen1-1-zen/build'
      ​​​​​​​​  CC [M]  /home/tsundere/Workspace/linux_2019_spr/Week2/fibdrv/fibdrv.o
      ​​​​​​​​/home/tsundere/Workspace/linux_2019_spr/Week2/fibdrv/fibdrv.c: In function ‘fib_sequence’:
      ​​​​​​​​/home/tsundere/Workspace/linux_2019_spr/Week2/fibdrv/fibdrv.c:30:5: warning: ISO C90 forbids variable length array ‘f’ [-Wvla]
      ​​​​​​​​     long long f[k + 2];
      ​​​​​​​​     ^~~~
      
    • Always use gcc ?

Variable Length Arrays in Kernel

fibdrv.c

MODULE_LICENSE, MODULE_AUTHOR, MODULE_DESCRIPTION

  • MODULE_* is defined in include/linux/module.h
  • Take a look at MODULE_LICENSE in module.h
    ​​​​​#define MODULE_LICENSE(_license) MODULE_INFO(license, _license)
    
  • Take a look at MODULE_INFO in module.h
    ​​​​​#define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
    
  • Okaywhere's __MODULE_INFO ?
    • Defined in include/linux/moduleparam.h, at line 20 ~ 36
      ​​​​​​​​​#ifdef MODULE
      ​​​​​​​​​#define __MODULE_INFO(tag, name, info)					  \
      ​​​​​​​​​static const char __UNIQUE_ID(name)[]					  \
      ​​​​​​​​​  __used __attribute__((section(".modinfo"), unused, aligned(1)))	  \
      ​​​​​​​​​  = __stringify(tag) "=" info
      ​​​​​​​​​#else  /* !MODULE */
      ​​​/* This struct is here for syntactic coherency, it is not used */
      ​​​#define __MODULE_INFO(tag, name, info)					  \
      ​​​  struct __UNIQUE_ID(name) {}
      ​​​#endif
      ​​​#define __MODULE_PARM_TYPE(name, _type)					  \
      ​​​  __MODULE_INFO(parmtype, name##type, #name ":" _type)
      ​​​
      ​​​/* One for each parameter, describing how to use it.  Some files do
      ​​​   multiple of these per line, so can't just use MODULE_INFO. */
      ​​​#define MODULE_PARM_DESC(_parm, desc) \
      ​​​__MODULE_INFO(parm, _parm, #_parm ":" desc)
      
    • MODULE_AUTHOR and MODULE_DESCRIPTION is same as MODULE_LICENSE

MODULE_VERSION

  • There are two ways to define MODULE_VERSION
    ​​#if defined(MODULE) || !defined(CONFIG_SYSFS)
    ​​#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
    ​​#else
    ​​#define MODULE_VERSION(_version)					\
    ​​    static struct module_version_attribute ___modver_attr = {	\
    ​​        .mattr	= {						\
    ​​            .attr	= {					\
    ​​                .name	= "version",			\
    ​​                .mode	= S_IRUGO,			\
    ​​            },						\
    ​​            .show	= __modver_version_show,		\
    ​​        },							\
    ​​        .module_name	= KBUILD_MODNAME,			\
    ​​        .version	= _version,				\
    ​​    };								\
    ​​    static const struct module_version_attribute			\
    ​​    __used __attribute__ ((__section__ ("__modver")))		\
    ​​    * __moduleparam_const __modver_attr = &___modver_attr
    ​​#endif
    
  • MODULE_VERSION would be different if CONFIG_SYSFS is defined
    • Most modern linux use virtual filesystem
    • Execute mount in your shell, if you see result like this
      ​​​​​​sys on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
      
      Then yeah, your system is using virtual filesystem
  • S_IRUGO
    • This is a macro defined in include/linux/stat.h
    • IRUGO means
      • I -> Inode
      • R -> Readonly
      • U -> User
      • G -> Group
      • O -> Others
    • So, S_IRUGO means the inode created is mode 0444
    • stat.h changes
      • After linux 3.7, lots of header files are moved into include/uapi or arch/xxxx/include/uapi
      • This is trying to solve include recursive issue
      • Source: Linux kernel uapi header

Command insmod

  • By the flow below, we can see that insmod is going to call init function of that module
    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

    Take a look at the end of fibdrv.c, we found these code
    ​​module_init(init_fib_dev);
    ​​module_exit(exit_fib_dev);
    
    Now, let's find how module_init(function) works
    • include/linux/module.h line 87
      • ​​​​​​​​​​#define module_init(x) __initcall(x)
        
    • include/linux/init.h line 231
      • ​​​​​​​​​​#define __initcall(fn) device_initcall(fn)
        
    • include/linux/init.h line 226
      • ​​​​​​​​​​#define device_initcall(fn) __define_initcall(fn, 6)
        
    • include/linux/init.h line 197
      • ​​​​​​​​​​#define __define_initcall(fn, id) ___define_initcall(fn, id, .initcall##id)
        
    • include/linux/init.h line 185
      • ​​​​​​​​​​​​#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
        ​​​​​​​​​​​​#define ___define_initcall(fn, id, __sec)			\
        ​​​​​​​​​​​​    __ADDRESSABLE(fn)					\
        ​​​​​​​​​​​​    asm(".section	\"" #__sec ".init\", \"a\"	\n"	\
        ​​​​​​​​​​​​    "__initcall_" #fn #id ":			\n"	\
        ​​​​​​​​​​​​        ".long	" #fn " - .			\n"	\
        ​​​​​​​​​​​​        ".previous					\n");
        ​​​​​​​​​​​​#else
        ​​​​​​​​​​​​#define ___define_initcall(fn, id, __sec) \
        ​​​​​​​​​​​​    static initcall_t __initcall_##fn##id __used \
        ​​​​​​​​​​​​        __attribute__((__section__(#__sec ".init"))) = fn;
        ​​​​​​​​​​​​#endif
        
    • So this code
      ​​​​​​module_init(init_fib_drv);
      
      would eventually turn into this (NEED TO CHECK)
      ​​​​​​static initcall_t __initcall_init_fib_drv6 __used \
      ​​​​​​__attribute__((__section__(.initcall6.init))) = init_fib_drv;
      
    • Okaywhat does that mean ?
      • gcc's section attribute
        • It's a way to let gcc know which section of the ELF you want that variable to live in
      • Code above would register this kernel module to kernel, let kernel know it can serve requests
        and terminates its initialization function right after registration
      • So, module_init(init_fib_drv) would register init_fib_drv to kernel, and initialize the module

Register and initialize the device

  • We want to focus on function static int __init init_fib_dev(void)
    • mutex_init(&fib_mutex)

The Linux Virtual File System

  • Virtual File System (VFS) is designed to create a uniform way for clients to access different kinds of file system
  • It creates an interface between kernel and file system, so it's easy to support new file systems
  • Three classes of VFS
    • Disk-based filesystems
      • Ext4, NTFS, UDF, ZFSetc
    • Network filesystems
      • NFS, CIFSetc
    • Special filesystems
      • Filesystems that do not manage disk space

TODO

  • Fix VLA in fibdrv.c

Environment

  • Ubuntu Server using Linux 4.15.0-46-generic
tsundere:~/ $ hostnamectl
   Static hostname: tsundere-ml350p-gen8
         Icon name: computer-desktop
           Chassis: desktop
  Operating System: Ubuntu 18.04.2 LTS
            Kernel: Linux 4.15.0-46-generic
      Architecture: x86-64
tsundere:~/ $ lscpu
Architecture:        x86_64
CPU op-mode(s):      32-bit, 64-bit
Byte Order:          Little Endian
CPU(s):              12
On-line CPU(s) list: 0-11
Thread(s) per core:  2
Core(s) per socket:  6
Socket(s):           1
NUMA node(s):        1
Vendor ID:           GenuineIntel
CPU family:          6
Model:               62
Model name:          Intel(R) Xeon(R) CPU E5-2630 v2 @ 2.60GHz
Stepping:            4
CPU MHz:             1652.487
CPU max MHz:         3100.0000
CPU min MHz:         1200.0000
BogoMIPS:            5186.67
Virtualization:      VT-x
L1d cache:           32K
L1i cache:           32K
L2 cache:            256K
L3 cache:            15360K
NUMA node0 CPU(s):   0-11
Flags:               fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm cons
tant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid dca sse4_1 s
se4_2 x2apic popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm cpuid_fault epb pti intel_ppin ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid fsgsbase sm
ep erms xsaveopt dtherm ida arat pln pts flush_l1d
tsundere:~/ $ free -h
              total        used        free      shared  buff/cache   available 
Mem:           7.7G        532M        139M        216K        7.1G        6.9G
Swap:          4.0G         12M        4.0G  
  • Arch Linux with linux-5.0.0-zen
tsundere:~/ $ hostnamectl
   Static hostname: Tsundere-X240s
         Icon name: computer-laptop
           Chassis: laptop
  Operating System: Arch Linux
            Kernel: Linux 5.0.0-zen1-1-zen
      Architecture: x86-64
tsundere:~/ $ 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):              4
On-line CPU(s) list: 0-3
Thread(s) per core:  2
Core(s) per socket:  2
Socket(s):           1
NUMA node(s):        1
Vendor ID:           GenuineIntel
CPU family:          6
Model:               69
Model name:          Intel(R) Core(TM) i7-4500U CPU @ 1.80GHz
Stepping:            1
CPU MHz:             1795.879
CPU max MHz:         3000.0000
CPU min MHz:         800.0000
BogoMIPS:            4790.23
Virtualization:      VT-x
L1d cache:           32K
L1i cache:           32K
L2 cache:            256K
L3 cache:            4096K
NUMA node0 CPU(s):   0-3
Flags:               fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt dtherm ida arat pln pts flush_l1d
tsundere:~/ $ free -h
              total        used        free      shared  buff/cache   available
Mem:          7.7Gi       1.9Gi       4.1Gi       493Mi       1.7Gi       5.1Gi
Swap:           9Gi          0B         9Gi

Reference