Root/
1 | /* |
2 | * Cleancache frontend |
3 | * |
4 | * This code provides the generic "frontend" layer to call a matching |
5 | * "backend" driver implementation of cleancache. See |
6 | * Documentation/vm/cleancache.txt for more information. |
7 | * |
8 | * Copyright (C) 2009-2010 Oracle Corp. All rights reserved. |
9 | * Author: Dan Magenheimer |
10 | * |
11 | * This work is licensed under the terms of the GNU GPL, version 2. |
12 | */ |
13 | |
14 | #include <linux/module.h> |
15 | #include <linux/fs.h> |
16 | #include <linux/exportfs.h> |
17 | #include <linux/mm.h> |
18 | #include <linux/cleancache.h> |
19 | |
20 | /* |
21 | * This global enablement flag may be read thousands of times per second |
22 | * by cleancache_get/put/flush even on systems where cleancache_ops |
23 | * is not claimed (e.g. cleancache is config'ed on but remains |
24 | * disabled), so is preferred to the slower alternative: a function |
25 | * call that checks a non-global. |
26 | */ |
27 | int cleancache_enabled; |
28 | EXPORT_SYMBOL(cleancache_enabled); |
29 | |
30 | /* |
31 | * cleancache_ops is set by cleancache_ops_register to contain the pointers |
32 | * to the cleancache "backend" implementation functions. |
33 | */ |
34 | static struct cleancache_ops cleancache_ops; |
35 | |
36 | /* useful stats available in /sys/kernel/mm/cleancache */ |
37 | static unsigned long cleancache_succ_gets; |
38 | static unsigned long cleancache_failed_gets; |
39 | static unsigned long cleancache_puts; |
40 | static unsigned long cleancache_flushes; |
41 | |
42 | /* |
43 | * register operations for cleancache, returning previous thus allowing |
44 | * detection of multiple backends and possible nesting |
45 | */ |
46 | struct cleancache_ops cleancache_register_ops(struct cleancache_ops *ops) |
47 | { |
48 | struct cleancache_ops old = cleancache_ops; |
49 | |
50 | cleancache_ops = *ops; |
51 | cleancache_enabled = 1; |
52 | return old; |
53 | } |
54 | EXPORT_SYMBOL(cleancache_register_ops); |
55 | |
56 | /* Called by a cleancache-enabled filesystem at time of mount */ |
57 | void __cleancache_init_fs(struct super_block *sb) |
58 | { |
59 | sb->cleancache_poolid = (*cleancache_ops.init_fs)(PAGE_SIZE); |
60 | } |
61 | EXPORT_SYMBOL(__cleancache_init_fs); |
62 | |
63 | /* Called by a cleancache-enabled clustered filesystem at time of mount */ |
64 | void __cleancache_init_shared_fs(char *uuid, struct super_block *sb) |
65 | { |
66 | sb->cleancache_poolid = |
67 | (*cleancache_ops.init_shared_fs)(uuid, PAGE_SIZE); |
68 | } |
69 | EXPORT_SYMBOL(__cleancache_init_shared_fs); |
70 | |
71 | /* |
72 | * If the filesystem uses exportable filehandles, use the filehandle as |
73 | * the key, else use the inode number. |
74 | */ |
75 | static int cleancache_get_key(struct inode *inode, |
76 | struct cleancache_filekey *key) |
77 | { |
78 | int (*fhfn)(struct dentry *, __u32 *fh, int *, int); |
79 | int len = 0, maxlen = CLEANCACHE_KEY_MAX; |
80 | struct super_block *sb = inode->i_sb; |
81 | |
82 | key->u.ino = inode->i_ino; |
83 | if (sb->s_export_op != NULL) { |
84 | fhfn = sb->s_export_op->encode_fh; |
85 | if (fhfn) { |
86 | struct dentry d; |
87 | d.d_inode = inode; |
88 | len = (*fhfn)(&d, &key->u.fh[0], &maxlen, 0); |
89 | if (len <= 0 || len == 255) |
90 | return -1; |
91 | if (maxlen > CLEANCACHE_KEY_MAX) |
92 | return -1; |
93 | } |
94 | } |
95 | return 0; |
96 | } |
97 | |
98 | /* |
99 | * "Get" data from cleancache associated with the poolid/inode/index |
100 | * that were specified when the data was put to cleanache and, if |
101 | * successful, use it to fill the specified page with data and return 0. |
102 | * The pageframe is unchanged and returns -1 if the get fails. |
103 | * Page must be locked by caller. |
104 | */ |
105 | int __cleancache_get_page(struct page *page) |
106 | { |
107 | int ret = -1; |
108 | int pool_id; |
109 | struct cleancache_filekey key = { .u.key = { 0 } }; |
110 | |
111 | VM_BUG_ON(!PageLocked(page)); |
112 | pool_id = page->mapping->host->i_sb->cleancache_poolid; |
113 | if (pool_id < 0) |
114 | goto out; |
115 | |
116 | if (cleancache_get_key(page->mapping->host, &key) < 0) |
117 | goto out; |
118 | |
119 | ret = (*cleancache_ops.get_page)(pool_id, key, page->index, page); |
120 | if (ret == 0) |
121 | cleancache_succ_gets++; |
122 | else |
123 | cleancache_failed_gets++; |
124 | out: |
125 | return ret; |
126 | } |
127 | EXPORT_SYMBOL(__cleancache_get_page); |
128 | |
129 | /* |
130 | * "Put" data from a page to cleancache and associate it with the |
131 | * (previously-obtained per-filesystem) poolid and the page's, |
132 | * inode and page index. Page must be locked. Note that a put_page |
133 | * always "succeeds", though a subsequent get_page may succeed or fail. |
134 | */ |
135 | void __cleancache_put_page(struct page *page) |
136 | { |
137 | int pool_id; |
138 | struct cleancache_filekey key = { .u.key = { 0 } }; |
139 | |
140 | VM_BUG_ON(!PageLocked(page)); |
141 | pool_id = page->mapping->host->i_sb->cleancache_poolid; |
142 | if (pool_id >= 0 && |
143 | cleancache_get_key(page->mapping->host, &key) >= 0) { |
144 | (*cleancache_ops.put_page)(pool_id, key, page->index, page); |
145 | cleancache_puts++; |
146 | } |
147 | } |
148 | EXPORT_SYMBOL(__cleancache_put_page); |
149 | |
150 | /* |
151 | * Flush any data from cleancache associated with the poolid and the |
152 | * page's inode and page index so that a subsequent "get" will fail. |
153 | */ |
154 | void __cleancache_flush_page(struct address_space *mapping, struct page *page) |
155 | { |
156 | /* careful... page->mapping is NULL sometimes when this is called */ |
157 | int pool_id = mapping->host->i_sb->cleancache_poolid; |
158 | struct cleancache_filekey key = { .u.key = { 0 } }; |
159 | |
160 | if (pool_id >= 0) { |
161 | VM_BUG_ON(!PageLocked(page)); |
162 | if (cleancache_get_key(mapping->host, &key) >= 0) { |
163 | (*cleancache_ops.flush_page)(pool_id, key, page->index); |
164 | cleancache_flushes++; |
165 | } |
166 | } |
167 | } |
168 | EXPORT_SYMBOL(__cleancache_flush_page); |
169 | |
170 | /* |
171 | * Flush all data from cleancache associated with the poolid and the |
172 | * mappings's inode so that all subsequent gets to this poolid/inode |
173 | * will fail. |
174 | */ |
175 | void __cleancache_flush_inode(struct address_space *mapping) |
176 | { |
177 | int pool_id = mapping->host->i_sb->cleancache_poolid; |
178 | struct cleancache_filekey key = { .u.key = { 0 } }; |
179 | |
180 | if (pool_id >= 0 && cleancache_get_key(mapping->host, &key) >= 0) |
181 | (*cleancache_ops.flush_inode)(pool_id, key); |
182 | } |
183 | EXPORT_SYMBOL(__cleancache_flush_inode); |
184 | |
185 | /* |
186 | * Called by any cleancache-enabled filesystem at time of unmount; |
187 | * note that pool_id is surrendered and may be reutrned by a subsequent |
188 | * cleancache_init_fs or cleancache_init_shared_fs |
189 | */ |
190 | void __cleancache_flush_fs(struct super_block *sb) |
191 | { |
192 | if (sb->cleancache_poolid >= 0) { |
193 | int old_poolid = sb->cleancache_poolid; |
194 | sb->cleancache_poolid = -1; |
195 | (*cleancache_ops.flush_fs)(old_poolid); |
196 | } |
197 | } |
198 | EXPORT_SYMBOL(__cleancache_flush_fs); |
199 | |
200 | #ifdef CONFIG_SYSFS |
201 | |
202 | /* see Documentation/ABI/xxx/sysfs-kernel-mm-cleancache */ |
203 | |
204 | #define CLEANCACHE_SYSFS_RO(_name) \ |
205 | static ssize_t cleancache_##_name##_show(struct kobject *kobj, \ |
206 | struct kobj_attribute *attr, char *buf) \ |
207 | { \ |
208 | return sprintf(buf, "%lu\n", cleancache_##_name); \ |
209 | } \ |
210 | static struct kobj_attribute cleancache_##_name##_attr = { \ |
211 | .attr = { .name = __stringify(_name), .mode = 0444 }, \ |
212 | .show = cleancache_##_name##_show, \ |
213 | } |
214 | |
215 | CLEANCACHE_SYSFS_RO(succ_gets); |
216 | CLEANCACHE_SYSFS_RO(failed_gets); |
217 | CLEANCACHE_SYSFS_RO(puts); |
218 | CLEANCACHE_SYSFS_RO(flushes); |
219 | |
220 | static struct attribute *cleancache_attrs[] = { |
221 | &cleancache_succ_gets_attr.attr, |
222 | &cleancache_failed_gets_attr.attr, |
223 | &cleancache_puts_attr.attr, |
224 | &cleancache_flushes_attr.attr, |
225 | NULL, |
226 | }; |
227 | |
228 | static struct attribute_group cleancache_attr_group = { |
229 | .attrs = cleancache_attrs, |
230 | .name = "cleancache", |
231 | }; |
232 | |
233 | #endif /* CONFIG_SYSFS */ |
234 | |
235 | static int __init init_cleancache(void) |
236 | { |
237 | #ifdef CONFIG_SYSFS |
238 | int err; |
239 | |
240 | err = sysfs_create_group(mm_kobj, &cleancache_attr_group); |
241 | #endif /* CONFIG_SYSFS */ |
242 | return 0; |
243 | } |
244 | module_init(init_cleancache) |
245 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9