Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
[cascardo/linux.git] / fs / readdir.c
index e69ef3b..9d0212c 100644 (file)
 int iterate_dir(struct file *file, struct dir_context *ctx)
 {
        struct inode *inode = file_inode(file);
+       bool shared = false;
        int res = -ENOTDIR;
-       if (!file->f_op->iterate)
+       if (file->f_op->iterate_shared)
+               shared = true;
+       else if (!file->f_op->iterate)
                goto out;
 
        res = security_file_permission(file, MAY_READ);
        if (res)
                goto out;
 
-       res = mutex_lock_killable(&inode->i_mutex);
-       if (res)
-               goto out;
+       if (shared) {
+               inode_lock_shared(inode);
+       } else {
+               res = down_write_killable(&inode->i_rwsem);
+               if (res)
+                       goto out;
+       }
 
        res = -ENOENT;
        if (!IS_DEADDIR(inode)) {
                ctx->pos = file->f_pos;
-               res = file->f_op->iterate(file, ctx);
+               if (shared)
+                       res = file->f_op->iterate_shared(file, ctx);
+               else
+                       res = file->f_op->iterate(file, ctx);
                file->f_pos = ctx->pos;
                fsnotify_access(file);
                file_accessed(file);
        }
-       inode_unlock(inode);
+       if (shared)
+               inode_unlock_shared(inode);
+       else
+               inode_unlock(inode);
 out:
        return res;
 }
@@ -111,7 +124,7 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
                struct old_linux_dirent __user *, dirent, unsigned int, count)
 {
        int error;
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        struct readdir_callback buf = {
                .ctx.actor = fillonedir,
                .dirent = dirent
@@ -124,7 +137,7 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
        if (buf.result)
                error = buf.result;
 
-       fdput(f);
+       fdput_pos(f);
        return error;
 }
 
@@ -169,6 +182,8 @@ static int filldir(struct dir_context *ctx, const char *name, int namlen,
        }
        dirent = buf->previous;
        if (dirent) {
+               if (signal_pending(current))
+                       return -EINTR;
                if (__put_user(offset, &dirent->d_off))
                        goto efault;
        }
@@ -208,7 +223,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
        if (!access_ok(VERIFY_WRITE, dirent, count))
                return -EFAULT;
 
-       f = fdget(fd);
+       f = fdget_pos(fd);
        if (!f.file)
                return -EBADF;
 
@@ -222,7 +237,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
                else
                        error = count - buf.count;
        }
-       fdput(f);
+       fdput_pos(f);
        return error;
 }
 
@@ -248,6 +263,8 @@ static int filldir64(struct dir_context *ctx, const char *name, int namlen,
                return -EINVAL;
        dirent = buf->previous;
        if (dirent) {
+               if (signal_pending(current))
+                       return -EINTR;
                if (__put_user(offset, &dirent->d_off))
                        goto efault;
        }
@@ -289,7 +306,7 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
        if (!access_ok(VERIFY_WRITE, dirent, count))
                return -EFAULT;
 
-       f = fdget(fd);
+       f = fdget_pos(fd);
        if (!f.file)
                return -EBADF;
 
@@ -304,6 +321,6 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
                else
                        error = count - buf.count;
        }
-       fdput(f);
+       fdput_pos(f);
        return error;
 }