読者です 読者をやめる 読者になる 読者になる

sys_mount()を読んでみる。

linux

mountってどんな感じで処理してるんだろ〜ということで、sys_mount()を読んでみます。
調べたのは、2.6.33です。

ソースは大概LXRで調べてるんですが、sys_mountで検索しても実体が見つからなくてちょっと苦労しました。
定義が、SYSCALL_DEFINEマクロを使ってたから、sys_mountで検索しても見つからなかっただけですが・・・
実体は、fs/namespace.cにいます。

SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
                char __user *, type, unsigned long, flags, void __user *, data)
{

実際はこんな感じになります。

 408asmlinkage long sys_mount(char __user *dev_name, char __user *dir_name,
 409                                char __user *type, unsigned long flags,
 410                                void __user *data);

あと、sys_mountはカーネル内からも呼ばれます。
例えば、init/do_mounts.cのrootファイルシステムをマウントするときのdo_mount_root()からとか。

 217static int __init do_mount_root(char *name, char *fs, int flags, void *data)
 218{
 219        int err = sys_mount(name, "/root", fs, flags, data);
 220        if (err)

それで、sys_mount()の実装ですが、実装は結構短めです。

2093SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
2094                char __user *, type, unsigned long, flags, void __user *, data)
2095{
2096        int ret;
2097        char *kernel_type;
2098        char *kernel_dir;
2099        char *kernel_dev;
2100        unsigned long data_page;
2101
2102        ret = copy_mount_string(type, &kernel_type);
2103        if (ret < 0)
2104                goto out_type;
2105
2106        kernel_dir = getname(dir_name);
2107        if (IS_ERR(kernel_dir)) {
2108                ret = PTR_ERR(kernel_dir);
2109                goto out_dir;
2110        }
2111
2112        ret = copy_mount_string(dev_name, &kernel_dev);
2113        if (ret < 0)
2114                goto out_dev;
2115
2116        ret = copy_mount_options(data, &data_page);
2117        if (ret < 0)
2118                goto out_data;
2119
2120        ret = do_mount(kernel_dev, kernel_dir, kernel_type, flags,
2121                (void *) data_page);
2122
2123        free_page(data_page);
2124out_data:
2125        kfree(kernel_dev);
2126out_dev:
2127        putname(kernel_dir);
2128out_dir:
2129        kfree(kernel_type);
2130out_type:
2131        return ret;
2132}
2133

sys_mount()で使ってる関数もこれぐらいですし。
copy_mount_string()、getname()、copy_mount_string()、copy_mount_options()、do_mount()、putname()
これらの関数も名前から仕様が想像できるのと、処理もそんなに興味深い訳ではないので、do_mount()だけ見てみます。

do_mount()もfs/namespace.cにいます。

1913long do_mount(char *dev_name, char *dir_name, char *type_page,
1914                  unsigned long flags, void *data_page)
1915{
1916        struct path path;
1917        int retval = 0;
1918        int mnt_flags = 0;
1919
1920        /* Discard magic */
1921        if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
1922                flags &= ~MS_MGC_MSK;
1923
1924        /* Basic sanity checks */
1925
1926        if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE))
1927                return -EINVAL;
1928
1929        if (data_page)
1930                ((char *)data_page)[PAGE_SIZE - 1] = 0;

この辺りは基本的なチェックが入っていて、次にパスをチェックして、

1931
1932        /* ... and get the mountpoint */
1933        retval = kern_path(dir_name, LOOKUP_FOLLOW, &path);
1934        if (retval)
1935                return retval;
1936

セキュリティ関係のチェックが入ります。

1937        retval = security_sb_mount(dev_name, &path,
1938                                   type_page, flags, data_page);
1939        if (retval)
1940                goto dput_out;
1941

security_sb_mount()はsecurity/security.cにいて、struct security_operations内の関数ポインタsb_mountにセットされてる関数を読んでます。
これは追うのが大変そうなので、ここまでしか調べてませんorz

 296int security_sb_mount(char *dev_name, struct path *path,
 297                       char *type, unsigned long flags, void *data)
 298{
 299        return security_ops->sb_mount(dev_name, path, type, flags, data);
 300}

この後は、フラグ関係の処理が続きます。

1942        /* Default to relatime unless overriden */
1943        if (!(flags & MS_NOATIME))
1944                mnt_flags |= MNT_RELATIME;
1945
1946        /* Separate the per-mountpoint flags */
1947        if (flags & MS_NOSUID)
1948                mnt_flags |= MNT_NOSUID;
1949        if (flags & MS_NODEV)
1950                mnt_flags |= MNT_NODEV;
1951        if (flags & MS_NOEXEC)
1952                mnt_flags |= MNT_NOEXEC;
1953        if (flags & MS_NOATIME)
1954                mnt_flags |= MNT_NOATIME;
1955        if (flags & MS_NODIRATIME)
1956                mnt_flags |= MNT_NODIRATIME;
1957        if (flags & MS_STRICTATIME)
1958                mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME);
1959        if (flags & MS_RDONLY)
1960                mnt_flags |= MNT_READONLY;
1961
1962        flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE |
1963                   MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |
1964                   MS_STRICTATIME);
1965

