シンボリックリンク
シンボリックリンクは、symlinkシステムコールからvfs_symlink()がコールされ、ディレクトリinodeコールバックのsymlinkがコールされます。
シンボリックリンク名が、inodeブロックの設定なら、inodeコールバックはext2_fast_symlink_inode_operations。データブロックの設定なら、ext2_symlink_inode_operationsとなります。これはreadlinkシステムコールで、シンボリックリンク名称取得する故の実装となります。
inodeはvfsのinode属性、ext2_inode_infoはファイルシステム毎(ext2)のinode属性で、ext2_inode_info.vfs_inode=inodeで、container_ofマクロでvfs_inodeのinodeから、struct ext2_inode_infoのinodeを取得します。
ext3も掛かる実装は同じです。ただしデータブロックの設定時、ジャーナル処理が追加されます。
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, }; int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) { int error = may_create(dir, dentry); if (error) return error; if (!dir->i_op->symlink) return -EPERM; error = security_inode_symlink(dir, dentry, oldname); if (error) return error; error = dir->i_op->symlink(dir, dentry, oldname); if (!error) fsnotify_create(dir, dentry); return error; }シンボリックリンク名称の長さは、ブロックサイズ(通常は4K)を超えるとエラーで、__le32 ext2_inode_info.i_data[15](15×32/8=60)以下なら、ext2_inode_info.i_data[15](inodeブロック)に、それ以上ならpage_symlink()でinode->i_mapping(データブロック)に設定され、このinodeをext2_add_nondir()で、親ディレクトリに追加します。
シンボリックリンク名が、inodeブロックの設定なら、inodeコールバックはext2_fast_symlink_inode_operations。データブロックの設定なら、ext2_symlink_inode_operationsとなります。これはreadlinkシステムコールで、シンボリックリンク名称取得する故の実装となります。
struct ext2_inode_info { __le32 i_data[15]; __u32 i_flags; __u32 i_faddr; __u8 i_frag_no; __u8 i_frag_size; __u16 i_state; __u32 i_file_acl; __u32 i_dir_acl; __u32 i_dtime; __u32 i_block_group; struct ext2_block_alloc_info *i_block_alloc_info; __u32 i_dir_start_lookup; #ifdef CONFIG_EXT2_FS_XATTR struct rw_semaphore xattr_sem; #endif rwlock_t i_meta_lock; struct mutex truncate_mutex; struct inode vfs_inode; struct list_head i_orphan; /* unlinked but open inodes */ }; static int ext2_symlink (struct inode * dir, struct dentry * dentry, const char * symname) { struct super_block * sb = dir->i_sb; int err = -ENAMETOOLONG; unsigned l = strlen(symname)+1; struct inode * inode; if (l > sb->s_blocksize) goto out; dquot_initialize(dir); inode = ext2_new_inode (dir, S_IFLNK | S_IRWXUGO, &dentry->d_name); err = PTR_ERR(inode); if (IS_ERR(inode)) goto out; if (l > sizeof (EXT2_I(inode)->i_data)) { inode->i_op = &ext2_symlink_inode_operations; if (test_opt(inode->i_sb, NOBH)) inode->i_mapping->a_ops = &ext2_nobh_aops; else inode->i_mapping->a_ops = &ext2_aops; err = page_symlink(inode, symname, l); if (err) goto out_fail; } else { inode->i_op = &ext2_fast_symlink_inode_operations; memcpy((char*)(EXT2_I(inode)->i_data),symname,l); inode->i_size = l-1; } mark_inode_dirty(inode); err = ext2_add_nondir(dentry, inode); out: return err; out_fail: inode_dec_link_count(inode); unlock_new_inode(inode); iput (inode); goto out; }
inodeはvfsのinode属性、ext2_inode_infoはファイルシステム毎(ext2)のinode属性で、ext2_inode_info.vfs_inode=inodeで、container_ofマクロでvfs_inodeのinodeから、struct ext2_inode_infoのinodeを取得します。
static inline struct ext2_inode_info *EXT2_I(struct inode *inode) { return container_of(inode, struct ext2_inode_info, vfs_inode); }
補足
通常ファイルのinodeコールバックは、ext2_fast_symlink_inode_operations/ext2_symlink_inode_operationsの.readlinkが定義されておらず、従って通常ファイルでのreadlinkシステムコールはエラーとなり、readlinkコマンドの-fオプションは、カーネルマターでなくコマンドマターです。ext3も掛かる実装は同じです。ただしデータブロックの設定時、ジャーナル処理が追加されます。