2016년 1월 16일 토요일

[Linux Kernel] 130주차(2016.01.16) vfs_caches_init()

KernelStudy : 130 주차
일시 : 2016.01.16 (130 주차 스터디 진행)
모임명 : KernelStudy_ARM
장소 : 토즈 서현점
장소지원 : 공개 소프트웨어 개발자 커뮤니티 지원 프로그램
참여인원 : 3명

130 주차 진도

  • 129 주차 진도를 복습하였습니다.
  • vfs_caches_init()
    • start_kernel 1 ~/kernel/iamroot/linux-stable/init/main.c
    • vfs_caches_init 925 ~/kernel/iamroot/linux-stable/init/main.c
    • mnt_init 3807 ~/kernel/iamroot/linux-stable/fs/dcache.c
    • kobject_create_and_add 3926 ~/kernel/iamroot/linux-stable/fs/namespace.c
    • kobject_add 828 retval = kobject_add(kobj, parent, "%s", name);
    • kobject_add_varg 457 retval = kobject_add_varg(kobj, parent, fmt, args);
    • kobject_set_name_vargs 395 retval = kobject_set_name_vargs(kobj, fmt, vargs);
  • 129주차 함수 호출 구조
  • call: start_kernel()->vfs_caches_init()
  • vfs_caches_init()
    • min()
    • kmem_cache_create() : names_caches
    • dcache_init()
    • inode_init()
    • files_init(): mempages
    • mnt_init()
      • kmem_cache_create(): mnt_cache
    • alloc_large_system_hash() : Mount_cache
    • alloc_large_system_hash() : Mountpoint-cache
    • INIT_HLIST_HEAD() : &mount_hashtable[u]
    • INIT_HLIST_HEAD() : &mountpoint_hashtable[u]
    • sysfs_init() 
    • kobject_create_and_add() : fs
  • kobject_create_and_add() : fs
    • kobject_create()
      • kzalloc()
      • kobject_init()
        • kobject_init_internal() : kobj
    • kobject_add()
      • va_start()
      • kobject_add_vargs() : kobj, fs
        • kobject_set_name_vargs()
          • kvasprintf()
            • va_copy()
            • vsnprintf()
              • format_decode()
            • va_end()
            • kmalloc_track_caller()
            • vsnprintf()

main.c::start_kernel()

  • call: start_kernel()->vfs_caches_init()
