This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / arch / x86_64 / ia32 / sys_ia32.c
index 73514ae..bc16ecf 100644 (file)
@@ -225,7 +225,10 @@ sys32_mmap(struct mmap_arg_struct __user *arg)
                if (!file)
                        return -EBADF;
        }
-       
+
+       if (a.prot & PROT_READ) 
+               a.prot |= vm_force_exec32;
+
        mm = current->mm; 
        down_write(&mm->mmap_sem); 
        retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset>>PAGE_SHIFT);
@@ -250,9 +253,12 @@ sys32_mprotect(unsigned long start, size_t len, unsigned long prot)
 {
        if ((start + PAGE_ALIGN(len)) >> 32)
                return -ENOMEM;
+       if (prot & PROT_READ) 
+               prot |= vm_force_exec32;
        return sys_mprotect(start,len,prot); 
 }
 
+asmlinkage long
 sys32_brk(unsigned long brk)
 {
        if (brk > IA32_PAGE_OFFSET)
@@ -261,12 +267,12 @@ sys32_brk(unsigned long brk)
 }
 
 extern unsigned long do_mremap(unsigned long addr,
-   unsigned long old_len, unsigned long new_len,
-   unsigned long flags, unsigned long new_addr);
+       unsigned long old_len, unsigned long new_len,
+       unsigned long flags, unsigned long new_addr);
 
 asmlinkage unsigned long sys32_mremap(unsigned long addr,
-   unsigned long old_len, unsigned long new_len,
-   unsigned long flags, unsigned long new_addr)
+       unsigned long old_len, unsigned long new_len,
+       unsigned long flags, unsigned long new_addr)
 {
        struct vm_area_struct *vma;
        unsigned long ret = -EINVAL;
@@ -296,7 +302,8 @@ asmlinkage unsigned long sys32_mremap(unsigned long addr,
 
                /* MREMAP_FIXED checked above. */
                new_addr = get_unmapped_area(file, addr, new_len,
-                       vma ? vma->vm_pgoff : 0, map_flags);
+                                   vma ? vma->vm_pgoff : 0,
+                                   map_flags);
                ret = new_addr;
                if (new_addr & ~PAGE_MASK)
                        goto out_sem;
@@ -306,10 +313,9 @@ asmlinkage unsigned long sys32_mremap(unsigned long addr,
 out_sem:
        up_write(&current->mm->mmap_sem);
 out:
-return ret;
+       return ret;       
 }
 
-
 asmlinkage long
 sys32_pipe(int __user *fd)
 {
@@ -548,6 +554,134 @@ sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
        return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
 }
 
+struct linux32_dirent {
+       u32     d_ino;
+       u32     d_off;
+       u16     d_reclen;
+       char    d_name[1];
+};
+
+struct old_linux32_dirent {
+       u32     d_ino;
+       u32     d_offset;
+       u16     d_namlen;
+       char    d_name[1];
+};
+
+struct getdents32_callback {
+       struct linux32_dirent __user * current_dir;
+       struct linux32_dirent __user * previous;
+       int count;
+       int error;
+};
+
+struct readdir32_callback {
+       struct old_linux32_dirent __user * dirent;
+       int count;
+};
+
+static int
+filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino,
+          unsigned int d_type)
+{
+       struct linux32_dirent __user * dirent;
+       struct getdents32_callback * buf = (struct getdents32_callback *) __buf;
+       int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 2, 4);
+
+       buf->error = -EINVAL;   /* only used if we fail.. */
+       if (reclen > buf->count)
+               return -EINVAL;
+       dirent = buf->previous;
+       if (dirent)
+               put_user(offset, &dirent->d_off);
+       dirent = buf->current_dir;
+       buf->previous = dirent;
+       put_user(ino, &dirent->d_ino);
+       put_user(reclen, &dirent->d_reclen);
+       copy_to_user(dirent->d_name, name, namlen);
+       put_user(0, dirent->d_name + namlen);
+       put_user(d_type, (char __user *)dirent + reclen - 1); 
+       dirent = ((void __user *)dirent) + reclen;
+       buf->current_dir = dirent;
+       buf->count -= reclen;
+       return 0;
+}
+
+asmlinkage long
+sys32_getdents (unsigned int fd, void __user * dirent, unsigned int count)
+{
+       struct file * file;
+       struct linux32_dirent __user * lastdirent;
+       struct getdents32_callback buf;
+       int error;
+
+       error = -EBADF;
+       file = fget(fd);
+       if (!file)
+               goto out;
+
+       buf.current_dir = (struct linux32_dirent __user *) dirent;
+       buf.previous = NULL;
+       buf.count = count;
+       buf.error = 0;
+
+       error = vfs_readdir(file, filldir32, &buf);
+       if (error < 0)
+               goto out_putf;
+       error = buf.error;
+       lastdirent = buf.previous;
+       if (lastdirent) {
+               put_user(file->f_pos, &lastdirent->d_off);
+               error = count - buf.count;
+       }
+
+out_putf:
+       fput(file);
+out:
+       return error;
+}
+
+static int
+fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t ino, unsigned d_type)
+{
+       struct readdir32_callback * buf = (struct readdir32_callback *) __buf;
+       struct old_linux32_dirent __user * dirent;
+
+       if (buf->count)
+               return -EINVAL;
+       buf->count++;
+       dirent = buf->dirent;
+       put_user(ino, &dirent->d_ino);
+       put_user(offset, &dirent->d_offset);
+       put_user(namlen, &dirent->d_namlen);
+       copy_to_user(dirent->d_name, name, namlen);
+       put_user(0, dirent->d_name + namlen);
+       return 0;
+}
+
+asmlinkage long
+sys32_oldreaddir (unsigned int fd, void __user * dirent, unsigned int count)
+{
+       int error;
+       struct file * file;
+       struct readdir32_callback buf;
+
+       error = -EBADF;
+       file = fget(fd);
+       if (!file)
+               goto out;
+
+       buf.count = 0;
+       buf.dirent = dirent;
+
+       error = vfs_readdir(file, fillonedir32, &buf);
+       if (error >= 0)
+               error = buf.count;
+       fput(file);
+out:
+       return error;
+}
+
 struct sel_arg_struct {
        unsigned int n;
        unsigned int inp;
@@ -995,6 +1129,9 @@ asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
                        return -EBADF;
        }
 
