Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 637e9cd0 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "filemap-drop-the-mmap_sem-for-all-blocking-operations-fix"

parents c08c6ed1 6834eced
Loading
Loading
Loading
Loading
+31 −14
Original line number Diff line number Diff line
@@ -2275,6 +2275,12 @@ static struct file *maybe_unlock_mmap_for_io(struct vm_fault *vmf,
	int flags = vmf->flags;
	if (fpin)
		return fpin;

	/*
	 * FAULT_FLAG_RETRY_NOWAIT means we don't want to wait on page locks or
	 * anything, so we only pin the file and drop the mmap_sem if only
	 * FAULT_FLAG_ALLOW_RETRY is set.
	 */
	if ((flags & (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_RETRY_NOWAIT)) ==
	    FAULT_FLAG_ALLOW_RETRY) {
		fpin = get_file(vmf->vma->vm_file);
@@ -2284,10 +2290,15 @@ static struct file *maybe_unlock_mmap_for_io(struct vm_fault *vmf,
}

/*
 * Works similar to lock_page_or_retry, except it will pin the file and drop the
 * mmap_sem if necessary and then lock the page, and return 1 in this case.
 * This means the caller needs to deal with the fpin appropriately.  0 return is
 * the same as in lock_page_or_retry.
 * lock_page_maybe_drop_mmap - lock the page, possibly dropping the mmap_sem
 * @vmf - the vm_fault for this fault.
 * @page - the page to lock.
 * @fpin - the pointer to the file we may pin (or is already pinned).
 *
 * This works similar to lock_page_or_retry in that it can drop the mmap_sem.
 * It differs in that it actually returns the page locked if it returns 1 and 0
 * if it couldn't lock the page.  If we did have to drop the mmap_sem then fpin
 * will point to the pinned file and needs to be fput()'ed at a later point.
 */
static int lock_page_maybe_drop_mmap(struct vm_fault *vmf, struct page *page,
				     struct file **fpin)
@@ -2295,9 +2306,10 @@ static int lock_page_maybe_drop_mmap(struct vm_fault *vmf, struct page *page,
	if (trylock_page(page))
		return 1;

	*fpin = maybe_unlock_mmap_for_io(vmf, *fpin);
	if (vmf->flags & FAULT_FLAG_RETRY_NOWAIT)
		return 0;

	*fpin = maybe_unlock_mmap_for_io(vmf, *fpin);
	if (vmf->flags & FAULT_FLAG_KILLABLE) {
		if (__lock_page_killable(page)) {
			/*
@@ -2317,8 +2329,11 @@ static int lock_page_maybe_drop_mmap(struct vm_fault *vmf, struct page *page,


/*
 * Synchronous readahead happens when we don't even find
 * a page in the page cache at all.
 * Synchronous readahead happens when we don't even find a page in the page
 * cache at all.  We don't want to perform IO under the mmap sem, so if we have
 * to drop the mmap sem we return the file that was pinned in order for us to do
 * that.  If we didn't pin a file then we return NULL.  The file that is
 * returned needs to be fput()'ed when we're done with it.
 */
static struct file *do_sync_mmap_readahead(struct vm_fault *vmf)
{
@@ -2365,7 +2380,8 @@ static struct file *do_sync_mmap_readahead(struct vm_fault *vmf)

/*
 * Asynchronous readahead happens when we find the page and PG_readahead,
 * so we want to possibly extend the readahead further..
 * so we want to possibly extend the readahead further.  We return the file that
 * was pinned if we have to drop the mmap_sem in order to do IO.
 */
static struct file *do_async_mmap_readahead(struct vm_fault *vmf,
					    struct page *page)
@@ -2441,23 +2457,24 @@ int filemap_fault(struct vm_fault *vmf)
		fpin = do_async_mmap_readahead(vmf, page);
	} else if (!page) {
		/* No page in the page cache at all */
		fpin = do_sync_mmap_readahead(vmf);
		count_vm_event(PGMAJFAULT);
		count_memcg_event_mm(vmf->vma->vm_mm, PGMAJFAULT);
		ret = VM_FAULT_MAJOR;
		fpin = do_sync_mmap_readahead(vmf);
retry_find:
		page = pagecache_get_page(mapping, offset,
					  FGP_CREAT|FGP_FOR_MMAP,
					  vmf->gfp_mask);
		if (!page)
		if (!page) {
			if (fpin)
				goto out_retry;
			return VM_FAULT_OOM;
		}

	if (!lock_page_maybe_drop_mmap(vmf, page, &fpin)) {
		put_page(page);
		return ret | VM_FAULT_RETRY;
	}

	if (!lock_page_maybe_drop_mmap(vmf, page, &fpin))
		goto out_retry;

	/* Did it get truncated? */
	if (unlikely(page->mapping != mapping)) {
		unlock_page(page);