anon_inodefs
inodeは親ディレクトリinodeに登録され、パスによるファイル走査を可能としていますが、ファイル走査の必要ないinodeは、親ディレクトリinodeに登録する必要ありません。このinodeの事をanon_inodeと言います。なお、参照中ファイルを削除した場合も、結果的にanon_inodeとなります。削はまず、親ディレクトリinodeから削除inodeを削除し、そのinodeを参照してなければデータブロックも含むinode事態を削除します。
ファイルの本質は、ユーザ空間とカーネル空間のインターフェースで、そのファイルにpath走査が必要ない場合のファイルシステムとしてanon_inodefsが実装されています。カーネルでは、eventfd/epoll_createシステムコールで使われています。
パスでのファイルが特定できない事は、ユーザ空間からのファイル作成できない事で、従ってかかるファイルシステム下の作成コールバックの実装の必要がありません。
anon_inode_init()でファイルシステムanon_inode_fs_typeが登録され、kern_mount()でマウントします。kern_mount()はfile_system_typeの.mount(anon_inodefs_mount)をコールし、anon_inode_mntを取得するのみで、既存ディレクトリにバインドしません。anon_inode_inodeは以降取得されるinodeの雛形となります。
ファイルの本質は、ユーザ空間とカーネル空間のインターフェースで、そのファイルにpath走査が必要ない場合のファイルシステムとしてanon_inodefsが実装されています。カーネルでは、eventfd/epoll_createシステムコールで使われています。
パスでのファイルが特定できない事は、ユーザ空間からのファイル作成できない事で、従ってかかるファイルシステム下の作成コールバックの実装の必要がありません。
anon_inode_init()でファイルシステムanon_inode_fs_typeが登録され、kern_mount()でマウントします。kern_mount()はfile_system_typeの.mount(anon_inodefs_mount)をコールし、anon_inode_mntを取得するのみで、既存ディレクトリにバインドしません。anon_inode_inodeは以降取得されるinodeの雛形となります。
static struct file_system_type anon_inode_fs_type = { .name = "anon_inodefs", .mount = anon_inodefs_mount, .kill_sb = kill_anon_super, }; static int __init anon_inode_init(void) { int error; error = register_filesystem(&anon_inode_fs_type); if (error) goto err_exit; anon_inode_mnt = kern_mount(&anon_inode_fs_type); if (IS_ERR(anon_inode_mnt)) { error = PTR_ERR(anon_inode_mnt); goto err_unregister_filesystem; } anon_inode_inode = anon_inode_mkinode(); if (IS_ERR(anon_inode_inode)) { error = PTR_ERR(anon_inode_inode); goto err_mntput; } return 0; err_mntput: kern_unmount(anon_inode_mnt); err_unregister_filesystem: unregister_filesystem(&anon_inode_fs_type); err_exit: panic(KERN_ERR "anon_inode_init() failed (%d)\n", error); } static const struct dentry_operations anon_inodefs_dentry_operations = { .d_dname = anon_inodefs_dname, }; static char *anon_inodefs_dname(struct dentry *dentry, char *buffer, int buflen) { return dynamic_dname(dentry, buffer, buflen, "anon_inode:%s", dentry->d_name.name); }スーパブロックオペレーションは設定せず(.statfsコールバックのみ有するsimple_super_operationsが設定されます。)、dentryオペレーションのanon_inodefs_dentry_operationsのみ設定されます。anon_inodefs_dentry_operationsで定義されているのは、/proc/pid/fd/で表示されるファイル名取得での.d_dnameコールバックのみです。
static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { return mount_pseudo(fs_type, "anon_inode:", NULL, &anon_inodefs_dentry_operations, ANON_INODE_FS_MAGIC); }anon_inode_getfile()はeventfd/epoll_createシステムコールでfile取得時にコールされます。通常はファイルシステム下のinodeをまず取得し、struct fileを取得した後、inodeのコールバックをファイルオペレーションコールバックとしますが、alloc_file()で引数のfopsを直接ファイルオペレーションコールバックとします。またfile->private_data = privはfopsコールバックが参照/制御するパラメータ群です。
struct file *anon_inode_getfile(const char *name, const struct file_operations *fops, void *priv, int flags) { struct qstr this; struct path path; struct file *file; int error; if (IS_ERR(anon_inode_inode)) return ERR_PTR(-ENODEV); if (fops->owner && !try_module_get(fops->owner)) return ERR_PTR(-ENOENT); error = -ENOMEM; this.name = name; this.len = strlen(name); this.hash = 0; path.dentry = d_alloc_pseudo(anon_inode_mnt->mnt_sb, &this); if (!path.dentry) goto err_module; path.mnt = mntget(anon_inode_mnt); ihold(anon_inode_inode); d_instantiate(path.dentry, anon_inode_inode); error = -ENFILE; file = alloc_file(&path, OPEN_FMODE(flags), fops); if (!file) goto err_dput; file->f_mapping = anon_inode_inode->i_mapping; file->f_pos = 0; file->f_flags = flags & (O_ACCMODE | O_NONBLOCK); file->f_version = 0; file->private_data = priv; return file; err_dput: path_put(&path); err_module: module_put(fops->owner); return ERR_PTR(error); } EXPORT_SYMBOL_GPL(anon_inode_getfile);
補足
mount_pseudo()でマウントされたファイルシステムのスーパブロックには、s->s_flags = MS_NOUSERし、ユーザ空間からmountできないようにしています。/proc/filesystemのファイルシステム群でmountできないファイルシステムは、mount_pseudo()をカーネル内でコールする事で、カーネルのみ参照できるファイルシステムとしているからです。struct dentry *mount_pseudo(struct file_system_type *fs_type, char *name, const struct super_operations *ops, const struct dentry_operations *dops, unsigned long magic) { struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL); struct dentry *dentry; struct inode *root; struct qstr d_name = {.name = name, .len = strlen(name)}; if (IS_ERR(s)) return ERR_CAST(s); s->s_flags = MS_NOUSER; s->s_maxbytes = MAX_LFS_FILESIZE; s->s_blocksize = PAGE_SIZE; s->s_blocksize_bits = PAGE_SHIFT; s->s_magic = magic; s->s_op = ops ? ops : &simple_super_operations; s->s_time_gran = 1; root = new_inode(s); if (!root) goto Enomem; root->i_ino = 1; root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR; root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME; dentry = __d_alloc(s, &d_name); if (!dentry) { iput(root); goto Enomem; } d_instantiate(dentry, root); s->s_root = dentry; s->s_d_op = dops; s->s_flags |= MS_ACTIVE; return dget(s->s_root); Enomem: deactivate_locked_super(s); return ERR_PTR(-ENOMEM); }