альтернатива container_of () - PullRequest
1 голос
/ 29 марта 2011

Я новичок, пытающийся закодировать последовательный драйвер (на основе PCI), и я не хочу использовать container_of() из-за отсутствия обратной совместимости. Версию ядра я могу скомпилировать будет <2.6.x, поэтому я хочу сделать его совместимым с большинством старых и новых версий. </p>

я хочу получить доступ к элементу (ам) структуры драйвера последовательной карты. Структура является пользовательской, содержащей атомарную переменную, например - use_count и связанную с ней операцию - atomic_inc(&serial_card->use_count). Я не хочу получать доступ их с помощью функции container_of(), которая даст мне содержащую структуру Есть ли какая-нибудь альтернатива функции container_of (). Если я не ошибаюсь, текст драйверов драйверов LINux от Аллесандро Рубини описывает путь на странице № 174 | Глава 6: Расширенные операции с драйверами Char. Но я все еще исправлен о том, как назначить что-то вроде struct scull_dev *dev = &scull_s_device. если сама структура содержит переменную типа struct pc_device *dev, вышеприведенный оператор заполняет аналогичную переменную, которая присваивается dev,

в моем случае я объявил структуру и связанную функцию, как показано ниже

struct serial_card
{
  unsigned int      id;     // to identify the each card
  //atomic_t        use_count;      //  variable used to check whether the device is already opened or not  
  wait_queue_head_t rx_queue[64];   // queue in which the process are stored
  unsigned int      data_ready[64]; //  queue in which  the process is ready 
  unsigned int      rx_chan;    // used by interrupt handler 
  unsigned int      base, len; // holds physical base address , holds the total area ( for each card )
  unsigned int      *base;      // holds virtual address 
  /*struct cdev     cdev;           //  kernel uses this structure to represent the EACH char device 
 not using the new method to represent char devices in kernel instead using the old method of register_chrdev();*/

  struct pci_dev        *device;    // pci_dev structure for EACH device.
  //struct semaphore    sem;        //Semaphore needed to handle the co-ordination of processes,use incase need arises
};

static struct serial_card *serial_cards;    // pointer to array of structures [ depending on number of cards ],NO_OF_CARDS #defined in header file


static int serialcard_open(struct inode *inode,struct file *filep)
{

  //getting the structure details of type struct serialcard,using the pointer inode->i_cdev and field type cdev

  //struct serial_card *serial_cards = container_of(inode->i_cdev, struct serial_card, cdev);

  // read the current value of use_count

  static int Device_Open = 0;
  if ( Device_Open )            //Device_Open is static varibale used here for checking the no of times a device is opened
  {
    printk("cPCIserial: Open attempt rejected\n");
    return -EBUSY;
  }
  Device_Open++;


  // using the card so increment use_count
  //atomic_inc(&serial_cards->use_count);
  //filep->private_data = serial_cards;

  return 0;
}

полное описание на стр. 174 - 175 выглядит следующим образом

одноразовые устройства

Грубым способом обеспечения контроля доступа является разрешение устройства открываться только один процесс за раз (одна открытость). Эту технику лучше избегать, потому что она подавляет изобретательность пользователя. Пользователь может захотеть запустить разные процессы на одном и том же устройство, одно считывает информацию о состоянии, а другое записывает данные. В некоторых случаях, пользователи могут многое сделать, запустив несколько простых программ через скрипт оболочки, как Пока они могут получить доступ к устройству одновременно. Другими словами, реализация SingleOpen поведение сводится к созданию политики, которая может помешать тому, что ваши пользователи хотят сделать. Разрешение только одному процессу открывать устройство имеет нежелательные свойства, но это также самый простой способ управления доступом для драйвера устройства, поэтому он показан здесь. Исходный код извлекается из устройства под названием scullsingle.

Устройство scullsingle поддерживает переменную atomic_t с именем scull_s_available; тот переменная инициализируется значением 1, указывающим, что устройство действительно доступно. Открытый вызов уменьшает и проверяет scull_s_available и отказывает в доступе, если кто-то еще устройство уже открыто:

static atomic_t scull_s_available = ATOMIC_INIT(1);
static int scull_s_open(struct inode *inode, struct file *filp)
{
  struct scull_dev *dev = &scull_s_device; /* device information */
  if (! atomic_dec_and_test (&scull_s_available)) {
    atomic_inc(&scull_s_available);
    return -EBUSY; /* already open */
  }

  /* then, everything else is copied from the bare scull device */
  if ( (filp->f_flags & O_ACCMODE) = = O_WRONLY) {
    scull_trim(dev);
    filp->private_data = dev;
    return 0; /* success */
  }

С другой стороны, разъединительный звонок помечает устройство как не занятое:

static int scull_s_release(struct inode *inode, struct file *filp)
{
  atomic_inc(&scull_s_available); /* release the device */
  return 0;
}

Обычно мы рекомендуем ставить флаг открытия scull_s_available внутри device structure (Scull_Dev here) потому что концептуально это относится к устройству. Драйвер scull, однако, использует автономные переменные для хранения флага, чтобы он мог использовать тот же структура и методы устройства как устройство с открытым исходным кодом и минимизация дублирования кода.

Пожалуйста, дайте мне знать любую альтернативу для этого

спасибо и всего наилучшего

Ответы [ 4 ]

3 голосов
/ 29 марта 2011

возможно, я упускаю суть, но "cotainer_of" - это не функция, а макрос. Если у вас есть проблемы с портированием, вы можете спокойно определить это по yourserlf, если системные заголовки не реализуют это. Вот базовая реализация:

#ifndef container_of
#define container_of(ptr, type, member) \
 ((type *)                              \
   (  ((char *)(ptr))                   \
    - ((char *)(&((type*)0)->member)) ))

#endif

Или вот реализация - более точная - из недавних заголовков Linux:

#define container_of(ptr, type, member) ({ \
                const typeof( ((type *)0)->member ) *__mptr = (ptr); 
                (type *)( (char *)__mptr - offsetof(type,member) );})
2 голосов
/ 16 декабря 2011

В этом коде containerof используется для простого хранения и получения правильной структуры dev.Правильная структура может быть извлечена внутри функций чтения и записи также без доступа к private_data.Я не знаю, почему вы не хотите использовать private-> data и containerof, но вы всегда можете получить свой младший номер из указателя файла структуры.

int minor=MINOR(filp->f_dentry_d_inode->i__rdev);

, а затем получить доступ к вектору нескольких устройств, используя что-токак

struct scull_dev* dev = &scull_devices[minor]:

и его использование.

0 голосов
/ 03 сентября 2013

@ Giuseppe Guerrini Некоторые компиляторы просто не могут распознать реализацию linux для container_of.Базовое определение хорошо, но мне интересно, есть ли какой-либо риск безопасности или совместимости в этой реализации:

 #ifndef container_of
#define container_of(ptr, type, member) \
 ((type *)                              \
   (  ((char *)(ptr))                   \
    - ((char *)(&((type*)0)->member)) ))

#endif
0 голосов
/ 16 апреля 2011

Вам нужно будет использовать filp-> privatedata для хранения «per-open» информации, которую вы также используете для чтения / записи.Вам нужно будет решить, что хранить, чтобы обеспечить доступность нужной информации.

Возможно, вам нужны две структуры.Одна «структура устройства» и одна «открытая структура».Открытая структура может динамически размещаться в «open» и храниться в private_data.В выпуске это освобождается.У него должны быть члены, чтобы вы могли использовать их в режиме чтения / записи для получения доступа к нужным вам данным.

Структура устройства будет соответствовать «карточке».В вашем драйвере init вы, вероятно, хотите зациклить количество карт и создать новую структуру устройства (serial_card) для каждой.Вы можете сделать их статическим массивом или динамически распределять, это не имеет значения.Я бы также сохранил младший номер в структуре.Младший номер выбран вами, поэтому начните с 1 и пройдите через #cards.Вы можете зарезервировать «0» для интерфейса системного уровня, если хотите, или просто начать с 0 для карт.

При открытии вы получите младший номер, который открыл пользователь.Просмотрите список serial_card в поисках совпадения.Если вы не нашли его, ошибка открыта.В противном случае у вас есть информация и вы можете использовать ее для выделения «открытой структуры», ее заполнения и сохранения в filp-> private_data.

...