autofs


/etc/auto.masterに以下の一行を追加します。
/mnt3   /etc/auto_bind.mnt3
/etc/auto_bind.mnt3で以下のファイルを作成します。これで、コマンドから、mount -bind /mnt3/test /home/kitamuraしたのと同じになります。
[root@localhost etc]# cat auto_bind.mnt3
test -bind  :/home/kitamura
/mnt3ディレクトリを作成して、/mnt3/testをautofsでマウントします。
[root@localhost etc]# systemctl restart autofs.service
/mnt3配下には、なんら変化はありません。
[root@localhost etc]# ls /mnt3
[root@localhost etc]# df
ファイルシス                 1K-ブロック     使用   使用可 使用% マウント位置
 :
tmpfs                             305084        0   305084    0% /media
/dev/sdb1                      103163948 34145500 63775572   35% /mnt
/dev/sda2                         508745    98449   384696   21% /boot
しかし、/mnt3/testを見ると、/mnt3/testに/dev/mapper/VolGroup-lv_rootがマウントされ、バインド先が表示されます。一定時間経過すると、このマウントはアンマウントされます。
[root@localhost etc]# ls /mnt3/test
Desktop    Downloads  Pictures  Templates  a.out  acl  lkm   test
Documents  Mail       Public    Videos     aaa    bbb  mnt2  umount2.c
[root@localhost etc]# df
ファイルシス                 1K-ブロック     使用   使用可 使用% マウント位置
 :
tmpfs                             305084        0   305084    0% /media
/dev/sdb1                      103163948 34145500 63775572   35% /mnt
/dev/sda2                         508745    98449   384696   21% /boot
/dev/mapper/VolGroup-lv_root     6182228  5287652   832672   87% /mnt3/test
autofsをマウントすると、afs_fs_typeの.mountコールバックafs_mount()がコールします。この時afs_fill_super()でスーパブロックを、save_mount_options()で実マウントするオプションがsb->s_optionsにリストされます。
struct file_system_type afs_fs_type = {
       .owner          = THIS_MODULE,
       .name           = "afs",
       .mount          = afs_mount,
       .kill_sb        = afs_kill_super,
       .fs_flags       = 0,
};

static struct dentry *afs_mount(struct file_system_type *fs_type,
                     int flags, const char *dev_name, void *options)
{
       struct afs_mount_params params;
       struct super_block *sb;
       struct afs_volume *vol;
       struct key *key;
       char *new_opts = kstrdup(options, GFP_KERNEL);
       struct afs_super_info *as;
       int ret;

       _enter(",,%s,%p", dev_name, options);

       memset(&params, 0, sizeof(params));

       if (options) {
               ret = afs_parse_options(&params, options, &dev_name);
               if (ret < 0)
                       goto error;
       }

       ret = afs_parse_device_name(&params, dev_name);
       if (ret < 0)
               goto error;

       key = afs_request_key(params.cell);
       if (IS_ERR(key)) {
               _leave(" = %ld [key]", PTR_ERR(key));
               ret = PTR_ERR(key);
               goto error;
       }
       params.key = key;

       vol = afs_volume_lookup(&params);
       if (IS_ERR(vol)) {
               ret = PTR_ERR(vol);
               goto error;
       }

       as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL);
       if (!as) {
               ret = -ENOMEM;
               afs_put_volume(vol);
               goto error;
       }
       as->volume = vol;

       sb = sget(fs_type, afs_test_super, afs_set_super, as);
       if (IS_ERR(sb)) {
               ret = PTR_ERR(sb);
               afs_put_volume(vol);
               kfree(as);
               goto error;
       }

       if (!sb->s_root) {
               _debug("create");
               sb->s_flags = flags;
               ret = afs_fill_super(sb, &params);
               if (ret < 0) {
                       deactivate_locked_super(sb);
                       goto error;
               }
               save_mount_options(sb, new_opts);
               sb->s_flags |= MS_ACTIVE;
       } else {
               _debug("reuse");
               ASSERTCMP(sb->s_flags, &, MS_ACTIVE);
               afs_put_volume(vol);
               kfree(as);
       }

       afs_put_cell(params.cell);
       kfree(new_opts);
       _leave(" = 0 [%p]", sb);
       return dget(sb->s_root);

error:
       afs_put_cell(params.cell);
       key_put(params.key);
       kfree(new_opts);
       _leave(" = %d", ret);
       return ERR_PTR(ret);
}
afs_fill_super()でsb->s_d_op = &afs_fs_dentry_operationsとします。これがautofsの重要なポイントですす。上記サンプルで/mnt3/testを参照すると、dentryを取得するわけですが、この時sb->s_d_opが/mnt3/testのdentryのコールバックとして設定されます。パス検索でsb->s_d_op.d_automountがNULLでなければ、このコールバック関数がコールされ、autofsされているvfsmnt構造体からスーパブロック内のマウントオプションを取得しマウントされるわけです。