asmlinkage void __init start_kernel(void)
{
    char * command_line;
    extern const struct kernel_param __start___param[], __stop___param[];
    // ATAG,DTB 정보로 사용

...

    proc_caches_init();
    // sighand_struct, signal_struct, files_struct, fs_struct, mm_struct, vm_area_struct, nsproxy
    // 를 사용하기 위한 kmem_cache 할당자 및 percpu list 초기화 수행

    buffer_init();
    // buffer_head 를 사용하기 위한 kmem_cache 할당자 및 max_buffer_heads 값 초기화 수행

    key_init(); // null funtion
    security_init(); // null funtion
    dbg_late_init(); // null funtion

    // totalram_pages: 총 free된 page 수
    vfs_caches_init(totalram_pages);

dcache.c::vfs_cache_init()

  • call: start_kernel()
    • vfs_caches_init()
// ARM10C 20151003
// totalram_pages: 총 free된 page 수
void __init vfs_caches_init(unsigned long mempages)
{
    unsigned long reserve;

    // mempages: 총 free된 page 수, nr_free_pages(): 현재의 free pages 수
    reserve = min((mempages - nr_free_pages()) * 3/2, mempages - 1);
    // reserve: XXX

    // mempages: 총 free된 page 수, reserve: XXX
    mempages -= reserve;
    // mempages: 총 free된 page 수 - XXX

    // PATH_MAX: 4096
    // SLAB_HWCACHE_ALIGN: 0x00002000UL, SLAB_PANIC: 0x00040000UL
    // kmem_cache_create("names_cache", 4096, 0, 0x42000, NULL): kmem_cache#6
    names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,
            SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
    // names_cachep: kmem_cache#6

    dcache_init();

    inode_init();

    // mempages: 총 free된 page 수 - XXX
    files_init(mempages);

    mnt_init();

namespace.c::mnt_init()

  • call: start_kernel()->vfs_caches_init()
    • mnt_init()
// ARM10C 20151024
void __init mnt_init(void)
{
    unsigned u;
    int err;
    // sizeof(struct mount): 152 bytes, SLAB_HWCACHE_ALIGN: 0x00002000UL, SLAB_PANIC: 0x00040000UL
    // kmem_cache_create("mnt_cache", 152, 0, 0x42000, NULL): kmem_cache#2
    mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct mount),
            0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
    // mnt_cache: kmem_cache#2

    // sizeof(struct hlist_head): 4 bytes, mhash_entries: 0
    // alloc_large_system_hash("Mount-cache", 4, 0, 19, 0, &m_hash_shift, &m_hash_mask, 0, 0): 16kB만큼 할당받은 메모리 주소
    mount_hashtable = alloc_large_system_hash("Mount-cache",
                sizeof(struct hlist_head),
                mhash_entries, 19,
                0,
                &m_hash_shift, &m_hash_mask, 0, 0);
    // mount_hashtable: 16kB만큼 할당받은 메모리 주소

    // sizeof(struct hlist_head): 4 bytes, mphash_entries: 0
    // alloc_large_system_hash("Mountpoint-cache", 4, 0, 19, 0, &m_hash_shift, &m_hash_mask, 0, 0): 16kB만큼 할당받은 메모리 주소
    mountpoint_hashtable = alloc_large_system_hash("Mountpoint-cache",
                sizeof(struct hlist_head),
                mphash_entries, 19,
                0,
                &mp_hash_shift, &mp_hash_mask, 0, 0);
    // mountpoint_hashtable: 16kB만큼 할당받은 메모리 주소

    // mount_hashtable: 16kB만큼 할당받은 메모리 주소, mountpoint_hashtable: 16kB만큼 할당받은 메모리 주소
    if (!mount_hashtable || !mountpoint_hashtable)
        panic("Failed to allocate mount hash table\n");

    // m_hash_mask: 0xFFF
    for (u = 0; u <= m_hash_mask; u++)
        // u: 0
        INIT_HLIST_HEAD(&mount_hashtable[u]);

        // INIT_HLIST_HEAD 에서 한일:
        // ((&mount_hashtable[0])->first = NULL)

        // u: 1...4095 까지 loop 수행

    // mp_hash_mask: 0xFFF
    for (u = 0; u <= mp_hash_mask; u++)
        // u: 0
        INIT_HLIST_HEAD(&mountpoint_hashtable[u]);

        // INIT_HLIST_HEAD 에서 한일:
        // ((&mountpoint_hashtable[0])->first = NULL)

        // u: 1...4095 까지 loop 수행

    // sysfs_init(): 0
    err = sysfs_init();
    // err: 0

    // err: 0
    if (err)
        printk(KERN_WARNING "%s: sysfs_init error: %d\n",
            __func__, err);
    fs_kobj = kobject_create_and_add("fs", NULL);

kobject.c::kobject_create_and_add()

  • call: start_kernel()->vfs_caches_init()->mnt_init()
    • kmem_cache_create()
    • alloc_large_system_hash() : mnt_cache
    • alloc_large_system_hash() : Mount-cache
    • alloc_large_system_hash() : Mountpoint-cache
    • INIT_HLIST_HEAD() : &mount_hashtable[u]
    • INIT_HLIST_HEAD() : &mountpoint_hashtable[u]
    • sysfs_init()
    • kobject_create_and_add() : fs
// ARM10C 20160109
// "fs", NULL
struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)
{
    struct kobject *kobj;
    int retval;

    // kobject_create(): kmem_cache#30-oX (struct kobject)
    kobj = kobject_create();

    // kobj: kmem_cache#30-oX (struct kobject)
    if (!kobj)
        return NULL;

    // kobj: kmem_cache#30-oX (struct kobject), parent: NULL, name: "fs"
    retval = kobject_add(kobj, parent, "%s", name);

kobject.c::kobject_add()

  • call: start_kernel()->vfs_caches_init()->mnt_init()
    • kmem_cache_create()
    • alloc_large_system_hash() : mnt_cache
    • alloc_large_system_hash() : Mount-cache
    • alloc_large_system_hash() : Mountpoint-cache
    • INIT_HLIST_HEAD() : &mount_hashtable[u]
    • INIT_HLIST_HEAD() : &mountpoint_hashtable[u]
    • sysfs_init()
    • kobject_create_and_add() : fs
      • kobject_add()
// ARM10C 20160109
// kobj: kmem_cache#30-oX (struct kobject), parent: NULL, "%s", name: "fs"
int kobject_add(struct kobject *kobj, struct kobject *parent,
        const char *fmt, ...)
{
    va_list args;
    int retval;

    // kobj: kmem_cache#30-oX (struct kobject)
    if (!kobj)
        return -EINVAL;

    // kobj->state_initialized: (kmem_cache#30-oX (struct kobject))->state_initialized: 1
    if (!kobj->state_initialized) {
        printk(KERN_ERR "kobject '%s' (%p): tried to add an "
               "uninitialized object, something is seriously wrong.\n",
               kobject_name(kobj), kobj);
        dump_stack();
        return -EINVAL;
    }

    // fmt: "%s"
    va_start(args, fmt);

    // va_start에서 한일:
    // (args): (((char *) &("%s")) + 4): "fs"

    // kobj: kmem_cache#30-oX (struct kobject), parent: NULL, fmt: "%s", args: "fs"
    retval = kobject_add_varg(kobj, parent, fmt, args);

kobject.c::kobject_set_name_vargs()

  • call: start_kernel()->vfs_caches_init()->mnt_init()
    • kmem_cache_create()
    • alloc_large_system_hash() : mnt_cache
    • alloc_large_system_hash() : Mount-cache
    • alloc_large_system_hash() : Mountpoint-cache
    • INIT_HLIST_HEAD() : &mount_hashtable[u]
    • INIT_HLIST_HEAD() : &mountpoint_hashtable[u]
    • sysfs_init()
    • kobject_create_and_add() : fs
      • kobject_add()
        • kobject_add_varg()
// ARM10C 20160109
// kobj: kmem_cache#30-oX (struct kobject), parent: NULL, fmt: "%s", args: "fs"
static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
                const char *fmt, va_list vargs)
{
    int retval;

    // kobj: kmem_cache#30-oX (struct kobject), fmt: "%s", vargs: "fs"
    retval = kobject_set_name_vargs(kobj, fmt, vargs);

kobject.c::kobject_set_name_vargs()

  • call: start_kernel()->vfs_caches_init()->mnt_init()
    • kmem_cache_create()
    • alloc_large_system_hash() : mnt_cache
    • alloc_large_system_hash() : Mount-cache
    • alloc_large_system_hash() : Mountpoint-cache
    • INIT_HLIST_HEAD() : &mount_hashtable[u]
    • INIT_HLIST_HEAD() : &mountpoint_hashtable[u]
    • sysfs_init()
    • kobject_create_and_add() : fs
      • kobject_add()
        • kobject_add_varg()
          • kobject_add_vargs()
// ARM10C 20160109
// kobj: kmem_cache#30-oX (struct kobject), fmt: "%s", vargs: "fs"
int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
                  va_list vargs)
{
    // kobj->name: (kmem_cache#30-oX (struct kobject))->name: NULL
    const char *old_name = kobj->name;
    // old_name: NULL

    char *s;

    // kobj->name: (kmem_cache#30-oX (struct kobject))->name: NULL, fmt: "%s"
    if (kobj->name && !fmt)
        return 0;

    // kobj->name: (kmem_cache#30-oX (struct kobject))->name: NULL
    // GFP_KERNEL: 0xD0, fmt: "%s", vargs: "fs"
    // kvasprintf(GFP_KERNEL: 0xD0, "%s", "fs"): kmem_cache#30-oX: "fs"
    kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
    // kobj->name: (kmem_cache#30-oX (struct kobject))->name: kmem_cache#30-oX: "fs"

    // kobj->name: (kmem_cache#30-oX (struct kobject))->name: kmem_cache#30-oX: "fs"
    if (!kobj->name)
        return -ENOMEM;

// 2016/01/09 종료

    /* ewww... some of these buggers have '/' in the name ... */
    while ((s = strchr(kobj->name, '/')))
        s[0] = '!';

    kfree(old_name);

kobject.c::kobject_set_name_vargs()

  • call: start_kernel()->vfs_caches_init()->mnt_init()
    • kmem_cache_create()
    • alloc_large_system_hash() : mnt_cache
    • alloc_large_system_hash() : Mount-cache
    • alloc_large_system_hash() : Mountpoint-cache
    • INIT_HLIST_HEAD() : &mount_hashtable[u]
    • INIT_HLIST_HEAD() : &mountpoint_hashtable[u]
    • sysfs_init()
    • kobject_create_and_add() : fs
      • kobject_add()
        • kobject_add_varg()
          • kobject_add_vargs()
            • kfree()
void kfree(const void *x)
{
    struct page *page;

    // x: kmem_cache#30-o11
    void *object = (void *)x;
    // object: kmem_cache#30-o11

    // _RET_IP_: __builtin_return_address(0), object: kmem_cache#30-o11
    trace_kfree(_RET_IP_, x);

    // x: kmem_cache#30-o11, ZERO_OR_NULL_PTR(kmem_cache#30-o11): 0
    if (unlikely(ZERO_OR_NULL_PTR(x)))
        return;

    // x: kmem_cache#30-o11
    // virt_to_head_page(kmem_cache#30-o11): kmem_cache#30-o11의 page 주소
    page = virt_to_head_page(x);
    // page: kmem_cache#30-o11의 page 주소

    // page: kmem_cache#30-o11의 page 주소
    // PageSlab(kmem_cache#30-o11의 page 주소): 1
    if (unlikely(!PageSlab(page))) {
        BUG_ON(!PageCompound(page));
        kfree_hook(x);
        __free_memcg_kmem_pages(page, compound_order(page));
        return;
    }

// 2014/11/29 종료
// 2014/12/06 시작

    // page->slab_cache: (kmem_cache#30-o11의 page 주소)->slab_cache,
    // page: kmem_cache#30-o11의 page 주소, object: kmem_cache#30-o11
    slab_free(page->slab_cache, page, object, _RET_IP_);

    // slab_free에서 한일:
    // (kmem_cache#30)->cpu_slab: struct kmem_cache_cpu 자료구조를 사용하기 위해 할당받은 pcp 16 byte 메모리 공간을 구하여
    // kmem_cache#30-o11의 freepointer의 값을
    // ((kmem_cache#30)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)->freelist 값으로 세팅
    // 값 s->cpu_slab->freelist와 c->freelist를 비교, 값 s->cpu_slab->tid와 tid을 비교 하여
    // 같을 경우에 s->cpu_slab->freelist와 s->cpu_slab->tid을 각각 object, next_tid(tid) 값으로 갱신하여
    // freelist와 tid 값을 변경함
    // kmem_cache_cpu의 freelist, tid 의 값을 변경함
}
EXPORT_SYMBOL(kfree);

kojbect.c::kobject_add_varg()

  • call: start_kernel()->vfs_caches_init()->mnt_init()
    • kmem_cache_create()
    • alloc_large_system_hash() : mnt_cache
    • alloc_large_system_hash() : Mount-cache
    • alloc_large_system_hash() : Mountpoint-cache
    • INIT_HLIST_HEAD() : &mount_hashtable[u]
    • INIT_HLIST_HEAD() : &mountpoint_hashtable[u]
    • sysfs_init()
    • kobject_create_and_add() : fs
      • kobject_create()
      • kobject_add()
  • call: kojbect_add()
    • kobject_add_varg()
      • kobject_set_name_vargs()
        • kfree()
      • kobject_add_internal()
static int kobject_add_internal(struct kobject *kobj)
{
    int error = 0;
    struct kobject *parent;

    if (!kobj)
        return -ENOENT;

    if (!kobj->name || !kobj->name[0]) {
        WARN(1, "kobject: (%p): attempted to be registered with empty "
             "name!\n", kobj);
        return -EINVAL;
    }

    parent = kobject_get(kobj->parent);
  • kobject_get()
struct kobject *kobject_get(struct kobject *kobj)
{
    if (kobj)
        kref_get(&kobj->kref);
    return kobj;
}

kobject.c::kobject_add()

  • call: start_kernel()->vfs_caches_init()->mnt_init()
    • kmem_cache_create()
    • alloc_large_system_hash() : mnt_cache
    • alloc_large_system_hash() : Mount-cache
    • alloc_large_system_hash() : Mountpoint-cache
    • INIT_HLIST_HEAD() : &mount_hashtable[u]
    • INIT_HLIST_HEAD() : &mountpoint_hashtable[u]
    • sysfs_init()
    • kobject_create_and_add() : fs
      • kobject_create()
      • kobject_add()
  • call: kojbect_add()
    • kobject_add_varg()
      • kobject_set_name_vargs()
        • kfree()
      • kobject_add_internal()

kobject.c::kobject_add_internal()

  • call: start_kernel()->vfs_caches_init()->mnt_init()
    • kmem_cache_create()
    • alloc_large_system_hash() : mnt_cache
    • alloc_large_system_hash() : Mount-cache
    • alloc_large_system_hash() : Mountpoint-cache
    • INIT_HLIST_HEAD() : &mount_hashtable[u]
    • INIT_HLIST_HEAD() : &mountpoint_hashtable[u]
    • sysfs_init()
    • kobject_create_and_add() : fs
      • kobject_create()
      • kobject_add()
  • call: kojbect_add()
    • kobject_add_varg()
      • kobject_set_name_vargs()
        • kfree()
      • kobject_add_internal()
// ARM10C 20160116
// kobj: kmem_cache#30-oX (struct kobject)
static int kobject_add_internal(struct kobject *kobj)
{
    int error = 0;
    // error: 0

    struct kobject *parent;

    // kobj: kmem_cache#30-oX (struct kobject)
    if (!kobj)
        return -ENOENT;

    // kobj->name: (kmem_cache#30-oX (struct kobject))->name: "fs"
    if (!kobj->name || !kobj->name[0]) {
        WARN(1, "kobject: (%p): attempted to be registered with empty "
             "name!\n", kobj);
        return -EINVAL;
    }

    // kobj->parent: (kmem_cache#30-oX (struct kobject))->parent: NULL
    // kobject_get(NULL): NULL
    parent = kobject_get(kobj->parent);
    // parent: NULL

    /* join kset if set, use it as parent if we do not already have one */
    // kobj->kset: (kmem_cache#30-oX (struct kobject))->kset: NULL
    if (kobj->kset) {
        if (!parent)
            parent = kobject_get(&kobj->kset->kobj);
        kobj_kset_join(kobj);
        kobj->parent = parent;
    }

    // kobj: kmem_cache#30-oX (struct kobject),
    // kobject_name(kmem_cache#30-oX (struct kobject)): "fs", parent: NULL,
    // kobj->kset: (kmem_cache#30-oX (struct kobject))->kset: NULL
    pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
         kobject_name(kobj), kobj, __func__,
         parent ? kobject_name(parent) : "<NULL>",
         kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
    // "kobject: 'fs' (kmem_cache#30-oX): kobject_add_internal: parent: '<NULL>', set: '<NULL>'\n"

    // kobj: kmem_cache#30-oX (struct kobject)
    error = create_dir(kobj);

dir.c::create_dir()

  • call: start_kernel()->vfs_caches_init()->mnt_init()
    • kmem_cache_create()
    • alloc_large_system_hash() : mnt_cache
    • alloc_large_system_hash() : Mount-cache
    • alloc_large_system_hash() : Mountpoint-cache
    • INIT_HLIST_HEAD() : &mount_hashtable[u]
    • INIT_HLIST_HEAD() : &mountpoint_hashtable[u]
    • sysfs_init()
    • kobject_create_and_add() : fs
      • kobject_create()
      • kobject_add()
  • call: kojbect_add()
    • kobject_add_varg()
      • kobject_set_name_vargs()
        • kfree()
      • kobject_add_internal()
        • create_dir()
  • call: carete_dir()
// ARM10C 20160116
// kobj: kmem_cache#30-oX (struct kobject), parent_sd: &sysfs_root, type: 0,
// kobject_name(kmem_cache#30-oX (struct kobject)): "fs", ns: NULL, &sd
static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
              enum kobj_ns_type type,
              const char *name, const void *ns,
              struct sysfs_dirent **p_sd)
{
    // S_IFDIR: 0040000, S_IRWXU: 00700, S_IRUGO: 00444, S_IXUGO: 00111
    umode_t mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
    // mode: 0x41ED

    struct sysfs_addrm_cxt acxt;
    struct sysfs_dirent *sd;
    int rc;

    /* allocate */
    // name: "fs", mode: 0x41ED, SYSFS_DIR: 0x0001
    // sysfs_new_dirent("fs", 0x41ED, 0x0001): kmem_cache#1-oX (struct sysfs_dirent)
    sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
  • sysfs_new_dirent에서 한일: // sysfs_dir_cachep: kmem_cache#1을 이용하여 struct sysfs_dirent 메모리를 할당받음 // kmem_cache#1-oX (struct sysfs_dirent) // // (&(&sysfs_ino_ida)->idr)->id_free: NULL // (&(&sysfs_ino_ida)->idr)->id_free_cnt: 6 // (&(&sysfs_ino_ida)->idr)->top: kmem_cache#21-o7 (struct idr_layer) // (&(&sysfs_ino_ida)->idr)->layers: 1 // (&sysfs_ino_ida)->free_bitmap: NULL // // (kmem_cache#21-o7 (struct idr_layer))->ary[0]: NULL // (kmem_cache#21-o7 (struct idr_layer))->layer: 0 // (kmem_cache#21-o7 (struct idr_layer))->ary[0]: kmem_cache#27-oX (struct ida_bitmap) // (kmem_cache#21-o7 (struct idr_layer))->count: 1 // // (kmem_cache#27-oX (struct ida_bitmap))->bitmap 의 0 bit를 1로 set 수행 // // (kmem_cache#1-oX (struct sysfs_dirent))->s_ino: 2 // // (&(kmem_cache#1-oX (struct sysfs_dirent))->s_count)->counter: 1 // (&(kmem_cache#1-oX (struct sysfs_dirent))->s_active)->counter: 0 // (kmem_cache#1-oX (struct sysfs_dirent))->s_name: "fs" // (kmem_cache#1-oX (struct sysfs_dirent))->s_mode: 0x41ED // (kmem_cache#1-oX (struct sysfs_dirent))->s_flags: 0x2001

dir.c::create_dir()

  • call: start_kernel()->vfs_caches_init()->mnt_init()
    • kmem_cache_create()
    • alloc_large_system_hash() : mnt_cache
    • alloc_large_system_hash() : Mount-cache
    • alloc_large_system_hash() : Mountpoint-cache
    • INIT_HLIST_HEAD() : &mount_hashtable[u]
    • INIT_HLIST_HEAD() : &mountpoint_hashtable[u]
    • sysfs_init()
    • kobject_create_and_add() : fs
      • kobject_create()
      • kobject_add()
  • call: kojbect_add()
    • kobject_add_varg()
      • kobject_set_name_vargs()
        • kfree()
      • kobject_add_internal()
        • create_dir()
  • call: carete_dir()
// ARM10C 20160116
// kobj: kmem_cache#30-oX (struct kobject), parent_sd: &sysfs_root, type: 0,
// kobject_name(kmem_cache#30-oX (struct kobject)): "fs", ns: NULL, &sd
static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
              enum kobj_ns_type type,
              const char *name, const void *ns,
              struct sysfs_dirent **p_sd)
{
    // S_IFDIR: 0040000, S_IRWXU: 00700, S_IRUGO: 00444, S_IXUGO: 00111
    umode_t mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
    // mode: 0x41ED

    struct sysfs_addrm_cxt acxt;
    struct sysfs_dirent *sd;
    int rc;

    /* allocate */
    // name: "fs", mode: 0x41ED, SYSFS_DIR: 0x0001
    // sysfs_new_dirent("fs", 0x41ED, 0x0001): kmem_cache#1-oX (struct sysfs_dirent)
    sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
  • sysfs_new_dirent에서 한일: // sysfs_dir_cachep: kmem_cache#1을 이용하여 struct sysfs_dirent 메모리를 할당받음 // kmem_cache#1-oX (struct sysfs_dirent) // // (&(&sysfs_ino_ida)->idr)->id_free: NULL // (&(&sysfs_ino_ida)->idr)->id_free_cnt: 6 // (&(&sysfs_ino_ida)->idr)->top: kmem_cache#21-o7 (struct idr_layer) // (&(&sysfs_ino_ida)->idr)->layers: 1 // (&sysfs_ino_ida)->free_bitmap: NULL // // (kmem_cache#21-o7 (struct idr_layer))->ary[0]: NULL // (kmem_cache#21-o7 (struct idr_layer))->layer: 0 // (kmem_cache#21-o7 (struct idr_layer))->ary[0]: kmem_cache#27-oX (struct ida_bitmap) // (kmem_cache#21-o7 (struct idr_layer))->count: 1 // // (kmem_cache#27-oX (struct ida_bitmap))->bitmap 의 0 bit를 1로 set 수행 // // (kmem_cache#1-oX (struct sysfs_dirent))->s_ino: 2 // // (&(kmem_cache#1-oX (struct sysfs_dirent))->s_count)->counter: 1 // (&(kmem_cache#1-oX (struct sysfs_dirent))->s_active)->counter: 0 // (kmem_cache#1-oX (struct sysfs_dirent))->s_name: "fs" // (kmem_cache#1-oX (struct sysfs_dirent))->s_mode: 0x41ED // (kmem_cache#1-oX (struct sysfs_dirent))->s_flags: 0x2001
  • configfs_attach_attr()
  • sysfs_new_dirent()
  • dir.c::sysfs_alloc_ino()
static int sysfs_alloc_ino(unsigned int *pino)
{
    int ino, rc;

 retry:
    spin_lock(&sysfs_ino_lock);
    rc = ida_get_new_above(&sysfs_ino_ida, 2, &ino);
    spin_unlock(&sysfs_ino_lock);

    if (rc == -EAGAIN) {
        if (ida_pre_get(&sysfs_ino_ida, GFP_KERNEL))
            goto retry;
        rc = -ENOMEM;
    }

    *pino = ino;
    return rc;
}
  • return sysfs_alloc_ino() 가 한일.

dir.c::create_dir()

  • call: start_kernel()->vfs_caches_init()->mnt_init()
    • kmem_cache_create()
    • alloc_large_system_hash() : mnt_cache
    • alloc_large_system_hash() : Mount-cache
    • alloc_large_system_hash() : Mountpoint-cache
    • INIT_HLIST_HEAD() : &mount_hashtable[u]
    • INIT_HLIST_HEAD() : &mountpoint_hashtable[u]
    • sysfs_init()
    • kobject_create_and_add() : fs
      • kobject_create()
      • kobject_add()
  • call: kojbect_add()
    • kobject_add_varg()
      • kobject_set_name_vargs()
        • kfree()
      • kobject_add_internal()
        • create_dir()
  • call: carete_dir()
    • sysfs_new_dirent()
  • struct sysfs_dirent *sd
// sizeof(struct sysfs_dirent): 64 bytes
struct sysfs_dirent {
    atomic_t        s_count;
    atomic_t        s_active;
#ifdef CONFIG_DEBUG_LOCK_ALLOC // CONFIG_DEBUG_LOCK_ALLOC=n
    struct lockdep_map  dep_map;
#endif
    struct sysfs_dirent *s_parent;
    const char      *s_name;

    struct rb_node      s_rb;

    union {
        struct completion   *completion;
        struct sysfs_dirent *removed_list;
    } u;

    const void      *s_ns; /* namespace tag */
    unsigned int        s_hash; /* ns + name hash */
    union {
        struct sysfs_elem_dir       s_dir;
        struct sysfs_elem_symlink   s_symlink;
        struct sysfs_elem_attr      s_attr;
    };

    unsigned short      s_flags;
    umode_t         s_mode;
    unsigned int        s_ino;
    struct sysfs_inode_attrs *s_iattr;
};
// ARM10C 20160116
// kobj: kmem_cache#30-oX (struct kobject), parent_sd: &sysfs_root, type: 0,
// kobject_name(kmem_cache#30-oX (struct kobject)): "fs", ns: NULL, &sd
static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
              enum kobj_ns_type type,
              const char *name, const void *ns,
              struct sysfs_dirent **p_sd)
{
    // S_IFDIR: 0040000, S_IRWXU: 00700, S_IRUGO: 00444, S_IXUGO: 00111
    umode_t mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
    // mode: 0x41ED

    struct sysfs_addrm_cxt acxt;
    struct sysfs_dirent *sd;
    int rc;

    /* allocate */
    // name: "fs", mode: 0x41ED, SYSFS_DIR: 0x0001
    // sysfs_new_dirent("fs", 0x41ED, 0x0001): kmem_cache#1-oX (struct sysfs_dirent)
    sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
    // sd: kmem_cache#1-oX (struct sysfs_dirent)

    // sd: kmem_cache#1-oX (struct sysfs_dirent)
    if (!sd)
        return -ENOMEM;

    sd->s_flags |= (type << SYSFS_NS_TYPE_SHIFT);
    sd->s_ns = ns;
    sd->s_dir.kobj = kobj;

    /* link in */
    sysfs_addrm_start(&acxt);

dir.c::sysfs_addrm_start()

  • call: start_kernel()->vfs_caches_init()->mnt_init()
    • kmem_cache_create()
    • alloc_large_system_hash() : mnt_cache
    • alloc_large_system_hash() : Mount-cache
    • alloc_large_system_hash() : Mountpoint-cache
    • INIT_HLIST_HEAD() : &mount_hashtable[u]
    • INIT_HLIST_HEAD() : &mountpoint_hashtable[u]
    • sysfs_init()
    • kobject_create_and_add() : fs
      • kobject_create()
      • kobject_add()
  • call: kojbect_add()
    • kobject_add_varg()
      • kobject_set_name_vargs()
        • kfree()
      • kobject_add_internal()
        • create_dir()
  • call: carete_dir()
    • sysfs_new_dirent()
    • sysfs_addrm_start()
``dir.c void sysfs_addrm_start(struct sysfs_addrm_cxt acxt) __acquires(sysfs_mutex) { memset(acxt, 0, sizeof(acxt));
mutex_lock(&sysfs_mutex);
}

* sysfs_addrm_start()에서 한일

## dir.c::create_dir()

* call: start_kernel()->vfs_caches_init()->mnt_init()
  - kmem_cache_create()
  - alloc_large_system_hash() : mnt_cache
  - alloc_large_system_hash() : Mount-cache
  - alloc_large_system_hash() : Mountpoint-cache
  - INIT_HLIST_HEAD() : &mount_hashtable[u]
  - INIT_HLIST_HEAD() : &mountpoint_hashtable[u]
  - sysfs_init()
  - kobject_create_and_add() : fs
    - kobject_create()
    - kobject_add()

* call: kojbect_add()
  - kobject_add_varg()
    - kobject_set_name_vargs()
      - kfree()
    - kobject_add_internal()
      - create_dir()

* call: create_dir()
  - sysfs_new_dirent()
  - sysfs_addrm_start()

```dir.c
// ARM10C 20160116
// kobj: kmem_cache#30-oX (struct kobject), parent_sd: &sysfs_root, type: 0,
// kobject_name(kmem_cache#30-oX (struct kobject)): "fs", ns: NULL, &sd
static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
              enum kobj_ns_type type,
              const char *name, const void *ns,
              struct sysfs_dirent **p_sd)
{
    // S_IFDIR: 0040000, S_IRWXU: 00700, S_IRUGO: 00444, S_IXUGO: 00111
    umode_t mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
    // mode: 0x41ED

    struct sysfs_addrm_cxt acxt;
    struct sysfs_dirent *sd;
    int rc;

    /* allocate */
    // name: "fs", mode: 0x41ED, SYSFS_DIR: 0x0001
    // sysfs_new_dirent("fs", 0x41ED, 0x0001): kmem_cache#1-oX (struct sysfs_dirent)
    sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
    // sd: kmem_cache#1-oX (struct sysfs_dirent)

    // sd: kmem_cache#1-oX (struct sysfs_dirent)
    if (!sd)
        return -ENOMEM;

    sd->s_flags |= (type << SYSFS_NS_TYPE_SHIFT);
    sd->s_ns = ns;
    sd->s_dir.kobj = kobj;

    /* link in */
    sysfs_addrm_start(&acxt);
    rc = sysfs_add_one(&acxt, sd, parent_sd);

dir.c::sysfs_add_one()

  • call: start_kernel()->vfs_caches_init()->mnt_init()
    • kmem_cache_create()
    • alloc_large_system_hash() : mnt_cache
    • alloc_large_system_hash() : Mount-cache
    • alloc_large_system_hash() : Mountpoint-cache
    • INIT_HLIST_HEAD() : &mount_hashtable[u]
    • INIT_HLIST_HEAD() : &mountpoint_hashtable[u]
    • sysfs_init()
    • kobject_create_and_add() : fs
      • kobject_create()
      • kobject_add()
  • call: kojbect_add()
    • kobject_add_varg()
      • kobject_set_name_vargs()
        • kfree()
      • kobject_add_internal()
        • create_dir()
  • call: create_dir()
    • sysfs_new_dirent()
    • sysfs_addrm_start()
    • sysfs_add_one()
int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd,
          struct sysfs_dirent *parent_sd)
{
    int ret;

    ret = __sysfs_add_one(acxt, sd, parent_sd);

    if (ret == -EEXIST)
        sysfs_warn_dup(parent_sd, sd->s_name);
    return ret;
}

dir.c::__sysfs_add_one()

  • call: start_kernel()->vfs_caches_init()->mnt_init()
    • kmem_cache_create()
    • alloc_large_system_hash() : mnt_cache
    • alloc_large_system_hash() : Mount-cache
    • alloc_large_system_hash() : Mountpoint-cache
    • INIT_HLIST_HEAD() : &mount_hashtable[u]
    • INIT_HLIST_HEAD() : &mountpoint_hashtable[u]
    • sysfs_init()
    • kobject_create_and_add() : fs
      • kobject_create()
      • kobject_add()
  • call: kojbect_add()
    • kobject_add_varg()
      • kobject_set_name_vargs()
        • kfree()
      • kobject_add_internal()
        • create_dir()
  • call: create_dir()
    • sysfs_new_dirent()
    • sysfs_addrm_start()
    • sysfs_add_one()
      • sysfs_add_one()
  • struct sysfs_inode_attrs
// ARM10C 20151205
struct sysfs_inode_attrs {
    struct iattr    ia_iattr;
    void        *ia_secdata;
    u32     ia_secdata_len;
};
int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd,
            struct sysfs_dirent *parent_sd)
{
    struct sysfs_inode_attrs *ps_iattr;
    int ret;

    if (!!sysfs_ns_type(parent_sd) != !!sd->s_ns) {
        WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n",
            sysfs_ns_type(parent_sd) ? "required" : "invalid",
            parent_sd->s_name, sd->s_name);
        return -EINVAL;
    }

    sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns);
    sd->s_parent = sysfs_get(parent_sd);

    ret = sysfs_link_sibling(sd);
    if (ret)
        return ret;

    /* Update timestamps on the parent */
    ps_iattr = parent_sd->s_iattr;
    if (ps_iattr) {
        struct iattr *ps_iattrs = &ps_iattr->ia_iattr;
        ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME;
    }

    /* Mark the entry added into directory tree */
    sd->s_flags &= ~SYSFS_FLAG_REMOVED;

    return 0;
}
  • sysfs.h::sysfs_ns_type()
static inline enum kobj_ns_type sysfs_ns_type(struct sysfs_dirent *sd)
{
    return (sd->s_flags & SYSFS_NS_TYPE_MASK) >> SYSFS_NS_TYPE_SHIFT;
}

dir.c::__sysfs_add_one()

  • call: start_kernel()->vfs_caches_init()->mnt_init()
    • kmem_cache_create()
    • alloc_large_system_hash() : mnt_cache
    • alloc_large_system_hash() : Mount-cache
    • alloc_large_system_hash() : Mountpoint-cache
    • INIT_HLIST_HEAD() : &mount_hashtable[u]
    • INIT_HLIST_HEAD() : &mountpoint_hashtable[u]
    • sysfs_init()
    • kobject_create_and_add() : fs
      • kobject_create()
      • kobject_add()
  • call: kojbect_add()
    • kobject_add_varg()
      • kobject_set_name_vargs()
        • kfree()
      • kobject_add_internal()
        • create_dir()
  • call: create_dir()
    • sysfs_new_dirent()
    • sysfs_addrm_start()
    • sysfs_add_one()
      • sysfs_add_one()
        • sysfs_ns_type()
        • sysfs_name_hash()
static unsigned int sysfs_name_hash(const char *name, const void *ns)
{
    unsigned long hash = init_name_hash();
    unsigned int len = strlen(name);
    while (len--)
        hash = partial_name_hash(*name++, hash);
    hash = (end_name_hash(hash) ^ hash_ptr((void *)ns, 31));
    hash &= 0x7fffffffU;
    /* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */
    if (hash < 1)
        hash += 2;
    if (hash >= INT_MAX)
        hash = INT_MAX - 1;
    return hash;
}
  • partial_name_hash()
static inline unsigned long
partial_name_hash(unsigned long c, unsigned long prevhash)
{
    return (prevhash + (c << 4) + (c >> 4)) * 11;
}
  • return 0x4662
  • call: start_kernel()->vfs_caches_init()->mnt_init()
    • kmem_cache_create()
    • alloc_large_system_hash() : mnt_cache
    • alloc_large_system_hash() : Mount-cache
    • alloc_large_system_hash() : Mountpoint-cache
    • INIT_HLIST_HEAD() : &mount_hashtable[u]
    • INIT_HLIST_HEAD() : &mountpoint_hashtable[u]
    • sysfs_init()
    • kobject_create_and_add() : fs
      • kobject_create()
      • kobject_add()
  • call: kojbect_add()
    • kobject_add_varg()
      • kobject_set_name_vargs()
        • kfree()
      • kobject_add_internal()
        • create_dir()
  • call: create_dir()
    • sysfs_new_dirent()
    • sysfs_addrm_start()
    • sysfs_add_one()
      • sysfs_add_one()
        • sysfs_ns_type()
        • sysfs_name_hash()
          • partial_name_hash()
        • sysfs_get()
        • sysfs_link_sibling()
  • sysfs_get()
// ARM10C 20151205
// sd: &sysfs_root
struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd)
{
    // sd: &sysfs_root
    // __sysfs_get(&sysfs_root): 2
    return __sysfs_get(sd);
    // return 2

    // __sysfs_get에서 한일:
    // (&sysfs_root)->s_count: 2
}
EXPORT_SYMBOL_GPL(sysfs_get);

dir.c::sysfs_link_sibling()

  • call: start_kernel()->vfs_caches_init()->mnt_init()
    • kmem_cache_create()
    • alloc_large_system_hash() : mnt_cache
    • alloc_large_system_hash() : Mount-cache
    • alloc_large_system_hash() : Mountpoint-cache
    • INIT_HLIST_HEAD() : &mount_hashtable[u]
    • INIT_HLIST_HEAD() : &mountpoint_hashtable[u]
    • sysfs_init()
    • kobject_create_and_add() : fs
      • kobject_create()
      • kobject_add()
  • call: kojbect_add()
    • kobject_add_varg()
      • kobject_set_name_vargs()
        • kfree()
      • kobject_add_internal()
        • create_dir()
  • call: create_dir()
    • sysfs_new_dirent()
    • sysfs_addrm_start()
    • sysfs_add_one()
      • sysfs_add_one()
        • sysfs_ns_type()
        • sysfs_name_hash()
          • partial_name_hash()
        • sysfs_get()
        • sysfs_link_sibling()
static int sysfs_link_sibling(struct sysfs_dirent *sd)
{
    struct rb_node **node = &sd->s_parent->s_dir.children.rb_node;
    struct rb_node *parent = NULL;

    if (sysfs_type(sd) == SYSFS_DIR)
        sd->s_parent->s_dir.subdirs++;

    while (*node) {
        struct sysfs_dirent *pos;
        int result;

        pos = to_sysfs_dirent(*node);
        parent = *node;
        result = sysfs_sd_compare(sd, pos);
        if (result < 0)
            node = &pos->s_rb.rb_left;
        else if (result > 0)
            node = &pos->s_rb.rb_right;
        else
            return -EEXIST;
    }
    /* add new node and rebalance the tree */
    rb_link_node(&sd->s_rb, parent, node);
    rb_insert_color(&sd->s_rb, &sd->s_parent->s_dir.children);
    return 0;
}

log

  • 1st log
f8705f2..87dee88  master     -> origin/master
Updating f8705f2..87dee88
Fast-forward
arch/arm/include/asm/atomic.h         |   4 +
fs/sysfs/dir.c                        | 168 ++++++++++++++++++++++++++++++++++
fs/sysfs/mount.c                      |   2 +
fs/sysfs/sysfs.h                      |  10 ++
include/asm-generic/bug.h             |   1 +
include/linux/gfp.h                   |   1 +
include/linux/idr.h                   |  20 ++++
include/linux/kobject.h               |   6 ++
include/linux/kobject_ns.h            |   3 +
include/linux/slab.h                  |   5 +
include/linux/spinlock.h              |   4 +
include/linux/spinlock_types.h        |  12 +++
include/linux/stat.h                  |   2 +
include/linux/sysfs.h                 |   1 +
include/linux/types.h                 |   1 +
include/uapi/asm-generic/errno-base.h |   1 +
include/uapi/linux/stat.h             |   3 +
lib/idr.c                             |   2 +
lib/kasprintf.c                       |  19 +++-
lib/kobject.c                         |  73 ++++++++++++++-
lib/string.c                          |   2 +
mm/slub.c                             |   2 +
22 files changed, 339 insertions(+), 3 deletions(-)
  • 2nd log
87dee88..cc4b18b  master     -> origin/master
Updating 87dee88..cc4b18b
Fast-forward
fs/sysfs/dir.c         | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
fs/sysfs/mount.c       |  12 ++++++++++--
fs/sysfs/sysfs.h       |  17 +++++++++++++++++
include/linux/dcache.h |  13 +++++++++++++
include/linux/fs.h     |   1 +
include/linux/hash.h   |   9 +++++++++
include/linux/rbtree.h |   4 ++++
include/linux/sysfs.h  |   1 +
kernel/locking/mutex.c |   2 ++
lib/rbtree.c           |   2 ++
lib/string.c           |   2 ++
11 files changed, 187 insertions(+), 2 deletions(-)