顯示具有 kernel 標籤的文章。 顯示所有文章
顯示具有 kernel 標籤的文章。 顯示所有文章

2012年12月3日 星期一

Note about Linux Kernel char Device Driver

There are two ways to create a struct cdev:
  1. static way
    • declare
      • embedded in your device structure statically
        struct dummy_device {
            struct cdev cdev;
        };
    • initialize
      •  use cdev_init() function to initialize the cdev structure
        struct dummy_device dev;
        ...
        cdev_init(&dev.cdev, &dummy_fops);
    • remove
      • call cdev_del()
  2. dynamic way
    • declare
      • memory of cdev structure is allocated dynamically
        struct dummy_device {
            struct cdev *cdev;
        };
        ...
        struct dymmy_device dev;
        dev->cdev = cdev_alloc();
    • initialize
      • dev->cdev.fops = &dummy_fops;
    • remove
      • call cdev_del()
      • You don't need to call kfree() to free memory. Kernel releases the memory automatically. (talk this later)  
There is one thing you need to know about the dynamic way. 
If you use dynamic way to create a cdev structure, you should better not use cdev_init() to initialize the structure.

Let's check source code.

void cdev_init(struct cdev *cdev, 
               const struct file_operations *fops)
{
    memset(cdev, 0, sizeof *cdev);
    INIT_LIST_HEAD(&cdev->list);
    kobject_init(&cdev->kobj, &ktype_cdev_default);

    cdev->ops = fops;
}

struct cdev *cdev_alloc(void)
{

    /* cdev is allocated here! */
    struct cdev *p = kzalloc(sizeof(struct cdev),
                     GFP_KERNEL);
    if (p) {
        INIT_LIST_HEAD(&p->list);
        kobject_init(&p->kobj, &ktype_cdev_dynamic);
    }
    return p;
}

If you use dynamic way to create the cdev structure, ktype_cdev_dynamic() is used to release cdev kobject.
If you use cdev_init() to initialize cdev structure that is created in dynamic way, release function of kobject is replaced with ktype_cdev_default().
In this case, after you invoke cdev_del() to remove a cdev device from kernel, this causes a memory leak.
You need to free memory manually and it is not recommended.

static void cdev_default_release(struct kobject *kobj)
{
    struct cdev *p = container_of(kobj, struct cdev, kobj);
    cdev_purge(p);
}

static void cdev_dynamic_release(struct kobject *kobj)
{
    struct cdev *p = container_of(kobj, struct cdev, kobj);
    cdev_purge(p);
    kfree(p);    /* cdev is freed here! */
}

static struct kobj_type ktype_cdev_default = {
    .release        = cdev_default_release,
};

static struct kobj_type ktype_cdev_dynamic = {
    .release        = cdev_dynamic_release,
};

2012年11月23日 星期五

How "mtdparts=" Kernel Command Line Work in Nexus One

I am just wondering how it works.
And...source code is your answers.

I clone kernel source from cm-kernel
https://github.com/CyanogenMod/cm-kernel.git
branch: android-msm-2.6.37

  1. arch/arm/mach-msm/nand_partitions.c:
    Extract partition information from ATAG setup by boot loader.

    static int __init parse_tag_msm_partition(...)

    {
        ....
        msm_nand_data.nr_parts = count;
        msm_nand_data.parts = msm_nand_partitions;

        return 0;
    }


    This puts partition information into flash_platform_data

  2. drivers/mtd/devices/msm_nand.c  (msm nand flash controller driver)

    // request to use cmdlinepart parser
    static const char *part_probes[] = { "cmdlinepart", NULL,  };
    ...
    static int __devinit msm_nand_probe(struct platform_device *pdev)
    {
        ...
    #ifdef CONFIG_MTD_PARTITIONS
        err = parse_mtd_partitions(&info->mtd, part_probes,    
                                   &info->parts, 0);

        // if kernel command line has partition information, use it!
        if (err > 0)
            add_mtd_partitions(&info->mtd, info->parts, err);
        else if (err <= 0 && pdata && pdata->parts) {
            // else use partition information from boot loader
            for (i = 0; i < pdata->nr_parts; ++i) {
                pdata->parts[i].offset *= info->mtd.erasesize;
                pdata->parts[i].size *= info->mtd.erasesize;
            }
            add_mtd_partitions(&info->mtd,
                               pdata->parts, pdata->nr_parts);
        } else
    #endif
            err = add_mtd_device(&info->mtd);
    }

