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:短い