From 84a795f90412ee575703476728f1522c06de4a2c Mon Sep 17 00:00:00 2001 From: Eric Mei Date: Wed, 22 Dec 2010 18:48:57 -0700 Subject: [PATCH] b=21122 fix a race between page fault and lock cancel. r=oleg.drokin r=vitaly.fertman --- lustre/llite/llite_mmap.c | 43 +++++++++++++++++++++++++++---------------- lustre/llite/vvp_io.c | 24 +++++++++++------------- lustre/obdclass/cl_page.c | 2 +- 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/lustre/llite/llite_mmap.c b/lustre/llite/llite_mmap.c index ae43a07..c955661 100644 --- a/lustre/llite/llite_mmap.c +++ b/lustre/llite/llite_mmap.c @@ -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; diff --git a/lustre/llite/vvp_io.c b/lustre/llite/vvp_io.c index 7ab7760..502ec4e 100644 --- a/lustre/llite/vvp_io.c +++ b/lustre/llite/vvp_io.c @@ -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); diff --git a/lustre/obdclass/cl_page.c b/lustre/obdclass/cl_page.c index 18c5ad3..926035e 100644 --- a/lustre/obdclass/cl_page.c +++ b/lustre/obdclass/cl_page.c @@ -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) { -- 1.8.3.1