You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
page cache: use xa_lock
Remove the address_space ->tree_lock and use the xa_lock newly added to the radix_tree_root. Rename the address_space ->page_tree to ->i_pages, since we don't really care that it's a tree. [willy@infradead.org: fix nds32, fs/dax.c] Link: http://lkml.kernel.org/r/20180406145415.GB20605@bombadil.infradead.orgLink: http://lkml.kernel.org/r/20180313132639.17387-9-willy@infradead.org Signed-off-by: Matthew Wilcox <mawilcox@microsoft.com> Acked-by: Jeff Layton <jlayton@redhat.com> Cc: Darrick J. Wong <darrick.wong@oracle.com> Cc: Dave Chinner <david@fromorbit.com> Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> Cc: Will Deacon <will.deacon@arm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
committed by
Linus Torvalds
parent
f6bb2a2c0b
commit
b93b016313
@@ -262,7 +262,7 @@ When oom event notifier is registered, event will be delivered.
|
||||
2.6 Locking
|
||||
|
||||
lock_page_cgroup()/unlock_page_cgroup() should not be called under
|
||||
mapping->tree_lock.
|
||||
the i_pages lock.
|
||||
|
||||
Other lock order is following:
|
||||
PG_locked.
|
||||
|
||||
@@ -90,7 +90,7 @@ Steps:
|
||||
|
||||
1. Lock the page to be migrated
|
||||
|
||||
2. Insure that writeback is complete.
|
||||
2. Ensure that writeback is complete.
|
||||
|
||||
3. Lock the new page that we want to move to. It is locked so that accesses to
|
||||
this (not yet uptodate) page immediately lock while the move is in progress.
|
||||
@@ -100,8 +100,8 @@ Steps:
|
||||
mapcount is not zero then we do not migrate the page. All user space
|
||||
processes that attempt to access the page will now wait on the page lock.
|
||||
|
||||
5. The radix tree lock is taken. This will cause all processes trying
|
||||
to access the page via the mapping to block on the radix tree spinlock.
|
||||
5. The i_pages lock is taken. This will cause all processes trying
|
||||
to access the page via the mapping to block on the spinlock.
|
||||
|
||||
6. The refcount of the page is examined and we back out if references remain
|
||||
otherwise we know that we are the only one referencing this page.
|
||||
@@ -114,12 +114,12 @@ Steps:
|
||||
|
||||
9. The radix tree is changed to point to the new page.
|
||||
|
||||
10. The reference count of the old page is dropped because the radix tree
|
||||
10. The reference count of the old page is dropped because the address space
|
||||
reference is gone. A reference to the new page is established because
|
||||
the new page is referenced to by the radix tree.
|
||||
the new page is referenced by the address space.
|
||||
|
||||
11. The radix tree lock is dropped. With that lookups in the mapping
|
||||
become possible again. Processes will move from spinning on the tree_lock
|
||||
11. The i_pages lock is dropped. With that lookups in the mapping
|
||||
become possible again. Processes will move from spinning on the lock
|
||||
to sleeping on the locked new page.
|
||||
|
||||
12. The page contents are copied to the new page.
|
||||
|
||||
@@ -318,10 +318,8 @@ static inline void flush_anon_page(struct vm_area_struct *vma,
|
||||
#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
|
||||
extern void flush_kernel_dcache_page(struct page *);
|
||||
|
||||
#define flush_dcache_mmap_lock(mapping) \
|
||||
spin_lock_irq(&(mapping)->tree_lock)
|
||||
#define flush_dcache_mmap_unlock(mapping) \
|
||||
spin_unlock_irq(&(mapping)->tree_lock)
|
||||
#define flush_dcache_mmap_lock(mapping) xa_lock_irq(&mapping->i_pages)
|
||||
#define flush_dcache_mmap_unlock(mapping) xa_unlock_irq(&mapping->i_pages)
|
||||
|
||||
#define flush_icache_user_range(vma,page,addr,len) \
|
||||
flush_dcache_page(page)
|
||||
|
||||
@@ -34,8 +34,8 @@ void flush_anon_page(struct vm_area_struct *vma,
|
||||
void flush_kernel_dcache_page(struct page *page);
|
||||
void flush_icache_range(unsigned long start, unsigned long end);
|
||||
void flush_icache_page(struct vm_area_struct *vma, struct page *page);
|
||||
#define flush_dcache_mmap_lock(mapping) spin_lock_irq(&(mapping)->tree_lock)
|
||||
#define flush_dcache_mmap_unlock(mapping) spin_unlock_irq(&(mapping)->tree_lock)
|
||||
#define flush_dcache_mmap_lock(mapping) xa_lock_irq(&(mapping)->i_pages)
|
||||
#define flush_dcache_mmap_unlock(mapping) xa_unlock_irq(&(mapping)->i_pages)
|
||||
|
||||
#else
|
||||
#include <asm-generic/cacheflush.h>
|
||||
|
||||
@@ -46,9 +46,7 @@ extern void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
|
||||
extern void flush_dcache_range(unsigned long start, unsigned long end);
|
||||
extern void invalidate_dcache_range(unsigned long start, unsigned long end);
|
||||
|
||||
#define flush_dcache_mmap_lock(mapping) \
|
||||
spin_lock_irq(&(mapping)->tree_lock)
|
||||
#define flush_dcache_mmap_unlock(mapping) \
|
||||
spin_unlock_irq(&(mapping)->tree_lock)
|
||||
#define flush_dcache_mmap_lock(mapping) xa_lock_irq(&mapping->i_pages)
|
||||
#define flush_dcache_mmap_unlock(mapping) xa_unlock_irq(&mapping->i_pages)
|
||||
|
||||
#endif /* _ASM_NIOS2_CACHEFLUSH_H */
|
||||
|
||||
@@ -55,10 +55,8 @@ void invalidate_kernel_vmap_range(void *vaddr, int size);
|
||||
#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
|
||||
extern void flush_dcache_page(struct page *page);
|
||||
|
||||
#define flush_dcache_mmap_lock(mapping) \
|
||||
spin_lock_irq(&(mapping)->tree_lock)
|
||||
#define flush_dcache_mmap_unlock(mapping) \
|
||||
spin_unlock_irq(&(mapping)->tree_lock)
|
||||
#define flush_dcache_mmap_lock(mapping) xa_lock_irq(&mapping->i_pages)
|
||||
#define flush_dcache_mmap_unlock(mapping) xa_unlock_irq(&mapping->i_pages)
|
||||
|
||||
#define flush_icache_page(vma,page) do { \
|
||||
flush_kernel_dcache_page(page); \
|
||||
|
||||
@@ -69,7 +69,7 @@ blkcnt_t dirty_cnt(struct inode *inode)
|
||||
void *results[1];
|
||||
|
||||
if (inode->i_mapping)
|
||||
cnt += radix_tree_gang_lookup_tag(&inode->i_mapping->page_tree,
|
||||
cnt += radix_tree_gang_lookup_tag(&inode->i_mapping->i_pages,
|
||||
results, 0, 1,
|
||||
PAGECACHE_TAG_DIRTY);
|
||||
if (cnt == 0 && atomic_read(&vob->vob_mmap_cnt) > 0)
|
||||
|
||||
@@ -934,14 +934,14 @@ static struct page *mdc_page_locate(struct address_space *mapping, __u64 *hash,
|
||||
struct page *page;
|
||||
int found;
|
||||
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
found = radix_tree_gang_lookup(&mapping->page_tree,
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
found = radix_tree_gang_lookup(&mapping->i_pages,
|
||||
(void **)&page, offset, 1);
|
||||
if (found > 0 && !radix_tree_exceptional_entry(page)) {
|
||||
struct lu_dirpage *dp;
|
||||
|
||||
get_page(page);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
/*
|
||||
* In contrast to find_lock_page() we are sure that directory
|
||||
* page cannot be truncated (while DLM lock is held) and,
|
||||
@@ -989,7 +989,7 @@ static struct page *mdc_page_locate(struct address_space *mapping, __u64 *hash,
|
||||
page = ERR_PTR(-EIO);
|
||||
}
|
||||
} else {
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
page = NULL;
|
||||
}
|
||||
return page;
|
||||
|
||||
+5
-4
@@ -570,10 +570,11 @@ static int afs_writepages_region(struct address_space *mapping,
|
||||
|
||||
_debug("wback %lx", page->index);
|
||||
|
||||
/* at this point we hold neither mapping->tree_lock nor lock on
|
||||
* the page itself: the page may be truncated or invalidated
|
||||
* (changing page->mapping to NULL), or even swizzled back from
|
||||
* swapper_space to tmpfs file mapping
|
||||
/*
|
||||
* at this point we hold neither the i_pages lock nor the
|
||||
* page lock: the page may be truncated or invalidated
|
||||
* (changing page->mapping to NULL), or even swizzled
|
||||
* back from swapper_space to tmpfs file mapping
|
||||
*/
|
||||
ret = lock_page_killable(page);
|
||||
if (ret < 0) {
|
||||
|
||||
@@ -458,7 +458,7 @@ static noinline int add_ra_bio_pages(struct inode *inode,
|
||||
break;
|
||||
|
||||
rcu_read_lock();
|
||||
page = radix_tree_lookup(&mapping->page_tree, pg_index);
|
||||
page = radix_tree_lookup(&mapping->i_pages, pg_index);
|
||||
rcu_read_unlock();
|
||||
if (page && !radix_tree_exceptional_entry(page)) {
|
||||
misses++;
|
||||
|
||||
@@ -3963,11 +3963,11 @@ retry:
|
||||
|
||||
done_index = page->index;
|
||||
/*
|
||||
* At this point we hold neither mapping->tree_lock nor
|
||||
* lock on the page itself: the page may be truncated or
|
||||
* invalidated (changing page->mapping to NULL), or even
|
||||
* swizzled back from swapper_space to tmpfs file
|
||||
* mapping
|
||||
* At this point we hold neither the i_pages lock nor
|
||||
* the page lock: the page may be truncated or
|
||||
* invalidated (changing page->mapping to NULL),
|
||||
* or even swizzled back from swapper_space to
|
||||
* tmpfs file mapping
|
||||
*/
|
||||
if (!trylock_page(page)) {
|
||||
flush_write_bio(epd);
|
||||
@@ -5174,13 +5174,13 @@ void clear_extent_buffer_dirty(struct extent_buffer *eb)
|
||||
WARN_ON(!PagePrivate(page));
|
||||
|
||||
clear_page_dirty_for_io(page);
|
||||
spin_lock_irq(&page->mapping->tree_lock);
|
||||
xa_lock_irq(&page->mapping->i_pages);
|
||||
if (!PageDirty(page)) {
|
||||
radix_tree_tag_clear(&page->mapping->page_tree,
|
||||
radix_tree_tag_clear(&page->mapping->i_pages,
|
||||
page_index(page),
|
||||
PAGECACHE_TAG_DIRTY);
|
||||
}
|
||||
spin_unlock_irq(&page->mapping->tree_lock);
|
||||
xa_unlock_irq(&page->mapping->i_pages);
|
||||
ClearPageError(page);
|
||||
unlock_page(page);
|
||||
}
|
||||
|
||||
+6
-7
@@ -185,10 +185,9 @@ EXPORT_SYMBOL(end_buffer_write_sync);
|
||||
* we get exclusion from try_to_free_buffers with the blockdev mapping's
|
||||
* private_lock.
|
||||
*
|
||||
* Hack idea: for the blockdev mapping, i_bufferlist_lock contention
|
||||
* Hack idea: for the blockdev mapping, private_lock contention
|
||||
* may be quite high. This code could TryLock the page, and if that
|
||||
* succeeds, there is no need to take private_lock. (But if
|
||||
* private_lock is contended then so is mapping->tree_lock).
|
||||
* succeeds, there is no need to take private_lock.
|
||||
*/
|
||||
static struct buffer_head *
|
||||
__find_get_block_slow(struct block_device *bdev, sector_t block)
|
||||
@@ -599,14 +598,14 @@ void __set_page_dirty(struct page *page, struct address_space *mapping,
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&mapping->tree_lock, flags);
|
||||
xa_lock_irqsave(&mapping->i_pages, flags);
|
||||
if (page->mapping) { /* Race with truncate? */
|
||||
WARN_ON_ONCE(warn && !PageUptodate(page));
|
||||
account_page_dirtied(page, mapping);
|
||||
radix_tree_tag_set(&mapping->page_tree,
|
||||
radix_tree_tag_set(&mapping->i_pages,
|
||||
page_index(page), PAGECACHE_TAG_DIRTY);
|
||||
}
|
||||
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||||
xa_unlock_irqrestore(&mapping->i_pages, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__set_page_dirty);
|
||||
|
||||
@@ -1096,7 +1095,7 @@ __getblk_slow(struct block_device *bdev, sector_t block,
|
||||
* inode list.
|
||||
*
|
||||
* mark_buffer_dirty() is atomic. It takes bh->b_page->mapping->private_lock,
|
||||
* mapping->tree_lock and mapping->host->i_lock.
|
||||
* i_pages lock and mapping->host->i_lock.
|
||||
*/
|
||||
void mark_buffer_dirty(struct buffer_head *bh)
|
||||
{
|
||||
|
||||
+4
-5
@@ -1987,11 +1987,10 @@ wdata_prepare_pages(struct cifs_writedata *wdata, unsigned int found_pages,
|
||||
for (i = 0; i < found_pages; i++) {
|
||||
page = wdata->pages[i];
|
||||
/*
|
||||
* At this point we hold neither mapping->tree_lock nor
|
||||
* lock on the page itself: the page may be truncated or
|
||||
* invalidated (changing page->mapping to NULL), or even
|
||||
* swizzled back from swapper_space to tmpfs file
|
||||
* mapping
|
||||
* At this point we hold neither the i_pages lock nor the
|
||||
* page lock: the page may be truncated or invalidated
|
||||
* (changing page->mapping to NULL), or even swizzled
|
||||
* back from swapper_space to tmpfs file mapping
|
||||
*/
|
||||
|
||||
if (nr_pages == 0)
|
||||
|
||||
@@ -158,11 +158,9 @@ static int wake_exceptional_entry_func(wait_queue_entry_t *wait, unsigned int mo
|
||||
}
|
||||
|
||||
/*
|
||||
* We do not necessarily hold the mapping->tree_lock when we call this
|
||||
* function so it is possible that 'entry' is no longer a valid item in the
|
||||
* radix tree. This is okay because all we really need to do is to find the
|
||||
* correct waitqueue where tasks might be waiting for that old 'entry' and
|
||||
* wake them.
|
||||
* @entry may no longer be the entry at the index in the mapping.
|
||||
* The important information it's conveying is whether the entry at
|
||||
* this index used to be a PMD entry.
|
||||
*/
|
||||
static void dax_wake_mapping_entry_waiter(struct address_space *mapping,
|
||||
pgoff_t index, void *entry, bool wake_all)
|
||||
@@ -174,7 +172,7 @@ static void dax_wake_mapping_entry_waiter(struct address_space *mapping,
|
||||
|
||||
/*
|
||||
* Checking for locked entry and prepare_to_wait_exclusive() happens
|
||||
* under mapping->tree_lock, ditto for entry handling in our callers.
|
||||
* under the i_pages lock, ditto for entry handling in our callers.
|
||||
* So at this point all tasks that could have seen our entry locked
|
||||
* must be in the waitqueue and the following check will see them.
|
||||
*/
|
||||
@@ -183,41 +181,39 @@ static void dax_wake_mapping_entry_waiter(struct address_space *mapping,
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the given slot is locked. The function must be called with
|
||||
* mapping->tree_lock held
|
||||
* Check whether the given slot is locked. Must be called with the i_pages
|
||||
* lock held.
|
||||
*/
|
||||
static inline int slot_locked(struct address_space *mapping, void **slot)
|
||||
{
|
||||
unsigned long entry = (unsigned long)
|
||||
radix_tree_deref_slot_protected(slot, &mapping->tree_lock);
|
||||
radix_tree_deref_slot_protected(slot, &mapping->i_pages.xa_lock);
|
||||
return entry & RADIX_DAX_ENTRY_LOCK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark the given slot is locked. The function must be called with
|
||||
* mapping->tree_lock held
|
||||
* Mark the given slot as locked. Must be called with the i_pages lock held.
|
||||
*/
|
||||
static inline void *lock_slot(struct address_space *mapping, void **slot)
|
||||
{
|
||||
unsigned long entry = (unsigned long)
|
||||
radix_tree_deref_slot_protected(slot, &mapping->tree_lock);
|
||||
radix_tree_deref_slot_protected(slot, &mapping->i_pages.xa_lock);
|
||||
|
||||
entry |= RADIX_DAX_ENTRY_LOCK;
|
||||
radix_tree_replace_slot(&mapping->page_tree, slot, (void *)entry);
|
||||
radix_tree_replace_slot(&mapping->i_pages, slot, (void *)entry);
|
||||
return (void *)entry;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark the given slot is unlocked. The function must be called with
|
||||
* mapping->tree_lock held
|
||||
* Mark the given slot as unlocked. Must be called with the i_pages lock held.
|
||||
*/
|
||||
static inline void *unlock_slot(struct address_space *mapping, void **slot)
|
||||
{
|
||||
unsigned long entry = (unsigned long)
|
||||
radix_tree_deref_slot_protected(slot, &mapping->tree_lock);
|
||||
radix_tree_deref_slot_protected(slot, &mapping->i_pages.xa_lock);
|
||||
|
||||
entry &= ~(unsigned long)RADIX_DAX_ENTRY_LOCK;
|
||||
radix_tree_replace_slot(&mapping->page_tree, slot, (void *)entry);
|
||||
radix_tree_replace_slot(&mapping->i_pages, slot, (void *)entry);
|
||||
return (void *)entry;
|
||||
}
|
||||
|
||||
@@ -228,7 +224,7 @@ static inline void *unlock_slot(struct address_space *mapping, void **slot)
|
||||
* put_locked_mapping_entry() when he locked the entry and now wants to
|
||||
* unlock it.
|
||||
*
|
||||
* The function must be called with mapping->tree_lock held.
|
||||
* Must be called with the i_pages lock held.
|
||||
*/
|
||||
static void *get_unlocked_mapping_entry(struct address_space *mapping,
|
||||
pgoff_t index, void ***slotp)
|
||||
@@ -241,7 +237,7 @@ static void *get_unlocked_mapping_entry(struct address_space *mapping,
|
||||
ewait.wait.func = wake_exceptional_entry_func;
|
||||
|
||||
for (;;) {
|
||||
entry = __radix_tree_lookup(&mapping->page_tree, index, NULL,
|
||||
entry = __radix_tree_lookup(&mapping->i_pages, index, NULL,
|
||||
&slot);
|
||||
if (!entry ||
|
||||
WARN_ON_ONCE(!radix_tree_exceptional_entry(entry)) ||
|
||||
@@ -254,10 +250,10 @@ static void *get_unlocked_mapping_entry(struct address_space *mapping,
|
||||
wq = dax_entry_waitqueue(mapping, index, entry, &ewait.key);
|
||||
prepare_to_wait_exclusive(wq, &ewait.wait,
|
||||
TASK_UNINTERRUPTIBLE);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
schedule();
|
||||
finish_wait(wq, &ewait.wait);
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,15 +262,15 @@ static void dax_unlock_mapping_entry(struct address_space *mapping,
|
||||
{
|
||||
void *entry, **slot;
|
||||
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
entry = __radix_tree_lookup(&mapping->page_tree, index, NULL, &slot);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
entry = __radix_tree_lookup(&mapping->i_pages, index, NULL, &slot);
|
||||
if (WARN_ON_ONCE(!entry || !radix_tree_exceptional_entry(entry) ||
|
||||
!slot_locked(mapping, slot))) {
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
return;
|
||||
}
|
||||
unlock_slot(mapping, slot);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
dax_wake_mapping_entry_waiter(mapping, index, entry, false);
|
||||
}
|
||||
|
||||
@@ -388,7 +384,7 @@ static void *grab_mapping_entry(struct address_space *mapping, pgoff_t index,
|
||||
void *entry, **slot;
|
||||
|
||||
restart:
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
entry = get_unlocked_mapping_entry(mapping, index, &slot);
|
||||
|
||||
if (WARN_ON_ONCE(entry && !radix_tree_exceptional_entry(entry))) {
|
||||
@@ -420,12 +416,12 @@ restart:
|
||||
if (pmd_downgrade) {
|
||||
/*
|
||||
* Make sure 'entry' remains valid while we drop
|
||||
* mapping->tree_lock.
|
||||
* the i_pages lock.
|
||||
*/
|
||||
entry = lock_slot(mapping, slot);
|
||||
}
|
||||
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
/*
|
||||
* Besides huge zero pages the only other thing that gets
|
||||
* downgraded are empty entries which don't need to be
|
||||
@@ -442,27 +438,27 @@ restart:
|
||||
put_locked_mapping_entry(mapping, index);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
|
||||
if (!entry) {
|
||||
/*
|
||||
* We needed to drop the page_tree lock while calling
|
||||
* We needed to drop the i_pages lock while calling
|
||||
* radix_tree_preload() and we didn't have an entry to
|
||||
* lock. See if another thread inserted an entry at
|
||||
* our index during this time.
|
||||
*/
|
||||
entry = __radix_tree_lookup(&mapping->page_tree, index,
|
||||
entry = __radix_tree_lookup(&mapping->i_pages, index,
|
||||
NULL, &slot);
|
||||
if (entry) {
|
||||
radix_tree_preload_end();
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
|
||||
if (pmd_downgrade) {
|
||||
dax_disassociate_entry(entry, mapping, false);
|
||||
radix_tree_delete(&mapping->page_tree, index);
|
||||
radix_tree_delete(&mapping->i_pages, index);
|
||||
mapping->nrexceptional--;
|
||||
dax_wake_mapping_entry_waiter(mapping, index, entry,
|
||||
true);
|
||||
@@ -470,11 +466,11 @@ restart:
|
||||
|
||||
entry = dax_radix_locked_entry(0, size_flag | RADIX_DAX_EMPTY);
|
||||
|
||||
err = __radix_tree_insert(&mapping->page_tree, index,
|
||||
err = __radix_tree_insert(&mapping->i_pages, index,
|
||||
dax_radix_order(entry), entry);
|
||||
radix_tree_preload_end();
|
||||
if (err) {
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
/*
|
||||
* Our insertion of a DAX entry failed, most likely
|
||||
* because we were inserting a PMD entry and it
|
||||
@@ -487,12 +483,12 @@ restart:
|
||||
}
|
||||
/* Good, we have inserted empty locked entry into the tree. */
|
||||
mapping->nrexceptional++;
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
return entry;
|
||||
}
|
||||
entry = lock_slot(mapping, slot);
|
||||
out_unlock:
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
return entry;
|
||||
}
|
||||
|
||||
@@ -501,23 +497,23 @@ static int __dax_invalidate_mapping_entry(struct address_space *mapping,
|
||||
{
|
||||
int ret = 0;
|
||||
void *entry;
|
||||
struct radix_tree_root *page_tree = &mapping->page_tree;
|
||||
struct radix_tree_root *pages = &mapping->i_pages;
|
||||
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(pages);
|
||||
entry = get_unlocked_mapping_entry(mapping, index, NULL);
|
||||
if (!entry || WARN_ON_ONCE(!radix_tree_exceptional_entry(entry)))
|
||||
goto out;
|
||||
if (!trunc &&
|
||||
(radix_tree_tag_get(page_tree, index, PAGECACHE_TAG_DIRTY) ||
|
||||
radix_tree_tag_get(page_tree, index, PAGECACHE_TAG_TOWRITE)))
|
||||
(radix_tree_tag_get(pages, index, PAGECACHE_TAG_DIRTY) ||
|
||||
radix_tree_tag_get(pages, index, PAGECACHE_TAG_TOWRITE)))
|
||||
goto out;
|
||||
dax_disassociate_entry(entry, mapping, trunc);
|
||||
radix_tree_delete(page_tree, index);
|
||||
radix_tree_delete(pages, index);
|
||||
mapping->nrexceptional--;
|
||||
ret = 1;
|
||||
out:
|
||||
put_unlocked_mapping_entry(mapping, index, entry);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(pages);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
@@ -587,7 +583,7 @@ static void *dax_insert_mapping_entry(struct address_space *mapping,
|
||||
void *entry, pfn_t pfn_t,
|
||||
unsigned long flags, bool dirty)
|
||||
{
|
||||
struct radix_tree_root *page_tree = &mapping->page_tree;
|
||||
struct radix_tree_root *pages = &mapping->i_pages;
|
||||
unsigned long pfn = pfn_t_to_pfn(pfn_t);
|
||||
pgoff_t index = vmf->pgoff;
|
||||
void *new_entry;
|
||||
@@ -604,7 +600,7 @@ static void *dax_insert_mapping_entry(struct address_space *mapping,
|
||||
unmap_mapping_pages(mapping, vmf->pgoff, 1, false);
|
||||
}
|
||||
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(pages);
|
||||
new_entry = dax_radix_locked_entry(pfn, flags);
|
||||
if (dax_entry_size(entry) != dax_entry_size(new_entry)) {
|
||||
dax_disassociate_entry(entry, mapping, false);
|
||||
@@ -624,17 +620,17 @@ static void *dax_insert_mapping_entry(struct address_space *mapping,
|
||||
void **slot;
|
||||
void *ret;
|
||||
|
||||
ret = __radix_tree_lookup(page_tree, index, &node, &slot);
|
||||
ret = __radix_tree_lookup(pages, index, &node, &slot);
|
||||
WARN_ON_ONCE(ret != entry);
|
||||
__radix_tree_replace(page_tree, node, slot,
|
||||
__radix_tree_replace(pages, node, slot,
|
||||
new_entry, NULL);
|
||||
entry = new_entry;
|
||||
}
|
||||
|
||||
if (dirty)
|
||||
radix_tree_tag_set(page_tree, index, PAGECACHE_TAG_DIRTY);
|
||||
radix_tree_tag_set(pages, index, PAGECACHE_TAG_DIRTY);
|
||||
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(pages);
|
||||
return entry;
|
||||
}
|
||||
|
||||
@@ -723,7 +719,7 @@ unlock_pte:
|
||||
static int dax_writeback_one(struct dax_device *dax_dev,
|
||||
struct address_space *mapping, pgoff_t index, void *entry)
|
||||
{
|
||||
struct radix_tree_root *page_tree = &mapping->page_tree;
|
||||
struct radix_tree_root *pages = &mapping->i_pages;
|
||||
void *entry2, **slot;
|
||||
unsigned long pfn;
|
||||
long ret = 0;
|
||||
@@ -736,7 +732,7 @@ static int dax_writeback_one(struct dax_device *dax_dev,
|
||||
if (WARN_ON(!radix_tree_exceptional_entry(entry)))
|
||||
return -EIO;
|
||||
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(pages);
|
||||
entry2 = get_unlocked_mapping_entry(mapping, index, &slot);
|
||||
/* Entry got punched out / reallocated? */
|
||||
if (!entry2 || WARN_ON_ONCE(!radix_tree_exceptional_entry(entry2)))
|
||||
@@ -755,7 +751,7 @@ static int dax_writeback_one(struct dax_device *dax_dev,
|
||||
}
|
||||
|
||||
/* Another fsync thread may have already written back this entry */
|
||||
if (!radix_tree_tag_get(page_tree, index, PAGECACHE_TAG_TOWRITE))
|
||||
if (!radix_tree_tag_get(pages, index, PAGECACHE_TAG_TOWRITE))
|
||||
goto put_unlocked;
|
||||
/* Lock the entry to serialize with page faults */
|
||||
entry = lock_slot(mapping, slot);
|
||||
@@ -763,11 +759,11 @@ static int dax_writeback_one(struct dax_device *dax_dev,
|
||||
* We can clear the tag now but we have to be careful so that concurrent
|
||||
* dax_writeback_one() calls for the same index cannot finish before we
|
||||
* actually flush the caches. This is achieved as the calls will look
|
||||
* at the entry only under tree_lock and once they do that they will
|
||||
* see the entry locked and wait for it to unlock.
|
||||
* at the entry only under the i_pages lock and once they do that
|
||||
* they will see the entry locked and wait for it to unlock.
|
||||
*/
|
||||
radix_tree_tag_clear(page_tree, index, PAGECACHE_TAG_TOWRITE);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
radix_tree_tag_clear(pages, index, PAGECACHE_TAG_TOWRITE);
|
||||
xa_unlock_irq(pages);
|
||||
|
||||
/*
|
||||
* Even if dax_writeback_mapping_range() was given a wbc->range_start
|
||||
@@ -787,16 +783,16 @@ static int dax_writeback_one(struct dax_device *dax_dev,
|
||||
* the pfn mappings are writeprotected and fault waits for mapping
|
||||
* entry lock.
|
||||
*/
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
radix_tree_tag_clear(page_tree, index, PAGECACHE_TAG_DIRTY);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(pages);
|
||||
radix_tree_tag_clear(pages, index, PAGECACHE_TAG_DIRTY);
|
||||
xa_unlock_irq(pages);
|
||||
trace_dax_writeback_one(mapping->host, index, size >> PAGE_SHIFT);
|
||||
put_locked_mapping_entry(mapping, index);
|
||||
return ret;
|
||||
|
||||
put_unlocked:
|
||||
put_unlocked_mapping_entry(mapping, index, entry2);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(pages);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1566,21 +1562,21 @@ static int dax_insert_pfn_mkwrite(struct vm_fault *vmf,
|
||||
pgoff_t index = vmf->pgoff;
|
||||
int vmf_ret, error;
|
||||
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
entry = get_unlocked_mapping_entry(mapping, index, &slot);
|
||||
/* Did we race with someone splitting entry or so? */
|
||||
if (!entry ||
|
||||
(pe_size == PE_SIZE_PTE && !dax_is_pte_entry(entry)) ||
|
||||
(pe_size == PE_SIZE_PMD && !dax_is_pmd_entry(entry))) {
|
||||
put_unlocked_mapping_entry(mapping, index, entry);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
trace_dax_insert_pfn_mkwrite_no_entry(mapping->host, vmf,
|
||||
VM_FAULT_NOPAGE);
|
||||
return VM_FAULT_NOPAGE;
|
||||
}
|
||||
radix_tree_tag_set(&mapping->page_tree, index, PAGECACHE_TAG_DIRTY);
|
||||
radix_tree_tag_set(&mapping->i_pages, index, PAGECACHE_TAG_DIRTY);
|
||||
entry = lock_slot(mapping, slot);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
switch (pe_size) {
|
||||
case PE_SIZE_PTE:
|
||||
error = vm_insert_mixed_mkwrite(vmf->vma, vmf->address, pfn);
|
||||
|
||||
+3
-3
@@ -2424,12 +2424,12 @@ void f2fs_set_page_dirty_nobuffers(struct page *page)
|
||||
SetPageDirty(page);
|
||||
spin_unlock(&mapping->private_lock);
|
||||
|
||||
spin_lock_irqsave(&mapping->tree_lock, flags);
|
||||
xa_lock_irqsave(&mapping->i_pages, flags);
|
||||
WARN_ON_ONCE(!PageUptodate(page));
|
||||
account_page_dirtied(page, mapping);
|
||||
radix_tree_tag_set(&mapping->page_tree,
|
||||
radix_tree_tag_set(&mapping->i_pages,
|
||||
page_index(page), PAGECACHE_TAG_DIRTY);
|
||||
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||||
xa_unlock_irqrestore(&mapping->i_pages, flags);
|
||||
unlock_page_memcg(page);
|
||||
|
||||
__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
|
||||
|
||||
+3
-3
@@ -732,10 +732,10 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
|
||||
|
||||
if (bit_pos == NR_DENTRY_IN_BLOCK &&
|
||||
!truncate_hole(dir, page->index, page->index + 1)) {
|
||||
spin_lock_irqsave(&mapping->tree_lock, flags);
|
||||
radix_tree_tag_clear(&mapping->page_tree, page_index(page),
|
||||
xa_lock_irqsave(&mapping->i_pages, flags);
|
||||
radix_tree_tag_clear(&mapping->i_pages, page_index(page),
|
||||
PAGECACHE_TAG_DIRTY);
|
||||
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||||
xa_unlock_irqrestore(&mapping->i_pages, flags);
|
||||
|
||||
clear_page_dirty_for_io(page);
|
||||
ClearPagePrivate(page);
|
||||
|
||||
+3
-3
@@ -226,10 +226,10 @@ int f2fs_write_inline_data(struct inode *inode, struct page *page)
|
||||
kunmap_atomic(src_addr);
|
||||
set_page_dirty(dn.inode_page);
|
||||
|
||||
spin_lock_irqsave(&mapping->tree_lock, flags);
|
||||
radix_tree_tag_clear(&mapping->page_tree, page_index(page),
|
||||
xa_lock_irqsave(&mapping->i_pages, flags);
|
||||
radix_tree_tag_clear(&mapping->i_pages, page_index(page),
|
||||
PAGECACHE_TAG_DIRTY);
|
||||
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||||
xa_unlock_irqrestore(&mapping->i_pages, flags);
|
||||
|
||||
set_inode_flag(inode, FI_APPEND_WRITE);
|
||||
set_inode_flag(inode, FI_DATA_EXIST);
|
||||
|
||||
+4
-4
@@ -91,11 +91,11 @@ static void clear_node_page_dirty(struct page *page)
|
||||
unsigned int long flags;
|
||||
|
||||
if (PageDirty(page)) {
|
||||
spin_lock_irqsave(&mapping->tree_lock, flags);
|
||||
radix_tree_tag_clear(&mapping->page_tree,
|
||||
xa_lock_irqsave(&mapping->i_pages, flags);
|
||||
radix_tree_tag_clear(&mapping->i_pages,
|
||||
page_index(page),
|
||||
PAGECACHE_TAG_DIRTY);
|
||||
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||||
xa_unlock_irqrestore(&mapping->i_pages, flags);
|
||||
|
||||
clear_page_dirty_for_io(page);
|
||||
dec_page_count(F2FS_M_SB(mapping), F2FS_DIRTY_NODES);
|
||||
@@ -1161,7 +1161,7 @@ void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
f2fs_bug_on(sbi, check_nid_range(sbi, nid));
|
||||
|
||||
rcu_read_lock();
|
||||
apage = radix_tree_lookup(&NODE_MAPPING(sbi)->page_tree, nid);
|
||||
apage = radix_tree_lookup(&NODE_MAPPING(sbi)->i_pages, nid);
|
||||
rcu_read_unlock();
|
||||
if (apage)
|
||||
return;
|
||||
|
||||
+11
-11
@@ -347,9 +347,9 @@ static void inode_switch_wbs_work_fn(struct work_struct *work)
|
||||
* By the time control reaches here, RCU grace period has passed
|
||||
* since I_WB_SWITCH assertion and all wb stat update transactions
|
||||
* between unlocked_inode_to_wb_begin/end() are guaranteed to be
|
||||
* synchronizing against mapping->tree_lock.
|
||||
* synchronizing against the i_pages lock.
|
||||
*
|
||||
* Grabbing old_wb->list_lock, inode->i_lock and mapping->tree_lock
|
||||
* Grabbing old_wb->list_lock, inode->i_lock and the i_pages lock
|
||||
* gives us exclusion against all wb related operations on @inode
|
||||
* including IO list manipulations and stat updates.
|
||||
*/
|
||||
@@ -361,7 +361,7 @@ static void inode_switch_wbs_work_fn(struct work_struct *work)
|
||||
spin_lock_nested(&old_wb->list_lock, SINGLE_DEPTH_NESTING);
|
||||
}
|
||||
spin_lock(&inode->i_lock);
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
|
||||
/*
|
||||
* Once I_FREEING is visible under i_lock, the eviction path owns
|
||||
@@ -373,22 +373,22 @@ static void inode_switch_wbs_work_fn(struct work_struct *work)
|
||||
/*
|
||||
* Count and transfer stats. Note that PAGECACHE_TAG_DIRTY points
|
||||
* to possibly dirty pages while PAGECACHE_TAG_WRITEBACK points to
|
||||
* pages actually under underwriteback.
|
||||
* pages actually under writeback.
|
||||
*/
|
||||
radix_tree_for_each_tagged(slot, &mapping->page_tree, &iter, 0,
|
||||
radix_tree_for_each_tagged(slot, &mapping->i_pages, &iter, 0,
|
||||
PAGECACHE_TAG_DIRTY) {
|
||||
struct page *page = radix_tree_deref_slot_protected(slot,
|
||||
&mapping->tree_lock);
|
||||
&mapping->i_pages.xa_lock);
|
||||
if (likely(page) && PageDirty(page)) {
|
||||
dec_wb_stat(old_wb, WB_RECLAIMABLE);
|
||||
inc_wb_stat(new_wb, WB_RECLAIMABLE);
|
||||
}
|
||||
}
|
||||
|
||||
radix_tree_for_each_tagged(slot, &mapping->page_tree, &iter, 0,
|
||||
radix_tree_for_each_tagged(slot, &mapping->i_pages, &iter, 0,
|
||||
PAGECACHE_TAG_WRITEBACK) {
|
||||
struct page *page = radix_tree_deref_slot_protected(slot,
|
||||
&mapping->tree_lock);
|
||||
&mapping->i_pages.xa_lock);
|
||||
if (likely(page)) {
|
||||
WARN_ON_ONCE(!PageWriteback(page));
|
||||
dec_wb_stat(old_wb, WB_WRITEBACK);
|
||||
@@ -430,7 +430,7 @@ skip_switch:
|
||||
*/
|
||||
smp_store_release(&inode->i_state, inode->i_state & ~I_WB_SWITCH);
|
||||
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
spin_unlock(&inode->i_lock);
|
||||
spin_unlock(&new_wb->list_lock);
|
||||
spin_unlock(&old_wb->list_lock);
|
||||
@@ -506,8 +506,8 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id)
|
||||
|
||||
/*
|
||||
* In addition to synchronizing among switchers, I_WB_SWITCH tells
|
||||
* the RCU protected stat update paths to grab the mapping's
|
||||
* tree_lock so that stat transfer can synchronize against them.
|
||||
* the RCU protected stat update paths to grab the i_page
|
||||
* lock so that stat transfer can synchronize against them.
|
||||
* Let's continue after I_WB_SWITCH is guaranteed to be visible.
|
||||
*/
|
||||
call_rcu(&isw->rcu_head, inode_switch_wbs_rcu_fn);
|
||||
|
||||
+5
-6
@@ -348,8 +348,7 @@ EXPORT_SYMBOL(inc_nlink);
|
||||
|
||||
static void __address_space_init_once(struct address_space *mapping)
|
||||
{
|
||||
INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC | __GFP_ACCOUNT);
|
||||
spin_lock_init(&mapping->tree_lock);
|
||||
INIT_RADIX_TREE(&mapping->i_pages, GFP_ATOMIC | __GFP_ACCOUNT);
|
||||
init_rwsem(&mapping->i_mmap_rwsem);
|
||||
INIT_LIST_HEAD(&mapping->private_list);
|
||||
spin_lock_init(&mapping->private_lock);
|
||||
@@ -504,14 +503,14 @@ EXPORT_SYMBOL(__remove_inode_hash);
|
||||
void clear_inode(struct inode *inode)
|
||||
{
|
||||
/*
|
||||
* We have to cycle tree_lock here because reclaim can be still in the
|
||||
* We have to cycle the i_pages lock here because reclaim can be in the
|
||||
* process of removing the last page (in __delete_from_page_cache())
|
||||
* and we must not free mapping under it.
|
||||
* and we must not free the mapping under it.
|
||||
*/
|
||||
spin_lock_irq(&inode->i_data.tree_lock);
|
||||
xa_lock_irq(&inode->i_data.i_pages);
|
||||
BUG_ON(inode->i_data.nrpages);
|
||||
BUG_ON(inode->i_data.nrexceptional);
|
||||
spin_unlock_irq(&inode->i_data.tree_lock);
|
||||
xa_unlock_irq(&inode->i_data.i_pages);
|
||||
BUG_ON(!list_empty(&inode->i_data.private_list));
|
||||
BUG_ON(!(inode->i_state & I_FREEING));
|
||||
BUG_ON(inode->i_state & I_CLEAR);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user