メジャー番号/マイナ番号の取り扱い


Rev.7を表示中。最新版はこちら

デバイスファイルのメジャー/マイナー番号は、inode->i_rdev=(((ma) << MINORBITS) | (mi))と設定されます。でメジャー番号でドライバを特定し、マイナー番号でドライバに依存した処理がなされる。と理解していました。しかし実装は、メジャー番号/マイナー番号の組み合わせで(厳密にはマイナー番号の範囲)で、ドライバーが特定できる事も可能となるような実装となっています。

メジャー番号のみでドライバーをhoge_fopsとし、ドライバ側でマイナー番号に掛かる処理を行っています。
#include <linux/module.h>
#include <linux/genhd.h>
#include <linux/uaccess.h>

#define HOGE_MAJOR      100

static int hoge_open (struct inode *inode, struct file *filp)
{
       return 0;
}

static ssize_t hoge_write (struct file *file, const char __user *user_buf,
                                    size_t count, loff_t *ppos)
{
       struct inode *inode = file->f_dentry->d_inode;
       unsigned char   buf[64];
       unsigned int minor = iminor(inode);

       if (_copy_from_user(buf, user_buf, count )) {
               return -EFAULT;
       }
       buf[count - 1] = 0;
       printk("<0>write %s by minor %d\n", buf, minor);
       return count;
}

static struct file_operations hoge_fops = {
       .owner          = THIS_MODULE,
       .write          = hoge_write,
       .open           = hoge_open,
};

static int hoge_init (void)
{
       if (register_chrdev(HOGE_MAJOR, "hoge", &hoge_fops)) {
               printk("<0>chrdev register err\n");
               return -1;
       }
       return 0;
}

static void __exit hoge_exit (void)
{
       unregister_chrdev(HOGE_MAJOR, "hoge");
}

module_init(hoge_init);
module_exit(hoge_exit);
メジャ/マイナ番号でのドライバー設定。メジャ/マイナ番号が100/1の時、hoge_fops1を、100/2の時、hoge_fops2となります。
#include <linux/module.h>
#include <linux/genhd.h>
#include <linux/uaccess.h>

#define         HOGE_MAJOR      100

static int hoge_open (struct inode *inode, struct file *filp)
{
       return 0;
}

static ssize_t hoge_write1 (struct file *file, const char __user *user_buf,
                                    size_t count, loff_t *ppos)
{
       unsigned char   buf[64];

       if (_copy_from_user(buf, user_buf, count )) {
               return -EFAULT;
       }
       buf[count - 1] = 0;
       printk("<0>write %s by minor 1\n", buf);
       return count;
}

static ssize_t hoge_write2 (struct file *file, const char __user *user_buf,
                                    size_t count, loff_t *ppos)
{
       unsigned char   buf[64];

       if (_copy_from_user(buf, user_buf, count )) {
               return -EFAULT;
       }
       buf[count - 1] = 0;
       printk("<0>write %s by minor 2\n", buf);
       return count;
}

static struct file_operations hoge_fops1 = {
       .owner          = THIS_MODULE,
       .write          = hoge_write1,
       .open           = hoge_open,
};

static struct file_operations hoge_fops2 = {
       .owner          = THIS_MODULE,
       .write          = hoge_write2,
       .open           = hoge_open,
};

static int hoge_init (void)
{
       if(__register_chrdev(HOGE_MAJOR, 1, 1, "hoge1", &hoge_fops1)) {
               printk("<0>chrdev register hoge1 err\n");
               return -1;
       }
       if(__register_chrdev(HOGE_MAJOR, 2, 1, "hoge2", &hoge_fops2)) {
               printk("<0>chrdev register hoge2 err\n");
               return -1;
       }
       return 0;
}

static void __exit hoge_exit (void)
{
       __unregister_chrdev(HOGE_MAJOR, 1, 1, "hoge1");
       __unregister_chrdev(HOGE_MAJOR, 2, 1, "hoge2");
}

module_init(hoge_init);
module_exit(hoge_exit);
デバイスファイルの作成
[root@localhost lkm]# mknod hoge1 c 100 1
[root@localhost lkm]# mknod hoge2 c 100 2
[root@localhost lkm]# mknod hoge3 c 100 3
メジャー番号によるコールバック
[root@localhost lkm]# insmod hoge.ko

[root@localhost lkm]# echo "abc" > hoge1
[root@localhost lkm]#
Message from syslogd@localhost at Sep  1 02:36:48 ...
 kernel:[ 4858.277987] write abc by minor 1

[root@localhost lkm]# echo "abc" > hoge2
[root@localhost lkm]#
Message from syslogd@localhost at Sep  1 02:36:56 ...
 kernel:[ 4865.619893] write abc by minor 2

[root@localhost lkm]# echo "abc" > hoge3
[root@localhost lkm]#
Message from syslogd@localhost at Sep  1 02:36:59 ...
 kernel:[ 4869.280976] write abc by minor 3
メジャ/マイナ番号によるコールバック(マイナ番号が3の時はエラー)
[root@localhost lkm]# insmod hoge.ko

[root@localhost lkm]# echo "abc" > hoge1
[root@localhost lkm]#
Message from syslogd@localhost at Sep  1 02:42:00 ...
 kernel:[ 5169.970628] write abc by minor 1

[root@localhost lkm]# echo "abc" > hoge2
[root@localhost lkm]#
Message from syslogd@localhost at Sep  1 02:42:04 ...
 kernel:[ 5173.357401] write abc by minor 2

[root@localhost lkm]# echo "abc" > hoge3
-bash: hoge3: そのようなデバイスやアドレスはありません

補足

カーネルがメジャー番号/マイナー番号でドライバが特定してくれれば、ドライバーの読み書き毎に、マイナー番号による処理を必要としません。入出力頻度の多いドライバを考慮しての実装かと思います。実際、ttyの/dev/ttyと/dev/console(メジャー番号は同じ)では利用されています。

register_chrdev()は__register_chrdev()をマイナー番号数を256としてコールしています。第二引数の0は、開始マイナ番号で、かかるメジャー番号の全てのマイナー番号のコールバックは、fopsというわけです。
static inline int register_chrdev(unsigned int major, const char *name,
                                 const struct file_operations *fops)
{
       return __register_chrdev(major, 0, 256, name, fops);
}

最終更新 2014/09/01 01:40:38 - north
(2014/08/24 18:23:56 作成)


検索

アクセス数
3575105
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。