a couple more questions about seq_files

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



  (just FYI, i used to think i knew all about seq_files.  but there's
nothing like trying to write about something to make you realize
there's lots you *don't* know.)

  ok, i have two more questions/observations about seq_files, then i
think i'll be sick of them.  consider a sample loadable module stolen
from the samples for LDD3.  the parts i added i've commented with
"//rday".  and i've snipped out some parts that aren't relevant.

=====

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

MODULE_LICENSE("Dual BSD/GPL");

static void *ct_seq_start(struct seq_file *s, loff_t *pos)
{
	seq_printf(s, "Entering start, pos = %Ld.\n", *pos); // rday
	loff_t *spos = kmalloc(sizeof(loff_t), GFP_KERNEL);
	if (!spos)
		return NULL;
	*spos = *pos;
	return spos;
}

static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
	seq_printf(s, "Entering next.\n");
	loff_t *spos = (loff_t *) v;
	*pos = ++(*spos);
	return spos;
}

static void ct_seq_stop(struct seq_file *s, void *v)
{
	seq_printf(s, "Entering stop."); // rday
	kfree (v);
}

static int ct_seq_show(struct seq_file *s, void *v)
{
	seq_printf(s, "Entering show.\n");
	loff_t *spos = (loff_t *) v;
	seq_printf(s, "%Ld\n", *spos);
	return 0;
}

static struct seq_operations ct_seq_ops = {
	.start = ct_seq_start,
	.next  = ct_seq_next,
	.stop  = ct_seq_stop,
	.show  = ct_seq_show
};


static int ct_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &ct_seq_ops);
};

static struct file_operations ct_file_ops = {
	.owner   = THIS_MODULE,
	.open    = ct_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.release = seq_release
};

static int ct_init(void)
{
	struct proc_dir_entry *entry;

	entry = create_proc_entry("sequence", 0, NULL);
	if (entry)
		entry->proc_fops = &ct_file_ops;
	return 0;
}

static void ct_exit(void)
{
	remove_proc_entry("sequence", NULL);
}

module_init(ct_init);
module_exit(ct_exit);

=====

  i've tested the above and it seems to work just fine -- prints
infinitely until you tell it to stop.  so here's what i discovered.

  first, consider the "start" routine:

=====

static void *ct_seq_start(struct seq_file *s, loff_t *pos)
{
        seq_printf(s, "Entering start, pos = %Ld.\n", *pos); // rday
        loff_t *spos = kmalloc(sizeof(loff_t), GFP_KERNEL);
        if (!spos)
                return NULL;
        *spos = *pos;
        return spos;
}

=====

  i noticed that, on each call to this routine, a new pointer to the
"offset" is dynamically allocated, and a *copy* is made there.  and
during each call to the stop routine, that value is freed.  yes, that
works.  but other examples of seq files i've seen simply use the value
pointed at directly by "pos".  is there some advantage to making your
own copy of that?  other than leaving the original value untouched,
does that make the seq file re-entrant, or something?  is there an
actual benefit to doing it as above?

  secondly, i finally noticed how the start routine is called multiple
times.  i loaded the module, then listed the contents of the
corresponding /proc/sequence file, and saw:

Entering start, pos = 0.
Entering show.
0
Entering next.
Entering show.
1
Entering next.
Entering show.
2
...
121
Entering next.
Entering show.
122
Entering stop^@Entering start, pos = 123.
Entering show.
123
...
241
Entering next.
Entering show.
242
Ent^@Entering start, pos = 243.
Entering show.
243
...

  ok, *now* i get it.  the seq file implementation itself keeps
"printing" until, what, it has close to a page of output, then
"stops", then restarts at the next value and so on?  that makes sense,
i just didn't immediately see why the start routine would be called
multiple times.  so does that occasional stop/start combination
represent a "page" of output from the file?  thanks.

rday
--

========================================================================
Robert P. J. Day                               Waterloo, Ontario, CANADA

        Linux Consulting, Training and Annoying Kernel Pedantry.

Web page:                                          http://crashcourse.ca
Twitter:                                       http://twitter.com/rpjday
"Kernel Newbie Corner" column @ linux.com:          http://cli.gs/WG6WYX
========================================================================

--
To unsubscribe from this list: send an email with
"unsubscribe kernelnewbies" to ecartis@xxxxxxxxxxxx
Please read the FAQ at http://kernelnewbies.org/FAQ


[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux