public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* proc_file_read bug?
@ 2002-01-25 13:36 Thomas Hood
  2002-01-25 14:29 ` Andreas Schwab
  0 siblings, 1 reply; 4+ messages in thread
From: Thomas Hood @ 2002-01-25 13:36 UTC (permalink / raw)
  To: linux-kernel

I don't understand this part of proc_file_read() in 
fs/proc/generic.c:

                /* This is a hack to allow mangling of file pos independent
                 * of actual bytes read.  Simply place the data at page,
                 * return the bytes, and set `start' to the desired offset
                 * as an unsigned int. - Paul.Russell@rustcorp.com.au
                 */
                n -= copy_to_user(buf, start < page ? page : start, n);
                if (n == 0) {
                        if (retval == 0)
                                retval = -EFAULT;
                        break;
                }

                *ppos += start < page ? (long)start : n; /* Move down the file */
                nbytes -= n;
                buf += n;
                retval += n;

When start >= page, we copy n bytes beginning at start and
increase *ppos by n.  Makes sense.  But what happens when
start < page?  We will copy n bytes starting at page, then
increase *ppos by start!!  What sense does that make?  If
there's cleverness happening here, someone please document it.

For your convenience, I append the whole existing proc_file_read
function below.
--
Thomas

static ssize_t
proc_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
{
	struct inode * inode = file->f_dentry->d_inode;
	char 	*page;
	ssize_t	retval=0;
	int	eof=0;
	ssize_t	n, count;
	char	*start;
	struct proc_dir_entry * dp;

	dp = (struct proc_dir_entry *) inode->u.generic_ip;
	if (!(page = (char*) __get_free_page(GFP_KERNEL)))
		return -ENOMEM;

	while ((nbytes > 0) && !eof)
	{
		count = MIN(PROC_BLOCK_SIZE, nbytes);

		start = NULL;
		if (dp->get_info) {
			/*
			 * Handle backwards compatibility with the old net
			 * routines.
			 */
			n = dp->get_info(page, &start, *ppos, count);
			if (n < count)
				eof = 1;
		} else if (dp->read_proc) {
			n = dp->read_proc(page, &start, *ppos,
					  count, &eof, dp->data);
		} else
			break;

		if (!start) {
			/*
			 * For proc files that are less than 4k
			 */
			start = page + *ppos;
			n -= *ppos;
			if (n <= 0)
				break;
			if (n > count)
				n = count;
		}
		if (n == 0)
			break;	/* End of file */
		if (n < 0) {
			if (retval == 0)
				retval = n;
			break;
		}
		
		/* This is a hack to allow mangling of file pos independent
 		 * of actual bytes read.  Simply place the data at page,
 		 * return the bytes, and set `start' to the desired offset
 		 * as an unsigned int. - Paul.Russell@rustcorp.com.au
		 */
 		n -= copy_to_user(buf, start < page ? page : start, n);
		if (n == 0) {
			if (retval == 0)
				retval = -EFAULT;
			break;
		}

		*ppos += start < page ? (long)start : n; /* Move down the file */
		nbytes -= n;
		buf += n;
		retval += n;
	}
	free_page((unsigned long) page);
	return retval;
}





^ permalink raw reply	[flat|nested] 4+ messages in thread
* Re: proc_file_read bug?
@ 2002-01-27  0:19 Thomas Hood
  0 siblings, 0 replies; 4+ messages in thread
From: Thomas Hood @ 2002-01-27  0:19 UTC (permalink / raw)
  To: linux-kernel

I discovered that this question is fully answered in
chapter 4 of Linux Device Drivers, 2nd Edition, by
Alessandro Rubini & Jonathan Corbet.  Excellent book.

This "hack" seems to me rather unfortunate.  It makes
a single argument serve two completely different and
not mutually exclusive purposes.  It means that when I
want to override the file offset increment I can't set the
data start position within the buffer, and vice versa.
Overloading "start" in this way also sets an arbitrary
and randomly varying upper limit on the overriding file
offset increment: it can't be equal to or greater than
the address at which the data buffer happens to start.
(It was the seeming irrationality of this that led me
to wonder earlier whether or not the code contained a bug.)

It might have been better to add a new argument to the
read function for the purpose of returning offset increase
overrides.





^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2002-01-27  0:19 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-01-25 13:36 proc_file_read bug? Thomas Hood
2002-01-25 14:29 ` Andreas Schwab
2002-01-25 15:00   ` Thomas Hood
  -- strict thread matches above, loose matches on Subject: below --
2002-01-27  0:19 Thomas Hood

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox