2010年1月5日 星期二

Linux Kernel(9)- Kthread


在kernel中建立thread可以使用kthread_create(),建立一個task,然後在調用wake_up_process(task)讓task真正的運行,如果要kill一個kthread可以使用kthread_stop()。
在kernel中,將kthread_create()和wake_up_process()包裝成kthread_run(),也就是調用了kthread_run()之後,該thread會立刻被執行。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>

MODULE_LICENSE("GPL");

static struct task_struct *brook_tsk;
static int data;
static int kbrook(void *arg);

static int kbrook(void *arg)
{
    unsigned int timeout;
    int *d = (int *) arg;

    for(;;) {
        if (kthread_should_stop()) break;
        printk("%s(): %d\n", __FUNCTION__, (*d)++);
        do {
            set_current_state(TASK_INTERRUPTIBLE);
            timeout = schedule_timeout(10 * HZ);
        } while(timeout);
    }
    printk("break\n");

    return 0;
}

static int __init init_modules(void)
{
    int ret;

    brook_tsk = kthread_create(kbrook, &data, "brook");
    if (IS_ERR(brook_tsk)) {
        ret = PTR_ERR(brook_tsk);
        brook_tsk = NULL;
        goto out;
    }
    wake_up_process(brook_tsk);

    return 0;

out:
    return ret;
}

static void __exit exit_modules(void)
{
    kthread_stop(brook_tsk);
}

module_init(init_modules);
module_exit(exit_modules);


linux/kthread.h
/**
 * kthread_run - create and wake a thread.
 * @threadfn: the function to run until signal_pending(current).
 * @data: data ptr for @threadfn.
 * @namefmt: printf-style name for the thread.
 *
 * Description: Convenient wrapper for kthread_create() followed by
 * wake_up_process().  Returns the kthread or ERR_PTR(-ENOMEM).
 */
#define kthread_run(threadfn, data, namefmt, ...)      \
({            \
 struct task_struct *__k         \
  = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
 if (!IS_ERR(__k))         \
  wake_up_process(__k);        \
 __k;           \
})


2010年1月4日 星期一

ubuntu package - bind9-host


host主要拿來作DNS的lookup,和nslookup一樣,可以作正解(lookup/由domain name找到IP),也可以作反解(reverse lookup/由IP找到domain name),大多數的User比較常接觸到的是正解。
brook@ubuntu:~$ host dns.hinet.net
dns.hinet.net has address 168.95.1.1
brook@ubuntu:~$ 
brook@ubuntu:~$ host 168.95.1.1
1.1.95.168.in-addr.arpa domain name pointer dns.hinet.net.
brook@ubuntu:~$ 
brook@ubuntu:~$ host www.google.com
www.google.com is an alias for www.l.google.com.
www.l.google.com has address 72.14.203.99
www.l.google.com has address 72.14.203.147
www.l.google.com has address 72.14.203.104
www.l.google.com has address 72.14.203.103
www.l.google.com has address 72.14.203.105
www.l.google.com has address 72.14.203.106
brook@ubuntu:~$ 
brook@ubuntu:~$ host 72.14.203.99
99.203.14.72.in-addr.arpa domain name pointer tx-in-f99.1e100.net.

建議參考資料︰
  http://linux.vbird.org/linux_server/0350dns.php
  http://plog.longwin.com.tw/news_security/2005/11/06/dns_error_top_3

2010年1月3日 星期日

Linux Kernel(8)- Notification


Kernel提供一個notifiers/notifier chains的機制,這是publish-and-subscribe的機制,也就是需要的人自己去訂閱(join到某個notifier chain中),當這個chain的provider有事件要發布,就publish出來(發布給join這個chain的所有人)。
kernel中也提供了一些notifier,如reboot,可以透過register_reboot_notifier()訂閱,用unregister_reboot_notifier()取消訂閱。我們也可以自訂自己的notifier,以下例子就是自訂一個notifier。此一範例為透過寫入/proc/brook_notifier將資料publish給訂閱brook_notifier_list的scbscriber

notifier publisher
#include <linux/init.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>

#include "notifier.h"

MODULE_LICENSE("GPL");
// 宣告一個新的notifier list – brook_notifier_list
BLOCKING_NOTIFIER_HEAD(brook_notifier_list);

// 訂閱brook_notifier_list事件的wrapper function
int register_brook_notifier(struct notifier_block *nb)
{
    return blocking_notifier_chain_register(&brook_notifier_list, nb);
}
EXPORT_SYMBOL(register_brook_notifier);

// 取消訂閱brook_notifier_list事件的wrapper function
int unregister_brook_notifier(struct notifier_block *nb)
{
    return blocking_notifier_chain_unregister(&brook_notifier_list, nb);
}
EXPORT_SYMBOL(unregister_brook_notifier);

// procfs的write function
static int write_proc(struct file *filp, const char __user *buf,
                               unsigned long count, void *data)
{
    char *p = kzalloc(sizeof(char) * count, GFP_KERNEL);
    if (!p) {
        printk("no mem\n");
        return -ENOMEM;
    }
    if (copy_from_user(p, buf, count)) {
        printk("fault\n");
        return -EFAULT;
    }
    printk("%s(): msg=\"%s\"\n", __FUNCTION__, p);

    // 將事件published給brook_notifier_list的subscriber
    blocking_notifier_call_chain(&brook_notifier_list, brook_num1, (void*)p);
    kfree(p);
    return count;
}

static int __init init_modules(void)
{
    struct proc_dir_entry *ent;

    ent = create_proc_entry("brook_notifier", S_IFREG | S_IWUSR, NULL);
    if (!ent) {
        printk("create proc child failed\n");
    } else {
        ent->write_proc = write_proc;
    }
    return 0;
}

static void __exit exit_modules(void)
{
    remove_proc_entry("brook_notifier", NULL);
}

module_init(init_modules);
module_exit(exit_modules);


notifier subscriber
#include <linux/init.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/notifier.h>

#include "notifier.h"

MODULE_LICENSE("GPL");

// callback function, 當brook_notifier_list有事件發生時, 會呼叫該function
static int brook_notify_sys(struct notifier_block *this,
                            unsigned long code, void *data)
{
    printk("%s(): code=%ld, msg=\"%s\"\n", __FUNCTION__, code, (char*)data);
    return 0;
}

// 宣告要註冊到brook_notifier_list的struct
static struct notifier_block brook_notifier = {
        .notifier_call =    brook_notify_sys,
};

static int __init init_modules(void)
{
    // 將brook_notifier註冊到brook_notifier_list
    register_brook_notifier(&brook_notifier);
    return 0;
}

static void __exit exit_modules(void)
{
    // 將brook_notifier自brook_notifier_list移除
    unregister_brook_notifier(&brook_notifier);
}

module_init(init_modules);
module_exit(exit_modules);


header file
#ifndef BROOK_NOTIFIER_H
#define BROOK_NOTIFIER_H

#include <linux/notifier.h>

int register_brook_notifier(struct notifier_block *nb);
int unregister_brook_notifier(struct notifier_block *nb);

// event type
enum brook_msg {
    brook_num1,
    brook_num2,
    brook_num3
};

#endif
基本上我們都透過notifier_chain_register()來訂閱某個notifier,透過notifier_chain_unregister()取消某個notifier的訂閱,用notifier_call_chain()來發布event,不過我們常常會用對訂閱與取消訂閱寫一層wrapper,如我們的register_brook_notifier()/unregister_brook_notifier()。



參考資料:



熱門文章