Semantic fix for sendfile

Pavel Machek (pavel@suse.cz)
Fri, 19 Nov 1999 23:01:32 +0100


Hi!

I really don't think userland applications should be expected to know
about what source is valid and what source is not (even some
filesystems are not valid source for sendfile). This patch adds
fallback method so that you can sendfile() from anything. It will
still be faster than same loop done in userland.
Pavel

--- clean/mm/filemap.c Mon Nov 15 22:13:07 1999
+++ linux/mm/filemap.c Mon Nov 15 22:09:27 1999
@@ -1215,6 +1215,48 @@
return written;
}

+ssize_t trivial_copyfd(int out_fd, int in_fd, size_t count)
+{
+extern asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count);
+extern asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count);
+
+ /* This is really trivial, we could be quite a bit more
+ * clever: checking both files outside of loop could be easily
+ * done... But this code is 'obviously right'. */
+ char *buffer = (char *) __get_free_page( GFP_KERNEL );
+ /* We do not need page to be cleared */
+ int i, j;
+ int res = 0;
+
+ if (!buffer)
+ return -ENOMEM;
+ set_fs(KERNEL_DS);
+ while (count && !signal_pending(current)) {
+ i = count>PAGE_SIZE ? PAGE_SIZE : count;
+ i = sys_read(in_fd, buffer, i );
+ if (i<0) {
+ res = i;
+ break;
+ }
+ if (!i)
+ break;
+ j = sys_write(out_fd, buffer, i );
+ if (j<0) {
+ res = j;
+ break;
+ }
+ res += j;
+ if (i!=j)
+ break;
+ count -= j;
+
+ }
+ set_fs(USER_DS);
+
+ free_page( (long) buffer );
+ return res;
+}
+
asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
{
ssize_t retval;
@@ -1233,9 +1275,10 @@
retval = -EINVAL;
in_inode = in_file->f_dentry->d_inode;
if (!in_inode)
- goto fput_in;
+ goto fallback;
if (!in_inode->i_op || !in_inode->i_op->readpage)
- goto fput_in;
+ goto fallback;
+
retval = locks_verify_area(FLOCK_VERIFY_READ, in_inode, in_file, in_file->f_pos, count);
if (retval)
goto fput_in;
@@ -1291,6 +1334,12 @@
fput(in_file);
out:
return retval;
+
+fallback:
+ fput(in_file);
+ unlock_kernel();
+ if (offset) return -EINVAL;
+ return trivial_copyfd( out_fd, in_fd, count );
}

/*

-- 
I'm really pavel@ucw.cz. Look at http://195.113.31.123/~pavel.  Pavel
Hi! I'm a .signature virus! Copy me into your ~/.signature, please!

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/