同時に、mnt_set_expiry(newmnt, &afs_vfsmounts);で、afs_vfsmountsをヘッドとするリストに、autoマウントされたファイルシステムがリストされ、ワークスレッドとして起動するafs_mntpt_expiry_timed_out()で、周期的にアンマウントするかどうかがチェックされます。
const struct dentry_operations afs_fs_dentry_operations = {
       .d_revalidate   = afs_d_revalidate,
       .d_delete       = afs_d_delete,
       .d_release      = afs_d_release,
       .d_automount    = afs_d_automount,
};

static int afs_fill_super(struct super_block *sb,
                         struct afs_mount_params *params)
{
       struct afs_super_info *as = sb->s_fs_info;
       struct afs_fid fid;
       struct dentry *root = NULL;
       struct inode *inode = NULL;
       int ret;

       _enter("");
 
       sb->s_blocksize         = PAGE_CACHE_SIZE;
       sb->s_blocksize_bits    = PAGE_CACHE_SHIFT;
       sb->s_magic             = AFS_FS_MAGIC;
       sb->s_op                = &afs_super_ops;
       sb->s_bdi               = &as->volume->bdi;
       strlcpy(sb->s_id, as->volume->vlocation->vldb.name, sizeof(sb->s_id));

       fid.vid         = as->volume->vid;
       fid.vnode       = 1;
       fid.unique      = 1;
       inode = afs_iget(sb, params->key, &fid, NULL, NULL);
       if (IS_ERR(inode))
               return PTR_ERR(inode);

       if (params->autocell)
               set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags);

       ret = -ENOMEM;
       root = d_alloc_root(inode);
       if (!root)
               goto error;

       sb->s_d_op = &afs_fs_dentry_operations;
       sb->s_root = root;

       _leave(" = 0");
       return 0;

error:
       iput(inode);
       _leave(" = %d", ret);
       return ret;
}

void save_mount_options(struct super_block *sb, char *options)
{
       BUG_ON(sb->s_options);
       rcu_assign_pointer(sb->s_options, kstrdup(options, GFP_KERNEL));
}

struct vfsmount *afs_d_automount(struct path *path)
{
       struct vfsmount *newmnt;

       _enter("{%s}", path->dentry->d_name.name);

       newmnt = afs_mntpt_do_automount(path->dentry);
       if (IS_ERR(newmnt))
               return newmnt;

       mntget(newmnt); /* prevent immediate expiration */
       mnt_set_expiry(newmnt, &afs_vfsmounts);
       queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer,
                          afs_mntpt_expiry_timeout * HZ);
       _leave(" = %p", newmnt);
       return newmnt;
}
パス検索では、do_lookup()で最後のエントリの処理が終わると、follow_managed()をコールして、そこがautofsされているかチェックします。 そこからfollow_automount()とコールされ、path->dentry->d_op->d_automount()が定義されているなら、autoマウントの処理となります。
static int follow_automount(struct path *path, unsigned flags,
                           bool *need_mntput)
{
       struct vfsmount *mnt;
       int err;

       if (!path->dentry->d_op || !path->dentry->d_op->d_automount)
               return -EREMOTE;

       if (!(flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY |
                    LOOKUP_OPEN | LOOKUP_CREATE | LOOKUP_AUTOMOUNT)) &&
           path->dentry->d_inode)
               return -EISDIR;

       current->total_link_count++;
       if (current->total_link_count >= 40)
               return -ELOOP;

       mnt = path->dentry->d_op->d_automount(path);
       if (IS_ERR(mnt)) {
               if (PTR_ERR(mnt) == -EISDIR && (flags & LOOKUP_PARENT))
                       return -EREMOTE;
               return PTR_ERR(mnt);
       }

       if (!mnt) /* mount collision */
               return 0;

       if (!*need_mntput) {
               /* lock_mount() may release path->mnt on error */
               mntget(path->mnt);
               *need_mntput = true;
       }
       err = finish_automount(mnt, path);

       switch (err) {
       case -EBUSY:
               return 0;
       case 0:
               path_put(path);
               path->mnt = mnt;
               path->dentry = dget(mnt->mnt_root);
               return 0;
       default:
               return err;
       }

}

追記

autoマウントされたファイルシステムは、自動的にアンマウントされるわけですが、先の例の/mnt3/testについて言えば、バインドマウントされている/home/kitamuraがアンマウントされるわけで、/mnt3/testにはautofsはずっとマウントしてるわけです。

ファイルシステムと言うと、データブロックのやり取りを含めた実装をイメージしますが、autofsは再マウントしdentry_operationsのd_automounコールバック関数(スーパブロックに再マウントする情報が設定されている。)をコールすることにあり、得意なファイルシステムと言うことです。mnt構造体は確かに独自に有して、vfs配下でマウント処理が行われるわけで、カーネルからみると、確かにファイルシステム処理としての位置づけですが、ユーザランドから見るファイルシステムのイメージからすると、むしろautomntと命名した方がいいのではと思いますが・・・。

最終更新 2014/01/06 03:36:20 - north
(2014/01/04 17:02:31 作成)


検索

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