proc: use down_read_killable mmap_sem for /proc/pid/map_files
authorKonstantin Khlebnikov <[email protected]>
Fri, 12 Jul 2019 04:00:03 +0000 (21:00 -0700)
committerLinus Torvalds <[email protected]>
Fri, 12 Jul 2019 18:05:47 +0000 (11:05 -0700)
Do not remain stuck forever if something goes wrong.  Using a killable
lock permits cleanup of stuck tasks and simplifies investigation.

It seems ->d_revalidate() could return any error (except ECHILD) to abort
validation and pass error as result of lookup sequence.

[[email protected]: fix proc_map_files_lookup() return value, per Andrei]
Link: http://lkml.kernel.org/r/156007493995.3335.9595044802115356911.stgit@buzz
Signed-off-by: Konstantin Khlebnikov <[email protected]>
Reviewed-by: Roman Gushchin <[email protected]>
Reviewed-by: Cyrill Gorcunov <[email protected]>
Reviewed-by: Kirill Tkhai <[email protected]>
Acked-by: Michal Hocko <[email protected]>
Cc: Alexey Dobriyan <[email protected]>
Cc: Al Viro <[email protected]>
Cc: Matthew Wilcox <[email protected]>
Cc: Michal Koutný <[email protected]>
Cc: Oleg Nesterov <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
fs/proc/base.c

index c40fca98f2b78ca6505ef9e9a635c1884fb27371..534fb1ae498aabade3c22228ed6b960d18ed05cc 100644 (file)
@@ -1962,9 +1962,12 @@ static int map_files_d_revalidate(struct dentry *dentry, unsigned int flags)
                goto out;
 
        if (!dname_to_vma_addr(dentry, &vm_start, &vm_end)) {
-               down_read(&mm->mmap_sem);
-               exact_vma_exists = !!find_exact_vma(mm, vm_start, vm_end);
-               up_read(&mm->mmap_sem);
+               status = down_read_killable(&mm->mmap_sem);
+               if (!status) {
+                       exact_vma_exists = !!find_exact_vma(mm, vm_start,
+                                                           vm_end);
+                       up_read(&mm->mmap_sem);
+               }
        }
 
        mmput(mm);
@@ -2010,8 +2013,11 @@ static int map_files_get_link(struct dentry *dentry, struct path *path)
        if (rc)
                goto out_mmput;
 
+       rc = down_read_killable(&mm->mmap_sem);
+       if (rc)
+               goto out_mmput;
+
        rc = -ENOENT;
-       down_read(&mm->mmap_sem);
        vma = find_exact_vma(mm, vm_start, vm_end);
        if (vma && vma->vm_file) {
                *path = vma->vm_file->f_path;
@@ -2107,7 +2113,11 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
        if (!mm)
                goto out_put_task;
 
-       down_read(&mm->mmap_sem);
+       result = ERR_PTR(-EINTR);
+       if (down_read_killable(&mm->mmap_sem))
+               goto out_put_mm;
+
+       result = ERR_PTR(-ENOENT);
        vma = find_exact_vma(mm, vm_start, vm_end);
        if (!vma)
                goto out_no_vma;
@@ -2118,6 +2128,7 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
 
 out_no_vma:
        up_read(&mm->mmap_sem);
+out_put_mm:
        mmput(mm);
 out_put_task:
        put_task_struct(task);
@@ -2160,7 +2171,12 @@ proc_map_files_readdir(struct file *file, struct dir_context *ctx)
        mm = get_task_mm(task);
        if (!mm)
                goto out_put_task;
-       down_read(&mm->mmap_sem);
+
+       ret = down_read_killable(&mm->mmap_sem);
+       if (ret) {
+               mmput(mm);
+               goto out_put_task;
+       }
 
        nr_files = 0;