]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - mm/z3fold.c
rtc: m41t80: remove excess kerneldoc
[linux.git] / mm / z3fold.c
index ed19d98c9dcd1641c5e66d27d586e93f43fadce1..05bdf90646e7937ab8435327f785afbb0deaabf1 100644 (file)
@@ -295,14 +295,11 @@ static void z3fold_unregister_migration(struct z3fold_pool *pool)
  }
 
 /* Initializes the z3fold header of a newly allocated z3fold page */
-static struct z3fold_header *init_z3fold_page(struct page *page,
+static struct z3fold_header *init_z3fold_page(struct page *page, bool headless,
                                        struct z3fold_pool *pool, gfp_t gfp)
 {
        struct z3fold_header *zhdr = page_address(page);
-       struct z3fold_buddy_slots *slots = alloc_slots(pool, gfp);
-
-       if (!slots)
-               return NULL;
+       struct z3fold_buddy_slots *slots;
 
        INIT_LIST_HEAD(&page->lru);
        clear_bit(PAGE_HEADLESS, &page->private);
@@ -310,6 +307,12 @@ static struct z3fold_header *init_z3fold_page(struct page *page,
        clear_bit(NEEDS_COMPACTING, &page->private);
        clear_bit(PAGE_STALE, &page->private);
        clear_bit(PAGE_CLAIMED, &page->private);
+       if (headless)
+               return zhdr;
+
+       slots = alloc_slots(pool, gfp);
+       if (!slots)
+               return NULL;
 
        spin_lock_init(&zhdr->page_lock);
        kref_init(&zhdr->refcount);
@@ -366,9 +369,10 @@ static inline int __idx(struct z3fold_header *zhdr, enum buddy bud)
  * Encodes the handle of a particular buddy within a z3fold page
  * Pool lock should be held as this function accesses first_num
  */
-static unsigned long encode_handle(struct z3fold_header *zhdr, enum buddy bud)
+static unsigned long __encode_handle(struct z3fold_header *zhdr,
+                               struct z3fold_buddy_slots *slots,
+                               enum buddy bud)
 {
-       struct z3fold_buddy_slots *slots;
        unsigned long h = (unsigned long)zhdr;
        int idx = 0;
 
@@ -385,11 +389,15 @@ static unsigned long encode_handle(struct z3fold_header *zhdr, enum buddy bud)
        if (bud == LAST)
                h |= (zhdr->last_chunks << BUDDY_SHIFT);
 
-       slots = zhdr->slots;
        slots->slot[idx] = h;
        return (unsigned long)&slots->slot[idx];
 }
 
+static unsigned long encode_handle(struct z3fold_header *zhdr, enum buddy bud)
+{
+       return __encode_handle(zhdr, zhdr->slots, bud);
+}
+
 /* Returns the z3fold page where a given handle is stored */
 static inline struct z3fold_header *handle_to_z3fold_header(unsigned long h)
 {
@@ -624,6 +632,7 @@ static void do_compact_page(struct z3fold_header *zhdr, bool locked)
        }
 
        if (unlikely(PageIsolated(page) ||
+                    test_bit(PAGE_CLAIMED, &page->private) ||
                     test_bit(PAGE_STALE, &page->private))) {
                z3fold_page_unlock(zhdr);
                return;
@@ -924,7 +933,7 @@ static int z3fold_alloc(struct z3fold_pool *pool, size_t size, gfp_t gfp,
        if (!page)
                return -ENOMEM;
 
-       zhdr = init_z3fold_page(page, pool, gfp);
+       zhdr = init_z3fold_page(page, bud == HEADLESS, pool, gfp);
        if (!zhdr) {
                __free_page(page);
                return -ENOMEM;
@@ -1100,6 +1109,7 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
        struct z3fold_header *zhdr = NULL;
        struct page *page = NULL;
        struct list_head *pos;
+       struct z3fold_buddy_slots slots;
        unsigned long first_handle = 0, middle_handle = 0, last_handle = 0;
 
        spin_lock(&pool->lock);
@@ -1118,16 +1128,22 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
                        /* this bit could have been set by free, in which case
                         * we pass over to the next page in the pool.
                         */
-                       if (test_and_set_bit(PAGE_CLAIMED, &page->private))
+                       if (test_and_set_bit(PAGE_CLAIMED, &page->private)) {
+                               page = NULL;
                                continue;
+                       }
 
-                       if (unlikely(PageIsolated(page)))
+                       if (unlikely(PageIsolated(page))) {
+                               clear_bit(PAGE_CLAIMED, &page->private);
+                               page = NULL;
                                continue;
+                       }
+                       zhdr = page_address(page);
                        if (test_bit(PAGE_HEADLESS, &page->private))
                                break;
 
-                       zhdr = page_address(page);
                        if (!z3fold_page_trylock(zhdr)) {
+                               clear_bit(PAGE_CLAIMED, &page->private);
                                zhdr = NULL;
                                continue; /* can't evict at this point */
                        }
@@ -1145,26 +1161,30 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
 
                if (!test_bit(PAGE_HEADLESS, &page->private)) {
                        /*
-                        * We need encode the handles before unlocking, since
-                        * we can race with free that will set
-                        * (first|last)_chunks to 0
+                        * We need encode the handles before unlocking, and
+                        * use our local slots structure because z3fold_free
+                        * can zero out zhdr->slots and we can't do much
+                        * about that
                         */
                        first_handle = 0;
                        last_handle = 0;
                        middle_handle = 0;
                        if (zhdr->first_chunks)
-                               first_handle = encode_handle(zhdr, FIRST);
+                               first_handle = __encode_handle(zhdr, &slots,
+                                                               FIRST);
                        if (zhdr->middle_chunks)
-                               middle_handle = encode_handle(zhdr, MIDDLE);
+                               middle_handle = __encode_handle(zhdr, &slots,
+                                                               MIDDLE);
                        if (zhdr->last_chunks)
-                               last_handle = encode_handle(zhdr, LAST);
+                               last_handle = __encode_handle(zhdr, &slots,
+                                                               LAST);
                        /*
                         * it's safe to unlock here because we hold a
                         * reference to this page
                         */
                        z3fold_page_unlock(zhdr);
                } else {
-                       first_handle = encode_handle(zhdr, HEADLESS);
+                       first_handle = __encode_handle(zhdr, &slots, HEADLESS);
                        last_handle = middle_handle = 0;
                }
 
@@ -1194,9 +1214,9 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
                        spin_lock(&pool->lock);
                        list_add(&page->lru, &pool->lru);
                        spin_unlock(&pool->lock);
+                       clear_bit(PAGE_CLAIMED, &page->private);
                } else {
                        z3fold_page_lock(zhdr);
-                       clear_bit(PAGE_CLAIMED, &page->private);
                        if (kref_put(&zhdr->refcount,
                                        release_z3fold_page_locked)) {
                                atomic64_dec(&pool->pages_nr);
@@ -1211,6 +1231,7 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
                        list_add(&page->lru, &pool->lru);
                        spin_unlock(&pool->lock);
                        z3fold_page_unlock(zhdr);
+                       clear_bit(PAGE_CLAIMED, &page->private);
                }
 
                /* We started off locked to we need to lock the pool back */
@@ -1315,7 +1336,8 @@ static bool z3fold_page_isolate(struct page *page, isolate_mode_t mode)
        VM_BUG_ON_PAGE(!PageMovable(page), page);
        VM_BUG_ON_PAGE(PageIsolated(page), page);
 
-       if (test_bit(PAGE_HEADLESS, &page->private))
+       if (test_bit(PAGE_HEADLESS, &page->private) ||
+           test_bit(PAGE_CLAIMED, &page->private))
                return false;
 
        zhdr = page_address(page);