LINUX.ORG.RU

Проблемы с container_of()


0

1

В драйвере шины объявлена структура:

struct chld_device {
	int state;
	int base_addr;
	unsigned long length;
	struct resource res[32];
	u64 dma_mask;
	struct device dev; 
	struct cdev cdev;
};

При инициализации шины,происходит инициализация дочерних устройств,с заполнением base_addr, res, dev, cdev.
В дальнейшем подгружаю драйвер устройства в котором запускается .open. В нем уже исполняю:
int dev_open(struct inode *inode, struct file *filp){
	struct chld_device *icd = container_of(inode->i_cdev, struct chld_device,cdev);
	filp->private_data = icd;
}
В итоге вижу что корректные значения находятся только в cdev. Остальные элементы структуры chld_device содержат явно не то на что я рассчитывал. Или я не совсем понимаю как работает контейнер или одно из двух.
Подскажите в какую сторону копать дальше.

Ответ на: комментарий от darkshvein

А по существу,то есть мысли куда копать

AndriAno
() автор топика

Контейнер по указателю на элемент структуры возвращает указатель на начало структуры

ttnl ★★★★★
()
Ответ на: комментарий от ttnl

Как в старом анекдоте про программистов. Максимально точный и столько же бесполезный ответ(без обид).

При просмотре кода натыкаюсь на следующие примеры использования:

struct phantom_device {
	unsigned int opened;
	void __iomem *caddr;
	u32 __iomem *iaddr;
	u32 __iomem *oaddr;
	unsigned long status;
	atomic_t counter;
	wait_queue_head_t wait;
	struct cdev cdev;
	struct mutex open_lock;
	spinlock_t regs_lock;
	struct phm_regs oregs;
	u32 ctl_reg;
};

static int phantom_open(struct inode *inode, struct file *file)
{
	struct phantom_device *dev = container_of(inode->i_cdev,struct phantom_device, cdev);

file->private_data = dev;
return 0;
}

static long phantom_ioctl(struct file *file, unsigned int cmd,
		unsigned long arg)
{
	struct phantom_device *dev = file->private_data;
	...
	...
	spin_lock_irqsave(&dev->regs_lock, flags);
	...
	dev->ctl_reg = r.value;
	...
	iowrite32(r.value, dev->iaddr + r.reg);
	...
}

То есть в функции phantom_ioctl имеется доступ ко всем элементам структуры phantom_device. В моем же случае так не получается. Содержимое элемента cdev корректно, остальные же элементы содержат некорректные значения. (Прошу сильно ногами не пинать, язык С к сожалению не является основным на котором я пишу,и тем более задачи написания драйверов)

AndriAno
() автор топика
Ответ на: комментарий от AndriAno

И да - тебе делать больше нечего, чем в 6 утра ядром заниматься?

Это черевато, предупреждаю тебя. По своему опыту.

ttnl ★★★★★
()
Ответ на: комментарий от ttnl

file: fs.h

