linux.3.3.8のvfsmount


動作環境はfedora16のlinux.3.3.8-1で、記事の内容はlinux.2.6.0です。mount実装の検証のためLKMを作成したのですが、どうもうまくいきません。そこでカーネルソースもlinux-3.3.8に更新しました。で、やはりその実装は変更されておりました。

linux.2.6.0では、vfsmount構造体内にかかる全ての情報を有していて、しかもLKMからの参照も可能となっています。しかしlinux.3.3.8-1のvfsmount構造体内は、動作に必要なdentry/super_block/mnt_flagsとし、LIST_HEADを初めとするそれ以外の管理情報は、mount構造体内に設定されるようになっています。また、マウント情報としても新たに追加項目もあり、LIST_HEADに関しては、共有/スレーブ/有効期限等の管理のためのリストヘッドが追加されています。しかも、LKMからこのmount構造体を参照することはできなくなっています。(たぶんセキュリティ故のことだと思いますが。)

linux.2.6.0のvfsmount
struct vfsmount
{
       struct list_head mnt_hash;
       struct vfsmount *mnt_parent;    /* fs we are mounted on */
       struct dentry *mnt_mountpoint;  /* dentry of mountpoint */
       struct dentry *mnt_root;        /* root of the mounted tree */
       struct super_block *mnt_sb;     /* pointer to superblock */
       struct list_head mnt_mounts;    /* list of children, anchored here */
       struct list_head mnt_child;     /* and going through their mnt_child */
       atomic_t mnt_count;
       int mnt_flags;
       char *mnt_devname;              /* Name of device e.g. /dev/dsk/hda1 */
       struct list_head mnt_list;
};
linux.3.3.8-1のvfsmount
struct vfsmount {
       struct dentry *mnt_root;        /* root of the mounted tree */
       struct super_block *mnt_sb;     /* pointer to superblock */
       int mnt_flags;
};

struct mount {
       struct list_head mnt_hash;
       struct mount *mnt_parent;
       struct dentry *mnt_mountpoint;
       struct vfsmount mnt;

       int mnt_count;
       int mnt_writers;

       struct list_head mnt_mounts;    /* list of children, anchored here */
       struct list_head mnt_child;     /* and going through their mnt_child */
       struct list_head mnt_instance;  /* mount instance on sb->s_mounts */
       const char *mnt_devname;        /* Name of device e.g. /dev/dsk/hda1 */
       struct list_head mnt_list;
       struct list_head mnt_expire;    /* link in fs-specific expiry list */
       struct list_head mnt_share;     /* circular list of shared mounts */
       struct list_head mnt_slave_list;/* list of slave mounts */
       struct list_head mnt_slave;     /* slave list entry */
       struct mount *mnt_master;       /* slave is on master->mnt_slave_list */
       struct mnt_namespace *mnt_ns;   /* containing namespace */

       int mnt_id;                     /* mount identifier */
       int mnt_group_id;               /* peer group identifier */
       int mnt_expiry_mark;            /* true if marked for expiry */
       int mnt_pinned;
       int mnt_ghosts;
};
マウント処理におけるカーネルの実装は、vfsmountでreal_mount()をコールする事で行っています。 vfsmoun構造体/mount構造体は別々に有していると書きましたが、vfsmoun構造体の実態は、mount構造体のmntメンバーになり、list_headの処理で使われるcontainer_of()にて、mount構造体を取得できるわけです。
static inline struct mount *real_mount(struct vfsmount *mnt)
{
       return container_of(mnt, struct mount, mnt);
}
LKMからmnt構造体を取得するサンプルです。先に書いたようにmount構造他および掛かるマクロ/関数を使用する事はできません。ここでは、struct mount/real_mount()をカーネルソースからのLKM内に埋め込む事で実現しました。
#include <linux/kernel.h>
#include <linux/namei.h>
#include <linux/mnt_namespace.h>
#include <linux/mount.h>

struct mount {
       struct list_head mnt_hash;
       struct mount *mnt_parent;
       struct dentry *mnt_mountpoint;
       struct vfsmount mnt;

       int mnt_count;
       int mnt_writers;

       struct list_head mnt_mounts;    /* list of children, anchored here */
       struct list_head mnt_child;     /* and going through their mnt_child */
       struct list_head mnt_instance;  /* mount instance on sb->s_mounts */
       const char *mnt_devname;        /* Name of device e.g. /dev/dsk/hda1 */
       struct list_head mnt_list;
       struct list_head mnt_expire;    /* link in fs-specific expiry list */
       struct list_head mnt_share;     /* circular list of shared mounts */
       struct list_head mnt_slave_list;/* list of slave mounts */
       struct list_head mnt_slave;     /* slave list entry */
       struct mount *mnt_master;       /* slave is on master->mnt_slave_list */
       struct mnt_namespace *mnt_ns;   /* containing namespace */

       int mnt_id;                     /* mount identifier */
       int mnt_group_id;               /* peer group identifier */
       int mnt_expiry_mark;            /* true if marked for expiry */
       int mnt_pinned;
       int mnt_ghosts;
};

static inline struct mount *real_mount(struct vfsmount *mnt)
{
       return container_of(mnt, struct mount, mnt);
}

void get_mnt(char *pathname)
{
       struct path path;
       struct mount *mnt;
       int     err;

       err = kern_path(pathname, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path);

       if (err) {
               printk("err\n");
       }
       else {
               mnt = real_mount(path.mnt);
               printk("%s\n", mnt->mnt_devname);
       }
}

int init_module(void)
{
       get_mnt("/");
       get_mnt("/sys");
       get_mnt("/proc");
   return 0;
}

void cleanup_module(void)
{
}

[root@localhost lkm]# insmod mnt_get.ko
[root@localhost lkm]# dmesg
  :
  :
[28732.966463] pcnet32 0000:02:01.0: eth0: link down
[28771.005229] pcnet32 0000:02:01.0: eth0: link up
[29651.255533] /dev/mapper/VolGroup-lv_root
[29651.255552] sysfs
[29651.255557] proc
kern_path()のフラグLOOKUP_FOLLOWはシンボリックリンクの有効、LOOKUP_AUTOMOUNTは動的なマウント(この時dentryのd_automountコールバック関数がコールされ、所定のマウント処理が行われるようです。)を有効とする。との設定のようです。

補足

サンプルのように、理屈の上ではカーネルソースからLKMで何でもできるわけですが、mount構造体にダミーのメンバーを入れ、オリジナル(?)なカーネルを作れば、サンプルのようにmount構造体を参照する事はできなくなります。

追記

LKMの実装においても、module_initマクロによるセクションへ配置することなく、init_moduleアドレスで__NR_init_moduleでシステムコールをコールすることで、insmodできるようになっています。
#define __NR_init_module 128
#define __NR_delete_module 129

最終更新 2013/06/28 18:17:13 - north
(2013/06/26 16:43:54 作成)


検索

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