dname_external
switch_names()はファイルrename等からコールされ、dentryとtargetのファイル名のd_name.nameを差し替えるだけの単純なはずの処理ですが、dname_external()と言う変な関数による込み入った処理となっています。dname_external()はdentry->d_name.name != dentry->d_inameを比較することで、dentryのファイル名長が一定のサイズかどうかチェックします。
故に、dentry->d_name.name != dentry->d_inameということは、kmalloc()で割り当てたメモリで、ファイル名長がDNAME_INLINE_LENを超えているということです。
target:長い/dentry:長い
target:長い/dentry:短い
target:短い/dentry:長い
target:短い/dentry:短い
dname_externalの名称は、dentry->d_name.nameは外部メモリから取得したかどうか。という事に由来してるものと思われます。
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は外部メモリから取得したかどうか。という事に由来してるものと思われます。



