autofs
Rev.1を表示中。最新版はこちら。
/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/testautofsをマウントすると、afs_fs_typeの.mountコールバックafs_mount()がコールします。この時afs_fill_super()でスーパブロックを、save_mount_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(¶ms, 0, sizeof(params)); if (options) { ret = afs_parse_options(¶ms, options, &dev_name); if (ret < 0) goto error; } ret = afs_parse_device_name(¶ms, 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(¶ms); 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, ¶ms); 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構造体からスーパブロック内のマウントオプションを取得しマウントされるわけです。
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; } }