Author: kib
Date: Wed Mar  1 10:22:07 2017
New Revision: 314486
URL: https://svnweb.freebsd.org/changeset/base/314486

Log:
  When deallocating the vm object in elf_map_insert() due to
  vm_map_insert() failure, drop the vnode lock around the call to
  vm_object_deallocate().
  
  Since the deallocated object is the vm object of the vnode, we might
  get the vnode lock recursion there.  In fact, it is almost impossible
  to make vm_map_insert() failing there on stock kernel.
  
  Tested by:    pho
  Sponsored by: The FreeBSD Foundation
  MFC after:    2 weeks

Modified:
  head/sys/kern/imgact_elf.c

Modified: head/sys/kern/imgact_elf.c
==============================================================================
--- head/sys/kern/imgact_elf.c  Wed Mar  1 09:05:12 2017        (r314485)
+++ head/sys/kern/imgact_elf.c  Wed Mar  1 10:22:07 2017        (r314486)
@@ -422,13 +422,14 @@ __elfN(map_partial)(vm_map_t map, vm_obj
 }
 
 static int
-__elfN(map_insert)(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
-    vm_offset_t start, vm_offset_t end, vm_prot_t prot, int cow)
+__elfN(map_insert)(struct image_params *imgp, vm_map_t map, vm_object_t object,
+    vm_ooffset_t offset, vm_offset_t start, vm_offset_t end, vm_prot_t prot,
+    int cow)
 {
        struct sf_buf *sf;
        vm_offset_t off;
        vm_size_t sz;
-       int error, rv;
+       int error, locked, rv;
 
        if (start != trunc_page(start)) {
                rv = __elfN(map_partial)(map, object, offset, start,
@@ -480,8 +481,12 @@ __elfN(map_insert)(vm_map_t map, vm_obje
                        rv = vm_map_insert(map, object, offset, start, end,
                            prot, VM_PROT_ALL, cow);
                        vm_map_unlock(map);
-                       if (rv != KERN_SUCCESS)
+                       if (rv != KERN_SUCCESS) {
+                               locked = VOP_ISLOCKED(imgp->vp);
+                               VOP_UNLOCK(imgp->vp, 0);
                                vm_object_deallocate(object);
+                               vn_lock(imgp->vp, locked | LK_RETRY);
+                       }
                }
                return (rv);
        } else {
@@ -538,7 +543,7 @@ __elfN(load_section)(struct image_params
                cow = MAP_COPY_ON_WRITE | MAP_PREFAULT |
                    (prot & VM_PROT_WRITE ? 0 : MAP_DISABLE_COREDUMP);
 
-               rv = __elfN(map_insert)(map,
+               rv = __elfN(map_insert)(imgp, map,
                                      object,
                                      file_addr,        /* file offset */
                                      map_addr,         /* virtual start */
@@ -568,8 +573,8 @@ __elfN(load_section)(struct image_params
 
        /* This had damn well better be true! */
        if (map_len != 0) {
-               rv = __elfN(map_insert)(map, NULL, 0, map_addr, map_addr +
-                   map_len, VM_PROT_ALL, 0);
+               rv = __elfN(map_insert)(imgp, map, NULL, 0, map_addr,
+                   map_addr + map_len, VM_PROT_ALL, 0);
                if (rv != KERN_SUCCESS) {
                        return (EINVAL);
                }
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to