public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* Nasty 2.6 sendfile() bug / regression; affects vsftpd
@ 2004-04-18  0:28 chris
  2004-04-18  3:12 ` Linus Torvalds
  0 siblings, 1 reply; 13+ messages in thread
From: chris @ 2004-04-18  0:28 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

Hi Andrew, linux-kernel,

Large-file download support with vsftpd and the 2.6 kernel is a broken
combination. After careful consideration, I'm pretty sure the bug is with
the 2.6 kernel. At the very least, behaviour has changed from 2.4. An
initial fix is included below.

vsftpd makes extensive use of sendfile to achieve high performance. When
vsftpd was first written, sendfile64 did not exist. So, in order to
transfer >2Gb files, multiple sendfile() calls are used [1]. The main
issue with sendfile() and >2Gb files is of course that the "offset" in/out
parameter cannot be used, because it is not 64-bit. The solution is
simple; use NULL for the offset parameter and keep track of the file
position in a purely user-space variable.
The above scheme works well with 2.4, but unfortunately fails with
EOVERFLOW in 2.6 at the 2Gb mark.
This failure seems to be a bug. I could be wrong here, but it seems the
intent of EOVERFLOW is to indicate to the user that a large 64-bit kernel
value cannot be stuffed into a 32-bit userspace return value. In the case
of using NULL as the offset paramter, userspace does not care about the
64-bit file offset and no truncation will ever occur.
The below patch fixes this up to restore 2.4 behaviour in the event of a
NULL offset parameter. It's currently under testing and looking good.

Any chance you can review this and sneak into 2.6.soon?

--- read_write.c.old	2004-04-17 18:39:11.000000000 +0100
+++ read_write.c	2004-04-17 23:38:04.000000000 +0100
@@ -545,6 +545,7 @@
 	loff_t pos;
 	ssize_t retval;
 	int fput_needed_in, fput_needed_out;
+	loff_t *orig_ppos = ppos;

 	/*
 	 * Get input file, and verify that it is ok..
@@ -599,7 +600,7 @@
 	retval = -EINVAL;
 	if (unlikely(pos < 0))
 		goto fput_out;
-	if (unlikely(pos + count > max)) {
+	if (unlikely(pos + count > max && orig_ppos != NULL)) {
 		retval = -EOVERFLOW;
 		if (pos >= max)
 			goto fput_out;
@@ -608,7 +609,7 @@

 	retval = in_file->f_op->sendfile(in_file, ppos, count, file_send_actor, out_file);

-	if (*ppos > max)
+	if (*ppos > max && orig_ppos != NULL)
 		retval = -EOVERFLOW;

 fput_out:

Cheers
Chris

[1] Note that I'm not inspired to use sendfile64, as it will STILL need
multiple sendfile64 calls - the "count" variabe is still 32-bit. The only
change from sendfile is that the offset parameter becomes 64-bit.

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

end of thread, other threads:[~2004-04-20 23:25 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-04-18  0:28 Nasty 2.6 sendfile() bug / regression; affects vsftpd chris
2004-04-18  3:12 ` Linus Torvalds
2004-04-18 13:49   ` chris
2004-04-19  0:46   ` Jamie Lokier
2004-04-19  5:28     ` Linus Torvalds
2004-04-19  9:44       ` [PATCH] Add 64-bit get_user and __get_user for i386 Jamie Lokier
2004-04-19 10:14         ` Jamie Lokier
2004-04-19 10:17           ` [PATCH] Use get_user for 64-bit read in sendfile64 Jamie Lokier
2004-04-19 10:36             ` Jamie Lokier
2004-04-19 14:56         ` [PATCH] Add 64-bit get_user and __get_user for i386 Linus Torvalds
     [not found]           ` <20040420020922.GA18348@mail.shareable.org>
     [not found]             ` <Pine.LNX.4.58.0404191945490.29941@ppc970.osdl.org>
2004-04-20 17:41               ` Jamie Lokier
2004-04-21  1:15                 ` Linus Torvalds
2004-04-20 23:21             ` Jim Wilson

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