diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-17 16:38:30 (GMT) |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-17 16:38:30 (GMT) |
commit | c397f8fa4379040bada53256c848e62c8b060392 (patch) | |
tree | 8101efb5c0c3b0a73e5e65f3474843c0914cc4d0 /mm/memory.c | |
parent | 796e1c55717e9a6ff5c81b12289ffa1ffd919b6f (diff) | |
parent | aaaf5fbf56f16c81a653713cc333b18ad6e25ea9 (diff) | |
download | linux-c397f8fa4379040bada53256c848e62c8b060392.tar.xz |
Merge branch 'akpm' (patches from Andrew)
Merge fifth set of updates from Andrew Morton:
- A few things which were awaiting merges from linux-next:
- rtc
- ocfs2
- misc others
- Willy's "dax" feature: direct fs access to memory (mainly NV-DIMMs)
which isn't backed by pageframes.
* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (37 commits)
rtc: add driver for DS1685 family of real time clocks
MAINTAINERS: add entry for Maxim PMICs on Samsung boards
lib/Kconfig: use bool instead of boolean
powerpc: drop _PAGE_FILE and pte_file()-related helpers
ocfs2: set append dio as a ro compat feature
ocfs2: wait for orphan recovery first once append O_DIRECT write crash
ocfs2: complete the rest request through buffer io
ocfs2: do not fallback to buffer I/O write if appending
ocfs2: allocate blocks in ocfs2_direct_IO_get_blocks
ocfs2: implement ocfs2_direct_IO_write
ocfs2: add orphan recovery types in ocfs2_recover_orphans
ocfs2: add functions to add and remove inode in orphan dir
ocfs2: prepare some interfaces used in append direct io
MAINTAINERS: fix spelling mistake & remove trailing WS
dax: does not work correctly with virtual aliasing caches
brd: rename XIP to DAX
ext4: add DAX functionality
dax: add dax_zero_page_range
ext2: get rid of most mentions of XIP in ext2
ext2: remove ext2_aops_xip
...
Diffstat (limited to 'mm/memory.c')
-rw-r--r-- | mm/memory.c | 42 |
1 files changed, 33 insertions, 9 deletions
diff --git a/mm/memory.c b/mm/memory.c index 9927532..8068893 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1965,6 +1965,7 @@ static int do_page_mkwrite(struct vm_area_struct *vma, struct page *page, vmf.pgoff = page->index; vmf.flags = FAULT_FLAG_WRITE|FAULT_FLAG_MKWRITE; vmf.page = page; + vmf.cow_page = NULL; ret = vma->vm_ops->page_mkwrite(vma, &vmf); if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE))) @@ -2329,6 +2330,7 @@ void unmap_mapping_range(struct address_space *mapping, details.last_index = ULONG_MAX; + /* DAX uses i_mmap_lock to serialise file truncate vs page fault */ i_mmap_lock_write(mapping); if (unlikely(!RB_EMPTY_ROOT(&mapping->i_mmap))) unmap_mapping_range_tree(&mapping->i_mmap, &details); @@ -2638,7 +2640,8 @@ oom: * See filemap_fault() and __lock_page_retry(). */ static int __do_fault(struct vm_area_struct *vma, unsigned long address, - pgoff_t pgoff, unsigned int flags, struct page **page) + pgoff_t pgoff, unsigned int flags, + struct page *cow_page, struct page **page) { struct vm_fault vmf; int ret; @@ -2647,10 +2650,13 @@ static int __do_fault(struct vm_area_struct *vma, unsigned long address, vmf.pgoff = pgoff; vmf.flags = flags; vmf.page = NULL; + vmf.cow_page = cow_page; ret = vma->vm_ops->fault(vma, &vmf); if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY))) return ret; + if (!vmf.page) + goto out; if (unlikely(PageHWPoison(vmf.page))) { if (ret & VM_FAULT_LOCKED) @@ -2664,6 +2670,7 @@ static int __do_fault(struct vm_area_struct *vma, unsigned long address, else VM_BUG_ON_PAGE(!PageLocked(vmf.page), vmf.page); + out: *page = vmf.page; return ret; } @@ -2834,7 +2841,7 @@ static int do_read_fault(struct mm_struct *mm, struct vm_area_struct *vma, pte_unmap_unlock(pte, ptl); } - ret = __do_fault(vma, address, pgoff, flags, &fault_page); + ret = __do_fault(vma, address, pgoff, flags, NULL, &fault_page); if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY))) return ret; @@ -2874,26 +2881,43 @@ static int do_cow_fault(struct mm_struct *mm, struct vm_area_struct *vma, return VM_FAULT_OOM; } - ret = __do_fault(vma, address, pgoff, flags, &fault_page); + ret = __do_fault(vma, address, pgoff, flags, new_page, &fault_page); if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY))) goto uncharge_out; - copy_user_highpage(new_page, fault_page, address, vma); + if (fault_page) + copy_user_highpage(new_page, fault_page, address, vma); __SetPageUptodate(new_page); pte = pte_offset_map_lock(mm, pmd, address, &ptl); if (unlikely(!pte_same(*pte, orig_pte))) { pte_unmap_unlock(pte, ptl); - unlock_page(fault_page); - page_cache_release(fault_page); + if (fault_page) { + unlock_page(fault_page); + page_cache_release(fault_page); + } else { + /* + * The fault handler has no page to lock, so it holds + * i_mmap_lock for read to protect against truncate. + */ + i_mmap_unlock_read(vma->vm_file->f_mapping); + } goto uncharge_out; } do_set_pte(vma, address, new_page, pte, true, true); mem_cgroup_commit_charge(new_page, memcg, false); lru_cache_add_active_or_unevictable(new_page, vma); pte_unmap_unlock(pte, ptl); - unlock_page(fault_page); - page_cache_release(fault_page); + if (fault_page) { + unlock_page(fault_page); + page_cache_release(fault_page); + } else { + /* + * The fault handler has no page to lock, so it holds + * i_mmap_lock for read to protect against truncate. + */ + i_mmap_unlock_read(vma->vm_file->f_mapping); + } return ret; uncharge_out: mem_cgroup_cancel_charge(new_page, memcg); @@ -2912,7 +2936,7 @@ static int do_shared_fault(struct mm_struct *mm, struct vm_area_struct *vma, int dirtied = 0; int ret, tmp; - ret = __do_fault(vma, address, pgoff, flags, &fault_page); + ret = __do_fault(vma, address, pgoff, flags, NULL, &fault_page); if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY))) return ret; |