ファイルシステム

					2012年02月28日
情報科学類 オペレーティングシステム II

                                       筑波大学 システム情報工学研究科 
                                       コンピュータサイエンス専攻, 電子・情報工学系
                                       新城 靖
                                       <yas@is.tsukuba.ac.jp>

このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/os2-2011/2012-02-28
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/

■連絡事項

試験について 欠席した時のクイズの回答を、レポートして受け取る。できるだけ休んだ 日の翌週、遅くても試験の日までに提出しなさい。紙はA4を使うこと。

■今日の大事な話

■ファイルシステム

◆求められる機能

システム・コール 様々な物理媒体と接続方法の利用 様々なディスク上の表現(ファイルシステム) 注意: 「ファイルシステム」という言葉が、様々な意味で使われる

◆層構造

問題: 様々な物理媒体やディスク上の表現の違いを吸収して、共通のシステム・ コールでファイルを扱いたい。

解決策:

図? システム・コール、VFS、ブロックデバイス

図? ファイル・システム実現に置ける層構造

ディスク・キャッシュの層もある。

◆継承

問題: ファイルシステム間で共通部分のコードを再利用したい。

解決策

◆VFSレベルのファイルの概念

◆inode番号

ls -i で inode 番号が表示される。
$ ls -l /bin/{gunzip,gzip,zcat} [←]
-rwxr-xr-x 3 root root 62872 Jan 21  2010 /bin/gunzip
-rwxr-xr-x 3 root root 62872 Jan 21  2010 /bin/gzip
-rwxr-xr-x 3 root root 62872 Jan 21  2010 /bin/zcat
$ ls -li /bin/{gunzip,gzip,zcat} [←]
5636134 -rwxr-xr-x 3 root root 62872 Jan 21  2010 /bin/gunzip
5636134 -rwxr-xr-x 3 root root 62872 Jan 21  2010 /bin/gzip
5636134 -rwxr-xr-x 3 root root 62872 Jan 21  2010 /bin/zcat
$ []

◆/etc/fstab

/etc/fstab は、「起動時に」にマウントすべきファイルシステムのリストを保 持している。
$ cat /etc/fstab  [←]
LABEL=/                 /                       ext3    defaults        1 1
tmpfs                   /dev/shm                tmpfs   defaults        0 0
devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
sysfs                   /sys                    sysfs   defaults        0 0
proc                    /proc                   proc    defaults        0 0
LABEL=SWAP-sda3         swap                    swap    defaults        0 0
130.158.86.2:/vol/vol1/home     /home   nfs     rw,hard,bg,nfsvers=3,intr      0 0
130.158.86.2:/vol/vol5/local3   /usr/local3     nfs     rw,hard,bg,nfsvers=3,intr       0 0
$ df -h [←]
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda2             222G   13G  198G   6% /
tmpfs                 2.0G     0  2.0G   0% /dev/shm
130.158.86.2:/vol/vol1/home
                      4.0T  1.5T  2.5T  38% /home
130.158.86.2:/vol/vol5/local3
                       80G  4.9G   76G   7% /usr/local3
$ []

■VFSのオブジェクト

VFSの実装では、次のようオブジェクトオブジェクト(データ+手続きをカプセル 化したもの)を通じて実装される。 ファイルシステム固有の処理は、_operations の手続きを入れ替えることで実 現される。固有のデータは、構造体を入れ子にしたり、固有データへのポイン タを使ったりして実現している。

図? struct file,struct dentry,struct inode,struct super_block

図? スーパーブロック、inode、dentry、file

◆struct file

struct file は、プロセスがファイルを open() した割り当てられる。 ディスク上には対応するデータ構造は存在しない。
linux-3.1.3/include/linux/fs.h
 953:	struct file {
...
 962:	        struct path             f_path;
 963:	#define f_dentry        f_path.dentry
 965:	        const struct file_operations    *f_op;
...
 970:	        atomic_long_t           f_count;
 972:	        fmode_t                 f_mode;
 973:	        loff_t                  f_pos;
...
 983:	        void                    *private_data;
...
 993:	};

