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:
parent
f6bb2a2c0b
commit
b93b016313
39 changed files with 345 additions and 366 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
13
fs/buffer.c
13
fs/buffer.c
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
124
fs/dax.c
124
fs/dax.c
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
11
fs/inode.c
11
fs/inode.c
|
@ -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);
|
||||
|
|
|
@ -193,9 +193,9 @@ retry:
|
|||
(unsigned long long)oldkey,
|
||||
(unsigned long long)newkey);
|
||||
|
||||
spin_lock_irq(&btnc->tree_lock);
|
||||
err = radix_tree_insert(&btnc->page_tree, newkey, obh->b_page);
|
||||
spin_unlock_irq(&btnc->tree_lock);
|
||||
xa_lock_irq(&btnc->i_pages);
|
||||
err = radix_tree_insert(&btnc->i_pages, newkey, obh->b_page);
|
||||
xa_unlock_irq(&btnc->i_pages);
|
||||
/*
|
||||
* Note: page->index will not change to newkey until
|
||||
* nilfs_btnode_commit_change_key() will be called.
|
||||
|
@ -251,11 +251,11 @@ void nilfs_btnode_commit_change_key(struct address_space *btnc,
|
|||
(unsigned long long)newkey);
|
||||
mark_buffer_dirty(obh);
|
||||
|
||||
spin_lock_irq(&btnc->tree_lock);
|
||||
radix_tree_delete(&btnc->page_tree, oldkey);
|
||||
radix_tree_tag_set(&btnc->page_tree, newkey,
|
||||
xa_lock_irq(&btnc->i_pages);
|
||||
radix_tree_delete(&btnc->i_pages, oldkey);
|
||||
radix_tree_tag_set(&btnc->i_pages, newkey,
|
||||
PAGECACHE_TAG_DIRTY);
|
||||
spin_unlock_irq(&btnc->tree_lock);
|
||||
xa_unlock_irq(&btnc->i_pages);
|
||||
|
||||
opage->index = obh->b_blocknr = newkey;
|
||||
unlock_page(opage);
|
||||
|
@ -283,9 +283,9 @@ void nilfs_btnode_abort_change_key(struct address_space *btnc,
|
|||
return;
|
||||
|
||||
if (nbh == NULL) { /* blocksize == pagesize */
|
||||
spin_lock_irq(&btnc->tree_lock);
|
||||
radix_tree_delete(&btnc->page_tree, newkey);
|
||||
spin_unlock_irq(&btnc->tree_lock);
|
||||
xa_lock_irq(&btnc->i_pages);
|
||||
radix_tree_delete(&btnc->i_pages, newkey);
|
||||
xa_unlock_irq(&btnc->i_pages);
|
||||
unlock_page(ctxt->bh->b_page);
|
||||
} else
|
||||
brelse(nbh);
|
||||
|
|
|
@ -331,15 +331,15 @@ repeat:
|
|||
struct page *page2;
|
||||
|
||||
/* move the page to the destination cache */
|
||||
spin_lock_irq(&smap->tree_lock);
|
||||
page2 = radix_tree_delete(&smap->page_tree, offset);
|
||||
xa_lock_irq(&smap->i_pages);
|
||||
page2 = radix_tree_delete(&smap->i_pages, offset);
|
||||
WARN_ON(page2 != page);
|
||||
|
||||
smap->nrpages--;
|
||||
spin_unlock_irq(&smap->tree_lock);
|
||||
xa_unlock_irq(&smap->i_pages);
|
||||
|
||||
spin_lock_irq(&dmap->tree_lock);
|
||||
err = radix_tree_insert(&dmap->page_tree, offset, page);
|
||||
xa_lock_irq(&dmap->i_pages);
|
||||
err = radix_tree_insert(&dmap->i_pages, offset, page);
|
||||
if (unlikely(err < 0)) {
|
||||
WARN_ON(err == -EEXIST);
|
||||
page->mapping = NULL;
|
||||
|
@ -348,11 +348,11 @@ repeat:
|
|||
page->mapping = dmap;
|
||||
dmap->nrpages++;
|
||||
if (PageDirty(page))
|
||||
radix_tree_tag_set(&dmap->page_tree,
|
||||
radix_tree_tag_set(&dmap->i_pages,
|
||||
offset,
|
||||
PAGECACHE_TAG_DIRTY);
|
||||
}
|
||||
spin_unlock_irq(&dmap->tree_lock);
|
||||
xa_unlock_irq(&dmap->i_pages);
|
||||
}
|
||||
unlock_page(page);
|
||||
}
|
||||
|
@ -474,15 +474,15 @@ int __nilfs_clear_page_dirty(struct page *page)
|
|||
struct address_space *mapping = page->mapping;
|
||||
|
||||
if (mapping) {
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
if (test_bit(PG_dirty, &page->flags)) {
|
||||
radix_tree_tag_clear(&mapping->page_tree,
|
||||
radix_tree_tag_clear(&mapping->i_pages,
|
||||
page_index(page),
|
||||
PAGECACHE_TAG_DIRTY);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
return clear_page_dirty_for_io(page);
|
||||
}
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
return 0;
|
||||
}
|
||||
return TestClearPageDirty(page);
|
||||
|
|
|
@ -329,7 +329,7 @@ static inline bool inode_to_wb_is_valid(struct inode *inode)
|
|||
* @inode: inode of interest
|
||||
*
|
||||
* Returns the wb @inode is currently associated with. The caller must be
|
||||
* holding either @inode->i_lock, @inode->i_mapping->tree_lock, or the
|
||||
* holding either @inode->i_lock, the i_pages lock, or the
|
||||
* associated wb's list_lock.
|
||||
*/
|
||||
static inline struct bdi_writeback *inode_to_wb(const struct inode *inode)
|
||||
|
@ -337,7 +337,7 @@ static inline struct bdi_writeback *inode_to_wb(const struct inode *inode)
|
|||
#ifdef CONFIG_LOCKDEP
|
||||
WARN_ON_ONCE(debug_locks &&
|
||||
(!lockdep_is_held(&inode->i_lock) &&
|
||||
!lockdep_is_held(&inode->i_mapping->tree_lock) &&
|
||||
!lockdep_is_held(&inode->i_mapping->i_pages.xa_lock) &&
|
||||
!lockdep_is_held(&inode->i_wb->list_lock)));
|
||||
#endif
|
||||
return inode->i_wb;
|
||||
|
@ -349,7 +349,7 @@ static inline struct bdi_writeback *inode_to_wb(const struct inode *inode)
|
|||
* @lockedp: temp bool output param, to be passed to the end function
|
||||
*
|
||||
* The caller wants to access the wb associated with @inode but isn't
|
||||
* holding inode->i_lock, mapping->tree_lock or wb->list_lock. This
|
||||
* holding inode->i_lock, the i_pages lock or wb->list_lock. This
|
||||
* function determines the wb associated with @inode and ensures that the
|
||||
* association doesn't change until the transaction is finished with
|
||||
* unlocked_inode_to_wb_end().
|
||||
|
@ -370,11 +370,11 @@ unlocked_inode_to_wb_begin(struct inode *inode, bool *lockedp)
|
|||
*lockedp = smp_load_acquire(&inode->i_state) & I_WB_SWITCH;
|
||||
|
||||
if (unlikely(*lockedp))
|
||||
spin_lock_irq(&inode->i_mapping->tree_lock);
|
||||
xa_lock_irq(&inode->i_mapping->i_pages);
|
||||
|
||||
/*
|
||||
* Protected by either !I_WB_SWITCH + rcu_read_lock() or tree_lock.
|
||||
* inode_to_wb() will bark. Deref directly.
|
||||
* Protected by either !I_WB_SWITCH + rcu_read_lock() or the i_pages
|
||||
* lock. inode_to_wb() will bark. Deref directly.
|
||||
*/
|
||||
return inode->i_wb;
|
||||
}
|
||||
|
@ -387,7 +387,7 @@ unlocked_inode_to_wb_begin(struct inode *inode, bool *lockedp)
|
|||
static inline void unlocked_inode_to_wb_end(struct inode *inode, bool locked)
|
||||
{
|
||||
if (unlikely(locked))
|
||||
spin_unlock_irq(&inode->i_mapping->tree_lock);
|
||||
xa_unlock_irq(&inode->i_mapping->i_pages);
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/list_lru.h>
|
||||
#include <linux/llist.h>
|
||||
#include <linux/radix-tree.h>
|
||||
#include <linux/xarray.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pid.h>
|
||||
|
@ -390,12 +391,11 @@ int pagecache_write_end(struct file *, struct address_space *mapping,
|
|||
|
||||
struct address_space {
|
||||
struct inode *host; /* owner: inode, block_device */
|
||||
struct radix_tree_root page_tree; /* radix tree of all pages */
|
||||
spinlock_t tree_lock; /* and lock protecting it */
|
||||
struct radix_tree_root i_pages; /* cached pages */
|
||||
atomic_t i_mmap_writable;/* count VM_SHARED mappings */
|
||||
struct rb_root_cached i_mmap; /* tree of private and shared mappings */
|
||||
struct rw_semaphore i_mmap_rwsem; /* protect tree, count, list */
|
||||
/* Protected by tree_lock together with the radix tree */
|
||||
/* Protected by the i_pages lock */
|
||||
unsigned long nrpages; /* number of total pages */
|
||||
/* number of shadow or DAX exceptional entries */
|
||||
unsigned long nrexceptional;
|
||||
|
@ -1989,7 +1989,7 @@ static inline void init_sync_kiocb(struct kiocb *kiocb, struct file *filp)
|
|||
*
|
||||
* I_WB_SWITCH Cgroup bdi_writeback switching in progress. Used to
|
||||
* synchronize competing switching instances and to tell
|
||||
* wb stat updates to grab mapping->tree_lock. See
|
||||
* wb stat updates to grab the i_pages lock. See
|
||||
* inode_switch_wb_work_fn() for details.
|
||||
*
|
||||
* I_OVL_INUSE Used by overlayfs to get exclusive ownership on upper
|
||||
|
|
|
@ -747,7 +747,7 @@ int finish_mkwrite_fault(struct vm_fault *vmf);
|
|||
* refcount. The each user mapping also has a reference to the page.
|
||||
*
|
||||
* The pagecache pages are stored in a per-mapping radix tree, which is
|
||||
* rooted at mapping->page_tree, and indexed by offset.
|
||||
* rooted at mapping->i_pages, and indexed by offset.
|
||||
* Where 2.4 and early 2.6 kernels kept dirty/clean pages in per-address_space
|
||||
* lists, we instead now tag pages as dirty/writeback in the radix tree.
|
||||
*
|
||||
|
|
|
@ -144,7 +144,7 @@ void release_pages(struct page **pages, int nr);
|
|||
* 3. check the page is still in pagecache (if no, goto 1)
|
||||
*
|
||||
* Remove-side that cares about stability of _refcount (eg. reclaim) has the
|
||||
* following (with tree_lock held for write):
|
||||
* following (with the i_pages lock held):
|
||||
* A. atomically check refcount is correct and set it to 0 (atomic_cmpxchg)
|
||||
* B. remove page from pagecache
|
||||
* C. free the page
|
||||
|
@ -157,7 +157,7 @@ void release_pages(struct page **pages, int nr);
|
|||
*
|
||||
* It is possible that between 1 and 2, the page is removed then the exact same
|
||||
* page is inserted into the same position in pagecache. That's OK: the
|
||||
* old find_get_page using tree_lock could equally have run before or after
|
||||
* old find_get_page using a lock could equally have run before or after
|
||||
* such a re-insertion, depending on order that locks are granted.
|
||||
*
|
||||
* Lookups racing against pagecache insertion isn't a big problem: either 1
|
||||
|
|
84
mm/filemap.c
84
mm/filemap.c
|
@ -66,7 +66,7 @@
|
|||
* ->i_mmap_rwsem (truncate_pagecache)
|
||||
* ->private_lock (__free_pte->__set_page_dirty_buffers)
|
||||
* ->swap_lock (exclusive_swap_page, others)
|
||||
* ->mapping->tree_lock
|
||||
* ->i_pages lock
|
||||
*
|
||||
* ->i_mutex
|
||||
* ->i_mmap_rwsem (truncate->unmap_mapping_range)
|
||||
|
@ -74,7 +74,7 @@
|
|||
* ->mmap_sem
|
||||
* ->i_mmap_rwsem
|
||||
* ->page_table_lock or pte_lock (various, mainly in memory.c)
|
||||
* ->mapping->tree_lock (arch-dependent flush_dcache_mmap_lock)
|
||||
* ->i_pages lock (arch-dependent flush_dcache_mmap_lock)
|
||||
*
|
||||
* ->mmap_sem
|
||||
* ->lock_page (access_process_vm)
|
||||
|
@ -84,7 +84,7 @@
|
|||
*
|
||||
* bdi->wb.list_lock
|
||||
* sb_lock (fs/fs-writeback.c)
|
||||
* ->mapping->tree_lock (__sync_single_inode)
|
||||
* ->i_pages lock (__sync_single_inode)
|
||||
*
|
||||
* ->i_mmap_rwsem
|
||||
* ->anon_vma.lock (vma_adjust)
|
||||
|
@ -95,11 +95,11 @@
|
|||
* ->page_table_lock or pte_lock
|
||||
* ->swap_lock (try_to_unmap_one)
|
||||
* ->private_lock (try_to_unmap_one)
|
||||
* ->tree_lock (try_to_unmap_one)
|
||||
* ->i_pages lock (try_to_unmap_one)
|
||||
* ->zone_lru_lock(zone) (follow_page->mark_page_accessed)
|
||||
* ->zone_lru_lock(zone) (check_pte_range->isolate_lru_page)
|
||||
* ->private_lock (page_remove_rmap->set_page_dirty)
|
||||
* ->tree_lock (page_remove_rmap->set_page_dirty)
|
||||
* ->i_pages lock (page_remove_rmap->set_page_dirty)
|
||||
* bdi.wb->list_lock (page_remove_rmap->set_page_dirty)
|
||||
* ->inode->i_lock (page_remove_rmap->set_page_dirty)
|
||||
* ->memcg->move_lock (page_remove_rmap->lock_page_memcg)
|
||||
|
@ -118,14 +118,15 @@ static int page_cache_tree_insert(struct address_space *mapping,
|
|||
void **slot;
|
||||
int error;
|
||||
|
||||
error = __radix_tree_create(&mapping->page_tree, page->index, 0,
|
||||
error = __radix_tree_create(&mapping->i_pages, page->index, 0,
|
||||
&node, &slot);
|
||||
if (error)
|
||||
return error;
|
||||
if (*slot) {
|
||||
void *p;
|
||||
|
||||
p = radix_tree_deref_slot_protected(slot, &mapping->tree_lock);
|
||||
p = radix_tree_deref_slot_protected(slot,
|
||||
&mapping->i_pages.xa_lock);
|
||||
if (!radix_tree_exceptional_entry(p))
|
||||
return -EEXIST;
|
||||
|
||||
|
@ -133,7 +134,7 @@ static int page_cache_tree_insert(struct address_space *mapping,
|
|||
if (shadowp)
|
||||
*shadowp = p;
|
||||
}
|
||||
__radix_tree_replace(&mapping->page_tree, node, slot, page,
|
||||
__radix_tree_replace(&mapping->i_pages, node, slot, page,
|
||||
workingset_lookup_update(mapping));
|
||||
mapping->nrpages++;
|
||||
return 0;
|
||||
|
@ -155,13 +156,13 @@ static void page_cache_tree_delete(struct address_space *mapping,
|
|||
struct radix_tree_node *node;
|
||||
void **slot;
|
||||
|
||||
__radix_tree_lookup(&mapping->page_tree, page->index + i,
|
||||
__radix_tree_lookup(&mapping->i_pages, page->index + i,
|
||||
&node, &slot);
|
||||
|
||||
VM_BUG_ON_PAGE(!node && nr != 1, page);
|
||||
|
||||
radix_tree_clear_tags(&mapping->page_tree, node, slot);
|
||||
__radix_tree_replace(&mapping->page_tree, node, slot, shadow,
|
||||
radix_tree_clear_tags(&mapping->i_pages, node, slot);
|
||||
__radix_tree_replace(&mapping->i_pages, node, slot, shadow,
|
||||
workingset_lookup_update(mapping));
|
||||
}
|
||||
|
||||
|
@ -253,7 +254,7 @@ static void unaccount_page_cache_page(struct address_space *mapping,
|
|||
/*
|
||||
* Delete a page from the page cache and free it. Caller has to make
|
||||
* sure the page is locked and that nobody else uses it - or that usage
|
||||
* is safe. The caller must hold the mapping's tree_lock.
|
||||
* is safe. The caller must hold the i_pages lock.
|
||||
*/
|
||||
void __delete_from_page_cache(struct page *page, void *shadow)
|
||||
{
|
||||
|
@ -296,9 +297,9 @@ void delete_from_page_cache(struct page *page)
|
|||
unsigned long flags;
|
||||
|
||||
BUG_ON(!PageLocked(page));
|
||||
spin_lock_irqsave(&mapping->tree_lock, flags);
|
||||
xa_lock_irqsave(&mapping->i_pages, flags);
|
||||
__delete_from_page_cache(page, NULL);
|
||||
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||||
xa_unlock_irqrestore(&mapping->i_pages, flags);
|
||||
|
||||
page_cache_free_page(mapping, page);
|
||||
}
|
||||
|
@ -309,14 +310,14 @@ EXPORT_SYMBOL(delete_from_page_cache);
|
|||
* @mapping: the mapping to which pages belong
|
||||
* @pvec: pagevec with pages to delete
|
||||
*
|
||||
* The function walks over mapping->page_tree and removes pages passed in @pvec
|
||||
* from the radix tree. The function expects @pvec to be sorted by page index.
|
||||
* It tolerates holes in @pvec (radix tree entries at those indices are not
|
||||
* The function walks over mapping->i_pages and removes pages passed in @pvec
|
||||
* from the mapping. The function expects @pvec to be sorted by page index.
|
||||
* It tolerates holes in @pvec (mapping entries at those indices are not
|
||||
* modified). The function expects only THP head pages to be present in the
|
||||
* @pvec and takes care to delete all corresponding tail pages from the radix
|
||||
* tree as well.
|
||||
* @pvec and takes care to delete all corresponding tail pages from the
|
||||
* mapping as well.
|
||||
*
|
||||
* The function expects mapping->tree_lock to be held.
|
||||
* The function expects the i_pages lock to be held.
|
||||
*/
|
||||
static void
|
||||
page_cache_tree_delete_batch(struct address_space *mapping,
|
||||
|
@ -330,11 +331,11 @@ page_cache_tree_delete_batch(struct address_space *mapping,
|
|||
pgoff_t start;
|
||||
|
||||
start = pvec->pages[0]->index;
|
||||
radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
|
||||
radix_tree_for_each_slot(slot, &mapping->i_pages, &iter, start) {
|
||||
if (i >= pagevec_count(pvec) && !tail_pages)
|
||||
break;
|
||||
page = radix_tree_deref_slot_protected(slot,
|
||||
&mapping->tree_lock);
|
||||
&mapping->i_pages.xa_lock);
|
||||
if (radix_tree_exceptional_entry(page))
|
||||
continue;
|
||||
if (!tail_pages) {
|
||||
|
@ -357,8 +358,8 @@ page_cache_tree_delete_batch(struct address_space *mapping,
|
|||
} else {
|
||||
tail_pages--;
|
||||
}
|
||||
radix_tree_clear_tags(&mapping->page_tree, iter.node, slot);
|
||||
__radix_tree_replace(&mapping->page_tree, iter.node, slot, NULL,
|
||||
radix_tree_clear_tags(&mapping->i_pages, iter.node, slot);
|
||||
__radix_tree_replace(&mapping->i_pages, iter.node, slot, NULL,
|
||||
workingset_lookup_update(mapping));
|
||||
total_pages++;
|
||||
}
|
||||
|
@ -374,14 +375,14 @@ void delete_from_page_cache_batch(struct address_space *mapping,
|
|||
if (!pagevec_count(pvec))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&mapping->tree_lock, flags);
|
||||
xa_lock_irqsave(&mapping->i_pages, flags);
|
||||
for (i = 0; i < pagevec_count(pvec); i++) {
|
||||
trace_mm_filemap_delete_from_page_cache(pvec->pages[i]);
|
||||
|
||||
unaccount_page_cache_page(mapping, pvec->pages[i]);
|
||||
}
|
||||
page_cache_tree_delete_batch(mapping, pvec);
|
||||
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||||
xa_unlock_irqrestore(&mapping->i_pages, flags);
|
||||
|
||||
for (i = 0; i < pagevec_count(pvec); i++)
|
||||
page_cache_free_page(mapping, pvec->pages[i]);
|
||||
|
@ -798,7 +799,7 @@ int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask)
|
|||
new->mapping = mapping;
|
||||
new->index = offset;
|
||||
|
||||
spin_lock_irqsave(&mapping->tree_lock, flags);
|
||||
xa_lock_irqsave(&mapping->i_pages, flags);
|
||||
__delete_from_page_cache(old, NULL);
|
||||
error = page_cache_tree_insert(mapping, new, NULL);
|
||||
BUG_ON(error);
|
||||
|
@ -810,7 +811,7 @@ int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask)
|
|||
__inc_node_page_state(new, NR_FILE_PAGES);
|
||||
if (PageSwapBacked(new))
|
||||
__inc_node_page_state(new, NR_SHMEM);
|
||||
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||||
xa_unlock_irqrestore(&mapping->i_pages, flags);
|
||||
mem_cgroup_migrate(old, new);
|
||||
radix_tree_preload_end();
|
||||
if (freepage)
|
||||
|
@ -852,7 +853,7 @@ static int __add_to_page_cache_locked(struct page *page,
|
|||
page->mapping = mapping;
|
||||
page->index = offset;
|
||||
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
error = page_cache_tree_insert(mapping, page, shadowp);
|
||||
radix_tree_preload_end();
|
||||
if (unlikely(error))
|
||||
|
@ -861,7 +862,7 @@ static int __add_to_page_cache_locked(struct page *page,
|
|||
/* hugetlb pages do not participate in page cache accounting. */
|
||||
if (!huge)
|
||||
__inc_node_page_state(page, NR_FILE_PAGES);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
if (!huge)
|
||||
mem_cgroup_commit_charge(page, memcg, false, false);
|
||||
trace_mm_filemap_add_to_page_cache(page);
|
||||
|
@ -869,7 +870,7 @@ static int __add_to_page_cache_locked(struct page *page,
|
|||
err_insert:
|
||||
page->mapping = NULL;
|
||||
/* Leave page->index set: truncation relies upon it */
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
if (!huge)
|
||||
mem_cgroup_cancel_charge(page, memcg, false);
|
||||
put_page(page);
|
||||
|
@ -1353,7 +1354,7 @@ pgoff_t page_cache_next_hole(struct address_space *mapping,
|
|||
for (i = 0; i < max_scan; i++) {
|
||||
struct page *page;
|
||||
|
||||
page = radix_tree_lookup(&mapping->page_tree, index);
|
||||
page = radix_tree_lookup(&mapping->i_pages, index);
|
||||
if (!page || radix_tree_exceptional_entry(page))
|
||||
break;
|
||||
index++;
|
||||
|
@ -1394,7 +1395,7 @@ pgoff_t page_cache_prev_hole(struct address_space *mapping,
|
|||
for (i = 0; i < max_scan; i++) {
|
||||
struct page *page;
|
||||
|
||||
page = radix_tree_lookup(&mapping->page_tree, index);
|
||||
page = radix_tree_lookup(&mapping->i_pages, index);
|
||||
if (!page || radix_tree_exceptional_entry(page))
|
||||
break;
|
||||
index--;
|
||||
|
@ -1427,7 +1428,7 @@ struct page *find_get_entry(struct address_space *mapping, pgoff_t offset)
|
|||
rcu_read_lock();
|
||||
repeat:
|
||||
page = NULL;
|
||||
pagep = radix_tree_lookup_slot(&mapping->page_tree, offset);
|
||||
pagep = radix_tree_lookup_slot(&mapping->i_pages, offset);
|
||||
if (pagep) {
|
||||
page = radix_tree_deref_slot(pagep);
|
||||
if (unlikely(!page))
|
||||
|
@ -1633,7 +1634,7 @@ unsigned find_get_entries(struct address_space *mapping,
|
|||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
|
||||
radix_tree_for_each_slot(slot, &mapping->i_pages, &iter, start) {
|
||||
struct page *head, *page;
|
||||
repeat:
|
||||
page = radix_tree_deref_slot(slot);
|
||||
|
@ -1710,7 +1711,7 @@ unsigned find_get_pages_range(struct address_space *mapping, pgoff_t *start,
|
|||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, *start) {
|
||||
radix_tree_for_each_slot(slot, &mapping->i_pages, &iter, *start) {
|
||||
struct page *head, *page;
|
||||
|
||||
if (iter.index > end)
|
||||
|
@ -1795,7 +1796,7 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index,
|
|||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
radix_tree_for_each_contig(slot, &mapping->page_tree, &iter, index) {
|
||||
radix_tree_for_each_contig(slot, &mapping->i_pages, &iter, index) {
|
||||
struct page *head, *page;
|
||||
repeat:
|
||||
page = radix_tree_deref_slot(slot);
|
||||
|
@ -1875,8 +1876,7 @@ unsigned find_get_pages_range_tag(struct address_space *mapping, pgoff_t *index,
|
|||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
radix_tree_for_each_tagged(slot, &mapping->page_tree,
|
||||
&iter, *index, tag) {
|
||||
radix_tree_for_each_tagged(slot, &mapping->i_pages, &iter, *index, tag) {
|
||||
struct page *head, *page;
|
||||
|
||||
if (iter.index > end)
|
||||
|
@ -1969,8 +1969,7 @@ unsigned find_get_entries_tag(struct address_space *mapping, pgoff_t start,
|
|||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
radix_tree_for_each_tagged(slot, &mapping->page_tree,
|
||||
&iter, start, tag) {
|
||||
radix_tree_for_each_tagged(slot, &mapping->i_pages, &iter, start, tag) {
|
||||
struct page *head, *page;
|
||||
repeat:
|
||||
page = radix_tree_deref_slot(slot);
|
||||
|
@ -2624,8 +2623,7 @@ void filemap_map_pages(struct vm_fault *vmf,
|
|||
struct page *head, *page;
|
||||
|
||||
rcu_read_lock();
|
||||
radix_tree_for_each_slot(slot, &mapping->page_tree, &iter,
|
||||
start_pgoff) {
|
||||
radix_tree_for_each_slot(slot, &mapping->i_pages, &iter, start_pgoff) {
|
||||
if (iter.index > end_pgoff)
|
||||
break;
|
||||
repeat:
|
||||
|
|
|
@ -2450,7 +2450,7 @@ static void __split_huge_page(struct page *page, struct list_head *list,
|
|||
} else {
|
||||
/* Additional pin to radix tree */
|
||||
page_ref_add(head, 2);
|
||||
spin_unlock(&head->mapping->tree_lock);
|
||||
xa_unlock(&head->mapping->i_pages);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(zone_lru_lock(page_zone(head)), flags);
|
||||
|
@ -2658,15 +2658,15 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
|
|||
if (mapping) {
|
||||
void **pslot;
|
||||
|
||||
spin_lock(&mapping->tree_lock);
|
||||
pslot = radix_tree_lookup_slot(&mapping->page_tree,
|
||||
xa_lock(&mapping->i_pages);
|
||||
pslot = radix_tree_lookup_slot(&mapping->i_pages,
|
||||
page_index(head));
|
||||
/*
|
||||
* Check if the head page is present in radix tree.
|
||||
* We assume all tail are present too, if head is there.
|
||||
*/
|
||||
if (radix_tree_deref_slot_protected(pslot,
|
||||
&mapping->tree_lock) != head)
|
||||
&mapping->i_pages.xa_lock) != head)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -2700,7 +2700,7 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
|
|||
}
|
||||
spin_unlock(&pgdata->split_queue_lock);
|
||||
fail: if (mapping)
|
||||
spin_unlock(&mapping->tree_lock);
|
||||
xa_unlock(&mapping->i_pages);
|
||||
spin_unlock_irqrestore(zone_lru_lock(page_zone(head)), flags);
|
||||
unfreeze_page(head);
|
||||
ret = -EBUSY;
|
||||
|
|
|
@ -1344,8 +1344,8 @@ static void collapse_shmem(struct mm_struct *mm,
|
|||
*/
|
||||
|
||||
index = start;
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
radix_tree_for_each_slot(slot, &mapping->i_pages, &iter, start) {
|
||||
int n = min(iter.index, end) - index;
|
||||
|
||||
/*
|
||||
|
@ -1358,7 +1358,7 @@ static void collapse_shmem(struct mm_struct *mm,
|
|||
}
|
||||
nr_none += n;
|
||||
for (; index < min(iter.index, end); index++) {
|
||||
radix_tree_insert(&mapping->page_tree, index,
|
||||
radix_tree_insert(&mapping->i_pages, index,
|
||||
new_page + (index % HPAGE_PMD_NR));
|
||||
}
|
||||
|
||||
|
@ -1367,16 +1367,16 @@ static void collapse_shmem(struct mm_struct *mm,
|
|||
break;
|
||||
|
||||
page = radix_tree_deref_slot_protected(slot,
|
||||
&mapping->tree_lock);
|
||||
&mapping->i_pages.xa_lock);
|
||||
if (radix_tree_exceptional_entry(page) || !PageUptodate(page)) {
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
/* swap in or instantiate fallocated page */
|
||||
if (shmem_getpage(mapping->host, index, &page,
|
||||
SGP_NOHUGE)) {
|
||||
result = SCAN_FAIL;
|
||||
goto tree_unlocked;
|
||||
}
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
} else if (trylock_page(page)) {
|
||||
get_page(page);
|
||||
} else {
|
||||
|
@ -1385,7 +1385,7 @@ static void collapse_shmem(struct mm_struct *mm,
|
|||
}
|
||||
|
||||
/*
|
||||
* The page must be locked, so we can drop the tree_lock
|
||||
* The page must be locked, so we can drop the i_pages lock
|
||||
* without racing with truncate.
|
||||
*/
|
||||
VM_BUG_ON_PAGE(!PageLocked(page), page);
|
||||
|
@ -1396,7 +1396,7 @@ static void collapse_shmem(struct mm_struct *mm,
|
|||
result = SCAN_TRUNCATED;
|
||||
goto out_unlock;
|
||||
}
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
|
||||
if (isolate_lru_page(page)) {
|
||||
result = SCAN_DEL_PAGE_LRU;
|
||||
|
@ -1406,11 +1406,11 @@ static void collapse_shmem(struct mm_struct *mm,
|
|||
if (page_mapped(page))
|
||||
unmap_mapping_pages(mapping, index, 1, false);
|
||||
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
|
||||
slot = radix_tree_lookup_slot(&mapping->page_tree, index);
|
||||
slot = radix_tree_lookup_slot(&mapping->i_pages, index);
|
||||
VM_BUG_ON_PAGE(page != radix_tree_deref_slot_protected(slot,
|
||||
&mapping->tree_lock), page);
|
||||
&mapping->i_pages.xa_lock), page);
|
||||
VM_BUG_ON_PAGE(page_mapped(page), page);
|
||||
|
||||
/*
|
||||
|
@ -1431,14 +1431,14 @@ static void collapse_shmem(struct mm_struct *mm,
|
|||
list_add_tail(&page->lru, &pagelist);
|
||||
|
||||
/* Finally, replace with the new page. */
|
||||
radix_tree_replace_slot(&mapping->page_tree, slot,
|
||||
radix_tree_replace_slot(&mapping->i_pages, slot,
|
||||
new_page + (index % HPAGE_PMD_NR));
|
||||
|
||||
slot = radix_tree_iter_resume(slot, &iter);
|
||||
index++;
|
||||
continue;
|
||||
out_lru:
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
putback_lru_page(page);
|
||||
out_isolate_failed:
|
||||
unlock_page(page);
|
||||
|
@ -1464,14 +1464,14 @@ out_unlock:
|
|||
}
|
||||
|
||||
for (; index < end; index++) {
|
||||
radix_tree_insert(&mapping->page_tree, index,
|
||||
radix_tree_insert(&mapping->i_pages, index,
|
||||
new_page + (index % HPAGE_PMD_NR));
|
||||
}
|
||||
nr_none += n;
|
||||
}
|
||||
|
||||
tree_locked:
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
tree_unlocked:
|
||||
|
||||
if (result == SCAN_SUCCEED) {
|
||||
|
@ -1520,9 +1520,8 @@ tree_unlocked:
|
|||
} else {
|
||||
/* Something went wrong: rollback changes to the radix-tree */
|
||||
shmem_uncharge(mapping->host, nr_none);
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
radix_tree_for_each_slot(slot, &mapping->page_tree, &iter,
|
||||
start) {
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
radix_tree_for_each_slot(slot, &mapping->i_pages, &iter, start) {
|
||||
if (iter.index >= end)
|
||||
break;
|
||||
page = list_first_entry_or_null(&pagelist,
|
||||
|
@ -1532,8 +1531,7 @@ tree_unlocked:
|
|||
break;
|
||||
nr_none--;
|
||||
/* Put holes back where they were */
|
||||
radix_tree_delete(&mapping->page_tree,
|
||||
iter.index);
|
||||
radix_tree_delete(&mapping->i_pages, iter.index);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1542,16 +1540,15 @@ tree_unlocked:
|
|||
/* Unfreeze the page. */
|
||||
list_del(&page->lru);
|
||||
page_ref_unfreeze(page, 2);
|
||||
radix_tree_replace_slot(&mapping->page_tree,
|
||||
slot, page);
|
||||
radix_tree_replace_slot(&mapping->i_pages, slot, page);
|
||||
slot = radix_tree_iter_resume(slot, &iter);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
putback_lru_page(page);
|
||||
unlock_page(page);
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
}
|
||||
VM_BUG_ON(nr_none);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
|
||||
/* Unfreeze new_page, caller would take care about freeing it */
|
||||
page_ref_unfreeze(new_page, 1);
|
||||
|
@ -1579,7 +1576,7 @@ static void khugepaged_scan_shmem(struct mm_struct *mm,
|
|||
swap = 0;
|
||||
memset(khugepaged_node_load, 0, sizeof(khugepaged_node_load));
|
||||
rcu_read_lock();
|
||||
radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
|
||||
radix_tree_for_each_slot(slot, &mapping->i_pages, &iter, start) {
|
||||
if (iter.index >= start + HPAGE_PMD_NR)
|
||||
break;
|
||||
|
||||
|
|
|
@ -5974,9 +5974,9 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
|
|||
|
||||
/*
|
||||
* Interrupts should be disabled here because the caller holds the
|
||||
* mapping->tree_lock lock which is taken with interrupts-off. It is
|
||||
* i_pages lock which is taken with interrupts-off. It is
|
||||
* important here to have the interrupts disabled because it is the
|
||||
* only synchronisation we have for udpating the per-CPU variables.
|
||||
* only synchronisation we have for updating the per-CPU variables.
|
||||
*/
|
||||
VM_BUG_ON(!irqs_disabled());
|
||||
mem_cgroup_charge_statistics(memcg, page, PageTransHuge(page),
|
||||
|
|
32
mm/migrate.c
32
mm/migrate.c
|
@ -467,20 +467,21 @@ int migrate_page_move_mapping(struct address_space *mapping,
|
|||
oldzone = page_zone(page);
|
||||
newzone = page_zone(newpage);
|
||||
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
|
||||
pslot = radix_tree_lookup_slot(&mapping->page_tree,
|
||||
pslot = radix_tree_lookup_slot(&mapping->i_pages,
|
||||
page_index(page));
|
||||
|
||||
expected_count += 1 + page_has_private(page);
|
||||
if (page_count(page) != expected_count ||
|
||||
radix_tree_deref_slot_protected(pslot, &mapping->tree_lock) != page) {
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
radix_tree_deref_slot_protected(pslot,
|
||||
&mapping->i_pages.xa_lock) != page) {
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (!page_ref_freeze(page, expected_count)) {
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
|
@ -494,7 +495,7 @@ int migrate_page_move_mapping(struct address_space *mapping,
|
|||
if (mode == MIGRATE_ASYNC && head &&
|
||||
!buffer_migrate_lock_buffers(head, mode)) {
|
||||
page_ref_unfreeze(page, expected_count);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
|
@ -522,7 +523,7 @@ int migrate_page_move_mapping(struct address_space *mapping,
|
|||
SetPageDirty(newpage);
|
||||
}
|
||||
|
||||
radix_tree_replace_slot(&mapping->page_tree, pslot, newpage);
|
||||
radix_tree_replace_slot(&mapping->i_pages, pslot, newpage);
|
||||
|
||||
/*
|
||||
* Drop cache reference from old page by unfreezing
|
||||
|
@ -531,7 +532,7 @@ int migrate_page_move_mapping(struct address_space *mapping,
|
|||
*/
|
||||
page_ref_unfreeze(page, expected_count - 1);
|
||||
|
||||
spin_unlock(&mapping->tree_lock);
|
||||
xa_unlock(&mapping->i_pages);
|
||||
/* Leave irq disabled to prevent preemption while updating stats */
|
||||
|
||||
/*
|
||||
|
@ -574,20 +575,19 @@ int migrate_huge_page_move_mapping(struct address_space *mapping,
|
|||
int expected_count;
|
||||
void **pslot;
|
||||
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
|
||||
pslot = radix_tree_lookup_slot(&mapping->page_tree,
|
||||
page_index(page));
|
||||
pslot = radix_tree_lookup_slot(&mapping->i_pages, page_index(page));
|
||||
|
||||
expected_count = 2 + page_has_private(page);
|
||||
if (page_count(page) != expected_count ||
|
||||
radix_tree_deref_slot_protected(pslot, &mapping->tree_lock) != page) {
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
radix_tree_deref_slot_protected(pslot, &mapping->i_pages.xa_lock) != page) {
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (!page_ref_freeze(page, expected_count)) {
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
|
@ -596,11 +596,11 @@ int migrate_huge_page_move_mapping(struct address_space *mapping,
|
|||
|
||||
get_page(newpage);
|
||||
|
||||
radix_tree_replace_slot(&mapping->page_tree, pslot, newpage);
|
||||
radix_tree_replace_slot(&mapping->i_pages, pslot, newpage);
|
||||
|
||||
page_ref_unfreeze(page, expected_count - 1);
|
||||
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
|
||||
return MIGRATEPAGE_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -2099,7 +2099,8 @@ void __init page_writeback_init(void)
|
|||
* so that it can tag pages faster than a dirtying process can create them).
|
||||
*/
|
||||
/*
|
||||
* We tag pages in batches of WRITEBACK_TAG_BATCH to reduce tree_lock latency.
|
||||
* We tag pages in batches of WRITEBACK_TAG_BATCH to reduce the i_pages lock
|
||||
* latency.
|
||||
*/
|
||||
void tag_pages_for_writeback(struct address_space *mapping,
|
||||
pgoff_t start, pgoff_t end)
|
||||
|
@ -2109,22 +2110,22 @@ void tag_pages_for_writeback(struct address_space *mapping,
|
|||
struct radix_tree_iter iter;
|
||||
void **slot;
|
||||
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
radix_tree_for_each_tagged(slot, &mapping->page_tree, &iter, start,
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
radix_tree_for_each_tagged(slot, &mapping->i_pages, &iter, start,
|
||||
PAGECACHE_TAG_DIRTY) {
|
||||
if (iter.index > end)
|
||||
break;
|
||||
radix_tree_iter_tag_set(&mapping->page_tree, &iter,
|
||||
radix_tree_iter_tag_set(&mapping->i_pages, &iter,
|
||||
PAGECACHE_TAG_TOWRITE);
|
||||
tagged++;
|
||||
if ((tagged % WRITEBACK_TAG_BATCH) != 0)
|
||||
continue;
|
||||
slot = radix_tree_iter_resume(slot, &iter);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
cond_resched();
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
}
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
}
|
||||
EXPORT_SYMBOL(tag_pages_for_writeback);
|
||||
|
||||
|
@ -2467,13 +2468,13 @@ int __set_page_dirty_nobuffers(struct page *page)
|
|||
return 1;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&mapping->tree_lock, flags);
|
||||
xa_lock_irqsave(&mapping->i_pages, flags);
|
||||
BUG_ON(page_mapping(page) != mapping);
|
||||
WARN_ON_ONCE(!PagePrivate(page) && !PageUptodate(page));
|
||||
account_page_dirtied(page, mapping);
|
||||
radix_tree_tag_set(&mapping->page_tree, page_index(page),
|
||||
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);
|
||||
|
||||
if (mapping->host) {
|
||||
|
@ -2718,11 +2719,10 @@ int test_clear_page_writeback(struct page *page)
|
|||
struct backing_dev_info *bdi = inode_to_bdi(inode);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&mapping->tree_lock, flags);
|
||||
xa_lock_irqsave(&mapping->i_pages, flags);
|
||||
ret = TestClearPageWriteback(page);
|
||||
if (ret) {
|
||||
radix_tree_tag_clear(&mapping->page_tree,
|
||||
page_index(page),
|
||||
radix_tree_tag_clear(&mapping->i_pages, page_index(page),
|
||||
PAGECACHE_TAG_WRITEBACK);
|
||||
if (bdi_cap_account_writeback(bdi)) {
|
||||
struct bdi_writeback *wb = inode_to_wb(inode);
|
||||
|
@ -2736,7 +2736,7 @@ int test_clear_page_writeback(struct page *page)
|
|||
PAGECACHE_TAG_WRITEBACK))
|
||||
sb_clear_inode_writeback(mapping->host);
|
||||
|
||||
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||||
xa_unlock_irqrestore(&mapping->i_pages, flags);
|
||||
} else {
|
||||
ret = TestClearPageWriteback(page);
|
||||
}
|
||||
|
@ -2766,7 +2766,7 @@ int __test_set_page_writeback(struct page *page, bool keep_write)
|
|||
struct backing_dev_info *bdi = inode_to_bdi(inode);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&mapping->tree_lock, flags);
|
||||
xa_lock_irqsave(&mapping->i_pages, flags);
|
||||
ret = TestSetPageWriteback(page);
|
||||
if (!ret) {
|
||||
bool on_wblist;
|
||||
|
@ -2774,8 +2774,7 @@ int __test_set_page_writeback(struct page *page, bool keep_write)
|
|||
on_wblist = mapping_tagged(mapping,
|
||||
PAGECACHE_TAG_WRITEBACK);
|
||||
|
||||
radix_tree_tag_set(&mapping->page_tree,
|
||||
page_index(page),
|
||||
radix_tree_tag_set(&mapping->i_pages, page_index(page),
|
||||
PAGECACHE_TAG_WRITEBACK);
|
||||
if (bdi_cap_account_writeback(bdi))
|
||||
inc_wb_stat(inode_to_wb(inode), WB_WRITEBACK);
|
||||
|
@ -2789,14 +2788,12 @@ int __test_set_page_writeback(struct page *page, bool keep_write)
|
|||
sb_mark_inode_writeback(mapping->host);
|
||||
}
|
||||
if (!PageDirty(page))
|
||||
radix_tree_tag_clear(&mapping->page_tree,
|
||||
page_index(page),
|
||||
radix_tree_tag_clear(&mapping->i_pages, page_index(page),
|
||||
PAGECACHE_TAG_DIRTY);
|
||||
if (!keep_write)
|
||||
radix_tree_tag_clear(&mapping->page_tree,
|
||||
page_index(page),
|
||||
radix_tree_tag_clear(&mapping->i_pages, page_index(page),
|
||||
PAGECACHE_TAG_TOWRITE);
|
||||
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||||
xa_unlock_irqrestore(&mapping->i_pages, flags);
|
||||
} else {
|
||||
ret = TestSetPageWriteback(page);
|
||||
}
|
||||
|
@ -2816,7 +2813,7 @@ EXPORT_SYMBOL(__test_set_page_writeback);
|
|||
*/
|
||||
int mapping_tagged(struct address_space *mapping, int tag)
|
||||
{
|
||||
return radix_tree_tagged(&mapping->page_tree, tag);
|
||||
return radix_tree_tagged(&mapping->i_pages, tag);
|
||||
}
|
||||
EXPORT_SYMBOL(mapping_tagged);
|
||||
|
||||
|
|
|
@ -175,7 +175,7 @@ int __do_page_cache_readahead(struct address_space *mapping, struct file *filp,
|
|||
break;
|
||||
|
||||
rcu_read_lock();
|
||||
page = radix_tree_lookup(&mapping->page_tree, page_offset);
|
||||
page = radix_tree_lookup(&mapping->i_pages, page_offset);
|
||||
rcu_read_unlock();
|
||||
if (page && !radix_tree_exceptional_entry(page))
|
||||
continue;
|
||||
|
|
|
@ -32,11 +32,11 @@
|
|||
* mmlist_lock (in mmput, drain_mmlist and others)
|
||||
* mapping->private_lock (in __set_page_dirty_buffers)
|
||||
* mem_cgroup_{begin,end}_page_stat (memcg->move_lock)
|
||||
* mapping->tree_lock (widely used)
|
||||
* i_pages lock (widely used)
|
||||
* inode->i_lock (in set_page_dirty's __mark_inode_dirty)
|
||||
* bdi.wb->list_lock (in set_page_dirty's __mark_inode_dirty)
|
||||
* sb_lock (within inode_lock in fs/fs-writeback.c)
|
||||
* mapping->tree_lock (widely used, in set_page_dirty,
|
||||
* i_pages lock (widely used, in set_page_dirty,
|
||||
* in arch-dependent flush_dcache_mmap_lock,
|
||||
* within bdi.wb->list_lock in __sync_single_inode)
|
||||
*
|
||||
|
|
60
mm/shmem.c
60
mm/shmem.c
|
@ -332,12 +332,12 @@ static int shmem_radix_tree_replace(struct address_space *mapping,
|
|||
|
||||
VM_BUG_ON(!expected);
|
||||
VM_BUG_ON(!replacement);
|
||||
item = __radix_tree_lookup(&mapping->page_tree, index, &node, &pslot);
|
||||
item = __radix_tree_lookup(&mapping->i_pages, index, &node, &pslot);
|
||||
if (!item)
|
||||
return -ENOENT;
|
||||
if (item != expected)
|
||||
return -ENOENT;
|
||||
__radix_tree_replace(&mapping->page_tree, node, pslot,
|
||||
__radix_tree_replace(&mapping->i_pages, node, pslot,
|
||||
replacement, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
@ -355,7 +355,7 @@ static bool shmem_confirm_swap(struct address_space *mapping,
|
|||
void *item;
|
||||
|
||||
rcu_read_lock();
|
||||
item = radix_tree_lookup(&mapping->page_tree, index);
|
||||
item = radix_tree_lookup(&mapping->i_pages, index);
|
||||
rcu_read_unlock();
|
||||
return item == swp_to_radix_entry(swap);
|
||||
}
|
||||
|
@ -590,14 +590,14 @@ static int shmem_add_to_page_cache(struct page *page,
|
|||
page->mapping = mapping;
|
||||
page->index = index;
|
||||
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
if (PageTransHuge(page)) {
|
||||
void __rcu **results;
|
||||
pgoff_t idx;
|
||||
int i;
|
||||
|
||||
error = 0;
|
||||
if (radix_tree_gang_lookup_slot(&mapping->page_tree,
|
||||
if (radix_tree_gang_lookup_slot(&mapping->i_pages,
|
||||
&results, &idx, index, 1) &&
|
||||
idx < index + HPAGE_PMD_NR) {
|
||||
error = -EEXIST;
|
||||
|
@ -605,14 +605,14 @@ static int shmem_add_to_page_cache(struct page *page,
|
|||
|
||||
if (!error) {
|
||||
for (i = 0; i < HPAGE_PMD_NR; i++) {
|
||||
error = radix_tree_insert(&mapping->page_tree,
|
||||
error = radix_tree_insert(&mapping->i_pages,
|
||||
index + i, page + i);
|
||||
VM_BUG_ON(error);
|
||||
}
|
||||
count_vm_event(THP_FILE_ALLOC);
|
||||
}
|
||||
} else if (!expected) {
|
||||
error = radix_tree_insert(&mapping->page_tree, index, page);
|
||||
error = radix_tree_insert(&mapping->i_pages, index, page);
|
||||
} else {
|
||||
error = shmem_radix_tree_replace(mapping, index, expected,
|
||||
page);
|
||||
|
@ -624,10 +624,10 @@ static int shmem_add_to_page_cache(struct page *page,
|
|||
__inc_node_page_state(page, NR_SHMEM_THPS);
|
||||
__mod_node_page_state(page_pgdat(page), NR_FILE_PAGES, nr);
|
||||
__mod_node_page_state(page_pgdat(page), NR_SHMEM, nr);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
} else {
|
||||
page->mapping = NULL;
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
page_ref_sub(page, nr);
|
||||
}
|
||||
return error;
|
||||
|
@ -643,13 +643,13 @@ static void shmem_delete_from_page_cache(struct page *page, void *radswap)
|
|||
|
||||
VM_BUG_ON_PAGE(PageCompound(page), page);
|
||||
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
error = shmem_radix_tree_replace(mapping, page->index, page, radswap);
|
||||
page->mapping = NULL;
|
||||
mapping->nrpages--;
|
||||
__dec_node_page_state(page, NR_FILE_PAGES);
|
||||
__dec_node_page_state(page, NR_SHMEM);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
put_page(page);
|
||||
BUG_ON(error);
|
||||
}
|
||||
|
@ -662,9 +662,9 @@ static int shmem_free_swap(struct address_space *mapping,
|
|||
{
|
||||
void *old;
|
||||
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
old = radix_tree_delete_item(&mapping->page_tree, index, radswap);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
old = radix_tree_delete_item(&mapping->i_pages, index, radswap);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
if (old != radswap)
|
||||
return -ENOENT;
|
||||
free_swap_and_cache(radix_to_swp_entry(radswap));
|
||||
|
@ -675,7 +675,7 @@ static int shmem_free_swap(struct address_space *mapping,
|
|||
* Determine (in bytes) how many of the shmem object's pages mapped by the
|
||||
* given offsets are swapped out.
|
||||
*
|
||||
* This is safe to call without i_mutex or mapping->tree_lock thanks to RCU,
|
||||
* This is safe to call without i_mutex or the i_pages lock thanks to RCU,
|
||||
* as long as the inode doesn't go away and racy results are not a problem.
|
||||
*/
|
||||
unsigned long shmem_partial_swap_usage(struct address_space *mapping,
|
||||
|
@ -688,7 +688,7 @@ unsigned long shmem_partial_swap_usage(struct address_space *mapping,
|
|||
|
||||
rcu_read_lock();
|
||||
|
||||
radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
|
||||
radix_tree_for_each_slot(slot, &mapping->i_pages, &iter, start) {
|
||||
if (iter.index >= end)
|
||||
break;
|
||||
|
||||
|
@ -717,7 +717,7 @@ unsigned long shmem_partial_swap_usage(struct address_space *mapping,
|
|||
* Determine (in bytes) how many of the shmem object's pages mapped by the
|
||||
* given vma is swapped out.
|
||||
*
|
||||
* This is safe to call without i_mutex or mapping->tree_lock thanks to RCU,
|
||||
* This is safe to call without i_mutex or the i_pages lock thanks to RCU,
|
||||
* as long as the inode doesn't go away and racy results are not a problem.
|
||||
*/
|
||||
unsigned long shmem_swap_usage(struct vm_area_struct *vma)
|
||||
|
@ -1132,7 +1132,7 @@ static int shmem_unuse_inode(struct shmem_inode_info *info,
|
|||
int error = 0;
|
||||
|
||||
radswap = swp_to_radix_entry(swap);
|
||||
index = find_swap_entry(&mapping->page_tree, radswap);
|
||||
index = find_swap_entry(&mapping->i_pages, radswap);
|
||||
if (index == -1)
|
||||
return -EAGAIN; /* tell shmem_unuse we found nothing */
|
||||
|
||||
|
@ -1448,7 +1448,7 @@ static struct page *shmem_alloc_hugepage(gfp_t gfp,
|
|||
|
||||
hindex = round_down(index, HPAGE_PMD_NR);
|
||||
rcu_read_lock();
|
||||
if (radix_tree_gang_lookup_slot(&mapping->page_tree, &results, &idx,
|
||||
if (radix_tree_gang_lookup_slot(&mapping->i_pages, &results, &idx,
|
||||
hindex, 1) && idx < hindex + HPAGE_PMD_NR) {
|
||||
rcu_read_unlock();
|
||||
return NULL;
|
||||
|
@ -1561,14 +1561,14 @@ static int shmem_replace_page(struct page **pagep, gfp_t gfp,
|
|||
* Our caller will very soon move newpage out of swapcache, but it's
|
||||
* a nice clean interface for us to replace oldpage by newpage there.
|
||||
*/
|
||||
spin_lock_irq(&swap_mapping->tree_lock);
|
||||
xa_lock_irq(&swap_mapping->i_pages);
|
||||
error = shmem_radix_tree_replace(swap_mapping, swap_index, oldpage,
|
||||
newpage);
|
||||
if (!error) {
|
||||
__inc_node_page_state(newpage, NR_FILE_PAGES);
|
||||
__dec_node_page_state(oldpage, NR_FILE_PAGES);
|
||||
}
|
||||
spin_unlock_irq(&swap_mapping->tree_lock);
|
||||
xa_unlock_irq(&swap_mapping->i_pages);
|
||||
|
||||
if (unlikely(error)) {
|
||||
/*
|
||||
|
@ -2634,7 +2634,7 @@ static void shmem_tag_pins(struct address_space *mapping)
|
|||
start = 0;
|
||||
rcu_read_lock();
|
||||
|
||||
radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
|
||||
radix_tree_for_each_slot(slot, &mapping->i_pages, &iter, start) {
|
||||
page = radix_tree_deref_slot(slot);
|
||||
if (!page || radix_tree_exception(page)) {
|
||||
if (radix_tree_deref_retry(page)) {
|
||||
|
@ -2642,10 +2642,10 @@ static void shmem_tag_pins(struct address_space *mapping)
|
|||
continue;
|
||||
}
|
||||
} else if (page_count(page) - page_mapcount(page) > 1) {
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
radix_tree_tag_set(&mapping->page_tree, iter.index,
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
radix_tree_tag_set(&mapping->i_pages, iter.index,
|
||||
SHMEM_TAG_PINNED);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
}
|
||||
|
||||
if (need_resched()) {
|
||||
|
@ -2677,7 +2677,7 @@ static int shmem_wait_for_pins(struct address_space *mapping)
|
|||
|
||||
error = 0;
|
||||
for (scan = 0; scan <= LAST_SCAN; scan++) {
|
||||
if (!radix_tree_tagged(&mapping->page_tree, SHMEM_TAG_PINNED))
|
||||
if (!radix_tree_tagged(&mapping->i_pages, SHMEM_TAG_PINNED))
|
||||
break;
|
||||
|
||||
if (!scan)
|
||||
|
@ -2687,7 +2687,7 @@ static int shmem_wait_for_pins(struct address_space *mapping)
|
|||
|
||||
start = 0;
|
||||
rcu_read_lock();
|
||||
radix_tree_for_each_tagged(slot, &mapping->page_tree, &iter,
|
||||
radix_tree_for_each_tagged(slot, &mapping->i_pages, &iter,
|
||||
start, SHMEM_TAG_PINNED) {
|
||||
|
||||
page = radix_tree_deref_slot(slot);
|
||||
|
@ -2713,10 +2713,10 @@ static int shmem_wait_for_pins(struct address_space *mapping)
|
|||
error = -EBUSY;
|
||||
}
|
||||
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
radix_tree_tag_clear(&mapping->page_tree,
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
radix_tree_tag_clear(&mapping->i_pages,
|
||||
iter.index, SHMEM_TAG_PINNED);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
continue_resched:
|
||||
if (need_resched()) {
|
||||
slot = radix_tree_iter_resume(slot, &iter);
|
||||
|
|
|
@ -124,10 +124,10 @@ int __add_to_swap_cache(struct page *page, swp_entry_t entry)
|
|||
SetPageSwapCache(page);
|
||||
|
||||
address_space = swap_address_space(entry);
|
||||
spin_lock_irq(&address_space->tree_lock);
|
||||
xa_lock_irq(&address_space->i_pages);
|
||||
for (i = 0; i < nr; i++) {
|
||||
set_page_private(page + i, entry.val + i);
|
||||
error = radix_tree_insert(&address_space->page_tree,
|
||||
error = radix_tree_insert(&address_space->i_pages,
|
||||
idx + i, page + i);
|
||||
if (unlikely(error))
|
||||
break;
|
||||
|
@ -145,13 +145,13 @@ int __add_to_swap_cache(struct page *page, swp_entry_t entry)
|
|||
VM_BUG_ON(error == -EEXIST);
|
||||
set_page_private(page + i, 0UL);
|
||||
while (i--) {
|
||||
radix_tree_delete(&address_space->page_tree, idx + i);
|
||||
radix_tree_delete(&address_space->i_pages, idx + i);
|
||||
set_page_private(page + i, 0UL);
|
||||
}
|
||||
ClearPageSwapCache(page);
|
||||
page_ref_sub(page, nr);
|
||||
}
|
||||
spin_unlock_irq(&address_space->tree_lock);
|
||||
xa_unlock_irq(&address_space->i_pages);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ void __delete_from_swap_cache(struct page *page)
|
|||
address_space = swap_address_space(entry);
|
||||
idx = swp_offset(entry);
|
||||
for (i = 0; i < nr; i++) {
|
||||
radix_tree_delete(&address_space->page_tree, idx + i);
|
||||
radix_tree_delete(&address_space->i_pages, idx + i);
|
||||
set_page_private(page + i, 0);
|
||||
}
|
||||
ClearPageSwapCache(page);
|
||||
|
@ -272,9 +272,9 @@ void delete_from_swap_cache(struct page *page)
|
|||
entry.val = page_private(page);
|
||||
|
||||
address_space = swap_address_space(entry);
|
||||
spin_lock_irq(&address_space->tree_lock);
|
||||
xa_lock_irq(&address_space->i_pages);
|
||||
__delete_from_swap_cache(page);
|
||||
spin_unlock_irq(&address_space->tree_lock);
|
||||
xa_unlock_irq(&address_space->i_pages);
|
||||
|
||||
put_swap_page(page, entry);
|
||||
page_ref_sub(page, hpage_nr_pages(page));
|
||||
|
@ -628,12 +628,11 @@ int init_swap_address_space(unsigned int type, unsigned long nr_pages)
|
|||
return -ENOMEM;
|
||||
for (i = 0; i < nr; i++) {
|
||||
space = spaces + i;
|
||||
INIT_RADIX_TREE(&space->page_tree, GFP_ATOMIC|__GFP_NOWARN);
|
||||
INIT_RADIX_TREE(&space->i_pages, GFP_ATOMIC|__GFP_NOWARN);
|
||||
atomic_set(&space->i_mmap_writable, 0);
|
||||
space->a_ops = &swap_aops;
|
||||
/* swap cache doesn't use writeback related tags */
|
||||
mapping_set_no_writeback_tags(space);
|
||||
spin_lock_init(&space->tree_lock);
|
||||
}
|
||||
nr_swapper_spaces[type] = nr;
|
||||
rcu_assign_pointer(swapper_spaces[type], spaces);
|
||||
|
|
|
@ -36,11 +36,11 @@ static inline void __clear_shadow_entry(struct address_space *mapping,
|
|||
struct radix_tree_node *node;
|
||||
void **slot;
|
||||
|
||||
if (!__radix_tree_lookup(&mapping->page_tree, index, &node, &slot))
|
||||
if (!__radix_tree_lookup(&mapping->i_pages, index, &node, &slot))
|
||||
return;
|
||||
if (*slot != entry)
|
||||
return;
|
||||
__radix_tree_replace(&mapping->page_tree, node, slot, NULL,
|
||||
__radix_tree_replace(&mapping->i_pages, node, slot, NULL,
|
||||
workingset_update_node);
|
||||
mapping->nrexceptional--;
|
||||
}
|
||||
|
@ -48,9 +48,9 @@ static inline void __clear_shadow_entry(struct address_space *mapping,
|
|||
static void clear_shadow_entry(struct address_space *mapping, pgoff_t index,
|
||||
void *entry)
|
||||
{
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
__clear_shadow_entry(mapping, index, entry);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -79,7 +79,7 @@ static void truncate_exceptional_pvec_entries(struct address_space *mapping,
|
|||
dax = dax_mapping(mapping);
|
||||
lock = !dax && indices[j] < end;
|
||||
if (lock)
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
|
||||
for (i = j; i < pagevec_count(pvec); i++) {
|
||||
struct page *page = pvec->pages[i];
|
||||
|
@ -102,7 +102,7 @@ static void truncate_exceptional_pvec_entries(struct address_space *mapping,
|
|||
}
|
||||
|
||||
if (lock)
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
pvec->nr = j;
|
||||
}
|
||||
|
||||
|
@ -518,8 +518,8 @@ void truncate_inode_pages_final(struct address_space *mapping)
|
|||
* modification that does not see AS_EXITING is
|
||||
* completed before starting the final truncate.
|
||||
*/
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
xa_lock_irq(&mapping->i_pages);
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
|
||||
truncate_inode_pages(mapping, 0);
|
||||
}
|
||||
|
@ -627,13 +627,13 @@ invalidate_complete_page2(struct address_space *mapping, struct page *page)
|
|||
if (page_has_private(page) && !try_to_release_page(page, GFP_KERNEL))
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&mapping->tree_lock, flags);
|
||||
xa_lock_irqsave(&mapping->i_pages, flags);
|
||||
if (PageDirty(page))
|
||||
goto failed;
|
||||
|
||||
BUG_ON(page_has_private(page));
|
||||
__delete_from_page_cache(page, NULL);
|
||||
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||||
xa_unlock_irqrestore(&mapping->i_pages, flags);
|
||||
|
||||
if (mapping->a_ops->freepage)
|
||||
mapping->a_ops->freepage(page);
|
||||
|
@ -641,7 +641,7 @@ invalidate_complete_page2(struct address_space *mapping, struct page *page)
|
|||
put_page(page); /* pagecache ref */
|
||||
return 1;
|
||||
failed:
|
||||
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||||
xa_unlock_irqrestore(&mapping->i_pages, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
12
mm/vmscan.c
12
mm/vmscan.c
|
@ -693,7 +693,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page,
|
|||
BUG_ON(!PageLocked(page));
|
||||
BUG_ON(mapping != page_mapping(page));
|
||||
|
||||
spin_lock_irqsave(&mapping->tree_lock, flags);
|
||||
xa_lock_irqsave(&mapping->i_pages, flags);
|
||||
/*
|
||||
* The non racy check for a busy page.
|
||||
*
|
||||
|
@ -717,7 +717,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page,
|
|||
* load is not satisfied before that of page->_refcount.
|
||||
*
|
||||
* Note that if SetPageDirty is always performed via set_page_dirty,
|
||||
* and thus under tree_lock, then this ordering is not required.
|
||||
* and thus under the i_pages lock, then this ordering is not required.
|
||||
*/
|
||||
if (unlikely(PageTransHuge(page)) && PageSwapCache(page))
|
||||
refcount = 1 + HPAGE_PMD_NR;
|
||||
|
@ -735,7 +735,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page,
|
|||
swp_entry_t swap = { .val = page_private(page) };
|
||||
mem_cgroup_swapout(page, swap);
|
||||
__delete_from_swap_cache(page);
|
||||
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||||
xa_unlock_irqrestore(&mapping->i_pages, flags);
|
||||
put_swap_page(page, swap);
|
||||
} else {
|
||||
void (*freepage)(struct page *);
|
||||
|
@ -756,13 +756,13 @@ static int __remove_mapping(struct address_space *mapping, struct page *page,
|
|||
* only page cache pages found in these are zero pages
|
||||
* covering holes, and because we don't want to mix DAX
|
||||
* exceptional entries and shadow exceptional entries in the
|
||||
* same page_tree.
|
||||
* same address_space.
|
||||
*/
|
||||
if (reclaimed && page_is_file_cache(page) &&
|
||||
!mapping_exiting(mapping) && !dax_mapping(mapping))
|
||||
shadow = workingset_eviction(mapping, page);
|
||||
__delete_from_page_cache(page, shadow);
|
||||
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||||
xa_unlock_irqrestore(&mapping->i_pages, flags);
|
||||
|
||||
if (freepage != NULL)
|
||||
freepage(page);
|
||||
|
@ -771,7 +771,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page,
|
|||
return 1;
|
||||
|
||||
cannot_free:
|
||||
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||||
xa_unlock_irqrestore(&mapping->i_pages, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -202,7 +202,7 @@ static void unpack_shadow(void *shadow, int *memcgidp, pg_data_t **pgdat,
|
|||
* @mapping: address space the page was backing
|
||||
* @page: the page being evicted
|
||||
*
|
||||
* Returns a shadow entry to be stored in @mapping->page_tree in place
|
||||
* Returns a shadow entry to be stored in @mapping->i_pages in place
|
||||
* of the evicted @page so that a later refault can be detected.
|
||||
*/
|
||||
void *workingset_eviction(struct address_space *mapping, struct page *page)
|
||||
|
@ -348,7 +348,7 @@ void workingset_update_node(struct radix_tree_node *node)
|
|||
*
|
||||
* Avoid acquiring the list_lru lock when the nodes are
|
||||
* already where they should be. The list_empty() test is safe
|
||||
* as node->private_list is protected by &mapping->tree_lock.
|
||||
* as node->private_list is protected by the i_pages lock.
|
||||
*/
|
||||
if (node->count && node->count == node->exceptional) {
|
||||
if (list_empty(&node->private_list))
|
||||
|
@ -366,7 +366,7 @@ static unsigned long count_shadow_nodes(struct shrinker *shrinker,
|
|||
unsigned long nodes;
|
||||
unsigned long cache;
|
||||
|
||||
/* list_lru lock nests inside IRQ-safe mapping->tree_lock */
|
||||
/* list_lru lock nests inside the IRQ-safe i_pages lock */
|
||||
local_irq_disable();
|
||||
nodes = list_lru_shrink_count(&shadow_nodes, sc);
|
||||
local_irq_enable();
|
||||
|
@ -419,21 +419,21 @@ static enum lru_status shadow_lru_isolate(struct list_head *item,
|
|||
|
||||
/*
|
||||
* Page cache insertions and deletions synchroneously maintain
|
||||
* the shadow node LRU under the mapping->tree_lock and the
|
||||
* the shadow node LRU under the i_pages lock and the
|
||||
* lru_lock. Because the page cache tree is emptied before
|
||||
* the inode can be destroyed, holding the lru_lock pins any
|
||||
* address_space that has radix tree nodes on the LRU.
|
||||
*
|
||||
* We can then safely transition to the mapping->tree_lock to
|
||||
* We can then safely transition to the i_pages lock to
|
||||
* pin only the address_space of the particular node we want
|
||||
* to reclaim, take the node off-LRU, and drop the lru_lock.
|
||||
*/
|
||||
|
||||
node = container_of(item, struct radix_tree_node, private_list);
|
||||
mapping = container_of(node->root, struct address_space, page_tree);
|
||||
mapping = container_of(node->root, struct address_space, i_pages);
|
||||
|
||||
/* Coming from the list, invert the lock order */
|
||||
if (!spin_trylock(&mapping->tree_lock)) {
|
||||
if (!xa_trylock(&mapping->i_pages)) {
|
||||
spin_unlock(lru_lock);
|
||||
ret = LRU_RETRY;
|
||||
goto out;
|
||||
|
@ -468,11 +468,11 @@ static enum lru_status shadow_lru_isolate(struct list_head *item,
|
|||
if (WARN_ON_ONCE(node->exceptional))
|
||||
goto out_invalid;
|
||||
inc_lruvec_page_state(virt_to_page(node), WORKINGSET_NODERECLAIM);
|
||||
__radix_tree_delete_node(&mapping->page_tree, node,
|
||||
__radix_tree_delete_node(&mapping->i_pages, node,
|
||||
workingset_lookup_update(mapping));
|
||||
|
||||
out_invalid:
|
||||
spin_unlock(&mapping->tree_lock);
|
||||
xa_unlock(&mapping->i_pages);
|
||||
ret = LRU_REMOVED_RETRY;
|
||||
out:
|
||||
local_irq_enable();
|
||||
|
@ -487,7 +487,7 @@ static unsigned long scan_shadow_nodes(struct shrinker *shrinker,
|
|||
{
|
||||
unsigned long ret;
|
||||
|
||||
/* list_lru lock nests inside IRQ-safe mapping->tree_lock */
|
||||
/* list_lru lock nests inside the IRQ-safe i_pages lock */
|
||||
local_irq_disable();
|
||||
ret = list_lru_shrink_walk(&shadow_nodes, sc, shadow_lru_isolate, NULL);
|
||||
local_irq_enable();
|
||||
|
@ -503,7 +503,7 @@ static struct shrinker workingset_shadow_shrinker = {
|
|||
|
||||
/*
|
||||
* Our list_lru->lock is IRQ-safe as it nests inside the IRQ-safe
|
||||
* mapping->tree_lock.
|
||||
* i_pages lock.
|
||||
*/
|
||||
static struct lock_class_key shadow_nodes_key;
|
||||
|
||||
|
|
Loading…
Reference in a new issue