]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/file.c
MAINTAINERS: fix indentation for Viresh Kumar
[karo-tx-linux.git] / fs / file.c
index 7f29544755d04324fe5a45d892b798330b96b239..0f1bda4bebfaa77280a1234a2b8e19edb4b8d94b 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -238,7 +238,7 @@ static int expand_fdtable(struct files_struct *files, int nr)
  * expanded and execution may have blocked.
  * The files->file_lock should be held on entry, and will be held on exit.
  */
-int expand_files(struct files_struct *files, int nr)
+static int expand_files(struct files_struct *files, int nr)
 {
        struct fdtable *fdt;
 
@@ -256,6 +256,26 @@ int expand_files(struct files_struct *files, int nr)
        return expand_fdtable(files, nr);
 }
 
+static inline void __set_close_on_exec(int fd, struct fdtable *fdt)
+{
+       __set_bit(fd, fdt->close_on_exec);
+}
+
+static inline void __clear_close_on_exec(int fd, struct fdtable *fdt)
+{
+       __clear_bit(fd, fdt->close_on_exec);
+}
+
+static inline void __set_open_fd(int fd, struct fdtable *fdt)
+{
+       __set_bit(fd, fdt->open_fds);
+}
+
+static inline void __clear_open_fd(int fd, struct fdtable *fdt)
+{
+       __clear_bit(fd, fdt->open_fds);
+}
+
 static int count_open_files(struct fdtable *fdt)
 {
        int size = fdt->max_fds;
@@ -499,6 +519,12 @@ struct files_struct init_files = {
        .file_lock      = __SPIN_LOCK_UNLOCKED(init_task.file_lock),
 };
 
+void daemonize_descriptors(void)
+{
+       atomic_inc(&init_files.count);
+       reset_files_struct(&init_files);
+}
+
 /*
  * allocate a file descriptor, mark it busy.
  */
@@ -560,7 +586,7 @@ out:
        return error;
 }
 
-int alloc_fd(unsigned start, unsigned flags)
+static int alloc_fd(unsigned start, unsigned flags)
 {
        return __alloc_fd(current->files, start, rlimit(RLIMIT_NOFILE), flags);
 }
@@ -771,6 +797,7 @@ struct file *fget_light(unsigned int fd, int *fput_needed)
 
        return file;
 }
+EXPORT_SYMBOL(fget_light);
 
 struct file *fget_raw_light(unsigned int fd, int *fput_needed)
 {
@@ -821,29 +848,12 @@ bool get_close_on_exec(unsigned int fd)
        return res;
 }
 
-SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags)
+static int do_dup2(struct files_struct *files,
+       struct file *file, unsigned fd, unsigned flags)
 {
-       int err = -EBADF;
-       struct file * file, *tofree;
-       struct files_struct * files = current->files;
+       struct file *tofree;
        struct fdtable *fdt;
 
-       if ((flags & ~O_CLOEXEC) != 0)
-               return -EINVAL;
-
-       if (newfd >= rlimit(RLIMIT_NOFILE))
-               return -EMFILE;
-
-       spin_lock(&files->file_lock);
-       err = expand_files(files, newfd);
-       file = fcheck(oldfd);
-       if (unlikely(!file))
-               goto Ebadf;
-       if (unlikely(err < 0)) {
-               if (err == -EMFILE)
-                       goto Ebadf;
-               goto out_unlock;
-       }
        /*
         * We need to detect attempts to do dup2() over allocated but still
         * not finished descriptor.  NB: OpenBSD avoids that at the price of
@@ -858,24 +868,74 @@ SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags)
         * scope of POSIX or SUS, since neither considers shared descriptor
         * tables and this condition does not arise without those.
         */
-       err = -EBUSY;
        fdt = files_fdtable(files);
-       tofree = fdt->fd[newfd];
-       if (!tofree && fd_is_open(newfd, fdt))
-               goto out_unlock;
+       tofree = fdt->fd[fd];
+       if (!tofree && fd_is_open(fd, fdt))
+               goto Ebusy;
        get_file(file);
-       rcu_assign_pointer(fdt->fd[newfd], file);
-       __set_open_fd(newfd, fdt);
+       rcu_assign_pointer(fdt->fd[fd], file);
+       __set_open_fd(fd, fdt);
        if (flags & O_CLOEXEC)
-               __set_close_on_exec(newfd, fdt);
+               __set_close_on_exec(fd, fdt);
        else
-               __clear_close_on_exec(newfd, fdt);
+               __clear_close_on_exec(fd, fdt);
        spin_unlock(&files->file_lock);
 
        if (tofree)
                filp_close(tofree, files);
 
-       return newfd;
+       return fd;
+
+Ebusy:
+       spin_unlock(&files->file_lock);
+       return -EBUSY;
+}
+
+int replace_fd(unsigned fd, struct file *file, unsigned flags)
+{
+       int err;
+       struct files_struct *files = current->files;
+
+       if (!file)
+               return __close_fd(files, fd);
+
+       if (fd >= rlimit(RLIMIT_NOFILE))
+               return -EMFILE;
+
+       spin_lock(&files->file_lock);
+       err = expand_files(files, fd);
+       if (unlikely(err < 0))
+               goto out_unlock;
+       return do_dup2(files, file, fd, flags);
+
+out_unlock:
+       spin_unlock(&files->file_lock);
+       return err;
+}
+
+SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags)
+{
+       int err = -EBADF;
+       struct file *file;
+       struct files_struct *files = current->files;
+
+       if ((flags & ~O_CLOEXEC) != 0)
+               return -EINVAL;
+
+       if (newfd >= rlimit(RLIMIT_NOFILE))
+               return -EMFILE;
+
+       spin_lock(&files->file_lock);
+       err = expand_files(files, newfd);
+       file = fcheck(oldfd);
+       if (unlikely(!file))
+               goto Ebadf;
+       if (unlikely(err < 0)) {
+               if (err == -EMFILE)
+                       goto Ebadf;
+               goto out_unlock;
+       }
+       return do_dup2(files, file, newfd, flags);
 
 Ebadf:
        err = -EBADF;
@@ -926,3 +986,24 @@ int f_dupfd(unsigned int from, struct file *file, unsigned flags)
        }
        return err;
 }
+
+int iterate_fd(struct files_struct *files, unsigned n,
+               int (*f)(const void *, struct file *, unsigned),
+               const void *p)
+{
+       struct fdtable *fdt;
+       struct file *file;
+       int res = 0;
+       if (!files)
+               return 0;
+       spin_lock(&files->file_lock);
+       fdt = files_fdtable(files);
+       while (!res && n < fdt->max_fds) {
+               file = rcu_dereference_check_fdtable(files, fdt->fd[n++]);
+               if (file)
+                       res = f(p, file, n);
+       }
+       spin_unlock(&files->file_lock);
+       return res;
+}
+EXPORT_SYMBOL(iterate_fd);