Whamcloud - gitweb
b=21122 fix a race between page fault and lock cancel.
authorEric Mei <eric.mei@oracle.com>
Thu, 23 Dec 2010 01:48:57 +0000 (18:48 -0700)
committerVitaly Fertman <vitaly.fertman@oracle.com>
Thu, 23 Dec 2010 22:51:34 +0000 (01:51 +0300)
r=oleg.drokin
r=vitaly.fertman

lustre/llite/llite_mmap.c
lustre/llite/vvp_io.c
lustre/obdclass/cl_page.c

index ae43a07..c955661 100644 (file)
@@ -69,9 +69,6 @@
                vma->vm_file->f_dentry->d_inode->i_ino,                       \
                vma->vm_file->f_dentry->d_iname, ## arg);                     \
 
-struct page *ll_nopage(struct vm_area_struct *vma, unsigned long address,
-                       int *type);
-
 static struct vm_operations_struct ll_file_vm_ops;
 
 void policy_from_vma(ldlm_policy_data_t *policy,
@@ -206,8 +203,8 @@ struct page *ll_nopage(struct vm_area_struct *vma, unsigned long address,
         struct lu_env           *env;
         struct cl_env_nest      nest;
         struct cl_io            *io;
-        struct page             *page  = NOPAGE_SIGBUS;
-        struct vvp_io           *vio = NULL;
+        struct page             *page;
+        struct vvp_io           *vio;
         unsigned long           ra_flags;
         pgoff_t                 pg_offset;
         int                     result;
@@ -223,22 +220,27 @@ struct page *ll_nopage(struct vm_area_struct *vma, unsigned long address,
                 goto out_err;
 
         vio = vvp_env_io(env);
-
         vio->u.fault.ft_vma            = vma;
+        vio->u.fault.ft_vmpage         = NULL;
         vio->u.fault.nopage.ft_address = address;
         vio->u.fault.nopage.ft_type    = type;
 
         result = cl_io_loop(env, io);
 
-out_err:
-        if (result == 0) {
-                LASSERT(io->u.ci_fault.ft_page != NULL);
-                page = vio->u.fault.ft_vmpage;
-        } else {
-                if (result == -ENOMEM)
-                        page = NOPAGE_OOM;
+        page = vio->u.fault.ft_vmpage;
+        if (page != NULL) {
+                LASSERT(PageLocked(page));
+                unlock_page(page);
+
+                if (result != 0)
+                        page_cache_release(page);
         }
 
+        LASSERT(ergo(result == 0, io->u.ci_fault.ft_page != NULL));
+out_err:
+        if (result != 0)
+                page = result == -ENOMEM ? NOPAGE_OOM : NOPAGE_SIGBUS;
+
         vma->vm_flags &= ~VM_RAND_READ;
         vma->vm_flags |= ra_flags;
 
@@ -263,7 +265,7 @@ int ll_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
         struct lu_env           *env;
         struct cl_io            *io;
-        struct vvp_io           *vio = NULL;
+        struct vvp_io           *vio;
         unsigned long            ra_flags;
         struct cl_env_nest       nest;
         int                      result;
@@ -279,13 +281,22 @@ int ll_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                 goto out_err;
 
         vio = vvp_env_io(env);
-
         vio->u.fault.ft_vma       = vma;
+        vio->u.fault.ft_vmpage    = NULL;
         vio->u.fault.fault.ft_vmf = vmf;
 
         result = cl_io_loop(env, io);
-        fault_ret = vio->u.fault.fault.ft_flags;
+        if (unlikely(result != 0 && vio->u.fault.ft_vmpage != NULL)) {
+                struct page *vmpage = vio->u.fault.ft_vmpage;
+
+                LASSERT((vio->u.fault.fault.ft_flags & VM_FAULT_LOCKED) &&
+                        PageLocked(vmpage));
+                unlock_page(vmpage);
+                page_cache_release(vmpage);
+                vmf->page = NULL;
+        }
 
+        fault_ret = vio->u.fault.fault.ft_flags;
 out_err:
         if (result != 0)
                 fault_ret |= VM_FAULT_ERROR;
index 7ab7760..502ec4e 100644 (file)
@@ -634,6 +634,14 @@ static int vvp_io_kernel_fault(struct vvp_fault_io *cfio)
         LL_CDEBUG_PAGE(D_PAGE, vmpage, "got addr %lu type %lx\n",
                        cfio->nopage.ft_address, (long)cfio->nopage.ft_type);
 
+        lock_page(vmpage);
+        if (vmpage->mapping == NULL) {
+                CERROR("vmpage %lu@%p was truncated!\n", vmpage->index, vmpage);
+                unlock_page(vmpage);
+                page_cache_release(vmpage);
+                return -EFAULT;
+        }
+
         cfio->ft_vmpage = vmpage;
 
         return 0;
@@ -647,12 +655,7 @@ static int vvp_io_kernel_fault(struct vvp_fault_io *cfio)
                 LL_CDEBUG_PAGE(D_PAGE, cfio->fault.ft_vmf->page,
                                "got addr %p type NOPAGE\n",
                                cfio->fault.ft_vmf->virtual_address);
-                /*XXX workaround to bug in CLIO - he deadlocked with
-                 lock cancel if page locked  */
-                if (likely(cfio->fault.ft_flags & VM_FAULT_LOCKED)) {
-                        unlock_page(cfio->fault.ft_vmf->page);
-                        cfio->fault.ft_flags &= ~VM_FAULT_LOCKED;
-                }
+                LASSERT(cfio->fault.ft_flags & VM_FAULT_LOCKED);
 
                 cfio->ft_vmpage = cfio->fault.ft_vmf->page;
                 return 0;
@@ -709,16 +712,11 @@ static int vvp_io_fault_start(const struct lu_env *env,
         kernel_result = vvp_io_kernel_fault(cfio);
         if (kernel_result != 0)
                 return kernel_result;
-        /* Temporarily lock vmpage to keep cl_page_find() happy. */
-        lock_page(cfio->ft_vmpage);
+
         page = cl_page_find(env, obj, fio->ft_index, cfio->ft_vmpage,
                             CPT_CACHEABLE);
-        unlock_page(cfio->ft_vmpage);
-        if (IS_ERR(page)) {
-                page_cache_release(cfio->ft_vmpage);
-                cfio->ft_vmpage = NULL;
+        if (IS_ERR(page))
                 return PTR_ERR(page);
-        }
 
         size = i_size_read(inode);
         last = cl_index(obj, size - 1);
index 18c5ad3..926035e 100644 (file)
@@ -412,7 +412,7 @@ static struct cl_page *cl_page_find0(const struct lu_env *env,
         hdr = cl_object_header(o);
         cfs_atomic_inc(&site->cs_pages.cs_lookup);
 
-        CDEBUG(D_PAGE, "%lu@"DFID" %p %lu %d\n",
+        CDEBUG(D_PAGE, "%lu@"DFID" %p %lx %d\n",
                idx, PFID(&hdr->coh_lu.loh_fid), vmpage, vmpage->private, type);
         /* fast path. */
         if (type == CPT_CACHEABLE) {