/proc/file read drops data

Do you have a question? Post it now! No Registration Necessary

Translate This Thread From English to

Threaded View
Hi ,
I'm using blooking read call to get some asyn. event from kerne space,
as some one suggested previously.

I have tried to use charater driver and /proc files system. The one
with c driver seems works fine. I got some problem with /proc/
when the application tries read data.

See my proc_read function bellow. This function will be waked up by
interrupt service routine. It appears that appcation has problem with
consecutive reads. First ready gets the same number of bytes, after
that I can see the folowing function return number of bytes, while the
user application's read returns always 0.

The same piece code is used in a charactor driver's read function, that
one works OK.

Any suggestions?

static int proc_read_foo(char *page, char **start,
                off_t off, int count,
                int *eof, void *data)
{
    int len;
        if (data_ready)
        {
           interruptibe_sleep_on(wait_queue);
        }
        memcpy(page, dada_buf, MAX_BUF_LEN);
        data_ready=0;

    return MAX_BUF_LEN;
}


Re: /proc/file read drops data

Some typo. post again

I'm using blooking read call to get some asyn. event from kerne space,
as some one suggested previously.


I have tried to use charater driver and /proc files system. The one
with c driver seems works fine. I got some problem with /proc/
when the application tries read data.


See my proc_read function bellow. This function will be waked up by
interrupt service routine. It appears that appcation has problem with
consecutive reads. First ready gets the same number of bytes, after
that I can see the folowing function return number of bytes, while the
user application's read returns always 0.


The same piece code is used in a charactor driver's read function, that
one works OK.


Any suggestions?


static int proc_read_foo(char *page, char **start,
                            off_t off, int count,
                            int *eof, void *data)
{
        int len;
        if (!data_ready)
        {
           interruptibe_sleep_on(wait_queAD%ue);
        }
        memcpy(page, dada_buf, MAX_BUF_LEN);
        data_ready3D%0;20%


        return MAX_BUF_LEN;20%
}


Re: /proc/file read drops data
snipped-for-privacy@yahoo.com writes:
Quoted text here. Click to load it

One thing that stands out is the use of interruptible_sleep_on() which has
a race condition associated with it. Look on google; the suggested replacement
is wait_event_interruptible().

There's also a discussion in the 2nd edition of Linux Device Drivers about
this, online at: http://www.xml.com/ldd/chapter/book/ch09.html

Simon.

--
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP      
Microsoft: The Standard Oil Company of the 21st century

Re: /proc/file read drops data
behavior is the same, if change it to
wait_event_interruptible(). If I tale trhe sleep part completely, it
returns correctly the number of bytes.
However I want to use the blocking feature.


Re: /proc/file read drops data
Quoted text here. Click to load it

On the second read() is the read handler actually completing ? Try putting
printk()'s into the handler and seeing if the read ever gets past the
memcpy(). Also, have you checked for any buffer overflow issues in your
driver ?

Can you post the actual code (without retyping it) of the read handler,
the code around the point in the interrupt handler when you wake up the
read handler, and the code around the application level read() ? Someone
may see the problem if presented with more code.

BTW, it's not directly related to your current problem, but you are supposed
to use copy_to_user() and copy_from_user() when moving data between user and
kernel space. This is in case any of the user's buffer has been paged out.
This is discussed in Chapter 3 of the LDD manual.

Simon.

--
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP      
Microsoft: The Standard Oil Company of the 21st century

Re: /proc/file read drops data
Following id the code. After load, /proc/sample si created.
mknod /dev/sample c 230 0

To do cat /proc/sample and /dev/sample to observe the difference.

Do echo > /dev/sample to issue an event.

#define MODULE
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h>

#include  <linux/proc_fs.h>

/*length of one entry*/
#define              ALARM_REPORT_LEN    (1<<6)
/*max number of entries*/
#define              MAX_ALARM_ENTRY     (1<<4)



static unsigned char          *sample_buf=NULL;
static volatile int           report_done=1;  /*yes*/
static volatile int           report_end=0;   /*empty*/
static int                    sample_major23%0;