+       if (prot & PROT_READ)
+               prot |= vm_force_exec32;
+
        down_write(&mm->mmap_sem);
        error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
        up_write(&mm->mmap_sem);
@@ -1085,11 +1222,8 @@ asmlinkage long sys32_execve(char __user *name, compat_uptr_t __user *argv,
        if (IS_ERR(filename))
                return error;
        error = compat_do_execve(filename, argv, envp, regs);
-       if (error == 0) {
-               task_lock(current);
+       if (error == 0)
                current->ptrace &= ~PT_DTRACE;
-               task_unlock(current);
-       }
        putname(filename);
        return error;
 }
@@ -1144,6 +1278,90 @@ long sys32_kill(int pid, int sig)
        return sys_kill(pid, sig);
 }
  
+
+long sys32_io_setup(unsigned nr_reqs, u32 __user *ctx32p)
+{ 
+       long ret; 
+       aio_context_t ctx64;
+       mm_segment_t oldfs = get_fs();  
+       set_fs(KERNEL_DS); 
+       ret = sys_io_setup(nr_reqs, &ctx64); 
+       set_fs(oldfs); 
+       /* truncating is ok because it's a user address */
+       if (!ret) 
+               ret = put_user((u32)ctx64, ctx32p);
+       return ret;
+} 
+
+asmlinkage long sys32_io_submit(aio_context_t ctx_id, int nr,
+                  compat_uptr_t __user *iocbpp)
+{
+       struct kioctx *ctx;
+       long ret = 0;
+       int i;
+       
+       if (unlikely(nr < 0))
+               return -EINVAL;
+
+       if (unlikely(!access_ok(VERIFY_READ, iocbpp, (nr*sizeof(*iocbpp)))))
+               return -EFAULT;
+
+       ctx = lookup_ioctx(ctx_id);
+       if (unlikely(!ctx)) {
+               pr_debug("EINVAL: io_submit: invalid context id\n");
+               return -EINVAL; 
+       } 
+
+       for (i=0; i<nr; i++) {
+               compat_uptr_t p32;
+               struct iocb __user *user_iocb;
+               struct iocb tmp;
+
+               if (unlikely(__get_user(p32, iocbpp + i))) {
+                       ret = -EFAULT;
+                       break;
+               } 
+               user_iocb = compat_ptr(p32);
+
+               if (unlikely(copy_from_user(&tmp, user_iocb, sizeof(tmp)))) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               ret = io_submit_one(ctx, user_iocb, &tmp);
+               if (ret)
+                       break;
+       }
+
+       put_ioctx(ctx);
+       return i ? i : ret;
+}
+
+
+asmlinkage long sys32_io_getevents(aio_context_t ctx_id,
+                                unsigned long min_nr,
+                                unsigned long nr,
+                                struct io_event __user *events,
+                                struct compat_timespec __user *timeout)
+{      
+       long ret;
+       mm_segment_t oldfs; 
+       struct timespec t;
+       /* Harden against bogus ptrace */
+       if (nr >= 0xffffffff || 
+           !access_ok(VERIFY_WRITE, events, nr * sizeof(struct io_event)))
+               return -EFAULT;
+       if (timeout && get_compat_timespec(&t, timeout))
+               return -EFAULT; 
+       oldfs = get_fs();
+       set_fs(KERNEL_DS); 
+       ret = sys_io_getevents(ctx_id,min_nr,nr,events,timeout ? &t : NULL); 
+       set_fs(oldfs); 
+       if (!ret && timeout && put_compat_timespec(&t, timeout))
+               return -EFAULT;                 
+       return ret;
+} 
+
 asmlinkage long sys32_open(const char __user * filename, int flags, int mode)
 {
        char * tmp;
@@ -1215,7 +1433,19 @@ long sys32_vm86_warning(void)
        if (strncmp(lastcomm, me->comm, sizeof(lastcomm))) {
                printk(KERN_INFO "%s: vm86 mode not supported on 64 bit kernel\n",
                       me->comm);
-               strncpy(lastcomm, me->comm, sizeof(lastcomm));
+               strncpy(lastcomm, me->comm, sizeof(lastcomm)); 
+       } 
+       return -ENOSYS;
+} 
+
+long sys32_quotactl(void)
+{ 
+       struct task_struct *me = current;
+       static char lastcomm[8];
+       if (strcmp(lastcomm, me->comm)) {
+               printk(KERN_INFO "%s: 32bit quotactl not supported on 64 bit kernel\n",
+                      me->comm);
+               strcpy(lastcomm, me->comm); 
        } 
        return -ENOSYS;
 }