無料Wikiサービス | デモページ
検索

アクセス数
最近のコメント
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
はじめ - ノース
はじめ - ノース
はじめ - 楽打連動ユーザー
はじめ - 楽打連動ユーザー
Adsense
広告情報が設定されていません。

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の雛形となります。
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);
}


最終更新 2015/05/08 15:12:18 - north
(2015/05/08 15:12:18 作成)