参数在scull的proc读取实现中意味着什么?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (1)
  • 关注 (0)
  • 查看 (26)

在LDD3(Linux设备驱动程序第3版)中scullpipe,参数static int scull_read_p_mem(char *buf, char **start, off_t offset, int count, int *eof, void *data)是什么意思?具体地讲,我不明白之间的差别startpageoffset

关于实际实现本身,我有很多问题(可以在下面找到):

struct scull_pipe {
        wait_queue_head_t inq, outq;       /* read and write queues */
        char *buffer, *end;                /* begin of buf, end of buf */
        int buffersize;                    /* used in pointer arithmetic */
        char *rp, *wp;                     /* where to read, where to write */
        int nreaders, nwriters;            /* number of openings for r/w */
        struct fasync_struct *async_queue; /* asynchronous readers */
        struct semaphore sem;              /* mutual exclusion semaphore */
        struct cdev cdev;                  /* Char device structure */
};

int scull_p_nr_devs;            /* the number of scull_pipe devices */
scull_pipe *scull_p_devices;    /* scull_pipe devices to be malloc'ed */

/* ...... */

/* our proc read implementation */
static int scull_read_p_mem(char *buf, char **start, off_t offset, int count,
        int *eof, void *data)
{
    int i, len;
    struct scull_pipe *p;

#define LIMIT (PAGE_SIZE-200)   /* don't print any more after this size */
    *start = buf;
    len = sprintf(buf, "Default buffersize is %i\n", scull_p_buffer);
    for(i = 0; i < scull_p_nr_devs && len <= LIMIT; i++) {
        p = &scull_p_devices[i];
        if (down_interruptible(&p->sem))
            return -ERESTARTSYS;
        len += sprintf(buf+len, "\nDevice %i: %p\n", i, p);
        len += sprintf(buf+len, "   Buffer: %p to %p (%i bytes)\n", 
                                    p->buffer, p->end, p->buffersize);
        len += sprintf(buf+len, "   rp %p   wp %p\n", p->rp, p->wp);
        len += sprintf(buf+len, "   readers %i   writers %i\n", 
                                    p->nreaders, p->nwriters);
        up(&p->sem);
        scullp_proc_offset(buf, start, &offset, &len);
    }
    *eof = (len <= LIMIT);
    return len;
}


static void scullp_proc_offset(char *buf, char **start, off_t *offset, int *len)
{
    /* QUESTION: what does this function do? */
    if (*offset == 0)
        return;
    if (*offset >= *len) {
        *offset -= *len;    /* QUESTION: what is the purpose of this? */
        *len = 0;
    }
    else {
        *start = buf + *offset; /* QUESTION: why do you need to change "start"? */
        *offset = 0;
    }
}

提问于
用户回答回答于

函数scull_read_p_mem用于使用create_proc_read_entry函数在此创建proc条目。一个5分钟的谷歌搜索给了这个页面,解释了传递给函数的函数指针中的参数。固定格式是sais:create_proc_read_entry

参数: * buf:内核为尝试读取proc条目的任何进程分配一页内存。页面指​​针指向写入数据的内存缓冲区。 ** start:当proc文件的读取不应该从文件的开头但是从某个偏移量开始时,使用此指针。对于小读取,通常将其设置为NULL。 off:文件指针当前指向的文件开头的偏移量 :要读取的 数据的字节数数据:从create_read_proc_entry函数调用传递的数据。 eof:设置为1表示文件结束

但过了一段时间我还在kenel fs / proc / generic.c中找到了一些文档。它有点长,但我认为这是总结start参数的唯一来源:

        /*
         * How to be a proc read function
         * ------------------------------
         * Prototype:
         *    int f(char *buffer, char **start, off_t offset,
         *          int count, int *peof, void *dat)
         *
         * Assume that the buffer is "count" bytes in size.
         *
         * If you know you have supplied all the data you
         * have, set *peof.
         *
         * You have three ways to return data:
         * 0) Leave *start = NULL.  (This is the default.)
         *    Put the data of the requested offset at that
         *    offset within the buffer.  Return the number (n)
         *    of bytes there are from the beginning of the
         *    buffer up to the last byte of data.  If the
         *    number of supplied bytes (= n - offset) is 
         *    greater than zero and you didn't signal eof
         *    and the reader is prepared to take more data
         *    you will be called again with the requested
         *    offset advanced by the number of bytes 
         *    absorbed.  This interface is useful for files
         *    no larger than the buffer.
         * 1) Set *start = an unsigned long value less than
         *    the buffer address but greater than zero.
         *    Put the data of the requested offset at the
         *    beginning of the buffer.  Return the number of
         *    bytes of data placed there.  If this number is
         *    greater than zero and you didn't signal eof
         *    and the reader is prepared to take more data
         *    you will be called again with the requested
         *    offset advanced by *start.  This interface is
         *    useful when you have a large file consisting
         *    of a series of blocks which you want to count
         *    and return as wholes.
         *    (Hack by Paul.Russell@rustcorp.com.au)
         * 2) Set *start = an address within the buffer.
         *    Put the data of the requested offset at *start.
         *    Return the number of bytes of data placed there.
         *    If this number is greater than zero and you
         *    didn't signal eof and the reader is prepared to
         *    take more data you will be called again with the
         *    requested offset advanced by the number of bytes
         *    absorbed.
         */

我们可以看到start使用后内部copy_to_user-该参数用于优化proc条目显示在biiiig文件。用户可以将count变量传递得非常小,但是您可以读取biig文件。因此,您可以使用一个*start参数从proc读取函数返回该文件的大小,该参数指示要读取的字节数。这样内核甚至可以传递count=0,但是proc_read函数可以像5000有效*start地址一样返回,稍后将在copy_to_user调用中使用它来加速读取。

所以:

static int scull_read_p_mem(char * buf,char ** start,off_t offset,int count,int * eof,void * data)中的参数是什么意思?

  • buf - 将结果复制到的目标缓冲区
  • start - 上面评论中解释的魔术指针用于加速proc阅读。
  • offset - 要读取的文件中的偏移量
  • count - 要读取的字节数
  • eof - 一个指向int的指针,需要设置为非零,以防整个文件被读取
  • data- 用户上下文,作为create_proc_entry函数中的最后一个参数传递。

关于实际实现本身,我有很多问题(可以在下面找到):

所述scullp_proc_offset操纵len内侧偏移buf缓冲器。如果offset != 0,那么scull_read_p_mem不需要从第一个字节读取,而是需要一些字节offset。因为它是懒惰写的,所以snprintf无论如何都要执行调用,你需要“移动”缓冲区。

what does this function do? - 实际上我发现这是计算/需要复制到用户的字节数的有趣方式。

what is the purpose of this?- 不知道。看起来有点儿,因为*offset会变得消极。该函数上方的评论/* FIXME this should use seq_file */说还有一些东西要修复。我认为ides返回的是scull_p_devices[i]一对一调用的确切信息。

why do you need to change "start"? - 来到这里。如果*offset不同于0,如果我们有一些字节要读,我们应该返回一个指针buf + offset,让内核知道从哪里读取。注意,*start = buf已经初始化了,所以内核会这样做copy_to_user(... *start, len)

扫码关注云+社区

领取腾讯云代金券