summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/mm.h5
-rw-r--r--include/linux/page-flags.h28
-rw-r--r--include/linux/swap.h14
3 files changed, 46 insertions, 1 deletions
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 163e19fd7b33..0c0b6d41dbb0 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -130,6 +130,9 @@ struct vm_operations_struct {
struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int unused);
};
+/* forward declaration; pte_chain is meant to be internal to rmap.c */
+struct pte_chain;
+
/*
* Each physical page in the system has a struct page associated with
* it to keep track of whatever it is we are using the page for at the
@@ -154,6 +157,8 @@ struct page {
updated asynchronously */
struct list_head lru; /* Pageout list, eg. active_list;
protected by pagemap_lru_lock !! */
+ struct pte_chain * pte_chain; /* Reverse pte mapping pointer.
+ * protected by PG_chainlock */
unsigned long private; /* mapping-private opaque data */
/*
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 93a6f27cb454..7cdd56c8cc3e 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -47,7 +47,7 @@
* locked- and dirty-page accounting. The top eight bits of page->flags are
* used for page->zone, so putting flag bits there doesn't work.
*/
-#define PG_locked 0 /* Page is locked. Don't touch. */
+#define PG_locked 0 /* Page is locked. Don't touch. */
#define PG_error 1
#define PG_referenced 2
#define PG_uptodate 3
@@ -65,6 +65,7 @@
#define PG_private 12 /* Has something at ->private */
#define PG_writeback 13 /* Page is under writeback */
#define PG_nosave 15 /* Used for system suspend/resume */
+#define PG_chainlock 16 /* lock bit for ->pte_chain */
/*
* Global page accounting. One instance per CPU.
@@ -217,6 +218,31 @@ extern void get_page_state(struct page_state *ret);
#define TestClearPageNosave(page) test_and_clear_bit(PG_nosave, &(page)->flags)
/*
+ * inlines for acquisition and release of PG_chainlock
+ */
+static inline void pte_chain_lock(struct page *page)
+{
+ /*
+ * Assuming the lock is uncontended, this never enters
+ * the body of the outer loop. If it is contended, then
+ * within the inner loop a non-atomic test is used to
+ * busywait with less bus contention for a good time to
+ * attempt to acquire the lock bit.
+ */
+ preempt_disable();
+ while (test_and_set_bit(PG_chainlock, &page->flags)) {
+ while (test_bit(PG_chainlock, &page->flags))
+ cpu_relax();
+ }
+}
+
+static inline void pte_chain_unlock(struct page *page)
+{
+ clear_bit(PG_chainlock, &page->flags);
+ preempt_enable();
+}
+
+/*
* The PageSwapCache predicate doesn't use a PG_flag at this time,
* but it may again do so one day.
*/
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 0b448a811a39..8ba0854d69af 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -142,6 +142,19 @@ struct sysinfo;
struct address_space;
struct zone_t;
+/* linux/mm/rmap.c */
+extern int FASTCALL(page_referenced(struct page *));
+extern void FASTCALL(page_add_rmap(struct page *, pte_t *));
+extern void FASTCALL(page_remove_rmap(struct page *, pte_t *));
+extern int FASTCALL(try_to_unmap(struct page *));
+extern int FASTCALL(page_over_rsslimit(struct page *));
+
+/* return values of try_to_unmap */
+#define SWAP_SUCCESS 0
+#define SWAP_AGAIN 1
+#define SWAP_FAIL 2
+#define SWAP_ERROR 3
+
/* linux/mm/swap.c */
extern void FASTCALL(lru_cache_add(struct page *));
extern void FASTCALL(__lru_cache_del(struct page *));
@@ -168,6 +181,7 @@ int rw_swap_page_sync(int rw, swp_entry_t entry, struct page *page);
extern void show_swap_cache_info(void);
#endif
extern int add_to_swap_cache(struct page *, swp_entry_t);
+extern int add_to_swap(struct page *);
extern void __delete_from_swap_cache(struct page *page);
extern void delete_from_swap_cache(struct page *page);
extern int move_to_swap_cache(struct page *page, swp_entry_t entry);