fast_symlink
シンボリックリンク作成は、ext3ファイルシステム時、dirオペレーションコールバック関数ext3_symlink()がコールされます。
ext3_new_inode()でシンボリックのinodeを作成し、symname(シンボリック名)が、sizeof (EXT3_I(inode)->i_data)より長ければ、ext3_symlink_inode_operations、短ければext3_fast_symlink_inode_operationsがinodeオペレーションコールバックとして設定されます。
sizeof (EXT3_I(inode)->i_data)は、indoe->vfs_inodeに設定してある、ファイルシステム依存のinode情報が設定されています。そのinode->vfs_inode->i_data[15]は、ファイルの中身のデータブロックのインデックスを設定する領域です。リンク先名称は、15×4=60バイト以下だとi_data[15]に、そうでないと、通常ファイルと同じようにデータブロック(i_data[]はそのデータブロックインデックス)に設定されます。
ext3_new_inode()でシンボリックのinodeを作成し、symname(シンボリック名)が、sizeof (EXT3_I(inode)->i_data)より長ければ、ext3_symlink_inode_operations、短ければext3_fast_symlink_inode_operationsがinodeオペレーションコールバックとして設定されます。
sizeof (EXT3_I(inode)->i_data)は、indoe->vfs_inodeに設定してある、ファイルシステム依存のinode情報が設定されています。そのinode->vfs_inode->i_data[15]は、ファイルの中身のデータブロックのインデックスを設定する領域です。リンク先名称は、15×4=60バイト以下だとi_data[15]に、そうでないと、通常ファイルと同じようにデータブロック(i_data[]はそのデータブロックインデックス)に設定されます。
struct inode_operations ext3_dir_inode_operations = { .create = ext3_create, .lookup = ext3_lookup, .link = ext3_link, .unlink = ext3_unlink, .symlink = ext3_symlink, .mkdir = ext3_mkdir, .rmdir = ext3_rmdir, .mknod = ext3_mknod, .rename = ext3_rename, .setattr = ext3_setattr, .setxattr = ext3_setxattr, .getxattr = ext3_getxattr, .listxattr = ext3_listxattr, .removexattr = ext3_removexattr, .permission = ext3_permission, }; static int ext3_symlink (struct inode * dir, struct dentry *dentry, const char * symname) { handle_t *handle; struct inode * inode; int l, err; l = strlen(symname)+1; if (l > dir->i_sb->s_blocksize) return -ENAMETOOLONG; handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5); if (IS_ERR(handle)) return PTR_ERR(handle); if (IS_DIRSYNC(dir)) handle->h_sync = 1; inode = ext3_new_inode (handle, dir, S_IFLNK|S_IRWXUGO); err = PTR_ERR(inode); if (IS_ERR(inode)) goto out_stop; if (l > sizeof (EXT3_I(inode)->i_data)) { inode->i_op = &ext3_symlink_inode_operations; ext3_set_aops(inode); err = page_symlink(inode, symname, l); if (err) { ext3_dec_count(handle, inode); ext3_mark_inode_dirty(handle, inode); iput (inode); goto out_stop; } } else { inode->i_op = &ext3_fast_symlink_inode_operations; memcpy((char*)&EXT3_I(inode)->i_data,symname,l); inode->i_size = l-1; } EXT3_I(inode)->i_disksize = inode->i_size; err = ext3_add_nondir(handle, dentry, inode); out_stop: ext3_journal_stop(handle); return err; } static inline struct ext3_inode_info *EXT3_I(struct inode *inode) { return container_of(inode, struct ext3_inode_info, vfs_inode); }リンク先取得のreadlinkシステムコールは、inodeコールバック関数の.readlinがコールされ、ext3_fast_symlink_inode_operationsならext3_readlink()をコールし、inode->vfs_inode->i_dataをそのまま返しますが、ext3_symlink_inode_operationsならpage_readlink()はデータブロックを読み込み(通常ファイルのデータの読込)それを返すことになります。
struct inode_operations ext3_fast_symlink_inode_operations = { .readlink = ext3_readlink, /* BKL not held. Don't need */ .follow_link = ext3_follow_link, /* BKL not held. Don't need */ .setxattr = ext3_setxattr, .getxattr = ext3_getxattr, .listxattr = ext3_listxattr, .removexattr = ext3_removexattr, }; struct inode_operations ext3_symlink_inode_operations = { .readlink = page_readlink, .follow_link = page_follow_link, .setxattr = ext3_setxattr, .getxattr = ext3_getxattr, .listxattr = ext3_listxattr, .removexattr = ext3_removexattr, }; static int ext3_readlink(struct dentry *dentry, char __user *buffer, int buflen) { struct ext3_inode_info *ei = EXT3_I(dentry->d_inode); return vfs_readlink(dentry, buffer, buflen, (char*)ei->i_data); } int page_readlink(struct dentry *dentry, char __user *buffer, int buflen) { struct page *page = NULL; char *s = page_getlink(dentry, &page); int res = vfs_readlink(dentry,buffer,buflen,s); if (page) { kunmap(page); page_cache_release(page); } return res; } int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const char *link) { int len; len = PTR_ERR(link); if (IS_ERR(link)) goto out; len = strlen(link); if (len > (unsigned) buflen) len = buflen; if (copy_to_user(buffer, link, len)) len = -EFAULT; out: return len; }
struct ext3_inode_info { __u32 i_data[15]; __u32 i_flags; #ifdef EXT3_FRAGMENTS __u32 i_faddr; __u8 i_frag_no; __u8 i_frag_size; #endif __u32 i_file_acl; __u32 i_dir_acl; __u32 i_dtime; __u32 i_block_group; __u32 i_state; /* Dynamic state flags for ext3 */ __u32 i_next_alloc_block; __u32 i_next_alloc_goal; #ifdef EXT3_PREALLOCATE __u32 i_prealloc_block; __u32 i_prealloc_count; #endif __u32 i_dir_start_lookup; #ifdef CONFIG_EXT3_FS_XATTR struct rw_semaphore xattr_sem; #endif #ifdef CONFIG_EXT3_FS_POSIX_ACL struct posix_acl *i_acl; struct posix_acl *i_default_acl; #endif struct list_head i_orphan; /* unlinked but open inodes */ loff_t i_disksize; struct semaphore truncate_sem; struct inode vfs_inode; };