Added patch headers.
[linux-flexiantxendom0-3.2.10.git] / mm / precache.c
1 /*
2  * linux/mm/precache.c
3  *
4  * Implements "precache" for filesystems/pagecache on top of transcendent
5  * memory ("tmem") API.  A filesystem creates an "ephemeral tmem pool"
6  * and retains the returned pool_id in its superblock.  Clean pages evicted
7  * from pagecache may be "put" into the pool and associated with a "handle"
8  * consisting of the pool_id, an object (inode) id, and an index (page offset).
9  * Note that the page is copied to tmem; no kernel mappings are changed.
10  * If the page is later needed, the filesystem (or VFS) issues a "get", passing
11  * the same handle and an empty pageframe.  If successful, the page is copied
12  * into the pageframe and a disk read is avoided.  But since the tmem pool
13  * is of indeterminate size, a "put" page has indeterminate longevity
14  * ("ephemeral"), and the "get" may fail, in which case the filesystem must
15  * read the page from disk as before.  Note that the filesystem/pagecache are
16  * responsible for maintaining coherency between the pagecache, precache,
17  * and the disk, for which "flush page" and "flush object" actions are
18  * provided.  And when a filesystem is unmounted, it must "destroy" the pool.
19  *
20  * Two types of pools may be created for a precache: "private" or "shared".
21  * For a private pool, a successful "get" always flushes, implementing
22  * exclusive semantics; for a "shared" pool (which is intended for use by
23  * co-resident nodes of a cluster filesystem), the "flush" is not guaranteed.
24  * In either case, a failed "duplicate" put (overwrite) always guarantee
25  * the old data is flushed.
26  *
27  * Note also that multiple accesses to a tmem pool may be concurrent and any
28  * ordering must be guaranteed by the caller.
29  *
30  * Copyright (C) 2008,2009 Dan Magenheimer, Oracle Corp.
31  */
32
33 #include <linux/precache.h>
34 #include <linux/module.h>
35 #include "tmem.h"
36
37 static int precache_auto_allocate; /* set to 1 to auto_allocate */
38
39 int precache_put(struct address_space *mapping, unsigned long index,
40  struct page *page)
41 {
42         u32 tmem_pool = mapping->host->i_sb->precache_poolid;
43         u64 obj = (unsigned long) mapping->host->i_ino;
44         u32 ind = (u32) index;
45         unsigned long mfn = pfn_to_mfn(page_to_pfn(page));
46         int ret;
47
48         if ((s32)tmem_pool < 0) {
49                 if (!precache_auto_allocate)
50                         return 0;
51                 /* a put on a non-existent precache may auto-allocate one */
52                 ret = tmem_new_pool(0, 0, 0);
53                 if (ret < 0)
54                         return 0;
55                 printk(KERN_INFO
56                         "Mapping superblock for s_id=%s to precache_id=%d\n",
57                         mapping->host->i_sb->s_id, tmem_pool);
58                 mapping->host->i_sb->precache_poolid = tmem_pool;
59         }
60         if (ind != index)
61                 return 0;
62         mb(); /* ensure page is quiescent; tmem may address it with an alias */
63         return tmem_put_page(tmem_pool, obj, ind, mfn);
64 }
65
66 int precache_get(struct address_space *mapping, unsigned long index,
67  struct page *empty_page)
68 {
69         u32 tmem_pool = mapping->host->i_sb->precache_poolid;
70         u64 obj = (unsigned long) mapping->host->i_ino;
71         u32 ind = (u32) index;
72         unsigned long mfn = pfn_to_mfn(page_to_pfn(empty_page));
73
74         if ((s32)tmem_pool < 0)
75                 return 0;
76         if (ind != index)
77                 return 0;
78
79         return tmem_get_page(tmem_pool, obj, ind, mfn);
80 }
81 EXPORT_SYMBOL(precache_get);
82
83 int precache_flush(struct address_space *mapping, unsigned long index)
84 {
85         u32 tmem_pool = mapping->host->i_sb->precache_poolid;
86         u64 obj = (unsigned long) mapping->host->i_ino;
87         u32 ind = (u32) index;
88
89         if ((s32)tmem_pool < 0)
90                 return 0;
91         if (ind != index)
92                 return 0;
93
94         return tmem_flush_page(tmem_pool, obj, ind);
95 }
96 EXPORT_SYMBOL(precache_flush);
97
98 int precache_flush_inode(struct address_space *mapping)
99 {
100         u32 tmem_pool = mapping->host->i_sb->precache_poolid;
101         u64 obj = (unsigned long) mapping->host->i_ino;
102
103         if ((s32)tmem_pool < 0)
104                 return 0;
105
106         return tmem_flush_object(tmem_pool, obj);
107 }
108 EXPORT_SYMBOL(precache_flush_inode);
109
110 int precache_flush_filesystem(struct super_block *sb)
111 {
112         u32 tmem_pool = sb->precache_poolid;
113         int ret;
114
115         if ((s32)tmem_pool < 0)
116                 return 0;
117         ret = tmem_destroy_pool(tmem_pool);
118         if (!ret)
119                 return 0;
120         printk(KERN_INFO
121                 "Unmapping superblock for s_id=%s from precache_id=%d\n",
122                 sb->s_id, ret);
123         sb->precache_poolid = 0;
124         return 1;
125 }
126 EXPORT_SYMBOL(precache_flush_filesystem);
127
128 void precache_init(struct super_block *sb)
129 {
130         sb->precache_poolid = tmem_new_pool(0, 0, 0);
131 }
132 EXPORT_SYMBOL(precache_init);
133
134 void shared_precache_init(struct super_block *sb, char *uuid)
135 {
136         u64 uuid_lo = *(u64 *)uuid;
137         u64 uuid_hi = *(u64 *)(&uuid[8]);
138         sb->precache_poolid = tmem_new_pool(uuid_lo, uuid_hi, TMEM_POOL_SHARED);
139 }
140 EXPORT_SYMBOL(shared_precache_init);