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);
}






