}
/*
- * This adds a page to the page cache, starting out as locked,
- * owned by us, but unreferenced, not uptodate and with no errors.
- * The caller must hold a write_lock on the mapping->page_lock.
+ * This adds a page to the page cache, starting out as locked, unreferenced,
+ * not uptodate and with no errors.
+ *
+ * The caller must hold a write_lock on mapping->page_lock.
+ *
+ * This function is used for two things: adding newly allocated pagecache
+ * pages and for moving existing anon pages into swapcache.
+ *
+ * In the case of pagecache pages, the page is new, so we can just run
+ * SetPageLocked() against it. The other page state flags were set by
+ * rmqueue()
+ *
+ * In the case of swapcache, try_to_swap_out() has already locked the page, so
+ * SetPageLocked() is ugly-but-OK there too. The required page state has been
+ * set up by swap_out_add_to_swap_cache().
*/
static int __add_to_page_cache(struct page *page,
struct address_space *mapping, unsigned long offset)
{
- page_cache_get(page);
- if (radix_tree_insert(&mapping->page_tree, offset, page) < 0)
- goto nomem;
- page->flags &= ~(1 << PG_uptodate | 1 << PG_error |
- 1 << PG_referenced | 1 << PG_arch_1 | 1 << PG_checked);
- SetPageLocked(page);
- ClearPageDirty(page);
- ___add_to_page_cache(page, mapping, offset);
- return 0;
- nomem:
- page_cache_release(page);
+ if (radix_tree_insert(&mapping->page_tree, offset, page) == 0) {
+ SetPageLocked(page);
+ ClearPageDirty(page);
+ ___add_to_page_cache(page, mapping, offset);
+ page_cache_get(page);
+ return 0;
+ }
return -ENOMEM;
}
if (PageWriteback(page))
BUG();
ClearPageDirty(page);
- page->flags &= ~(1<<PG_referenced);
if (current->flags & PF_FREE_PAGES)
goto local_freelist;
return page;
}
+/*
+ * This page is about to be returned from the page allocator
+ */
+static inline void prep_new_page(struct page *page)
+{
+ BUG_ON(page->mapping);
+ BUG_ON(PagePrivate(page));
+ BUG_ON(PageLocked(page));
+ BUG_ON(PageLRU(page));
+ BUG_ON(PageActive(page));
+ BUG_ON(PageDirty(page));
+ BUG_ON(PageWriteback(page));
+ page->flags &= ~(1 << PG_uptodate | 1 << PG_error |
+ 1 << PG_referenced | 1 << PG_arch_1 |
+ 1 << PG_checked);
+ set_page_count(page, 1);
+}
+
static FASTCALL(struct page * rmqueue(zone_t *zone, unsigned int order));
static struct page * rmqueue(zone_t *zone, unsigned int order)
{
page = expand(zone, page, index, order, curr_order, area);
spin_unlock_irqrestore(&zone->lock, flags);
- set_page_count(page, 1);
if (bad_range(zone, page))
BUG();
- if (PageLRU(page))
- BUG();
- if (PageActive(page))
- BUG();
+ prep_new_page(page);
return page;
}
curr_order++;
tmp = list_entry(entry, struct page, list);
if (tmp->index == order && memclass(page_zone(tmp), classzone)) {
list_del(entry);
- current->nr_local_pages--;
- set_page_count(tmp, 1);
page = tmp;
-
- if (PagePrivate(page))
- BUG();
- if (page->mapping)
- BUG();
- if (PageLocked(page))
- BUG();
- if (PageLRU(page))
- BUG();
- if (PageActive(page))
- BUG();
- if (PageDirty(page))
- BUG();
- if (PageWriteback(page))
- BUG();
-
+ current->nr_local_pages--;
+ prep_new_page(page);
break;
}
} while ((entry = entry->next) != local_pages);
/* Add it to the swap cache */
*pslot = page;
- page->flags &= ~(1 << PG_uptodate | 1 << PG_error
- | 1 << PG_referenced | 1 << PG_arch_1
- | 1 << PG_checked);
+ /*
+ * This code used to clear PG_uptodate, PG_error, PG_arch1,
+ * PG_referenced and PG_checked. What _should_ it clear?
+ */
+ ClearPageUptodate(page);
+ ClearPageReferenced(page);
+
SetPageLocked(page);
ClearPageDirty(page);
___add_to_page_cache(page, &swapper_space, entry.val);
__delete_from_swap_cache(page);
*pslot = page;
- page->flags &= ~(1 << PG_uptodate | 1 << PG_error |
- 1 << PG_referenced | 1 << PG_arch_1 |
- 1 << PG_checked);
+
+ /*
+ * This code used to clear PG_uptodate, PG_error, PG_referenced,
+ * PG_arch_1 and PG_checked. It's not really clear why.
+ */
+ ClearPageUptodate(page);
+ ClearPageReferenced(page);
+
/*
* ___add_to_page_cache puts the page on ->clean_pages,
* but it's dirty. If it's on ->clean_pages, it will basically
current->flags &= ~PF_MEMALLOC;
current->flags |= PF_RADIX_TREE;
+ ClearPageUptodate(page); /* why? */
+ ClearPageReferenced(page); /* why? */
ret = add_to_swap_cache(page, entry);
current->flags = flags;
return ret;