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.
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.
27 * Note also that multiple accesses to a tmem pool may be concurrent and any
28 * ordering must be guaranteed by the caller.
30 * Copyright (C) 2008,2009 Dan Magenheimer, Oracle Corp.
33 #include <linux/precache.h>
34 #include <linux/module.h>
37 static int precache_auto_allocate; /* set to 1 to auto_allocate */
39 int precache_put(struct address_space *mapping, unsigned long index,
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));
48 if ((s32)tmem_pool < 0) {
49 if (!precache_auto_allocate)
51 /* a put on a non-existent precache may auto-allocate one */
52 ret = tmem_new_pool(0, 0, 0);
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;
62 mb(); /* ensure page is quiescent; tmem may address it with an alias */
63 return tmem_put_page(tmem_pool, obj, ind, mfn);
66 int precache_get(struct address_space *mapping, unsigned long index,
67 struct page *empty_page)
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));
74 if ((s32)tmem_pool < 0)
79 return tmem_get_page(tmem_pool, obj, ind, mfn);
81 EXPORT_SYMBOL(precache_get);
83 int precache_flush(struct address_space *mapping, unsigned long index)
85 u32 tmem_pool = mapping->host->i_sb->precache_poolid;
86 u64 obj = (unsigned long) mapping->host->i_ino;
87 u32 ind = (u32) index;
89 if ((s32)tmem_pool < 0)
94 return tmem_flush_page(tmem_pool, obj, ind);
96 EXPORT_SYMBOL(precache_flush);
98 int precache_flush_inode(struct address_space *mapping)
100 u32 tmem_pool = mapping->host->i_sb->precache_poolid;
101 u64 obj = (unsigned long) mapping->host->i_ino;
103 if ((s32)tmem_pool < 0)
106 return tmem_flush_object(tmem_pool, obj);
108 EXPORT_SYMBOL(precache_flush_inode);
110 int precache_flush_filesystem(struct super_block *sb)
112 u32 tmem_pool = sb->precache_poolid;
115 if ((s32)tmem_pool < 0)
117 ret = tmem_destroy_pool(tmem_pool);
121 "Unmapping superblock for s_id=%s from precache_id=%d\n",
123 sb->precache_poolid = 0;
126 EXPORT_SYMBOL(precache_flush_filesystem);
128 void precache_init(struct super_block *sb)
130 sb->precache_poolid = tmem_new_pool(0, 0, 0);
132 EXPORT_SYMBOL(precache_init);
134 void shared_precache_init(struct super_block *sb, char *uuid)
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);
140 EXPORT_SYMBOL(shared_precache_init);