LWN: Comments on "Driver porting: The seq_file interface" https://lwn.net/Articles/22355/ This is a special feed containing comments posted to the individual LWN article titled "Driver porting: The seq_file interface". en-us Wed, 03 Sep 2025 05:39:59 +0000 Wed, 03 Sep 2025 05:39:59 +0000 https://www.rssboard.org/rss-specification lwn@lwn.net Driver porting: The seq_file interface https://lwn.net/Articles/577005/ https://lwn.net/Articles/577005/ Lieta <div class="FormattedComment"> ...<br> .stop(A)<br> .start<br> .stop(B)<br> ---EOF---<br> There is a problem to differ the .stop(A) from .stop(B) when you have to return some resource (e.g. semaphore), that has been taken in .start, back at the end of sequence. The position counter is equal in both (A) and (B), because you are at EOF.<br> <p> </div> Sat, 14 Dec 2013 15:23:31 +0000 Driver porting: The seq_file interface https://lwn.net/Articles/577004/ https://lwn.net/Articles/577004/ Lieta <div class="FormattedComment"> I think it calls stop at the end of every page (4 KB), followed by the start.<br> At the end of file it calls stop, then start, followed by one more stop.<br> So it works like this:<br> .start<br> .stop<br> ---PAGE---<br> .start<br> .stop<br> ---PAGE---<br> ...<br> .stop<br> .start<br> .stop<br> ---EOF---<br> Special case is when the file is empty. Then there are just two calls (not 4): one .start one .stop.<br> </div> Sat, 14 Dec 2013 15:15:25 +0000 Driver porting: The seq_file interface https://lwn.net/Articles/576320/ https://lwn.net/Articles/576320/ Lieta <div class="FormattedComment"> If I want to disable interrupts (call local_irq_save/local_irq_restore) during seq_file output. What is the correct way to do it, if I'm using the same .start, .stop, .next, .show functions for many proc file entries?<br> </div> Tue, 10 Dec 2013 09:55:56 +0000 Driver porting: The seq_file interface https://lwn.net/Articles/576319/ https://lwn.net/Articles/576319/ Lieta <div class="FormattedComment"> I got it. .start is called on every new page. Previously I was returning NULL if *pos != 0 in .start function.<br> </div> Tue, 10 Dec 2013 09:35:49 +0000 Driver porting: The seq_file interface https://lwn.net/Articles/576317/ https://lwn.net/Articles/576317/ Lieta <div class="FormattedComment"> How to ouput more than one page (4 KB) of data? If the amount reaches one page, it simply quits calling the .next and .show functions.<br> </div> Tue, 10 Dec 2013 09:03:50 +0000 Driver porting: The seq_file interface https://lwn.net/Articles/399592/ https://lwn.net/Articles/399592/ rtwertw <div class="FormattedComment"> author need to learn to express his thoughts so not only himself, but ppl around could understand it. After reading it i only got more confused. Comments helped a bit. Thanks ppl. <br> </div> Wed, 11 Aug 2010 16:06:03 +0000 Driver porting: The seq_file interface https://lwn.net/Articles/311063/ https://lwn.net/Articles/311063/ iw2lsi <div class="FormattedComment"> Hi all<br> <p> is it normal to have more than one stop while reading a seq file ?<br> <p> actually I have a list with 37 items but I get a "spontaneous" stop while processing element nine, and than a new start with the element ten (*pos=10).<br> <p> after some hours (ok, two day :D) of debugging, it's all working now.. but it was really difficult for me to understand seq_file interface :D<br> <p> thanks<br> <p> Giampaolo<br> </div> Fri, 12 Dec 2008 11:26:27 +0000 Driver porting: The seq_file interface https://lwn.net/Articles/264990/ https://lwn.net/Articles/264990/ arafel <div class="FormattedComment"><pre> Hi, Just wanted to say thanks for the comment. You've probably saved me a good few minutes trying to work out why seq_file kept calling my code. It must be said, the seq_file interface is one of the uglier APIs I've seen in the kernel. Clear and easy to use it is not. </pre></div> Mon, 14 Jan 2008 10:04:31 +0000 Driver porting: The seq_file interface https://lwn.net/Articles/130184/ https://lwn.net/Articles/130184/ guest This article describes how to generate an infinite series of integers. It would have been much more practical if this article had talked about generating finite series of integers ... I had trouble getting the seq_file iterator to stop calling my functions. <br> <p> I read this article and <a href="http://www.kernelnewbies.org/documents/seq_file_howto.txt">http://www.kernelnewbies.org/documents/seq_file_howto.txt</a>. Nevertheless, I still wasted a lot of time trying to get it to work. <br> <p> My notes:<br> <p> you write the routines your_start, your_stop, your_next, and your_show<br> <p> The pos parameter to your_start and your_next is an index into the set of items that you wish to enumerate. your_next must increment this index, as in ++*pos. <br> <p> your_start must know the number of items in your set so that it can check the validity of *pos. your_start will be called again, even after your_next returns NULL and your_stop has been called. <br> <p> Let's say that you want to count from 0 through 9. your_start is called with *pos==0. It returns a pointer to your iterator data structure. your_show is called, then your_next is called. This happens until your_next returns NULL or ERR_PTR(some-negative-error-code). your_stop is then called. At this point, your_start will be called *again*, with *pos==10 ... seems strange to me, but that is the behavior. <br> <p> The iterator pointer returned by your_start/your_next can be whatever you want, including integer values. However, be advised that the values in the range -1000 &lt;= n &lt;= 0 are interpreted as error conditions/NULL. Therefore, you probably want to return a pointer. <br> <p> The kernelnewbies.org seq_file_howto.txt document says your_start should return error codes like EACCES if the *pos position is out of bounds. Note that if you want to do this, then you must return -EACCES, not EACCES. Maybe that was obvious to experienced kernel hackers, but it certainly was not obvious to me. Do this by returning ERR_PTR(-EACCES). If this value is not negative, then the seq_file code will assume that you have returned a valid iterator pointer and it will call your_show. <br> <p> It is probably easier to simply return NULL on error conditions (like *pos out of bounds) and not worry about it. When I tried to worry about it and do the right thing, it just caused trouble for me. <br> <p> I spent some time looking at the seq_file code. Frankly, I was quite disappointed ... the implementation looked pretty ugly to me. <br> <p> Michael<br> <p> Fri, 01 Apr 2005 17:40:45 +0000 Driver porting: The seq_file interface https://lwn.net/Articles/68942/ https://lwn.net/Articles/68942/ gcc Users should be clear about the difference between a position and an iterator (this confused me for a while). The position is your means of communication with the seq_file interface, telling it where you are, and for it to tell you where to go. <p>The iterator is an opaque value, about which seq_file understands nothing, except that you return it from your <code>start</code> and <code>next</code> handlers, and it will give it back to you in <code>next</code>, <code>stop</code> and <code>show</code>. <p>Examples of iterators given in the article are a simple index (using the pointer as an integer, i.e. it doesn't really point to anything), or a pointer to a linked list entry or an array member. However, if you have to navigate some more complex structure, such as a hash table, it can be useful to have a struct which holds several values, for example: <ul><pre>struct my_pos { my_hash_table *table; int hash; my_ht_entry *entry; } </pre></ul> This allows a single value (your iterator, <code>void *v</code>) to tell you everything you need to know in order to walk the hashtable. In this case, as in the <code>/proc/sequence</code> example, <code>v</code> remains the same throughout the walk. <p>On the other hand, the position, <code>loff_t *pos</code>, is a strange beast. If you start reading the <code>/proc</code> file from the beginning, then <code>start</code> will be called with position 0, 1, 2, etc. until it returns NULL. At this point the user gets EOF, and they can then seek around and start reading again, which results in your <code>start</code> handler being called again. <p>However, if the user skips more than the length of the file, (e.g. <code>dd if=/proc/my_file bs=1G skip=1</code>, then your code will be called with position 0 twice! The user doesn't get what they were expecting (an empty file), but the whole file, as if the seek never happened. <code>strace</code> shows that the seek appears to succeed. I think this behavious is wrong and constitutes a mental health hazard. <p>If you want to use the same set of operations for multiple files in /proc, you need a way for them to distinguish what object they operate on. The article mentions <code>s->private</code>, but you can only use this after you have called seq_open, because the seq_file object doesn't exist before that. On the 2.6 kernel, it appears that a good place to store this private data is in the <code>struct inode *inode</code> which is passed to your <code>open</code> handler: <ul><pre>static int my_open (struct inode *inode, struct file *file)</pre></ul> In particular, 2.6 has a function called <code>PROC_I</code> which converts your <code>struct inode</code> into a <code>struct proc_inode</code>, which has a member called <code>pde</code>, which is your <code>struct proc_dir_entry</code>. <p>So you can create the <code>proc_dir_entry</code>, initialise its <code>data</code> member with a pointer to your private data, and then in the <code>open</code> handler you can get to it from <code>inode->pde</code>. For example: <ul><pre>// module init static int __init init() { my_proc_entry = create_proc_entry(filename, 0, NULL); /* ... check for failure ... */ my_proc_entry->data = my_data; } static int my_open (struct inode *inode, struct file *file) { struct seq_file *s; result = seq_open(file, &amp;seq_ops); /* ... check for failure ... */ /* file->private_data was initialised by seq_open */ s = (struct seq_file *)file->private_data; my_data = PROC_I(inode)->pde->data; s->private = my_data; } static int my_seq_start (...) { my_data = s->private; } </pre></ul> I'm still looking for a good way to do this on 2.4, which lacks <code>PROC_I</code> and <code>struct proc_inode</code>. Can anyone help? Fri, 30 Jan 2004 23:08:17 +0000 Driver porting: The seq_file interface https://lwn.net/Articles/58438/ https://lwn.net/Articles/58438/ giraffedata <i>I am now kfree()ing in ct_seq_next(), just before it returns with NULL at the end of the table</i> <p> Seems like that would be a problem if the user chooses not to read all the way to EOF. <p> This just sounds like a basic bug in the seq_file interface. If ct_seq_start() fails, it should be ct_seq_start's responsibility to not change any state, and thus ct_seq_stop doesn't need to be, and should not be, called. After all, does a POSIX program call close(-1) when open() fails? Sat, 15 Nov 2003 01:53:45 +0000 Driver porting: The seq_file interface https://lwn.net/Articles/58355/ https://lwn.net/Articles/58355/ laf0rge After using this article as an example to port the /proc/net/ip_conntrack interface over to seq_file, and about 5 hours of crashing/rebooting/debugging, I have to admit that there are some shortcomings in it.<p>Some hints for other people, so they don't fall into the same pits as I did:<p>1) If you allocate something in ct_seq_start(), the place to free it is _NOT_ in ct_seq_stop(). This is because ct_seq_stop() is even called if ct_seq_start() returns an error (Like ERR_PTR(-ENOMEM)). You would then end up calling kfree(ERR_PTR(-ENOMEM)) which your mm subsystem doesn't really like. I am now kfree()ing in ct_seq_next(), just before it returns with NULL at the end of the table.<p>2) If you take a lock in ct_seq_start(), do it unconditionally as the first thing. Even if ct_seq_start() fails, ct_seq_stop() is called. In ct_seq_stop() you have no idea of knowing if ct_seq_start() failed or not - so you will unconditionally unlock.<br> Fri, 14 Nov 2003 13:13:24 +0000