DECLARE_WAIT_QUEUE_HEAD (report_queue);



static ssize_t sample_read(struct file *filp, char *buf, size_t count,
  loff_t *f_pos)
{
    int i=0,len=0;
    unsigned long flags;

    if( wait_event_interruptible(report_queue, (!report_done)))
    {
        printk(KERN_ERR"/dev/sample I got a sig\n");
        return -ERESTARTSYS;
    }
    save_flags(flags);
    cli();
    for (i = 0; i <report_end; i++ )
    {
        copy_to_user(buf + i*ALARM_REPORT_LEN, sample_buf
+i*ALARM_REPORT_LEN, ALARM_REPORT_LEN);
    }

    printk(KERN_DEBUG"done=%x, end=%d from read\n", report_done,
report_end);
    report_done=1;
    report_end=0;
    memset( sample_buf, 0, MAX_ALARM_ENTRY*ALARM_REPORT_LEN);
    restore_flags(flags);
    len=i*ALARM_REPORT_LEN;

    printk(KERN_DEBUG"%d return from read \n", len);
    return len;
}

static int sample_open(struct inode *inode, struct file *filp)
{
    MOD_INC_USE_COUNT;
    return 0;
}

static int sample_release(struct inode *inode, struct file *filp)
{
    MOD_DEC_USE_COUNT;
    return 0;
}

void report_alarm( char *str )
{
    size_t len = strlen( str );
    if (len > ALARM_REPORT_LEN) {
        len = ALARM_REPORT_LEN;
    }
    memcpy( sample_buf+ALARM_REPORT_LEN*report_end, str, len);
    report_end++;
    report_done=0;
    wake_up_interruptible(&report_queue);
    printk(KERN_WARNING"done=%x, end=%d from report\n", report_done,
report_end);
}



static int sample_proc_read(char *buf, char **start, off_t offset,
                   int count, int *eof, void *data)
{
    int i=0,len=0;
    unsigned long flags;
    MOD_INC_USE_COUNT;
#define SLEEP
#ifdef SLEEP
    if( wait_event_interruptible(report_queue, (!report_done)))
    {
        printk(KERN_ERR"/proc I got a sig\n");
        MOD_INC_USE_COUNT;
        return -ERESTARTSYS;
    }
#endif
    save_flags(flags);
    cli();
    for (i = 0; i <report_end; i++ )
    {
        memcpy(buf + i*ALARM_REPORT_LEN, sample_buf
+i*ALARM_REPORT_LEN, ALARM_REPORT_LEN);
    }
    printk(KERN_DEBUG"done=%x, end=%d from read\n", report_done,
report_end);
    report_done=1;
    report_end=0;
    memset( sample_buf, 0, MAX_ALARM_ENTRY*ALARM_REPORT_LEN);
    restore_flags(flags);
    *eof = 0;
    len=i*ALARM_REPORT_LEN;

    MOD_INC_USE_COUNT;
    return len;
}

static void my_isr()
{
    report_alarm("1 2 3 alarm report   ");
}

ssize_t sample_write (struct file *f, const char *c, size_t s, loff_t
*l)
{
    printk(KERN_WARNING"stimulate one interrupt \n");
    my_isr();
    return 1;
}


struct file_operations sample_fops = {
 read:  sample_read,
 open:  sample_open,
 write: sample_write,
 release: sample_release,
};


int init_module(void)
{
    int result=0;

    printk( KERN_DEBUG"Hello,");
    sample_buf = kmalloc(MAX_ALARM_ENTRY*ALARM_REPORT_LEN, GFP_KERNEL);
    if( sample_buf==0)
    {
        printk(KERN_ERR"can not allocate memory");
        return -ENOMEM;
    }

    result = register_chrdev( sample_major, "fpga",&sample_fops );
    if (result < 0)
    {
        printk(KERN_ERR "can't get major\n" );
        return result;
    }


    if( NULL==create_proc_read_entry("sample",
                       0    /* default mode */,
                       NULL /* parent dir */,
                       sample_proc_read,
                       NULL /* client data */))
    {

        printk(KERN_DEBUG "can't create read entry\n" );
        return -ENOMEM;
    }
    return 0;
}


