Я пытаюсь собрать модуль ядра Linux, и, в частности, у меня есть эти файлы в одной папке:
syscalls.h
/.c
user.h
/.c
proc.h
/.c
module.h
/.c
Я хочу разместить файл конфигурации в каталоге /proc
, поэтому в файлах proc.h
/.c
я определил драйвер для правильного управления им:
проц.ч
#include <linux/proc_fs.h>
extern struct proc_ops proc_fops;
ssize_t read_proc(struct file *filp, char *buf, size_t count, loff_t *offp );
ssize_t write_proc(struct file *filp, const char *buf, size_t count, loff_t *offp );
proc.c
#include "proc.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0)
struct file_operations proc_fops = {
.read = read_proc,
.write = write_proc
};
#else
struct proc_ops proc_fops= {
.proc_read = read_proc,
.proc_write = write_proc
};
#endif
//...
ssize_t write_proc(struct file *filp, const char *buf, size_t count, loff_t *offp ) {
//...
}
ssize_t read_proc(struct file *filp, char *buf, size_t count, loff_t *offp ) {
//...
}
Я записал его в отдельный блок кода «proc», потому что хочу, чтобы файл управлялся как user.c
, так и syscalls.c
.
Я реализовал только вызов user.c
, то есть:
proc_create(PROCFILE, 0, NULL, proc_fops);
но я получаю эту ошибку:
error: ‘proc_fops’ has an incomplete type ‘struct proc_ops’
182 | proc_create(PROCFILE, 0, NULL, proc_fops);
| ^~~~~~~~~
и не могу найти в чем проблема. У кого-нибудь есть какие-нибудь подсказки? Моя версия ядра (uname -r
) — 5.4.0-192-generic.
Привет, спасибо за ваш ответ. Учитывая исправленный #ifdef
(теперь правильный в отредактированном посте), не могли бы вы объяснить, что вы имеете в виду? У меня есть #include <linux/proc_fs.h>
и в proc.h
, и в proc.c
.
owner: THIS_MODULE
Что это должно быть? Очередное утомительное расширение GNU или...?
На самом деле скопировано из другого кода: P, но комментирование не меняет результат (кстати: теперь удалено из сообщения)
Я имел в виду запятую. Это неверный синтаксис C внутри списка инициализаторов. Судя по всему, это расширение GNU, которое устарело в какой-то момент еще в меловой период.
Вы имели в виду использование обозначения .read=read_proc
вместо обозначения read:read_proc
? В таком случае менять наверняка правильно, но проблема все равно остается - ОТРЕДАКТИРОВАНО В ПОСТЕ
Глядя на этот код на Github, может показаться, что определение структуры находится ни в proc.h, ни в proc.c, а предположительно в каком-то другом заголовке, включенном в proc.h? #include <machine/proc.h>
вероятно, так что, возможно, тогда его не хватает.
Возможно, это связано: stackoverflow.com/questions/18564550/…
На самом деле proc.h
и proc.c
— это файлы, которые я определил, они не существуют в ядре Linux. Единственная ссылка на ядро — это импорт в proc_fs.h
В любом случае у вас должно быть где-то определение структуры, иначе вы получите сообщение об ошибке «неполный тип».
Разве определения extern struct proc_ops proc_fops;
(proc.h
) недостаточно? (Я имею в виду, нет, это риторика, но почему?
Это предварительное заявление, а не определение. Отсюда неполный тип: вы сообщаете компилятору, что «пока вот структура, о деталях расскажу позже (в той же единице перевода)»
Хорошо, возможно, основная причина проблемы — отсутствие определения. Не могли бы вы показать пример? Чтобы я мог узнать, что делать и как все организовать, чтобы решить проблему.
proc_create(PROCFILE, 0, NULL, proc_fops);
должно быть proc_create(PROCFILE, 0, NULL, &proc_fops);
. (Но proc_fops
мог быть объявлен с неправильным типом #include "proc.h"
, в зависимости от версии ядра.)
Это действительно базовые вещи... struct proc_ops { int proc_read ; int proc_write; /* ... */ };
Или какие бы типы они ни имели — я ничего не знаю о том, что должен делать этот код.
Примечательно, что struct proc_ops proc_fops= { .proc_read = read_proc, .proc_write = write_proc };
— это просто объявление переменной со списком инициализаторов. Он не определяет структуру. Возможно, это источник путаницы.
Действительно ли «user.c» должен знать о proc_fops
? Разве вы не можете просто вызвать proc_create
из функции интерфейса в «proc.c» (вызываемой из «user.c») и объявить proc_fops
, proc_read
и proc_write
static
?
Вам нужно #include <linux/version.h>
, чтобы определить макросы LINUX_VERSION_CODE
и KERNEL_VERSION(a,b,c)
.
Прежде всего, спасибо за вашу помощь, я очень ценю ваш вклад. У меня есть обновление: поскольку моя версия ядра <5.6.0, мне приходится использовать file_operations
(импортировано из fs.h
) вместо proc_ops
(импортировано из proc_fs.h
). Итак, при изменении объявления в proc.h
с proc_ops
на files_operations
оно компилируется без ошибок. Я все еще экспериментирую, но это может быть способом решения (и это имеет смысл). Возможно, я мог бы использовать тот же #if
, что и в proc.c
.
@IanAbbott, спасибо, уже включено (вырезал пост для удобства чтения)
Не имеет значения, имеет ли proc_fops
неполный тип при вызове proc_create
, если он имеет правильный неполный тип. Вы просто называете это неправильно. Он ожидает указателя.
Забыл упомянуть: теперь вызов proc_create
— это proc_create(PROCFILE, 0, NULL, &proc_fops);
(теперь с &
). Это тот указатель, на который вы ссылаетесь?
Решено (см. ответ). Спасибо всем за вашу поддержку!
Решена, проблема заключалась в том, что объявление в proc.h
содержало только объявление для типа proc_ops
, действительное только для версии ядра выше 5.6.0. Итак, для полного соответствия, я просто изменил его на:
проц.ч
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0)
extern struct file_operations proc_fops;
#else
extern struct proc_ops proc_fops;
#endif
а также правильно указать указатель с &
в:
proc.c
proc_create(PROCFILE, 0, NULL, &proc_fops);
Ваш
#ifdef
неверен; Ядра 5.4 (и 5.5) все еще используютstruct file_operations
,proc_ops
является новым для 5.6 и более поздних версий. Учитывая, что"proc.h"
не является включенным в ядро Linux, и вы предоставляете там пустое предварительное объявление, возникнет эта ошибка. Вы должны получить правильное определение изproc_fs.h
, если оно есть в версии ядра, для которой вы собираете.