summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorCatalin Marinas <catalin.marinas@arm.com>2012-09-19 13:01:52 +0200
committerAl Viro <viro@zeniv.linux.org.uk>2012-10-03 03:35:55 +0200
commit8f9c0119d7ba94c3ad13876acc240d7f12b6d8e1 (patch)
tree44d618a21b60c5a268088bfae6c78c591f1e4334 /fs
parentfs: push rcu_barrier() from deactivate_locked_super() to filesystems (diff)
downloadlinux-8f9c0119d7ba94c3ad13876acc240d7f12b6d8e1.tar.xz
linux-8f9c0119d7ba94c3ad13876acc240d7f12b6d8e1.zip
compat: fs: Generic compat_sys_sendfile implementation
This function is used by sparc, powerpc and arm64 for compat support. The patch adds a generic implementation which calls do_sendfile() directly and avoids set_fs(). The sparc architecture has wrappers for the sign extensions while powerpc relies on the compiler to do the this. The patch adds wrappers for powerpc to handle the u32->int type conversion. compat_sys_sendfile64() can be replaced by a sys_sendfile() call since compat_loff_t has the same size as off_t on a 64-bit system. On powerpc, the patch also changes the 64-bit sendfile call from sys_sendile64 to sys_sendfile. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Acked-by: David S. Miller <davem@davemloft.net> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/compat.c22
-rw-r--r--fs/read_write.c4
-rw-r--r--fs/read_write.h2
3 files changed, 26 insertions, 2 deletions
diff --git a/fs/compat.c b/fs/compat.c
index d72d51e19025..b7a24d0ca30d 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1792,3 +1792,25 @@ compat_sys_open_by_handle_at(int mountdirfd,
return do_handle_open(mountdirfd, handle, flags);
}
#endif
+
+#ifdef __ARCH_WANT_COMPAT_SYS_SENDFILE
+asmlinkage long compat_sys_sendfile(int out_fd, int in_fd,
+ compat_off_t __user *offset, compat_size_t count)
+{
+ loff_t pos;
+ off_t off;
+ ssize_t ret;
+
+ if (offset) {
+ if (unlikely(get_user(off, offset)))
+ return -EFAULT;
+ pos = off;
+ ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS);
+ if (unlikely(put_user(pos, offset)))
+ return -EFAULT;
+ return ret;
+ }
+
+ return do_sendfile(out_fd, in_fd, NULL, count, 0);
+}
+#endif /* __ARCH_WANT_COMPAT_SYS_SENDFILE */
diff --git a/fs/read_write.c b/fs/read_write.c
index 28b38279a219..d06534857e9e 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -862,8 +862,8 @@ SYSCALL_DEFINE5(pwritev, unsigned long, fd, const struct iovec __user *, vec,
return ret;
}
-static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
- size_t count, loff_t max)
+ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count,
+ loff_t max)
{
struct fd in, out;
struct inode *in_inode, *out_inode;
diff --git a/fs/read_write.h b/fs/read_write.h
index d07b954c6e0c..d3e00ef67420 100644
--- a/fs/read_write.h
+++ b/fs/read_write.h
@@ -12,3 +12,5 @@ ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov,
unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn);
ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov,
unsigned long nr_segs, loff_t *ppos, io_fn_t fn);
+ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count,
+ loff_t max);