Я пытаюсь собрать модуль ядра Linux, и, в частности, у меня есть эти файлы в одной папке:
syscalls.h/.cuser.h/.cproc.h/.cmodule.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_writestatic?
Вам нужно #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, если оно есть в версии ядра, для которой вы собираете.