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[]はそのデータブロックインデックス)に設定されます。
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;
};

補足

ファイルシステム依存ですが、ext3ではシンボリックリンク名長は60以下と推奨される所以です。


最終更新 2014/08/19 05:50:15 - north
(2010/01/10 02:56:48 作成)


検索

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