Возвращаемое значение последовательности ядра Linux 'show' рутина - PullRequest
0 голосов
/ 30 июня 2019

Я пытаюсь понять последовательность файлов в ядре Linux.ИМХО, они довольно непонятый зверь, и с учетом этого я скомпилировал готовый модуль ядра из web .Я воспроизводю (модифицированный) код здесь для простоты доступа:

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>
#include <linux/seq_file.h>
#include <linux/slab.h>

static int limit = 10; //default value, it can be changed here or
module_param(limit, int, S_IRUGO); //transfered as a module parameter

static int* even_ptr; //we will work with dynamic memory

/**
 * start
 */
static void *ct_seq_start(struct seq_file *s, loff_t *pos) {
     printk(KERN_INFO "Entering start(), pos = %Ld, seq-file pos = %lu.\n", *pos, s->count);

     if ((*pos) >= limit) {     // are we done?
         printk(KERN_INFO "Apparently, we're done.\n");
         return NULL;
     }
     //Allocate an integer to hold our increasing even value
     even_ptr = kmalloc(sizeof(int), GFP_KERNEL);

     if (!even_ptr)     // fatal kernel allocation error
         return NULL;

     printk(KERN_INFO "In start(), even_ptr = 0x%pX.\n", even_ptr);
     *even_ptr = (*pos)*2;
     return even_ptr;
}

/**
 * show
 */
static int ct_seq_show(struct seq_file *s, void *v) {
     printk(KERN_INFO "In show(), even = %d.\n", *(int*)v);
     seq_printf(s, "The current value of the even number is %d\n", *(int*)v);
     // return (*(int *)v); // <-- Instead of a customary 'zero' I return the value of 'v' which is the actual even number that we are printing to the kernel log as well as the seq file
     return 0;
}

/**
 * next
 */
static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos) {
     printk(KERN_INFO "In next(), v = 0x%pX, *(int*)v=%d, pos=%Ld, seq-file pos=%lu.\n", v, *(int*)v, *pos, s->count);

     (*pos)++;              //increase my position counter
     if (*pos >= limit)     //are we done?
          return NULL;

     *(int*)v += 2;         //to the next even value

     return v;
 }

/**
 * stop
 */
static void ct_seq_stop(struct seq_file *s, void *v) {
     printk(KERN_INFO "Entering stop().\n");

     if (v)
         printk(KERN_INFO "v is %pX.\n", v);
     else
         printk(KERN_INFO "v is null.\n");

     printk(KERN_INFO "In stop(), even_ptr = %pX.\n", even_ptr);

     if (even_ptr) {
         printk(KERN_INFO "Freeing and clearing even_ptr.\n");
         kfree(even_ptr);
         even_ptr = NULL;
     } else
         printk(KERN_INFO "even_ptr is already null.\n");
}

/**
 * This structure gathers functions which control the sequential reading
 */
static struct seq_operations ct_seq_ops = {
     .start = ct_seq_start,
     .next  = ct_seq_next,
     .stop  = ct_seq_stop,
     .show  = ct_seq_show
};

/**
 * This function is called when a file from /proc is opened
 */
static int ct_open(struct inode *inode, struct file *file) {
     return seq_open(file, &ct_seq_ops);
};

/**
 * This structure gathers functions for a /proc-file operations
 */
static struct file_operations ct_file_ops = {
     .owner   = THIS_MODULE,
     .open    = ct_open,
     .read    = seq_read,
     .llseek  = seq_lseek,
     .release = seq_release
};

/**
 * This function is called when this module is loaded into the kernel
 */
static int __init ct_init(void) {
     proc_create("evens", 0, NULL, &ct_file_ops);
     return 0;
}

/**
 * This function is called when this module is removed from the kernel
 */
static void __exit ct_exit(void) {
     remove_proc_entry("evens", NULL);
}

module_init(ct_init);
module_exit(ct_exit);

MODULE_LICENSE("GPL");

Мой журнал ядра читает:

Jun 30 19:10:22 mintab kernel: [ 8213.539959] Entering start(), pos = 0, seq-file pos = 0.
Jun 30 19:10:22 mintab kernel: [ 8213.539960] In start(), even_ptr = 0xffff9241772a8000.
Jun 30 19:10:22 mintab kernel: [ 8213.539960] In show(), even = 0.
Jun 30 19:10:22 mintab kernel: [ 8213.539962] In next(), v = 0xffff9241772a8000, *(int*)v=0, pos=0, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539962] In show(), even = 2.
Jun 30 19:10:22 mintab kernel: [ 8213.539963] In next(), v = 0xffff9241772a8000, *(int*)v=2, pos=1, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539963] In show(), even = 4.
Jun 30 19:10:22 mintab kernel: [ 8213.539964] In next(), v = 0xffff9241772a8000, *(int*)v=4, pos=2, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539964] In show(), even = 6.
Jun 30 19:10:22 mintab kernel: [ 8213.539965] In next(), v = 0xffff9241772a8000, *(int*)v=6, pos=3, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539965] In show(), even = 8.
Jun 30 19:10:22 mintab kernel: [ 8213.539966] In next(), v = 0xffff9241772a8000, *(int*)v=8, pos=4, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539966] In show(), even = 10.
Jun 30 19:10:22 mintab kernel: [ 8213.539967] In next(), v = 0xffff9241772a8000, *(int*)v=10, pos=5, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539967] In show(), even = 12.
Jun 30 19:10:22 mintab kernel: [ 8213.539968] In next(), v = 0xffff9241772a8000, *(int*)v=12, pos=6, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539969] In show(), even = 14.
Jun 30 19:10:22 mintab kernel: [ 8213.539969] In next(), v = 0xffff9241772a8000, *(int*)v=14, pos=7, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539970] In show(), even = 16.
Jun 30 19:10:22 mintab kernel: [ 8213.539970] In next(), v = 0xffff9241772a8000, *(int*)v=16, pos=8, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539971] In show(), even = 18.
Jun 30 19:10:22 mintab kernel: [ 8213.539971] In next(), v = 0xffff9241772a8000, *(int*)v=18, pos=9, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539972] Entering stop().
Jun 30 19:10:22 mintab kernel: [ 8213.539972] v is null.
Jun 30 19:10:22 mintab kernel: [ 8213.539972] In stop(), even_ptr = ffff9241772a8000.
Jun 30 19:10:22 mintab kernel: [ 8213.539973] Freeing and clearing even_ptr.
Jun 30 19:10:22 mintab kernel: [ 8213.539996] Entering start(), pos = 10, seq-file pos = 0.
Jun 30 19:10:22 mintab kernel: [ 8213.539996] Apparently, we're done.
Jun 30 19:10:22 mintab kernel: [ 8213.539997] Entering stop().
Jun 30 19:10:22 mintab kernel: [ 8213.539997] v is null.
Jun 30 19:10:22 mintab kernel: [ 8213.539997] In stop(), even_ptr =           (null).
Jun 30 19:10:22 mintab kernel: [ 8213.539998] even_ptr is already null.

И файл proc дает только следующий вывод, а затем останавливается: Текущее значение четного числа: 0

Я предполагаю, что подпрограмма 'show' должна вернуть 0, чтобы считаться безошибочной для базовой экосистемы файлов seq.Однако не будет ли небольшое положительное целое число указывать то же самое?или они используют какой-то другой способ ??

ОБНОВЛЕНИЕ 1: Как уже упоминалось в ответе ответа нашего друга Цыварева, явно требуется вернуть 0 из подпрограммы шоу, поскольку все остальное считается ошибкойпоэтому вернулся обратно соответственно.Сказав это, кто-нибудь может объяснить, почему мы вводим старт заново после того, как исчерпали все числа и v наконец NULL ??Мне особенно интересно знать, почему мы делаем это?

Jul  1 11:16:59 mintab kernel: [31765.915542] v is null.
Jul  1 11:16:59 mintab kernel: [31765.915542] In stop(), even_ptr = ffff9c7df619b340.
Jul  1 11:16:59 mintab kernel: [31765.915542] Freeing and clearing even_ptr.
Jul  1 11:16:59 mintab kernel: [31765.915551] Entering start(), pos = 200, seq-file pos = 0.
Jul  1 11:16:59 mintab kernel: [31765.915551] Apparently, we're done.
Jul  1 11:16:59 mintab kernel: [31765.915552] Entering stop().
Jul  1 11:16:59 mintab kernel: [31765.915552] v is null.
Jul  1 11:16:59 mintab kernel: [31765.915553] In stop(), even_ptr =           (null).

Кроме того, приветствуются дополнительные ссылки на более подробное и (надеюсь) более простое объяснение механизма файла последовательности.

1 Ответ

0 голосов
/ 01 июля 2019

Последовательные файлы описаны в документации ядра под Documentation / filesystems / seq_file.txt . Согласно документации, функция show должна вернуть:

  • 0 в случае успеха
  • -ERR (отрицательный код ошибки) при ошибке
  • SEQ_SKIP для отмены любого вывода для текущего элемента

Текущая реализация обрабатывает любое положительное возвращаемое значение show как SEQ_SKIP:

// (from traverse() function in fs/seq_file.c)
// ...
error = m->op->show(m, p);

if (error < 0) // <-- negative return value is an error indicator
    break;
if (unlikely(error)) { // <-- this is for positive return values
    error = 0; // <-- as if 'show' returns 0...
    m->count = 0; // <-- ... but with output dropped
}

Итак, если вы хотите сообщить, что show будет успешным, просто верните 0.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...