2010年2月21日 星期日

My First Linux Kernel Patch

看到自己的 patch 被加到其它 kernel hacker 的 git tree 中...
還蠻感動的...
http://git.kernel.org/?p=linux/kernel/git/sarah/xhci.git;a=commit;h=583f156bde78f678bad42ddd815b43bab89309e1

ps: 不知道什麼時候才會真的進 mainline

不過 patch 有兩個地方有點錯誤..
1. Subject line 的 subsystem
USB: xhci: 應該為 xhci: 比較正確
2. Body of the explanation 有 typo
最後一行的 legacy sup support. 應該是 legacy support.

呼~下次會多注意這些小地方..
希望末來還有機會能 submit kernel patch .. :)

2009年10月6日 星期二

Linux Kernel netconsole

[Server]
./netcat -u -l -p 6666 | tee /tmp/123.log

[Client]
ifconfig eth0 up
ifconfig eth0 192.168.19.183 netmask 255.255.255.0 up

insmode netconsole.ko netconsole=@/eth0,@192.168.19.43/

記錄一下下~~

2009年4月23日 星期四

Linux init call

[linux-2.6.28.3]
在 Linux kernel 中做 init call 的做法..很有趣..
在 link script 中加入幾個section..

include/asm-generic/vmlinux.lds.h
#define INITCALLS \
*(.initcallearly.init) \
VMLINUX_SYMBOL(__early_initcall_end) = .; \
*(.initcall0.init) \
*(.initcall0s.init) \
*(.initcall1.init) \
*(.initcall1s.init) \
*(.initcall2.init) \
*(.initcall2s.init) \
*(.initcall3.init) \
*(.initcall3s.init) \
*(.initcall4.init) \
*(.initcall4s.init) \
*(.initcall5.init) \
*(.initcall5s.init) \
*(.initcallrootfs.init) \
*(.initcall6.init) \
*(.initcall6s.init) \
*(.initcall7.init) \
*(.initcall7s.init)

arch/x86/kernel/vmlinux_32.lds.S
.initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
__initcall_start = .;
INITCALLS
__initcall_end = .;
}

include/linux/init.h
#define __define_initcall(level,fn,id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" level ".init"))) = fn

/*
* Early initcalls run before initializing SMP.
*
* Only for built-in code, not modules.
*/
#define early_initcall(fn) __define_initcall("early",fn,early)

/*
* A "pure" initcall has no dependencies on anything else, and purely
* initializes variables that couldn't be statically initialized.
*
* This only exists for built-in code, not for modules.
*/
#define pure_initcall(fn) __define_initcall("",fn,0)

#define core_initcall(fn) __define_initcall("1",fn,1)
#define core_initcall_sync(fn) __define_initcall("1s",fn,1s)
#define postcore_initcall(fn) __define_initcall("2",fn,2)
#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)
#define arch_initcall(fn) __define_initcall("3",fn,3)
#define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)
#define subsys_initcall(fn) __define_initcall("4",fn,4)
#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)
#define fs_initcall(fn) __define_initcall("5",fn,5)
#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)
#define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)
#define device_initcall(fn) __define_initcall("6",fn,6)
#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
#define late_initcall(fn) __define_initcall("7",fn,7)
#define late_initcall_sync(fn) __define_initcall("7s",fn,7s)

init/main.c
static void __init do_initcalls(void)
{
initcall_t *call;

for (call = __early_initcall_end; call < __initcall_end; call++)
do_one_initcall(*call);

/* Make sure there is no pending stuff from the initcall sequence */
flush_scheduled_work();
}

static void __init do_pre_smp_initcalls(void)
{
initcall_t *call;

for (call = __initcall_start; call < __early_initcall_end; call++)
do_one_initcall(*call);
}


2009年4月1日 星期三

Kernel Modesetting (KMS)

將原本 X server 設定 graphics mode 的工作(在 X server's DDX drivers 中)..搬到 kernel 來做..
還蠻有趣的.. 在 2.6.29 中己加入~~

下面是一些相關的link
Kernel Modesetting and Memory Management



2009年3月31日 星期二

Real World Benchmarks Of The EXT4 File-System

Phoronix 上給 EXT4 做的測試 ..
裡面提到一些 I/O testing 的工具..
可以做為參考...

[Phoronix] Real World Benchmarks Of The EXT4 File-System