linux-bk/fs/compat.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/compat.c
   3 *
   4 *  Kernel compatibililty routines for e.g. 32 bit syscall support
   5 *  on 64 bit kernels.
   6 *
   7 *  Copyright (C) 2002       Stephen Rothwell, IBM Corporation
   8 *  Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
   9 *  Copyright (C) 1998       Eddie C. Dost  (ecd@skynet.be)
  10 *  Copyright (C) 2001,2002  Andi Kleen, SuSE Labs 
  11 *  Copyright (C) 2003       Pavel Machek (pavel@suse.cz)
  12 *
  13 *  This program is free software; you can redistribute it and/or modify
  14 *  it under the terms of the GNU General Public License version 2 as
  15 *  published by the Free Software Foundation.
  16 */
  17
  18#include <linux/linkage.h>
  19#include <linux/compat.h>
  20#include <linux/errno.h>
  21#include <linux/time.h>
  22#include <linux/fs.h>
  23#include <linux/fcntl.h>
  24#include <linux/namei.h>
  25#include <linux/file.h>
  26#include <linux/vfs.h>
  27#include <linux/ioctl32.h>
  28#include <linux/init.h>
  29#include <linux/sockios.h>      /* for SIOCDEVPRIVATE */
  30#include <linux/smp_lock.h>
  31#include <linux/ctype.h>
  32#include <linux/module.h>
  33#include <net/sock.h>           /* siocdevprivate_ioctl */
  34
  35#include <asm/uaccess.h>
  36
  37/*
  38 * Not all architectures have sys_utime, so implement this in terms
  39 * of sys_utimes.
  40 */
  41asmlinkage long compat_sys_utime(char *filename, struct compat_utimbuf *t)
  42{
  43        struct timeval tv[2];
  44
  45        if (t) {
  46                if (get_user(tv[0].tv_sec, &t->actime) ||
  47                    get_user(tv[1].tv_sec, &t->modtime))
  48                        return -EFAULT;
  49                tv[0].tv_usec = 0;
  50                tv[1].tv_usec = 0;
  51        }
  52        return do_utimes(filename, t ? tv : NULL);
  53}
  54
  55asmlinkage long compat_sys_utimes(char *filename, struct compat_timeval *t)
  56{
  57        struct timeval tv[2];
  58
  59        if (t) { 
  60                if (get_user(tv[0].tv_sec, &t[0].tv_sec) ||
  61                    get_user(tv[0].tv_usec, &t[0].tv_usec) ||
  62                    get_user(tv[1].tv_sec, &t[1].tv_sec) ||
  63                    get_user(tv[1].tv_usec, &t[1].tv_usec))
  64                        return -EFAULT; 
  65        } 
  66        return do_utimes(filename, t ? tv : NULL);
  67}
  68
  69asmlinkage long compat_sys_newstat(char * filename,
  70                struct compat_stat *statbuf)
  71{
  72        struct kstat stat;
  73        int error = vfs_stat(filename, &stat);
  74
  75        if (!error)
  76                error = cp_compat_stat(&stat, statbuf);
  77        return error;
  78}
  79
  80asmlinkage long compat_sys_newlstat(char * filename,
  81                struct compat_stat *statbuf)
  82{
  83        struct kstat stat;
  84        int error = vfs_lstat(filename, &stat);
  85
  86        if (!error)
  87                error = cp_compat_stat(&stat, statbuf);
  88        return error;
  89}
  90
  91asmlinkage long compat_sys_newfstat(unsigned int fd,
  92                struct compat_stat * statbuf)
  93{
  94        struct kstat stat;
  95        int error = vfs_fstat(fd, &stat);
  96
  97        if (!error)
  98                error = cp_compat_stat(&stat, statbuf);
  99        return error;
 100}
 101
 102static int put_compat_statfs(struct compat_statfs *ubuf, struct kstatfs *kbuf)
 103{
 104        
 105        if (sizeof ubuf->f_blocks == 4) {
 106                if ((kbuf->f_blocks | kbuf->f_bfree |
 107                     kbuf->f_bavail | kbuf->f_files | kbuf->f_ffree) &
 108                    0xffffffff00000000ULL)
 109                        return -EOVERFLOW;
 110        }
 111        if (verify_area(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
 112            __put_user(kbuf->f_type, &ubuf->f_type) ||
 113            __put_user(kbuf->f_bsize, &ubuf->f_bsize) ||
 114            __put_user(kbuf->f_blocks, &ubuf->f_blocks) ||
 115            __put_user(kbuf->f_bfree, &ubuf->f_bfree) ||
 116            __put_user(kbuf->f_bavail, &ubuf->f_bavail) ||
 117            __put_user(kbuf->f_files, &ubuf->f_files) ||
 118            __put_user(kbuf->f_ffree, &ubuf->f_ffree) ||
 119            __put_user(kbuf->f_namelen, &ubuf->f_namelen) ||
 120            __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
 121            __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
 122            __put_user(kbuf->f_frsize, &ubuf->f_frsize) ||
 123            __put_user(0, &ubuf->f_spare[0]) || 
 124            __put_user(0, &ubuf->f_spare[1]) || 
 125            __put_user(0, &ubuf->f_spare[2]) || 
 126            __put_user(0, &ubuf->f_spare[3]) || 
 127            __put_user(0, &ubuf->f_spare[4]))
 128                return -EFAULT;
 129        return 0;
 130}
 131
 132/*
 133 * The following statfs calls are copies of code from fs/open.c and
 134 * should be checked against those from time to time
 135 */
 136asmlinkage long compat_sys_statfs(const char *path, struct compat_statfs *buf)
 137{
 138        struct nameidata nd;
 139        int error;
 140
 141        error = user_path_walk(path, &nd);
 142        if (!error) {
 143                struct kstatfs tmp;
 144                error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
 145                if (!error && put_compat_statfs(buf, &tmp))
 146                        error = -EFAULT;
 147                path_release(&nd);
 148        }
 149        return error;
 150}
 151
 152asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs *buf)
 153{
 154        struct file * file;
 155        struct kstatfs tmp;
 156        int error;
 157
 158        error = -EBADF;
 159        file = fget(fd);
 160        if (!file)
 161                goto out;
 162        error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
 163        if (!error && put_compat_statfs(buf, &tmp))
 164                error = -EFAULT;
 165        fput(file);
 166out:
 167        return error;
 168}
 169
 170static int put_compat_statfs64(struct compat_statfs64 *ubuf, struct kstatfs *kbuf)
 171{
 172        if (sizeof ubuf->f_blocks == 4) {
 173                if ((kbuf->f_blocks | kbuf->f_bfree |
 174                     kbuf->f_bavail | kbuf->f_files | kbuf->f_ffree) &
 175                    0xffffffff00000000ULL)
 176                        return -EOVERFLOW;
 177        }
 178        if (verify_area(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
 179            __put_user(kbuf->f_type, &ubuf->f_type) ||
 180            __put_user(kbuf->f_bsize, &ubuf->f_bsize) ||
 181            __put_user(kbuf->f_blocks, &ubuf->f_blocks) ||
 182            __put_user(kbuf->f_bfree, &ubuf->f_bfree) ||
 183            __put_user(kbuf->f_bavail, &ubuf->f_bavail) ||
 184            __put_user(kbuf->f_files, &ubuf->f_files) ||
 185            __put_user(kbuf->f_ffree, &ubuf->f_ffree) ||
 186            __put_user(kbuf->f_namelen, &ubuf->f_namelen) ||
 187            __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
 188            __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
 189            __put_user(kbuf->f_frsize, &ubuf->f_frsize))
 190                return -EFAULT;
 191        return 0;
 192}
 193
 194asmlinkage long compat_statfs64(const char *path, compat_size_t sz, struct compat_statfs64 *buf)
 195{
 196        struct nameidata nd;
 197        int error;
 198
 199        if (sz != sizeof(*buf))
 200                return -EINVAL;
 201
 202        error = user_path_walk(path, &nd);
 203        if (!error) {
 204                struct kstatfs tmp;
 205                error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
 206                if (!error && put_compat_statfs64(buf, &tmp))
 207                        error = -EFAULT;
 208                path_release(&nd);
 209        }
 210        return error;
 211}
 212
 213asmlinkage long compat_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 *buf)
 214{
 215        struct file * file;
 216        struct kstatfs tmp;
 217        int error;
 218
 219        if (sz != sizeof(*buf))
 220                return -EINVAL;
 221
 222        error = -EBADF;
 223        file = fget(fd);
 224        if (!file)
 225                goto out;
 226        error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
 227        if (!error && put_compat_statfs64(buf, &tmp))
 228                error = -EFAULT;
 229        fput(file);
 230out:
 231        return error;
 232}
 233
 234/* ioctl32 stuff, used by sparc64, parisc, s390x, ppc64, x86_64 */
 235
 236#define IOCTL_HASHSIZE 256
 237struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE];
 238
 239extern struct ioctl_trans ioctl_start[];
 240extern int ioctl_table_size;
 241
 242static inline unsigned long ioctl32_hash(unsigned long cmd)
 243{
 244        return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE;
 245}
 246
 247static void ioctl32_insert_translation(struct ioctl_trans *trans)
 248{
 249        unsigned long hash;
 250        struct ioctl_trans *t;
 251
 252        hash = ioctl32_hash (trans->cmd);
 253        if (!ioctl32_hash_table[hash])
 254                ioctl32_hash_table[hash] = trans;
 255        else {
 256                t = ioctl32_hash_table[hash];
 257                while (t->next)
 258                        t = t->next;
 259                trans->next = 0;
 260                t->next = trans;
 261        }
 262}
 263
 264static int __init init_sys32_ioctl(void)
 265{
 266        int i;
 267
 268        for (i = 0; i < ioctl_table_size; i++) {
 269                if (ioctl_start[i].next != 0) { 
 270                        printk("ioctl translation %d bad\n",i); 
 271                        return -1;
 272                }
 273
 274                ioctl32_insert_translation(&ioctl_start[i]);
 275        }
 276        return 0;
 277}
 278
 279__initcall(init_sys32_ioctl);
 280
 281static struct ioctl_trans *ioctl_free_list;
 282
 283/* Never free them really. This avoids SMP races. With a Read-Copy-Update
 284   enabled kernel we could just use the RCU infrastructure for this. */
 285static void free_ioctl(struct ioctl_trans *t) 
 286{ 
 287        t->cmd = 0; 
 288        mb();
 289        t->next = ioctl_free_list;
 290        ioctl_free_list = t;
 291} 
 292
 293int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *))
 294{
 295        struct ioctl_trans *t;
 296        unsigned long hash = ioctl32_hash(cmd);
 297
 298        lock_kernel(); 
 299        for (t = (struct ioctl_trans *)ioctl32_hash_table[hash];
 300             t;
 301             t = t->next) { 
 302                if (t->cmd == cmd) {
 303                        printk("Trying to register duplicated ioctl32 handler %x\n", cmd);
 304                        unlock_kernel();
 305                        return -EINVAL; 
 306                }
 307        } 
 308
 309        if (ioctl_free_list) { 
 310                t = ioctl_free_list; 
 311                ioctl_free_list = t->next; 
 312        } else { 
 313                t = kmalloc(sizeof(struct ioctl_trans), GFP_KERNEL); 
 314                if (!t) { 
 315                        unlock_kernel();
 316                        return -ENOMEM;
 317                }
 318        }
 319        
 320        t->next = NULL;
 321        t->cmd = cmd;
 322        t->handler = handler; 
 323        ioctl32_insert_translation(t);
 324
 325        unlock_kernel();
 326        return 0;
 327}
 328
 329static inline int builtin_ioctl(struct ioctl_trans *t)
 330{ 
 331        return t >= ioctl_start && t < (ioctl_start + ioctl_table_size);
 332} 
 333
 334/* Problem: 
 335   This function cannot unregister duplicate ioctls, because they are not
 336   unique.
 337   When they happen we need to extend the prototype to pass the handler too. */
 338
 339int unregister_ioctl32_conversion(unsigned int cmd)
 340{
 341        unsigned long hash = ioctl32_hash(cmd);
 342        struct ioctl_trans *t, *t1;
 343
 344        lock_kernel(); 
 345
 346        t = (struct ioctl_trans *)ioctl32_hash_table[hash];
 347        if (!t) { 
 348                unlock_kernel();
 349                return -EINVAL;
 350        } 
 351
 352        if (t->cmd == cmd) { 
 353                if (builtin_ioctl(t)) {
 354                        printk("%p tried to unregister builtin ioctl %x\n",
 355                               __builtin_return_address(0), cmd);
 356                } else { 
 357                ioctl32_hash_table[hash] = t->next;
 358                        free_ioctl(t); 
 359                        unlock_kernel();
 360                return 0;
 361                }
 362        } 
 363        while (t->next) {
 364                t1 = (struct ioctl_trans *)(long)t->next;
 365                if (t1->cmd == cmd) { 
 366                        if (builtin_ioctl(t1)) {
 367                                printk("%p tried to unregister builtin ioctl %x\n",
 368                                       __builtin_return_address(0), cmd);
 369                                goto out;
 370                        } else { 
 371                        t->next = t1->next;
 372                                free_ioctl(t1); 
 373                                unlock_kernel();
 374                        return 0;
 375                        }
 376                }
 377                t = t1;
 378        }
 379        printk(KERN_ERR "Trying to free unknown 32bit ioctl handler %x\n", cmd);
 380 out:
 381        unlock_kernel();
 382        return -EINVAL;
 383}
 384
 385EXPORT_SYMBOL(register_ioctl32_conversion); 
 386EXPORT_SYMBOL(unregister_ioctl32_conversion); 
 387
 388asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 389{
 390        struct file * filp;
 391        int error = -EBADF;
 392        struct ioctl_trans *t;
 393
 394        filp = fget(fd);
 395        if(!filp)
 396                goto out2;
 397
 398        if (!filp->f_op || !filp->f_op->ioctl) {
 399                error = sys_ioctl (fd, cmd, arg);
 400                goto out;
 401        }
 402
 403        t = (struct ioctl_trans *)ioctl32_hash_table [ioctl32_hash (cmd)];
 404
 405        while (t && t->cmd != cmd)
 406                t = (struct ioctl_trans *)t->next;
 407        if (t) {
 408                if (t->handler)
 409                        error = t->handler(fd, cmd, arg, filp);
 410                else
 411                        error = sys_ioctl(fd, cmd, arg);
 412        } else if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
 413                error = siocdevprivate_ioctl(fd, cmd, arg);
 414        } else {
 415                static int count;
 416                if (++count <= 50) { 
 417                        char buf[10];
 418                        char *path = (char *)__get_free_page(GFP_KERNEL), *fn = "?"; 
 419
 420                        /* find the name of the device. */
 421                        if (path) {
 422                                fn = d_path(filp->f_dentry, filp->f_vfsmnt, 
 423                                            path, PAGE_SIZE);
 424                        }
 425
 426                        sprintf(buf,"'%c'", (cmd>>24) & 0x3f); 
 427                        if (!isprint(buf[1]))
 428                            sprintf(buf, "%02x", buf[1]);
 429                        printk("ioctl32(%s:%d): Unknown cmd fd(%d) "
 430                               "cmd(%08x){%s} arg(%08x) on %s\n",
 431                               current->comm, current->pid,
 432                               (int)fd, (unsigned int)cmd, buf, (unsigned int)arg,
 433                               fn);
 434                        if (path) 
 435                                free_page((unsigned long)path); 
 436                }
 437                error = -EINVAL;
 438        }
 439out:
 440        fput(filp);
 441out2:
 442        return error;
 443}
 444
 445static int get_compat_flock(struct flock *kfl, struct compat_flock *ufl)
 446{
 447        if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
 448            __get_user(kfl->l_type, &ufl->l_type) ||
 449            __get_user(kfl->l_whence, &ufl->l_whence) ||
 450            __get_user(kfl->l_start, &ufl->l_start) ||
 451            __get_user(kfl->l_len, &ufl->l_len) ||
 452            __get_user(kfl->l_pid, &ufl->l_pid))
 453                return -EFAULT;
 454        return 0;
 455}
 456
 457static int put_compat_flock(struct flock *kfl, struct compat_flock *ufl)
 458{
 459        if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
 460            __put_user(kfl->l_type, &ufl->l_type) ||
 461            __put_user(kfl->l_whence, &ufl->l_whence) ||
 462            __put_user(kfl->l_start, &ufl->l_start) ||
 463            __put_user(kfl->l_len, &ufl->l_len) ||
 464            __put_user(kfl->l_pid, &ufl->l_pid))
 465                return -EFAULT;
 466        return 0;
 467}
 468
 469#ifndef HAVE_ARCH_GET_COMPAT_FLOCK64
 470static int get_compat_flock64(struct flock *kfl, struct compat_flock64 *ufl)
 471{
 472        if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
 473            __get_user(kfl->l_type, &ufl->l_type) ||
 474            __get_user(kfl->l_whence, &ufl->l_whence) ||
 475            __get_user(kfl->l_start, &ufl->l_start) ||
 476            __get_user(kfl->l_len, &ufl->l_len) ||
 477            __get_user(kfl->l_pid, &ufl->l_pid))
 478                return -EFAULT;
 479        return 0;
 480}
 481#endif
 482
 483#ifndef HAVE_ARCH_PUT_COMPAT_FLOCK64
 484static int put_compat_flock64(struct flock *kfl, struct compat_flock64 *ufl)
 485{
 486        if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
 487            __put_user(kfl->l_type, &ufl->l_type) ||
 488            __put_user(kfl->l_whence, &ufl->l_whence) ||
 489            __put_user(kfl->l_start, &ufl->l_start) ||
 490            __put_user(kfl->l_len, &ufl->l_len) ||
 491            __put_user(kfl->l_pid, &ufl->l_pid))
 492                return -EFAULT;
 493        return 0;
 494}
 495#endif
 496
 497extern asmlinkage long sys_fcntl(unsigned int, unsigned int, unsigned long);
 498
 499asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
 500                unsigned long arg)
 501{
 502        mm_segment_t old_fs;
 503        struct flock f;
 504        long ret;
 505
 506        switch (cmd) {
 507        case F_GETLK:
 508        case F_SETLK:
 509        case F_SETLKW:
 510                ret = get_compat_flock(&f, compat_ptr(arg));
 511                if (ret != 0)
 512                        break;
 513                old_fs = get_fs();
 514                set_fs(KERNEL_DS);
 515                ret = sys_fcntl(fd, cmd, (unsigned long)&f);
 516                set_fs(old_fs);
 517                if ((cmd == F_GETLK) && (ret == 0)) {
 518                        if ((f.l_start >= COMPAT_OFF_T_MAX) ||
 519                            ((f.l_start + f.l_len) >= COMPAT_OFF_T_MAX))
 520                                ret = -EOVERFLOW;
 521                        if (ret == 0)
 522                                ret = put_compat_flock(&f, compat_ptr(arg));
 523                }
 524                break;
 525
 526        case F_GETLK64:
 527        case F_SETLK64:
 528        case F_SETLKW64:
 529                ret = get_compat_flock64(&f, compat_ptr(arg));
 530                if (ret != 0)
 531                        break;
 532                old_fs = get_fs();
 533                set_fs(KERNEL_DS);
 534                ret = sys_fcntl(fd, (cmd == F_GETLK64) ? F_GETLK :
 535                                ((cmd == F_SETLK64) ? F_SETLK : F_SETLKW),
 536                                (unsigned long)&f);
 537                set_fs(old_fs);
 538                if ((cmd == F_GETLK64) && (ret == 0)) {
 539                        if ((f.l_start >= COMPAT_LOFF_T_MAX) ||
 540                            ((f.l_start + f.l_len) >= COMPAT_LOFF_T_MAX))
 541                                ret = -EOVERFLOW;
 542                        if (ret == 0)
 543                                ret = put_compat_flock64(&f, compat_ptr(arg));
 544                }
 545                break;
 546
 547        default:
 548                ret = sys_fcntl(fd, cmd, arg);
 549                break;
 550        }
 551        return ret;
 552}
 553
 554asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd,
 555                unsigned long arg)
 556{
 557        if ((cmd == F_GETLK64) || (cmd == F_SETLK64) || (cmd == F_SETLKW64))
 558                return -EINVAL;
 559        return compat_sys_fcntl64(fd, cmd, arg);
 560}
 561
 562extern asmlinkage long sys_io_setup(unsigned nr_reqs, aio_context_t *ctx);
 563
 564asmlinkage long
 565compat_sys_io_setup(unsigned nr_reqs, u32 *ctx32p)
 566{
 567        long ret;
 568        aio_context_t ctx64;
 569
 570        mm_segment_t oldfs = get_fs();
 571        if (unlikely(get_user(ctx64, ctx32p)))
 572                return -EFAULT;
 573
 574        set_fs(KERNEL_DS);
 575        ret = sys_io_setup(nr_reqs, &ctx64);
 576        set_fs(oldfs);
 577        /* truncating is ok because it's a user address */
 578        if (!ret)
 579                ret = put_user((u32) ctx64, ctx32p);
 580        return ret;
 581}
 582
 583extern asmlinkage long sys_io_getevents(aio_context_t ctx_id,
 584                                          long min_nr,
 585                                          long nr,
 586                                          struct io_event *events,
 587                                          struct timespec *timeout);
 588
 589asmlinkage long
 590compat_sys_io_getevents(aio_context_t ctx_id,
 591                                 unsigned long min_nr,
 592                                 unsigned long nr,
 593                                 struct io_event *events,
 594                                 struct compat_timespec *timeout)
 595{
 596        long ret;
 597        struct timespec t;
 598        struct timespec *ut = NULL;
 599
 600        ret = -EFAULT;
 601        if (unlikely(!access_ok(VERIFY_WRITE, events, 
 602                                nr * sizeof(struct io_event))))
 603                goto out;
 604        if (timeout) {
 605                if (get_compat_timespec(&t, timeout))
 606                        goto out;
 607
 608                ut = compat_alloc_user_space(sizeof(*ut));
 609                if (copy_to_user(ut, &t, sizeof(t)) )
 610                        goto out;
 611        } 
 612        ret = sys_io_getevents(ctx_id, min_nr, nr, events, ut);
 613out:
 614        return ret;
 615}
 616
 617extern asmlinkage long sys_io_submit(aio_context_t, long, 
 618                                struct iocb __user **);
 619
 620static inline long
 621copy_iocb(long nr, u32 *ptr32, u64 *ptr64)
 622{
 623        compat_uptr_t uptr;
 624        int i;
 625
 626        for (i = 0; i < nr; ++i) {
 627                if (get_user(uptr, ptr32 + i))
 628                        return -EFAULT;
 629                if (put_user((u64)compat_ptr(uptr), ptr64 + i))
 630                        return -EFAULT;
 631        }
 632        return 0;
 633}
 634
 635#define MAX_AIO_SUBMITS         (PAGE_SIZE/sizeof(struct iocb *))
 636
 637asmlinkage long
 638compat_sys_io_submit(aio_context_t ctx_id, int nr, u32 *iocb)
 639{
 640        struct iocb **iocb64; 
 641        long ret;
 642
 643        if (unlikely(nr < 0))
 644                return -EINVAL;
 645
 646        if (nr > MAX_AIO_SUBMITS)
 647                nr = MAX_AIO_SUBMITS;
 648        
 649        iocb64 = compat_alloc_user_space(nr * sizeof(*iocb64));
 650        ret = copy_iocb(nr, iocb, (u64 *) iocb64);
 651        if (!ret)
 652                ret = sys_io_submit(ctx_id, nr, iocb64);
 653        return ret;
 654}
 655
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.