◆struct file_operations

デバイスドライバの回 でも登場している。再掲。

struct fileの操作は、たとえば次のような形で行われる。 第1引数は、struct file *。

    struct file *file;
    file->f_op->read(file, buf, count, pos);
f_op には、次のような手続きがある。各ファイルシステム (ext4,nfs,tmpfs,...) ごとに、手続きの実体は異なるが、インタフェースは同じ。
linux-3.1.3/include/linux/fs.h

1563:	struct file_operations {
1564:	        struct module *owner;
1565:	        loff_t (*llseek) (struct file *, loff_t, int);
1566:	        ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
1567:	        ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
1568:	        ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
1569:	        ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
1570:	        int (*readdir) (struct file *, void *, filldir_t);
1571:	        unsigned int (*poll) (struct file *, struct poll_table_struct *);
1572:	        long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
1573:	        long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
1574:	        int (*mmap) (struct file *, struct vm_area_struct *);
1575:	        int (*open) (struct inode *, struct file *);
1576:	        int (*flush) (struct file *, fl_owner_t id);
1577:	        int (*release) (struct inode *, struct file *);
1578:	        int (*fsync) (struct file *, loff_t, loff_t, int datasync);
1579:	        int (*aio_fsync) (struct kiocb *, int datasync);
1580:	        int (*fasync) (int, struct file *, int);
1581:	        int (*lock) (struct file *, int, struct file_lock *);
1582:	        ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
1583:	        unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
1584:	        int (*check_flags)(int);
1585:	        int (*flock) (struct file *, int, struct file_lock *);
1586:	        ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
1587:	        ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
1588:	        int (*setlease)(struct file *, long, struct file_lock **);
1589:	        long (*fallocate)(struct file *file, int mode, loff_t offset,
1590:	                          loff_t len);
1591:	};
主な手続きの意味

◆struct dentry

struct dentry は、ディレクトリに含まれている名前の要素(「/」を含まない 名前)を表す構造体。 struct dentry は、メモリ中にのみ存在する。ディスク中に対応するデータは ない。ディレクトリで名前を検索したりファイルを作成する時にメモリ中に作 られる。
linux-3.1.3/include/linux/dcache.h
 116:	struct dentry {
...
 121:	        struct dentry *d_parent;        /* parent directory */
 122:	        struct qstr d_name;
 123:	        struct inode *d_inode;          /* Where the name belongs to - NULL is
 124:	                                         * negative */
 125:	        unsigned char d_iname[DNAME_INLINE_LEN];        /* small names */
...
 128:	        unsigned int d_count;           /* protected by d_lock */
 130:	        const struct dentry_operations *d_op;
 131:	        struct super_block *d_sb;       /* The root of the dentry tree */
 133:	        void *d_fsdata;                 /* fs-specific data */
...
 143:	        struct list_head d_subdirs;     /* our children */
...
 145:	};
...
  35:	struct qstr {
  36:	        unsigned int hash;
  37:	        unsigned int len;
  38:	        const unsigned char *name;
  39:	};
...
 112:	#  define DNAME_INLINE_LEN 40 /* 128 bytes */
dentry は、 スラブアロケータ (kmem_cache_create(),kmem_cache_alloc(),kmem_cache_free())で管理されて いる。

◆struct inode

struct inode は、全てのファイル・システムで共通の要素を保持する、メモリ 中の構造体。各ファイル・システムは、これに含まれるようなデータをそれぞ れ独自の方法でディスクに保存する。
linux-3.1.3/include/linux/fs.h

 748:	struct inode {
 749:	        umode_t                 i_mode;
 750:	        unsigned short          i_opflags;
 751:	        uid_t                   i_uid;
 752:	        gid_t                   i_gid;
...
 760:	        const struct inode_operations   *i_op;
 761:	        struct super_block      *i_sb;
...
 769:	        unsigned long           i_ino;
 770:	        unsigned int            i_nlink;
 771:	        dev_t                   i_rdev;
 772:	        loff_t                  i_size;
 773:	        struct timespec         i_atime;
 774:	        struct timespec         i_mtime;
 775:	        struct timespec         i_ctime;
 776:	        unsigned int            i_blkbits;
 777:	        blkcnt_t                i_blocks;
...
 784:	        unsigned long           i_state;
 790:	        struct hlist_node       i_hash;
 795:	                struct list_head        i_dentry;
 798:	        atomic_t                i_count;
...
 826:	        void                    *i_private; /* fs or device private pointer */
 827:	};

