dname_external


Rev.1を表示中。最新版はこちら

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:長い/target:長い
dentry:長い/target:短い
dentry:短い/target:長い
dentry:短い/target:短い

補足

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

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


検索

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