親ディレクトリ/カレントディレクトリ


親ディレクトリ/カレントディレクトリは、link_walk()の実装から、バーチャルなディレクトリかと思っていましたが、そうでなく、ハードリンクとして実ディレクトリとして作成されます。

lsコマンド一覧です。左からnode番号/パーミッション/ハードリンク数となります。hoge1/hoge2/.はhoge1/hoge2とinode番号163877と共有(ハードリンク)、hoge1/hoge2/..はhoge1/.(kitamura/hoge1)とinode番号163876と共有(ハードリンク)しています。

従って、新規にディレクトリを作成すると、.ディレクトリのハードリンク数は、自分自身inodeと親inodeの2、..ディレクトリのハードリンク数は、自分自身inodeと親inode、親inodeの.ディレクトリの3となります。
[root@localhost kitamura]# mkdir hoge1
[root@localhost kitamura]# mkdir hoge1/hoge2

[root@localhost kitamura]# ls -lia hoge1/
合計 12
163876 drwxr-xr-x   3 root     root     4096  4月  2 02:07 .
147478 drwxrwxrwx. 47 kitamura kitamura 4096  4月  2 02:06 ..
163877 drwxr-xr-x   2 root     root     4096  4月  2 02:07 hoge2

[root@localhost kitamura]# ls -lia hoge1/hoge2/
合計 8
163877 drwxr-xr-x 2 root root 4096  4月  2 02:07 .
163876 drwxr-xr-x 3 root root 4096  4月  2 02:07 ..
ディレクトリ作成は、ディレクトリ用inodeの.mkdirコールバックで行います。ext2_mkdir()はext2ファイルシステムの.mkdirです。

ext2_new_inode()でディレクトリinodeを取得した後、ext2_make_empty()でカレント/親ディレクトリを作成します。
const struct inode_operations ext2_dir_inode_operations = {
       .create         = ext2_create,
       .lookup         = ext2_lookup,
       .link           = ext2_link,
       .unlink         = ext2_unlink,
       .symlink        = ext2_symlink,
       .mkdir          = ext2_mkdir,
       .rmdir          = ext2_rmdir,
       .mknod          = ext2_mknod,
       .rename         = ext2_rename,
#ifdef CONFIG_EXT2_FS_XATTR
       .setxattr       = generic_setxattr,
       .getxattr       = generic_getxattr,
       .listxattr      = ext2_listxattr,
       .removexattr    = generic_removexattr,
#endif
       .setattr        = ext2_setattr,
       .get_acl        = ext2_get_acl,
};

static int ext2_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
{
       struct inode * inode;
       int err = -EMLINK;

       if (dir->i_nlink >= EXT2_LINK_MAX)
               goto out;

       dquot_initialize(dir);

       inode_inc_link_count(dir);

       inode = ext2_new_inode(dir, S_IFDIR | mode, &dentry->d_name);
       err = PTR_ERR(inode);
       if (IS_ERR(inode))
               goto out_dir;

       inode->i_op = &ext2_dir_inode_operations;
       inode->i_fop = &ext2_dir_operations;
       if (test_opt(inode->i_sb, NOBH))
               inode->i_mapping->a_ops = &ext2_nobh_aops;
       else
               inode->i_mapping->a_ops = &ext2_aops;

       inode_inc_link_count(inode);

       err = ext2_make_empty(inode, dir);
       if (err)
               goto out_fail;

       err = ext2_add_link(dentry, inode);
       if (err)
               goto out_fail;

       d_instantiate(dentry, inode);
       unlock_new_inode(inode);
out:
       return err;

out_fail:
       inode_dec_link_count(inode);
       inode_dec_link_count(inode);
       unlock_new_inode(inode);
       iput(inode);
out_dir:
       inode_dec_link_count(dir);
       goto out;
}
引数のinodeは新規に作成されたディレクトリで、parentはその親ディレクトリです。ディレクトリ名"."をinode->i_inoとし、 ".."をparent->i_inoとするinodeをハードリンクとして作成し、ext2_commit_chunk()でこのpageをdirtyとし、デバイスに書き込まれます。
int ext2_make_empty(struct inode *inode, struct inode *parent)
{
       struct page *page = grab_cache_page(inode->i_mapping, 0);
       unsigned chunk_size = ext2_chunk_size(inode);
       struct ext2_dir_entry_2 * de;
       int err;
       void *kaddr;

       if (!page)
               return -ENOMEM;

       err = ext2_prepare_chunk(page, 0, chunk_size);
       if (err) {
               unlock_page(page);
               goto fail;
       }
       kaddr = kmap_atomic(page, KM_USER0);
       memset(kaddr, 0, chunk_size);
       de = (struct ext2_dir_entry_2 *)kaddr;
       de->name_len = 1;
       de->rec_len = ext2_rec_len_to_disk(EXT2_DIR_REC_LEN(1));
       memcpy (de->name, ".\0\0", 4);
       de->inode = cpu_to_le32(inode->i_ino);
       ext2_set_de_type (de, inode);

       de = (struct ext2_dir_entry_2 *)(kaddr + EXT2_DIR_REC_LEN(1));
       de->name_len = 2;
       de->rec_len = ext2_rec_len_to_disk(chunk_size - EXT2_DIR_REC_LEN(1));
       de->inode = cpu_to_le32(parent->i_ino);
       memcpy (de->name, "..\0", 4);
       ext2_set_de_type (de, inode);
       kunmap_atomic(kaddr, KM_USER0);
       err = ext2_commit_chunk(page, 0, chunk_size);
fail:
       page_cache_release(page);
       return err;
}

備考

ハードリンクはリンク先inode配下のinodeの参照カウンタはインクリメントしないため、システムコールでのディレクトリハードリンクは作成できませんが、このケースでは、親/子の直下階層配置のディレクトリ故に問題ありません。


最終更新 2015/04/01 20:31:36 - north
(2015/04/01 20:30:23 作成)


検索

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