Как я могу использовать SpinLocks в списке записей внутри ядра Linux?

StackOverflow https://stackoverflow.com/questions/3610253

  •  25-09-2019
  •  | 
  •  

Вопрос

Я разрабатываю патч для ядра Linux. Я должен использовать несколько списков, и я должен защитить от одновременной модификации на многократной машине. Я пытаюсь использовать SpinLocks для этой цели, но что-то я не могу понять. Я должен заблокировать записи списка (я использую реализацию связанных списков Linux по умолчанию), и может случиться, что процесс вызывает SYSCall для удаления одного элемента списка, когда тот же элемент, который заблокирован, потому что некоторые модификации на самом деле быть сделанным на нем. Если я вставку спинлок внутри ввода списка, что произойдет, если процесс удастся удалить его, пока кто-то спинет на нем ?? Должен ли я заблокировать весь список? Я ищу кусок кода, который может объяснить, как выполнять эту ситуацию.

Например, этот код не должен работать (см. Комментарий к последней строке кода):

   struct lista{
    int c;
    spinlock_t lock;
    struct list_head;
}

spinlock_t list_lock;
struct lista lista;


//INSERT
struct lista* cursor;
struct lista* new = (struct lista*) kmalloc(sizeof(struct lista),GFP_KERNEL);

/*do something*/
spin_lock(&list_lock);     //Lock on the whole list
list_for_each_entry(cursor,&lista.list,list){
    if (cursor->c == something ){
        ...
        spin_unlock(&list_lock)  //unlock
        spin_lock(&cursor->lock) // Lock on list entry
        list_add(&new->list, &lista.list);
        spin_unlock(&cursor->lock)  // unlock of the list entry
        ...
    }
}


//REMOVAL
struct lista* cursor;

spin_lock(&list_lock);  
list_for_each_entry(cursor,&lista.list,list){
    if (cursor->c == something ){
        ...
        spin_unlock(&list_lock)  //unlock
        spin_lock(&cursor->lock) // Lock on list entry
        list_del(&cursor.list,&lista.list);
        spin_unlock(&cursor->lock)  // unlock of the list entry
        kfree(cursor);  //WHEN THE ENTRY IS FREED SOMEONE COULD HAVE TAKEN THE LOCK SINCE IT IS UNLOCKED
        ...
    }
}

Вы можете помочь мне??

Это было полезно?

Решение

Не выпускай list_lock пока вы не сделаете удаление предмета.

Вы можете в конечном итоге с слегка неловкой процедурой:

  1. Приобретение блокировки списка (это заблокирует другие входящие потоки)
  2. Приобретайте блокировку элементов, отпустите блокировку элементов (это страшено, что все более ранние потоки выполнены)
  3. Убрать предмет
  4. Выпуск списка замок.

Вариация: используйте замок для чтения писателя для блокировки списка.

Темы, которые хотят изменять элементы списка, возьмите замок считывателя; Это позволяет нескольким потокам работать в списке параллельно.

Темы, которые хотят удалить элементы списка Возьмите замок писателя; Это ждет всех читателей выходить и блокирует их, пока вы не выпустите его. В этом случае вы все еще должны держать блокировку списка, пока не закончите удаление элемента,

Таким образом, вы можете избежать шага 2 выше. Это может показаться концептуально яснее, так как вам не нужно объяснять бессмысленно выглядящий замок / выпуск.

Другие советы

Вы почти наверняка наверняка не должны использовать SpinLocks вообще, если нет одновременного доступа от Card IRQ контекста. Используйте Mutexes вместо этого.

Самый простой вариант для вашего списка - просто заблокировать весь список, пока вы работаете на нем. Не беспокойтесь о замках в зависимости от предметов, если и до тех пор, пока вы не обнаружите, что в блокировке списка есть достаточное соглашение о том, что вам это нужно (и в этом случае, вы, вероятно, хотите посмотреть на использование RCU вместо этого).

Ваш список головой не должен быть struct lista, это должно быть просто struct list_head. Отказ Обратите внимание, что вы продолжаете использовать &lista.list, что должно быть просто list_head называется «список» или что-то. См. Например, код в drivers/pci/msi.c, Заметь dev->msi_list просто А. list_head, а не а struct msi_desc.

Вы не можете безопасно бросить блокировку списка, а затем захватить блокировку курсора. Возможно, после того, как вы бросили замок списка, но перед тем, как вы получите замок курсора, кто-то еще вошел и освободил ваш курсор. Вы можете жонглировать замки, но это очень легко ошибаться.

Вы почти определенно просто хотите, чтобы один замок, для всего списка, и без замков на элементы. И замок списка должен быть mutex Если вам не нужно манипулировать списком из контекста прерывания.

Если вы не имеете дело с устройствами и или критически важные разделы ядра, где спиновой замок является обязательным (поскольку он отключает вытеснение и прерывание (по запросу)), то y 2 используют спиновые замки, которые будут не обязательно закрывать вашу докурие и прерывания Отказ Использование семафорна или MUTEX, которые тоже в списке и не списком элемент выглядит лучшее решение.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top