dname_external


switch_names()はファイルrename等からコールされ、dentryとtargetのファイル名のd_name.nameを差し替えるだけの単純なはずの処理ですが、dname_external()と言う変な関数による込み入った処理となっています。dname_external()はdentry->d_name.name != dentry->d_inameを比較することで、dentryのファイル名長が一定のサイズかどうかチェックします。
static void switch_names(struct dentry *dentry, struct dentry *target)
{
       if (dname_external(target)) {
               if (dname_external(dentry)) {
                       swap(target->d_name.name, dentry->d_name.name);
               } else {
                       memcpy(target->d_iname, dentry->d_name.name,
                                       dentry->d_name.len + 1);
                       dentry->d_name.name = target->d_name.name;
                       target->d_name.name = target->d_iname;
               }
       } else {
               if (dname_external(dentry)) {
                       memcpy(dentry->d_iname, target->d_name.name,
                                       target->d_name.len + 1);
                       target->d_name.name = dentry->d_name.name;
                       dentry->d_name.name = dentry->d_iname;
               } else {
                       memcpy(dentry->d_iname, target->d_name.name,
                                       target->d_name.len + 1);
                       dentry->d_name.len = target->d_name.len;
                       return;
               }
       }
       swap(dentry->d_name.len, target->d_name.len);
}

static inline int dname_external(struct dentry *dentry)
{
       return dentry->d_name.name != dentry->d_iname;
}
dname_external()を理解するには、dentryの取得の実装を見ると分かります。ファイル名サイズがDNAME_INLINE_LENより長い場合、kmalloc()で割り当てたメモリをdentry->d_name.nameとし、そうでない場合dentry->d_name.name = d_iname[DNAME_INLINE_LEN]とし、dentry->d_name.nameにファイル名を設定し、dentry取得毎に逐次kmalloc()する負荷を軽減させています。

故に、dentry->d_name.name != dentry->d_inameということは、kmalloc()で割り当てたメモリで、ファイル名長がDNAME_INLINE_LENを超えているということです。
#ifdef CONFIG_64BIT
# define DNAME_INLINE_LEN 32 /* 192 bytes */
#else
# ifdef CONFIG_SMP
#  define DNAME_INLINE_LEN 36 /* 128 bytes */
# else
#  define DNAME_INLINE_LEN 40 /* 128 bytes */
# endif
#endif

struct qstr {
       unsigned int hash;
       unsigned int len;
       const unsigned char *name;
};

struct dentry {
  :
        struct qstr d_name;
  :
        unsigned char d_iname[DNAME_INLINE_LEN];        /* small names */
  :
}

struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
{
       struct dentry *dentry;
       char *dname;

       dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);
       if (!dentry)
               return NULL;

       if (name->len > DNAME_INLINE_LEN-1) {
               dname = kmalloc(name->len + 1, GFP_KERNEL);
               if (!dname) {
                       kmem_cache_free(dentry_cache, dentry); 
                       return NULL;
               }
       } else  {
               dname = dentry->d_iname;
       }       
       dentry->d_name.name = dname;

       dentry->d_name.len = name->len;
       dentry->d_name.hash = name->hash;
       memcpy(dname, name->name, name->len);
       dname[name->len] = 0;
  :
       return dentry;
}
switch_names()は、dentry名称がdentry構造体メンバのd_iname[DNAME_INLINE_LEN]に設定される場合、構造体内のメンバー故それを考慮してd_name.nameを差し替えなければならないからです。ちなみに上から順に以下のケースの処理で、これらを考慮してプログラムを追っていただいた方がいいかと思います。
target:長い/dentry:長い
target:長い/dentry:短い
target:短い/dentry:長い
target:短い/dentry:短い

dname_externalの名称は、dentry->d_name.nameは外部メモリから取得したかどうか。という事に由来してるものと思われます。

補足

以前はLinux2を今はlinux3を読んでいます。linux3では、このようなカーネルの実機能とは違う目的での込み入った実装が多々あって、カーネルの本質を知ってみたい。と言う方は、まずは、linux2から読まれて取っ掛かりを捕まれて、ステップアップされた方がいいのでは。と思いますが・・・・。

最終更新 2014/03/28 02:36:49 - north
(2014/03/26 01:41:40 作成)


検索

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