ここまできて、最後に、マウントの仕方(再マウント、新規マウントとか)によって、呼ぶ関数を変えるといったことをしてます。
通常のマウントを行う場合は、do_new_mount()が呼ばれます。

1966        if (flags & MS_REMOUNT)
1967                retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
1968                                    data_page);
1969        else if (flags & MS_BIND)
1970                retval = do_loopback(&path, dev_name, flags & MS_REC);
1971        else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
1972                retval = do_change_type(&path, flags);
1973        else if (flags & MS_MOVE)
1974                retval = do_move_mount(&path, dev_name);
1975        else
1976                retval = do_new_mount(&path, type_page, flags, mnt_flags,
1977                                      dev_name, data_page);
1978dput_out:
1979        path_put(&path);
1980        return retval;
1981}
1982

do_new_mount()もfs/namespace.cにいます。ここでの主要な処理は、do_kern_mount()ですね。
というわけで、do_kern_mount()を調べます。

static int do_new_mount(struct path *path, char *type, int flags,
1645                        int mnt_flags, char *name, void *data)
1646{
1647        struct vfsmount *mnt;
1648
1649        if (!type)
1650                return -EINVAL;
1651
1652        /* we need capabilities... */
1653        if (!capable(CAP_SYS_ADMIN))
1654                return -EPERM;
1655
1656        lock_kernel();
1657        mnt = do_kern_mount(type, flags, name, data);
1658        unlock_kernel();
1659        if (IS_ERR(mnt))
1660                return PTR_ERR(mnt);
1661
1662        return do_add_mount(mnt, path, mnt_flags, NULL);
1663}

こいつは、fs/super.cにいます。この中で重要そうなのはvfs_kern_mount()だろ!ということで、vfs_kern_mount()を見ます。

 998struct vfsmount *
 999do_kern_mount(const char *fstype, int flags, const char *name, void *data)
1000{

1001        struct file_system_type *type = get_fs_type(fstype);
1002        struct vfsmount *mnt;
1003        if (!type)
1004                return ERR_PTR(-ENODEV);
1005        mnt = vfs_kern_mount(type, flags, name, data);
1006        if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
1007            !mnt->mnt_sb->s_subtype)
1008                mnt = fs_set_subtype(mnt, fstype);
1009        put_filesystem(type);
1010        return mnt;
1011}

これも同じくfs/super.cにいます。
ここの主要な処理は、type->get_sb()だと思うんですが、これはファイルシステム固有の実装になってるはずなので、そのコードを読む必要があります。
例えば、ramfsの場合は、前に書いた日記これとかこれで調べたのがありますので、参考にしてみてください。

 913struct vfsmount *
 914vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
 915{
 916        struct vfsmount *mnt;
 917        char *secdata = NULL;
 918        int error;
 919
 920        if (!type)
 921                return ERR_PTR(-ENODEV);
 922
 923        error = -ENOMEM;
 924        mnt = alloc_vfsmnt(name);
 925        if (!mnt)
 926                goto out;
 927
 928        if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
 929                secdata = alloc_secdata();
 930                if (!secdata)
 931                        goto out_mnt;
 932
 933                error = security_sb_copy_data(data, secdata);
 934                if (error)
 935                        goto out_free_secdata;
 936        }
 937
 938        error = type->get_sb(type, flags, name, data, mnt);
 939        if (error < 0)
 940                goto out_free_secdata;
 941        BUG_ON(!mnt->mnt_sb);
 942
 943        error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);
 944        if (error)
 945                goto out_sb;
 946
 947        /*
 948         * filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE
 949         * but s_maxbytes was an unsigned long long for many releases. Throw
 950         * this warning for a little while to try and catch filesystems that
 951         * violate this rule. This warning should be either removed or
 952         * converted to a BUG() in 2.6.34.
 953         */
 954        WARN((mnt->mnt_sb->s_maxbytes < 0), "%s set sb->s_maxbytes to "
 955                "negative value (%lld)\n", type->name, mnt->mnt_sb->s_maxbytes);
 956
 957        mnt->mnt_mountpoint = mnt->mnt_root;
 958        mnt->mnt_parent = mnt;
 959        up_write(&mnt->mnt_sb->s_umount);
 960        free_secdata(secdata);
 961        return mnt;
 962out_sb:
 963        dput(mnt->mnt_root);
 964        deactivate_locked_super(mnt->mnt_sb);
 965out_free_secdata:
 966        free_secdata(secdata);
 967out_mnt:
 968        free_vfsmnt(mnt);
 969out:
 970        return ERR_PTR(error);
 971}

というわけで、思ったよりも長くなったんですが、ここまでがsys_mount()の処理内容でした。