iget (4)

とりあえず hlist_entry マクロというか container_of マクロの謎はある程度解けたので元に戻ります。その前に hlist_for_each マクロも確認必要。

#define hlist_for_each(pos, head) \
	for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
	     pos = pos->next)

ええと、include/linux/list.h にて定義。
あと struct hlist_head 型とか struct hlist_node 型などの定義は include/linux/list.h で以下

struct hlist_head {
	struct hlist_node *first;
};

struct hlist_node {
	struct hlist_node *next, **pprev;
};

む pprev な属性の意図が不明。とりあえず hlist_for_each マクロでは使っていないのでスルー。あと謎なのが prefetch という手続き。
で、掘ってみたのですが i386 なソレだと include/asm-i386/processor.h で以下

static inline void prefetch(const void *x)
{
	alternative_input(ASM_NOP4,
			  "prefetchnta (%1)",
			  X86_FEATURE_XMM,
			  "r" (x));
}

で、alternative_input マクロは include/asm-i386/alternative.h にて定義されてて以下

#define alternative_input(oldinstr, newinstr, feature, input...)	\
	asm volatile ("661:\n\t" oldinstr "\n662:\n"			\
		      ".section .altinstructions,\"a\"\n"		\
		      "  .align 4\n"					\
		      "  .long 661b\n"            /* label */		\
		      "  .long 663f\n"		  /* new instruction */ \
		      "  .byte %c0\n"             /* feature bit */	\
		      "  .byte 662b-661b\n"       /* sourcelen */	\
		      "  .byte 664f-663f\n"       /* replacementlen */ 	\
		      ".previous\n"					\
		      ".section .altinstr_replacement,\"ax\"\n"		\
		      "663:\n\t" newinstr "\n664:\n"   /* replacement */\
		      ".previous" :: "i" (feature), ##input)

ぎゃー。とりあえず hlist_for_each マクロは pos が NULL になったら終わるはずなので、意図としては

  • node を持ってる inode オブジェクトの
    • inode 番号が同一
    • super block オブジェクトも同じ
  • i_state が I_FREEING でも I_CLEAR でも I_WILL_FREE でもない

のであれば inode オブジェクトのポインタを戻す、という理解でええんかな。

戻って

fs/inode.c の ifind_fast 手続き。上記の find_inode_fast 手続きが NULL を戻したら spin_unlock して NULL を戻します。そうでなかった場合は以下

	if (inode) {
		__iget(inode);
		spin_unlock(&inode_lock);
		wait_on_inode(inode);
		return inode;
	}

__iget 手続きは何なんだろ。fs/inode.c で定義されてて以下

/*
 * inode_lock must be held
 */
void __iget(struct inode * inode)
{
	if (atomic_read(&inode->i_count)) {
		atomic_inc(&inode->i_count);
		return;
	}
	atomic_inc(&inode->i_count);
	if (!(inode->i_state & (I_DIRTY|I_LOCK)))
		list_move(&inode->i_list, &inode_in_use);
	inodes_stat.nr_unused--;
}

i_count を云々してますがこの属性は_参照カウント_とある。ざっくり的に理解するとしたらば cache 見に行ってあれば参照カウント上げとく、という事なのかなぁ。

iget_locked

再掲。

struct inode *iget_locked(struct super_block *sb, unsigned long ino)
{
	struct hlist_head *head = inode_hashtable + hash(sb, ino);
	struct inode *inode;

	inode = ifind_fast(sb, head, ino);
	if (inode)
		return inode;
	/*
	 * get_new_inode_fast() will do the right thing, re-trying the search
	 * in case it had to block at any point.
	 */
	return get_new_inode_fast(sb, head, ino);
}

inode cache 見に行ってあったら戻す。参照カウントも上げとく。無かった場合どうなるか。

get_new_inode_fast 手続き

これと get_new_inode 手続きのナニが不明ですが、以下なコメントがある。

/*
 * get_new_inode_fast is the fast path version of get_new_inode, see the
 * comment at iget_locked for details.
 */

うーん。ちょっと fast とそうでない違いが理解できてない。
体調微妙なので今日はこれで終了。