kernel 구조체 중 list_head를 보면..

lantelt의 이미지

list_head 구조체는 포인트 두개로 이루어져 있습니다.

struct list_head {
	struct list_head *next, *prev;
};

대부분 모든 자료형들이 저 리스트 구조체를 이용해서 링크드 리스트를 형성하는데요.
어떻게 저 리스트 구조체가 다른 구조체의 주소 역할을 할 수 있는 것입니까?
예를 들면

struct page {
	unsigned long flags;		
					  
	atomic_t count;			
	struct list_head list;		
	struct address_space *mapping;	
	unsigned long index;		
	struct list_head lru;		
				
	union {
		struct pte_chain *chain;
				
		pte_addr_t direct;
	} pte;
	unsigned long private;	

	
#if defined(WANT_PAGE_VIRTUAL)
	void *virtual;	
#endif /* CONFIG_HIGMEM || WANT_PAGE_VIRTUAL */
};

page 구조체에서도 저 리스트 구조체를 이용해서 서로 연결되고 있는데요.
그게 어떻게 가능한건가요?
jjong_park의 이미지

include/linux/list.h 에 보면
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

이걸 사용해서 하지요. 즉,

struct page *p;
라고 해 놓고 이 페이지에 연결된 다음 페이지는

list_entry(p->list.next, struct page*, list);

가 됩니다.
p->list.next 포인터는 struct page 안의 struct list를 가리키고 있죠.
그러므로 struct page로의 포인터는 거기에서 struct list의 struct page안에서의 오프셋 (4 byte)만큼을 뺀 것이 되겠네요.
그림 잘 그려서 해 보면 될껍니다~