vserver 1.9.5.x5
[linux-2.6.git] / fs / fcntl.c
index c8c39b7..65c30d6 100644 (file)
@@ -4,6 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
+#include <linux/syscalls.h>
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/fs.h>
@@ -14,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/security.h>
 #include <linux/ptrace.h>
+#include <linux/vs_limit.h>
 
 #include <asm/poll.h>
 #include <asm/siginfo.h>
@@ -40,38 +42,6 @@ static inline int get_close_on_exec(unsigned int fd)
        return res;
 }
 
-
-/* Expand files.  Return <0 on error; 0 nothing done; 1 files expanded,
- * we may have blocked. 
- *
- * Should be called with the files->file_lock spinlock held for write.
- */
-static int expand_files(struct files_struct *files, int nr)
-{
-       int err, expand = 0;
-#ifdef FDSET_DEBUG     
-       printk (KERN_ERR "%s %d: nr = %d\n", __FUNCTION__, current->pid, nr);
-#endif
-       
-       if (nr >= files->max_fdset) {
-               expand = 1;
-               if ((err = expand_fdset(files, nr)))
-                       goto out;
-       }
-       if (nr >= files->max_fds) {
-               expand = 1;
-               if ((err = expand_fd_array(files, nr)))
-                       goto out;
-       }
-       err = expand;
- out:
-#ifdef FDSET_DEBUG     
-       if (err)
-               printk (KERN_ERR "%s %d: return %d\n", __FUNCTION__, current->pid, err);
-#endif
-       return err;
-}
-
 /*
  * locate_fd finds a free file descriptor in the open_fds fdset,
  * expanding the fd arrays if necessary.  Must be called with the
@@ -86,7 +56,7 @@ static int locate_fd(struct files_struct *files,
        int error;
 
        error = -EINVAL;
-       if (orig_start >= current->rlim[RLIMIT_NOFILE].rlim_cur)
+       if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
                goto out;
 
 repeat:
@@ -105,7 +75,7 @@ repeat:
        }
        
        error = -EMFILE;
-       if (newfd >= current->rlim[RLIMIT_NOFILE].rlim_cur)
+       if (newfd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
                goto out;
        if (!vx_files_avail(1))
                goto out;
@@ -164,7 +134,7 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd)
        if (newfd == oldfd)
                goto out_unlock;
        err = -EBADF;
-       if (newfd >= current->rlim[RLIMIT_NOFILE].rlim_cur)
+       if (newfd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
                goto out_unlock;
        get_file(file);                 /* We are now finished with oldfd */
 
@@ -189,10 +159,12 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd)
        FD_SET(newfd, files->open_fds);
        FD_CLR(newfd, files->close_on_exec);
        spin_unlock(&files->file_lock);
-       vx_openfd_inc(newfd);
 
        if (tofree)
                filp_close(tofree, files);
+       else
+               vx_openfd_inc(newfd);   /* fd was unused */
+
        err = newfd;
 out:
        return err;
@@ -216,7 +188,7 @@ asmlinkage long sys_dup(unsigned int fildes)
        return ret;
 }
 
-#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC | O_DIRECT)
+#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC | O_DIRECT | O_NOATIME)
 
 static int setfl(int fd, struct file * filp, unsigned long arg)
 {
@@ -227,6 +199,11 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
        if (!(arg & O_APPEND) && IS_APPEND(inode))
                return -EPERM;
 
+       /* O_NOATIME can only be set by the owner or superuser */
+       if ((arg & O_NOATIME) && !(filp->f_flags & O_NOATIME))
+               if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
+                       return -EPERM;
+
        /* required for strict SunOS emulation */
        if (O_NONBLOCK != O_NDELAY)
               if (arg & O_NDELAY)
@@ -238,6 +215,11 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
                                return -EINVAL;
        }
 
+       if (filp->f_op && filp->f_op->check_flags)
+               error = filp->f_op->check_flags(arg);
+       if (error)
+               return error;
+
        lock_kernel();
        if ((arg ^ filp->f_flags) & FASYNC) {
                if (filp->f_op && filp->f_op->fasync) {
@@ -284,10 +266,8 @@ void f_delown(struct file *filp)
        f_modown(filp, 0, 0, 0, 1);
 }
 
-EXPORT_SYMBOL(f_delown);
-
-long generic_file_fcntl(int fd, unsigned int cmd,
-                       unsigned long arg, struct file *filp)
+static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
+               struct file *filp)
 {
        long err = -EINVAL;
 
@@ -355,17 +335,8 @@ long generic_file_fcntl(int fd, unsigned int cmd,
        }
        return err;
 }