struct inode {
717         struct hlist_node       i_hash;
718         struct list_head        i_list;
719         struct list_head        i_sb_list;
720         struct list_head        i_dentry;
721         unsigned long           i_ino;
722         atomic_t                i_count;
723         unsigned int            i_nlink;
724         uid_t                   i_uid;
725         gid_t                   i_gid;
726         dev_t                   i_rdev;
727         u64                     i_version;
728         loff_t                  i_size;
729 #ifdef __NEED_I_SIZE_ORDERED
730         seqcount_t              i_size_seqcount;
731 #endif
732         struct timespec         i_atime;
733         struct timespec         i_mtime;
734         struct timespec         i_ctime;
735         blkcnt_t                i_blocks;
736         unsigned int            i_blkbits;
737         unsigned short          i_bytes;
738         umode_t                 i_mode;
739         spinlock_t              i_lock; /* i_blocks, i_bytes, maybe i_size */
740         struct mutex            i_mutex;
741         struct rw_semaphore     i_alloc_sem;
742         const struct inode_operations   *i_op;
743         const struct file_operations    *i_fop; /* former ->i_op->default_file_ops */
744         struct super_block      *i_sb;
745         struct file_lock        *i_flock;
746         struct address_space    *i_mapping;
747         struct address_space    i_data;
748 #ifdef CONFIG_QUOTA
749         struct dquot            *i_dquot[MAXQUOTAS];
750 #endif
751         struct list_head        i_devices;
752         union {
753                 struct pipe_inode_info  *i_pipe;
754                 struct block_device     *i_bdev;
755                 struct cdev             *i_cdev;
756         };

Насколько я понимаю в i_cdev содержится указатель на cdev, конкретного устройства к которому приатачен открываемый файл.

struct chld_device {
	int state;
	int base_addr;
	unsigned long length;
	struct resource res[32];
	u64 dma_mask;
	struct device dev; 
	struct cdev cdev;
};
Во время загрузки драйвера шины создается несколько однотипных устройств в /sys/bus/mybus/devices,после этого при подгрузке драйвера устройств вызывается несколько раз .probe.
drv_probe(struct device *dev)
{
	dev->devt = MKDEV(MAJ,MIN);
	device_create(drv_class,NULL,dev->devt,NULL,dev->kobj.name);
}
В /dev появляются файлы устройств. При открытии произвольного устройства, вызывается .open.
int dev_open(struct inode *inode,struct file *filp)
{
printk("imajor = %d, iminor = %d\n",imajor(inode),iminor(inode));// выдает коректные значения major и minor

struct chld_device *icd = container_of(inode->i_cdev, struct chld_device,cdev);
filp->private_data = icd;
}
В дальнейшем вызывается .read.
static ssize_t dev_read(struct file *filp, char __user *buf, size_t count,
		loff_t *offset) {
	struct chld_device *icd = filp->private_data;
#ifdef IIS_DEBUG
	print_inf
#endif
	
	printk("Read Major = %d,Minor = %d\n",MAJOR(icd->cdev.dev),MINOR(icd->cdev.dev));//выдает корректные значения
	printk("icd->cdev.kobj.name = %s\n",icd->cdev.kobj.name);//корректно
	printk("icd->res[0].start =  %d\n",icd->res[0].start);//некорректно как и многое другое

AndriAno
() автор топика
Ответ на: комментарий от ttnl

Ну а задача в общем стоит такая: определить к какому из одинаковых устройств управляемых одним драйвером производиться обращение. Если есть другие способы с удовольствием выслушаю.

AndriAno
() автор топика
Ответ на: комментарий от AndriAno
static int my_open(struct inode *inode, struct file *filp)
{
	unsigned int minor = MINOR(inode->i_rdev);

	/* Тут всякие проверки */
	...

	...
	filp->private_data = minor;

	return ret;
}

static ssize_t my_read(struct file *filp, char __user *buf, size_t count, loff_t *offset)
{
	switch (filp->private_data) {
		case 0...665:
				printk(KERN_INFO "Заебись\n");
				break;
		case 666:
				panic("Полный пиздец, мы все умрем!\n");
	}
}
ttnl ★★★★★
()
Ответ на: комментарий от ttnl

ну это то понятно, и даже работает как я выше писал. MAJOR(icd->cdev.dev) MINOR(icd->cdev.dev) я получаю, а вот как теперь получить указатель на структурку с адресами моего устойства

AndriAno
() автор топика
Ответ на: комментарий от AndriAno

Я не понимаю, почему ты считаешь, что в inode->i_cdev должно быть хоть какое-то упоминание phantom_device.

Выложи весь код

ttnl ★★★★★
()
Ответ на: комментарий от AndriAno

как впрочем подобное встречается во многих других драйверах, просто этот как то под руку подвернулся

AndriAno
() автор топика
Ответ на: комментарий от AndriAno

i_cdev заполняется в chrdev_open, если ты все правильно проинициализировал в probe.

cdev_init, cdev_add и device_create сделал? Туда нормальные указатели передаются?

ttnl ★★★★★
()
Ответ на: комментарий от ttnl

Точно смогу ответить только завтра, когда на работу приду.

AndriAno
() автор топика
Ответ на: комментарий от ttnl

Напрямую cdev_init и cdev_add не вызываю.

file: char_dev.c

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;
 }
операции инициализации kobject производятся в драйвере шины при вызове device_register()
file: core.c

int device_register(struct device *dev)
1012 {
1013         device_initialize(dev);
1014         return device_add(dev);
1015 }

void device_initialize(struct device *dev)
549 {
550         dev->kobj.kset = devices_kset;
551         kobject_init(&dev->kobj, &device_ktype);
552         INIT_LIST_HEAD(&dev->dma_pools);
553         init_MUTEX(&dev->sem);
554         spin_lock_init(&dev->devres_lock);
555         INIT_LIST_HEAD(&dev->devres_head);
556         device_init_wakeup(dev, 0);
557         device_pm_init(dev);
558         set_dev_node(dev, -1);
559 }

Вместо cdev_add при регистрации драйвера устройства вызываю register_chrdev()

261 int register_chrdev(unsigned int major, const char *name,
262                     const struct file_operations *fops)
263 {
264         struct char_device_struct *cd;
265         struct cdev *cdev;
266         char *s;
267         int err = -ENOMEM;
268 
269         cd = __register_chrdev_region(major, 0, 256, name);
270         if (IS_ERR(cd))
271                 return PTR_ERR(cd);
272         
273         cdev = cdev_alloc();
274         if (!cdev)
275                 goto out2;
276 
277         cdev->owner = fops->owner;
278         cdev->ops = fops;
279         kobject_set_name(&cdev->kobj, "%s", name);
280         for (s = strchr(kobject_name(&cdev->kobj),'/'); s; s = strchr(s, '/'))
281                 *s = '!';
282                 
283         err = cdev_add(cdev, MKDEV(cd->major, 0), 256);
284         if (err)
285                 goto out;
286 
287         cd->cdev = cdev;
288 
289         return major ? 0 : cd->major;
290 out:
291         kobject_put(&cdev->kobj);
292 out2:
293         kfree(__unregister_chrdev_region(cd->major, 0, 256));
294         return err;
295 }
Ну и соответственно при вызове .probe выполняется device_create
err_dev = device_create(dev_class, NULL, dev->devt, NULL, dev->kobj.name);
Вот как-то так

AndriAno
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.