◆struct inode_operations

inodeの操作は、たとえば次のような形で行われる。
    struct inode *inode;
    ...
    inode->i_op->truncate(inode);
i_op には、次のような手続きがある。各ファイルシステム (ext3,nfs,tmpfs,...) ごとに、手続きの実体は異なるが、インタフェースは同じ。
linux-3.1.3/include/linux/fs.h
1593:	struct inode_operations {
1594:	        struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
1595:	        void * (*follow_link) (struct dentry *, struct nameidata *);
1596:	        int (*permission) (struct inode *, int);
1597:	        struct posix_acl * (*get_acl)(struct inode *, int);
1598:	
1599:	        int (*readlink) (struct dentry *, char __user *,int);
1600:	        void (*put_link) (struct dentry *, struct nameidata *, void *);
1601:	
1602:	        int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
1603:	        int (*link) (struct dentry *,struct inode *,struct dentry *);
1604:	        int (*unlink) (struct inode *,struct dentry *);
1605:	        int (*symlink) (struct inode *,struct dentry *,const char *);
1606:	        int (*mkdir) (struct inode *,struct dentry *,int);
1607:	        int (*rmdir) (struct inode *,struct dentry *);
1608:	        int (*mknod) (struct inode *,struct dentry *,int,dev_t);
1609:	        int (*rename) (struct inode *, struct dentry *,
1610:	                        struct inode *, struct dentry *);
1611:	        void (*truncate) (struct inode *);
1612:	        int (*setattr) (struct dentry *, struct iattr *);
1613:	        int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
1614:	        int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
1615:	        ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
1616:	        ssize_t (*listxattr) (struct dentry *, char *, size_t);
1617:	        int (*removexattr) (struct dentry *, const char *);
1618:	        void (*truncate_range)(struct inode *, loff_t, loff_t);
1619:	        int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
1620:	                      u64 len);
1621:	} ____cacheline_aligned;

◆struct super_block

スーパーブロックは、ファイルシステムの起点となるデータ構造。そのファイ ル・システムに含まれている inode を管理する。

◆task_struct と struct file

struct task_struct から指される。ファイル記述子fdは、struct task_struct *p; の時、p->files->fd_array[fd] の struct file を表 す。
linux-3.1.3/include/linux/sched.h
1220:	struct task_struct {
...
1386:	        struct files_struct *files;
...
1572:	};

linux-3.1.3/include/linux/fdtable.h
  44:	struct files_struct {
...
  58:	        struct file __rcu * fd_array[NR_OPEN_DEFAULT];
  59:	};

図? p->files->fd_array[fd]

図? task_struct、ファイル記述子、file構造体

■read() システムコールと Ext4 ファイルシステム

read() システム・コールの実装。

◆stat() システム・コール

linux-3.1.3/fs/read_write.c

 444:	SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
 445:	{
 446:	        struct file *file;
 447:	        ssize_t ret = -EBADF;
 448:	        int fput_needed;
 449:	
 450:	        file = fget_light(fd, &fput_needed);
 451:	        if (file) {
 452:	                loff_t pos = file_pos_read(file);
 453:	                ret = vfs_read(file, buf, count, &pos);
 454:	                file_pos_write(file, pos);
 455:	                fput_light(file, fput_needed);
 456:	        }
 457:	
 458:	        return ret;
 459:	}

