(a bit involved so bear with me, i really want to figure out how this works.) i'm following the sample code in the LDD3 book for the "scull" driver, and i *think* i know the answer to this but i just want to make sure. it has to do with how defining a new character device and opening it manages to set the i_cdev pointer back in the inode structure. first, from <linux/fs.h>, we have the definition of an inode, with only the relevant fields that i care about: struct inode { ... union { struct pipe_inode_info *i_pipe; struct block_device *i_bdev; struct cdev *i_cdev; }; ... so, depending on the type of file, only one of those pointers will be valid. but, initially, if nothing has opened the file represented by this inode yet, none of those pointers will point at anything meaningful, right? so, in the beginning, the pointer i_cdev will not have a valid address. so far, so good? now consider how this relates to the "scull" example from LDD3. here's the structure for representing that new kind of character device: struct scull_dev { struct scull_qset *data; /* Pointer to first quantum set */ int quantum; /* the current quantum size */ int qset; /* the current array size */ unsigned long size; /* amount of data stored here */ unsigned int access_key; /* used by sculluid and scullpriv */ struct semaphore sem; /* mutual exclusion semaphore */ struct cdev cdev; /* Char device structure */ }; and there at the bottom is the embedded "struct cdev" you're supposed to build in to your new character device. the question is -- how does that structure get associated with the structure pointer back in the inode? moving on, here's the character device initialization routine for that sample "scull" char device: /* * 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); } so what does this code do? from fs/char_dev.c, here's the code for cdev_init(): void cdev_init(struct cdev *cdev, const struct file_operations *fops) { memset(cdev, 0, sizeof *cdev); INIT_LIST_HEAD(&cdev->list); kobject_init(&cdev->kobj, &ktype_cdev_default); cdev->ops = fops; } that doesn't appear to link the cdev back to the inode, but it *does* create an initialized kobject for the character device. following that, cdev_add() is run: int cdev_add(struct cdev *p, dev_t dev, unsigned count) { p->dev = dev; p->count = count; return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p); } which appears to fill in the new kobject with information corresponding to this new character device, but *still*, there's no connection back to the inode for the device file. finally, it looks like it happens here: /* * Called every time a character special file is opened */ static int chrdev_open(struct inode *inode, struct file *filp) { struct cdev *p; struct cdev *new = NULL; int ret = 0; spin_lock(&cdev_lock); p = inode->i_cdev; if (!p) { struct kobject *kobj; int idx; spin_unlock(&cdev_lock); kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx); if (!kobj) return -ENXIO; new = container_of(kobj, struct cdev, kobj); spin_lock(&cdev_lock); p = inode->i_cdev; if (!p) { inode->i_cdev = p = new; inode->i_cindex = idx; list_add(&inode->i_devices, &p->list); new = NULL; ... snip ... that routine might be called every time a char special file is opened but, at this point, it still seems that the inode "i_cdev" pointer isn't yet pointing to the "struct cdev" we've created and initialized. finally, it seems to happen in this routine, where a test is done to see if that pointer is set yet: p = inode->i_cdev; if (!p) { and if it isn't, then: kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx); if (!kobj) return -ENXIO; new = container_of(kobj, struct cdev, kobj); that *appears* to do a wide-ranging kobject lookup, looking for the kobject that matches the device ID (inode->i_rdev) and, if it finds it, then the struct cdev we're looking for is simply the container of that kobject. and *finally*, if (!p) { inode->i_cdev = p = new; the "i_cdev" struct cdev pointer back in the inode is set and can be used from now on. does all that make sense? in short, the very first time a character device file is opened and it's noticed that the inode->i_cdev pointer hasn't been set yet, a kobject-based search is done to find the corresponding "struct cdev" address to fill into the inode. does all this seem to follow? rday p.s. i am a bit confused as to why there are two tests for whether inode->i_cdev is non-NULL: p = inode->i_cdev; if (!p) { <-- first test of p struct kobject *kobj; int idx; spin_unlock(&cdev_lock); kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx); if (!kobj) return -ENXIO; new = container_of(kobj, struct cdev, kobj); spin_lock(&cdev_lock); p = inode->i_cdev; if (!p) { <-- second test of p inode->i_cdev = p = new; why is that first test being repeated further down? if p was NULL at that first test, how could it possibly have changed before that second test? isn't that second test redundant? or am i missing something? ======================================================================== Robert P. J. Day Linux Consulting, Training and Annoying Kernel Pedantry: Have classroom, will lecture. http://crashcourse.ca Waterloo, Ontario, CANADA ======================================================================== -- To unsubscribe from this list: send an email with "unsubscribe kernelnewbies" to ecartis@xxxxxxxxxxxx Please read the FAQ at http://kernelnewbies.org/FAQ