container_of 가 어떻게 동작하는지
/**
* container_of - cast a member of a structure out to the containing structure
*
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
kernel에서 container_of의 구현이 저렇게 되어있는데.. 흠 리눅스 디바이스 드라이버 3판을 보고 있는데, 거기선 이렇게 사용하더라구요.. open시에 사용해서 private_data에 넣어두는..
int scull_open(struct inode *inode, struct file *filp)
{
struct scull_dev *dev; /* device information */
dev = container_of(inode->i_cdev, struct scull_dev, cdev);
filp->private_data = dev; /* for other methods */
/* now trim to 0 the length of the device if open was write-only */
if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) {
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
scull_trim(dev); /* ignore errors */
up(&dev->sem);
}
return 0; /* success */
}
이와 같은 구조로 사용하고 있네요.. 헌데.. 저렇게 사용하면 어디에 있는 scull_dev의 포인터를 구해오는 거죠?! 흠.. container_of를 해석 해 보면 inode->i_cdev에서 scull_dev구조체 내의 cdev의 위치만큼 차이를 빼서 구한게 dev로 대입되는거 같은데.. 흠.. 정리가 잘 안되지만 저렇게 구하면 inode내에서의 포인터를 구하는건데 그렇게 하면 안되지 않을까요?! 흠.. 어렵네요..
어떻게 설명해야 할지 모르겠습니다만 위와 같은 내용인것 같습니다. 고수님들 답변 부탁드립니다.
container_of
아시다시피 container_of(ptr, type, member) 는 ptr 포인터로부터 ptr 이 속한
type 구조체의 포인터를 얻어오는 매크로입니다.
해당 inode 구조체는 scull 장치에 해당하는 것이므로
그러므로 inode 구조체의 i_cdev 필드는
scull_setup_cdev() 함수에서 설정한대로
scull_dev 구조체의 cdev 필드를 가리킬 것입니다.
즉 inode->i_cdev 포인터(ptr)가
scull_dev 구조체(type)의 cdev 필드(member)이므로
이를 통해 원래의 scull_dev 구조체의 포인터를 얻어오게 됩니다.
/* * Set up the char_dev
/*
* Set up the char_dev structure for this device.
*/
static void scull_setup_cdev(struct scull_dev *dev, int index)
{
int err, devno = MKDEV(scull_major, scull_minor + index);
cdev_init(&dev->cdev, &scull_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &scull_fops;
err = cdev_add (&dev->cdev, devno, 1);
/* Fail gracefully if need be */
if (err)
printk(KERN_NOTICE "Error %d adding scull%d", err, index);
}
scull_setup_cdev()입니다. 여기서 보면 아무래도 inode->i_cdev와 연결되는 부분이 없는거 같은데..
흠.. 제가 삽질하는 중인가요?! ㅡㅡ; cdev_init()과 cdev_add()에서도 inode->i_cdev와 연결되는 부분이 없는거 같습니다. 어떻게 되는건지.. 의문이네요 ㅡㅡ;
댓글 달기