void cleanup_module(void)
{
 unregister_chrdev( sample_major, "sample");
 remove_proc_entry("sample", NULL /* parent dir */);
 kfree(sample_buf);
 printk( KERN_DEBUG "Bye from Sample");
}


Re: /proc/file read drops data
You could remove define SLEEP to see the difference as well.


Re: /proc/file read drops data
Quoted text here. Click to load it

I've had a quick look at your code and got it (apparently) working on
Redhat 7.2 (a 2.4 series kernel).

If you modify your sample_proc_read to dump the values of the passed
arguments, you will see that offset increments on each call.

I've never created pseudo devices in /proc before, but it looks like you
are expected to write your data into buf at the offset given in offset,
set start to the start address of this new data in buf, and set eof to 1.

When I modified your code to do this, it appears to work ok, emitting one
instance of your test string for each time that I issue the echo command.

I further modified the sample_proc_read routine to return a length of zero
(in order to indicate end of file) when the offset got to 256 bytes. This
correctly resulted in the "cat /proc/sample" command terminating when this
offset was reached.

Some notes:

1) Be careful not to write past the end of the passed buffer

2) You are using MOD_INC_USE_COUNT and not decrementing it, but instead
calling MOD_INC_USE_COUNT again. This means that you can't unload your
driver after use.

3) You are registering and deregistering the device using different names.
This means that you can't reload your driver again.

Simon.

--
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP      
Microsoft: The Standard Oil Company of the 21st century

Re: /proc/file read drops data
Hi Thnaks for your reply.
Did notice, if you do do echo first for a couple of times, and then do
cat /proc/sample, the cat does not return what it read immediately, and
do another read, until, you do another echo, it return all reports.

While if you try with /dev/sample, it always returns imediately.

Another thing is that, I want cat block there, and never return. It I
update continuousely the offset, event it will  grow across page
boundaries, and I am not if they pages ever get released.

Nice talk.


Re: /proc/file read drops data
Nice talk with you.

The original thought was to repeatly to use the same page. It woks OK
like you suggested to update "start" and put data into "buf+offset". As
I understand from LDD book, the kernel use pages to get my data, if I
keep updating start, it would think my file is of infinit long, and it
would keep all those pages, I dont know if kernel release them all keep
them until the proc_read return a 0. Overtime it ocvcupies a lot of
resource.

Ideally, I would like "cat" or any application thinks that the file
still has data to come at any time, but just use one page, not more.

I think at this point, I am not sure, if I keep updating the offset, if
it grow into mutiple pages, can old pages released  or still kept.

If I use /dev/sample, I dont have any problem, as data copied from
kernel to uaer space by the driver code.


Re: /proc/file read drops data
Quoted text here. Click to load it

You can do as I suggested, and use printk to display the arguments passed
to your proc read routine. You may see that the offset returns to zero,
but with the same buffer address after more than a page of data has been
passed back to the caller.

If it's doesn't (cat may issue large read()'s), then write a small program
with a static buffer, say 1024 bytes long, that reads /proc/sample and see
what values get passed to your driver's proc read routine. Focus on the
buffer address, count and offset values.

Quoted text here. Click to load it

The data that you pass back in your proc read routine still has to make it
back to user space. If it's buffered by the kernel, instead of the address of
the user level buffer been passed to your routine directly, (and I haven't
checked the source to see what happens) the buffer may be released once
the user level read() has been satisfied.

Simon.

--
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP      
Microsoft: The Standard Oil Company of the 21st century

Re: /proc/file read drops data
I observe that the offset keeps going up never goes back. I even try
after offset > 1024, return a 0, and put *start to buf again. Of cause
it
terminate "cat", when offset gets 1064 for example. In a small app, I
keep calling read, the offset will be always the very last
value, 1064. I guess the kernel will continue try the same offset until
a close happens.


Site Timeline