◆vfs_read()

 348:	ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
 349:	{
 350:	        ssize_t ret;
 351:	
 352:	        if (!(file->f_mode & FMODE_READ))
 353:	                return -EBADF;
 354:	        if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read))
 355:	                return -EINVAL;
 356:	        if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))
 357:	                return -EFAULT;
 358:	
 359:	        ret = rw_verify_area(READ, file, pos, count);
 360:	        if (ret >= 0) {
 361:	                count = ret;
 362:	                if (file->f_op->read)
 363:	                        ret = file->f_op->read(file, buf, count, pos);
 364:	                else
 365:	                        ret = do_sync_read(file, buf, count, pos);
 366:	                if (ret > 0) {
 367:	                        fsnotify_access(file);
 368:	                        add_rchar(current, ret);
 369:	                }
 370:	                inc_syscr(current);
 371:	        }
 372:	
 373:	        return ret;
 374:	}

◆Ext4 の file_operations

linux-3.1.3/fs/ext4/file.c

 276:	const struct file_operations ext4_file_operations = {
 277:	        .llseek         = ext4_llseek,
 278:	        .read           = do_sync_read,
 279:	        .write          = do_sync_write,
 280:	        .aio_read       = generic_file_aio_read,
 281:	        .aio_write      = ext4_file_write,
 282:	        .unlocked_ioctl = ext4_ioctl,
 283:	#ifdef CONFIG_COMPAT
 284:	        .compat_ioctl   = ext4_compat_ioctl,
 285:	#endif
 286:	        .mmap           = ext4_file_mmap,
 287:	        .open           = ext4_file_open,
 288:	        .release        = ext4_release_file,
 289:	        .fsync          = ext4_sync_file,
 290:	        .splice_read    = generic_file_splice_read,
 291:	        .splice_write   = generic_file_splice_write,
 292:	        .fallocate      = ext4_fallocate,
 293:	};


 295:	const struct inode_operations ext4_file_inode_operations = {
...
 306:	};

linux-3.1.3/fs/ext4/super.c
1256:	static const struct super_operations ext4_sops = {
...
1275:	};

◆Ext4 の inode

Ext4 では、メモリ中のデータを構造体 struct ext4_inode_info で表す。
linux-3.1.3/fs/ext4/ext4.h
 761:	struct ext4_inode_info {
 762:	        __le32  i_data[15];     /* unconverted */
 763:	        __u32   i_dtime;
 764:	        ext4_fsblk_t    i_file_acl;
...
 821:	        struct inode vfs_inode;
...
 869:	};

1230:	static inline struct ext4_inode_info *EXT4_I(struct inode *inode)
1231:	{
1232:	        return container_of(inode, struct ext4_inode_info, vfs_inode);
1233:	}

linux-3.1.3/include/linux/kernel.h
 653:	#define container_of(ptr, type, member) ({                      \
 654:	        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
 655:	        (type *)( (char *)__mptr - offsetof(type,member) );}
)

図? struct ext4_inode_info、struct inode、container_of()

図? Ext4 ファイルシステムで使う構造体 ext4_inode_info での struct inode の保持

■クイズ10 ファイルシステム

★問題(1001) オブジェクト指向

Linux におけるファイルシステムの実装では、C言語であるが、オブジェクト指 向的な考え方が取り入れられている。どの部分で取り入れられているか、次の 項目を埋めながら説明しなさい。

★問題(1002) struct fileの役割

Linux カーネルの中で、ファイルを表現するためのオブジェクトとしてstruct inode と struct file がある。struct inode だけでも、ファイルの操作(読 み、書き、属性変更)では十分と思えるが、struct file も使われている。 struct file の役割を1つ選んで簡単に説明しなさい。

★問題(1003) write()システムコール

次の関数は、write() システム・コールを実装している vfs_write() の一部で ある。空欄を埋めなさい。
ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
{
...
        ret = rw_verify_area(WRITE, file, pos, count);
        if (ret >= 0) {
                count = ret;
                if (file->f_op->/*空欄(a)*/)
                        ret = /*空欄(b)*/(/*空欄(c)*/, buf, count, pos);
...
	}
        return ret;
}

Last updated: 2012/03/06 14:48:01
Yasushi Shinjo / <yas@is.tsukuba.ac.jp>