親ディレクトリ/カレントディレクトリ
Rev.1を表示中。最新版はこちら。
親ディレクトリ/カレントディレクトリは、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; }