aboutsummaryrefslogtreecommitdiffstats
path: root/fs/compat.c
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2009-04-02 19:59:20 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-02 22:05:07 -0400
commitdac1213842f5caf081804a11d87d2a39a21d6f55 (patch)
tree0b357e0a70fc872c400eb764ec7243969a5439d6 /fs/compat.c
parent98310e581e098514867573031b2bfa4ba89c0d93 (diff)
preadv/pwritev: create compat_readv()
This patch series: Implement the preadv() and pwritev() syscalls. *BSD has this syscall for quite some time. Test code: #if 0 set -x gcc -Wall -O2 -o preadv $0 exit 0 #endif /* * preadv demo / test * * (c) 2008 Gerd Hoffmann <kraxel@redhat.com> * * build with "sh $thisfile" */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <inttypes.h> #include <sys/uio.h> /* ----------------------------------------------------------------- */ /* syscall windup */ #include <sys/syscall.h> #if 0 /* WARNING: Be sure you know what you are doing if you enable this. * linux syscall code isn't upstream yet, syscall numbers are subject * to change */ # ifndef __NR_preadv # ifdef __i386__ # define __NR_preadv 333 # define __NR_pwritev 334 # endif # ifdef __x86_64__ # define __NR_preadv 295 # define __NR_pwritev 296 # endif # endif #endif #ifndef __NR_preadv # error preadv/pwritev syscall numbers are unknown #endif static ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) { uint32_t pos_high = (offset >> 32) & 0xffffffff; uint32_t pos_low = offset & 0xffffffff; return syscall(__NR_preadv, fd, iov, iovcnt, pos_high, pos_low); } static ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) { uint32_t pos_high = (offset >> 32) & 0xffffffff; uint32_t pos_low = offset & 0xffffffff; return syscall(__NR_pwritev, fd, iov, iovcnt, pos_high, pos_low); } /* ----------------------------------------------------------------- */ /* demo/test app */ static char filename[] = "/tmp/preadv-XXXXXX"; static char outbuf[11] = "0123456789"; static char inbuf[11] = "----------"; static struct iovec ovec[2] = {{ .iov_base = outbuf + 5, .iov_len = 5, },{ .iov_base = outbuf + 0, .iov_len = 5, }}; static struct iovec ivec[3] = {{ .iov_base = inbuf + 6, .iov_len = 2, },{ .iov_base = inbuf + 4, .iov_len = 2, },{ .iov_base = inbuf + 2, .iov_len = 2, }}; void cleanup(void) { unlink(filename); } int main(int argc, char **argv) { int fd, rc; fd = mkstemp(filename); if (-1 == fd) { perror("mkstemp"); exit(1); } atexit(cleanup); /* write to file: "56789-01234" */ rc = pwritev(fd, ovec, 2, 0); if (rc < 0) { perror("pwritev"); exit(1); } /* read from file: "78-90-12" */ rc = preadv(fd, ivec, 3, 2); if (rc < 0) { perror("preadv"); exit(1); } printf("result : %s\n", inbuf); printf("expected: %s\n", "--129078--"); exit(0); } This patch: Factor out some code from compat_sys_readv() which can be shared with the upcoming compat_sys_preadv(). Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: <linux-api@vger.kernel.org> Cc: <linux-arch@vger.kernel.org> Cc: Ralf Baechle <ralf@linux-mips.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/compat.c')
-rw-r--r--fs/compat.c26
1 files changed, 18 insertions, 8 deletions
diff --git a/fs/compat.c b/fs/compat.c
index 55efdfebdf5a..e99048c21c56 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1195,16 +1195,12 @@ out:
1195 return ret; 1195 return ret;
1196} 1196}
1197 1197
1198asmlinkage ssize_t 1198static size_t compat_readv(struct file *file,
1199compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen) 1199 const struct compat_iovec __user *vec,
1200 unsigned long vlen, loff_t *pos)
1200{ 1201{
1201 struct file *file;
1202 ssize_t ret = -EBADF; 1202 ssize_t ret = -EBADF;
1203 1203
1204 file = fget(fd);
1205 if (!file)
1206 return -EBADF;
1207
1208 if (!(file->f_mode & FMODE_READ)) 1204 if (!(file->f_mode & FMODE_READ))
1209 goto out; 1205 goto out;
1210 1206
@@ -1212,12 +1208,26 @@ compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, unsign
1212 if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read)) 1208 if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read))
1213 goto out; 1209 goto out;
1214 1210
1215 ret = compat_do_readv_writev(READ, file, vec, vlen, &file->f_pos); 1211 ret = compat_do_readv_writev(READ, file, vec, vlen, pos);
1216 1212
1217out: 1213out:
1218 if (ret > 0) 1214 if (ret > 0)
1219 add_rchar(current, ret); 1215 add_rchar(current, ret);
1220 inc_syscr(current); 1216 inc_syscr(current);
1217 return ret;
1218}
1219
1220asmlinkage ssize_t
1221compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec,
1222 unsigned long vlen)
1223{
1224 struct file *file;
1225 ssize_t ret;
1226
1227 file = fget(fd);
1228 if (!file)
1229 return -EBADF;
1230 ret = compat_readv(file, vec, vlen, &file->f_pos);
1221 fput(file); 1231 fput(file);
1222 return ret; 1232 return ret;
1223} 1233}