-EXPORT_SYMBOL(generic_file_fcntl);
 
-static long do_fcntl(int fd, unsigned int cmd,
-                       unsigned long arg, struct file *filp)
-{
-       if (filp->f_op && filp->f_op->fcntl)
-               return filp->f_op->fcntl(fd, cmd, arg, filp);
-       return generic_file_fcntl(fd, cmd, arg, filp);
-}
-
-asmlinkage long sys_fcntl(int fd, unsigned int cmd, unsigned long arg)
+asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {      
        struct file *filp;
        long err = -EBADF;
@@ -435,11 +406,12 @@ static long band_table[NSIGPOLL] = {
 };
 
 static inline int sigio_perm(struct task_struct *p,
-                             struct fown_struct *fown)
+                             struct fown_struct *fown, int sig)
 {
-       return ((fown->euid == 0) ||
-               (fown->euid == p->suid) || (fown->euid == p->uid) ||
-               (fown->uid == p->suid) || (fown->uid == p->uid));
+       return (((fown->euid == 0) ||
+                (fown->euid == p->suid) || (fown->euid == p->uid) ||
+                (fown->uid == p->suid) || (fown->uid == p->uid)) &&
+               !security_file_send_sigiotask(p, fown, sig));
 }
 
 static void send_sigio_to_task(struct task_struct *p,
@@ -447,10 +419,7 @@ static void send_sigio_to_task(struct task_struct *p,
                               int fd,
                               int reason)
 {
-       if (!sigio_perm(p, fown))
-               return;
-
-       if (security_file_send_sigiotask(p, fown, fd, reason))
+       if (!sigio_perm(p, fown, fown->signum))
                return;
 
        switch (fown->signum) {
@@ -495,16 +464,14 @@ void send_sigio(struct fown_struct *fown, int fd, int band)
        
        read_lock(&tasklist_lock);
        if (pid > 0) {
-               p = find_task_by_pid(pid);
+               p = find_task_by_real_pid(pid);
                if (p) {
                        send_sigio_to_task(p, fown, fd, band);
                }
        } else {
-               struct list_head *l;
-               struct pid *pidptr;
-               for_each_task_pid(-pid, PIDTYPE_PGID, p, l, pidptr) {
+               do_each_task_pid(-pid, PIDTYPE_PGID, p) {
                        send_sigio_to_task(p, fown, fd, band);
-               }
+               } while_each_task_pid(-pid, PIDTYPE_PGID, p);
        }
        read_unlock(&tasklist_lock);
  out_unlock_fown:
@@ -514,7 +481,7 @@ void send_sigio(struct fown_struct *fown, int fd, int band)
 static void send_sigurg_to_task(struct task_struct *p,
                                 struct fown_struct *fown)
 {
-       if (sigio_perm(p, fown))
+       if (sigio_perm(p, fown, SIGURG))
                send_group_sig_info(SIGURG, SEND_SIG_PRIV, p);
 }
 
@@ -532,16 +499,14 @@ int send_sigurg(struct fown_struct *fown)
        
        read_lock(&tasklist_lock);
        if (pid > 0) {
-               p = find_task_by_pid(pid);
+               p = find_task_by_real_pid(pid);
                if (p) {
                        send_sigurg_to_task(p, fown);
                }
        } else {
-               struct list_head *l;
-               struct pid *pidptr;
-               for_each_task_pid(-pid, PIDTYPE_PGID, p, l, pidptr) {
+               do_each_task_pid(-pid, PIDTYPE_PGID, p) {
                        send_sigurg_to_task(p, fown);
-               }
+               } while_each_task_pid(-pid, PIDTYPE_PGID, p);
        }
        read_unlock(&tasklist_lock);
  out_unlock_fown:
@@ -549,7 +514,7 @@ int send_sigurg(struct fown_struct *fown)
        return ret;
 }
 
-static rwlock_t fasync_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(fasync_lock);
 static kmem_cache_t *fasync_cache;
 
 /*
@@ -631,15 +596,12 @@ void kill_fasync(struct fasync_struct **fp, int sig, int band)
                read_unlock(&fasync_lock);
        }
 }
-
 EXPORT_SYMBOL(kill_fasync);
 
 static int __init fasync_init(void)
 {
        fasync_cache = kmem_cache_create("fasync_cache",
-               sizeof(struct fasync_struct), 0, 0, NULL, NULL);
-       if (!fasync_cache)
-               panic("cannot create fasync slab cache");
+               sizeof(struct fasync_struct), 0, SLAB_PANIC, NULL, NULL);
        return 0;
 }