シンボリックリンク
シンボリックリンクは、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も掛かる実装は同じです。ただしデータブロックの設定時、ジャーナル処理が追加されます。






