情報学類 オペレーティングシステムII 2007年02月06日
筑波大学システム情報工学研究科
コンピュータサイエンス専攻, 電子・情報工学系
新城 靖
<yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/os2-2006/2007-02-06
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/
アプリケーションからの使い方は、2種類
デバイス・ファイルは、2つの番号で区別される。
デバイス・ファイルは、主に、/dev というディレクトリ以下に作られ
る(他の場所にも作れる)。
ls -l で見ると、先頭に b と表示される。
% ls -l /dev/disk*普通のファイルなら容量が表示される所に、メジャー番号(この例では14)とマ イナー番号(この例では0から10)が表示される。 ブロック型デバイスファイルは、主にファイルシステムをマウントする時に使う。brw-r----- 1 root operator 14, 0 Dec 26 13:57 /dev/disk0 br--r----- 1 root operator 14, 1 Dec 26 13:57 /dev/disk0s1 brw-r----- 1 root operator 14, 2 Dec 26 13:57 /dev/disk0s3 brw-r----- 1 root operator 14, 3 Dec 26 13:57 /dev/disk1 br--r----- 1 root operator 14, 4 Dec 26 13:57 /dev/disk1s1 br--r----- 1 root operator 14, 5 Dec 26 13:57 /dev/disk1s2 br--r----- 1 root operator 14, 6 Dec 26 13:57 /dev/disk1s3 br--r----- 1 root operator 14, 7 Dec 26 13:57 /dev/disk1s5 br--r----- 1 root operator 14, 8 Dec 26 13:57 /dev/disk1s6 br--r----- 1 root operator 14, 9 Dec 26 13:57 /dev/disk1s7 brw-r----- 1 root operator 14, 10 Dec 26 13:57 /dev/disk1s9 %
![]()
int mount(const char *source, const char *target,
const char *filesystemtype, unsigned long mountflags, const void *data);
ls -l で見ると、先頭に c と表示される。
% ls -l cu.Bluetooth-*crw-rw-rw- 1 root wheel 9, 3 Dec 26 13:57 cu.Bluetooth-Modem crw-rw-rw- 1 root wheel 9, 1 Dec 26 13:57 cu.Bluetooth-PDA-Sync %
![]()
int open(const char *pathname, int flags); int close(int fildes); ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, const void *buf, size_t count); int ioctl(int fildes, int request, ... /* arg */);ioctl() の第2引数、第3引数は、デバイス依存。
伝統的な Unix (BSD含む)には、ブロック型デバイスに、対応する文字型デバイ スがある。これを「生のデバイス(raw device)」と呼ぶ。
生のデバイスでは、読み書きすると必ずハードウェアのレベルでも入出力が生 じる。ブロック型デバイスをアクセスすると、キャッシングが行われる。
生のデバイスの利用方法
生のデバイスのファイル名には、先頭に r を付ける習慣がある。
% ls -l /dev/{r,}disk0
brw-r----- 1 root operator 14, 0 Dec 26 13:57 /dev/disk0
crw-r----- 1 root operator 14, 0 Dec 26 13:57 /dev/rdisk0
%
(MacOSX での例)
Linux には、「生のデバイス」の概念が希薄。明示的には存在しない。
/dev/hd*, SCSI /dev/sd*,
/dev/fd*
/dev/cdrom
/dev/nrst0
/dev/tty0
/dev/fb、キーボード /dev/kbd、マウス /dev/mouse
/dev/mem, /dev/kmem
対応するハードウェアが存在しない。Unix のカーネルがソフトウェア的に作り 出したもの。
/dev/ttyp0 と同じ記号と番号の /dev/ptyp0 が
対になっており、
/dev/ttyp0 に書き込まれたシェルなどの出力が、
/dev/ptyp0 を見ている sshd や
xterm に読み込まれる。
syslogd が吸い上げる
/dev/random, /dev/urandom
デバイス・ドライバ(device driver)は、カーネル内で動作するモジュール。 デバイス(ハードウェア)を操作して入出力を行う。
新しくハードウェアを開発したら、オペレーティング・システムで定めた仕様 に従ったデバイス・ドライバを開発する。
図? デバイス・ドライバとオペレーティング・システム本体のインタフェース
Linux で、文字型のデバイス・ドライバをカーネルに登録するには、 register_chrdev() という関数を使う。struct file_operations にある関数を 定義し、register_chrdev() を呼ぶ。
/* fs/char_dev.c */
int register_chrdev(unsigned int major, const char *name,
const struct file_operations *fops);
/* linux/fs.h */
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*dir_notify)(struct file *filp, unsigned long arg);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
};
ファイルを開く時に、struct file の f_op というフィールドは、デバイスご
とのstruct file_operations へポインタで初期化される。以後、
f->f_op->read(...) のようにアクセスされる。
/* drivers/char/random.c */
struct file_operations urandom_fops = {
.read = urandom_read,
.write = random_write,
.ioctl = random_ioctl,
};
static ssize_t
urandom_read(struct file * file, char __user * buf,
size_t nbytes, loff_t *ppos)
{
return extract_entropy_user(&nonblocking_pool, buf, nbytes);
}
static ssize_t
random_write(struct file * file, const char __user * buffer,
size_t count, loff_t *ppos)
{
...
const char __user *p = buffer;
size_t c = count;
while (c > 0) {
bytes = min(c, sizeof(buf));
bytes -= copy_from_user(&buf, p, bytes);
if (!bytes) {
ret = -EFAULT;
break;
}
c -= bytes;
p += bytes;
add_entropy_words(&input_pool, buf, (bytes + 3) / 4);
}
if (p == buffer) {
return (ssize_t)ret;
} else {
...
}
}
static int
random_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
int size, ent_count;
int __user *p = (int __user *)arg;
int retval;
switch (cmd) {
case RNDGETENTCNT:
ent_count = input_pool.entropy_count;
if (put_user(ent_count, p))
return -EFAULT;
return 0;
case RNDADDTOENTCNT:
...
default:
return -EINVAL;
}
}
int register_blkdev(unsigned int major, const char *name)
typedef struct request_queue request_queue_t;
typedef void (request_fn_proc) (request_queue_t *q);
request_queue_t *blk_init_queue(request_fn_proc *, spinlock_t *);
struct request_queue
{
...
request_fn_proc *request_fn;
...
};
blk_init_queue() で、request関数を登録する。オペレーティング・システム の上位層は、必要に応じてデバイス・ドライバの request 関数を呼び出す。
void __generic_unplug_device(request_queue_t *q)
{
...
q->request_fn(q);
}
入出力の記述には、struct bio を使う。仮想記憶と統合的に使える。
struct net_device
{
...
int (*init)(struct net_device *dev);
// 統計
struct net_device_stats* (*get_stats)(struct net_device *dev);
// 送信開始
int (*hard_start_xmit) (struct sk_buff *skb,
struct net_device *dev);
void (*destructor)(struct net_device *dev);
// ifconfig up
int (*open)(struct net_device *dev);
// ifconfig down
int (*stop)(struct net_device *dev);
// ヘッダを作る
int (*rebuild_header)(struct sk_buff *skb);
// MAC アドレスの変更
int (*set_mac_address)(struct net_device *dev,
void *addr);
// 送信失敗
void (*tx_timeout) (struct net_device *dev);
};
受信は、この関数の表にはない。割り込みから起動される。