cleancache.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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. #include <linux/module.h>
  14. #include <linux/fs.h>
  15. #include <linux/exportfs.h>
  16. #include <linux/mm.h>
  17. #include <linux/cleancache.h>
  18. /*
  19. * This global enablement flag may be read thousands of times per second
  20. * by cleancache_get/put/flush even on systems where cleancache_ops
  21. * is not claimed (e.g. cleancache is config'ed on but remains
  22. * disabled), so is preferred to the slower alternative: a function
  23. * call that checks a non-global.
  24. */
  25. int cleancache_enabled;
  26. EXPORT_SYMBOL(cleancache_enabled);
  27. /*
  28. * cleancache_ops is set by cleancache_ops_register to contain the pointers
  29. * to the cleancache "backend" implementation functions.
  30. */
  31. static struct cleancache_ops cleancache_ops;
  32. /* useful stats available in /sys/kernel/mm/cleancache */
  33. static unsigned long cleancache_succ_gets;
  34. static unsigned long cleancache_failed_gets;
  35. static unsigned long cleancache_puts;
  36. static unsigned long cleancache_flushes;
  37. /*
  38. * register operations for cleancache, returning previous thus allowing
  39. * detection of multiple backends and possible nesting
  40. */
  41. struct cleancache_ops cleancache_register_ops(struct cleancache_ops *ops)
  42. {
  43. struct cleancache_ops old = cleancache_ops;
  44. cleancache_ops = *ops;
  45. cleancache_enabled = 1;
  46. return old;
  47. }
  48. EXPORT_SYMBOL(cleancache_register_ops);
  49. /* Called by a cleancache-enabled filesystem at time of mount */
  50. void __cleancache_init_fs(struct super_block *sb)
  51. {
  52. sb->cleancache_poolid = (*cleancache_ops.init_fs)(PAGE_SIZE);
  53. }
  54. EXPORT_SYMBOL(__cleancache_init_fs);
  55. /* Called by a cleancache-enabled clustered filesystem at time of mount */
  56. void __cleancache_init_shared_fs(char *uuid, struct super_block *sb)
  57. {
  58. sb->cleancache_poolid =
  59. (*cleancache_ops.init_shared_fs)(uuid, PAGE_SIZE);
  60. }
  61. EXPORT_SYMBOL(__cleancache_init_shared_fs);
  62. /*
  63. * If the filesystem uses exportable filehandles, use the filehandle as
  64. * the key, else use the inode number.
  65. */
  66. static int cleancache_get_key(struct inode *inode,
  67. struct cleancache_filekey *key)
  68. {
  69. int (*fhfn)(struct dentry *, __u32 *fh, int *, int);
  70. int len = 0, maxlen = CLEANCACHE_KEY_MAX;
  71. struct super_block *sb = inode->i_sb;
  72. key->u.ino = inode->i_ino;
  73. if (sb->s_export_op != NULL) {
  74. fhfn = sb->s_export_op->encode_fh;
  75. if (fhfn) {
  76. struct dentry d;
  77. d.d_inode = inode;
  78. len = (*fhfn)(&d, &key->u.fh[0], &maxlen, 0);
  79. if (len <= 0 || len == 255)
  80. return -1;
  81. if (maxlen > CLEANCACHE_KEY_MAX)
  82. return -1;
  83. }
  84. }
  85. return 0;
  86. }
  87. /*
  88. * "Get" data from cleancache associated with the poolid/inode/index
  89. * that were specified when the data was put to cleanache and, if
  90. * successful, use it to fill the specified page with data and return 0.
  91. * The pageframe is unchanged and returns -1 if the get fails.
  92. * Page must be locked by caller.
  93. */
  94. int __cleancache_get_page(struct page *page)
  95. {
  96. int ret = -1;
  97. int pool_id;
  98. struct cleancache_filekey key = { .u.key = { 0 } };
  99. VM_BUG_ON(!PageLocked(page));
  100. pool_id = page->mapping->host->i_sb->cleancache_poolid;
  101. if (pool_id < 0)
  102. goto out;
  103. if (cleancache_get_key(page->mapping->host, &key) < 0)
  104. goto out;
  105. ret = (*cleancache_ops.get_page)(pool_id, key, page->index, page);
  106. if (ret == 0)
  107. cleancache_succ_gets++;
  108. else
  109. cleancache_failed_gets++;
  110. out:
  111. return ret;
  112. }
  113. EXPORT_SYMBOL(__cleancache_get_page);
  114. /*
  115. * "Put" data from a page to cleancache and associate it with the
  116. * (previously-obtained per-filesystem) poolid and the page's,
  117. * inode and page index. Page must be locked. Note that a put_page
  118. * always "succeeds", though a subsequent get_page may succeed or fail.
  119. */
  120. void __cleancache_put_page(struct page *page)
  121. {
  122. int pool_id;
  123. struct cleancache_filekey key = { .u.key = { 0 } };
  124. VM_BUG_ON(!PageLocked(page));
  125. pool_id = page->mapping->host->i_sb->cleancache_poolid;
  126. if (pool_id >= 0 &&
  127. cleancache_get_key(page->mapping->host, &key) >= 0) {
  128. (*cleancache_ops.put_page)(pool_id, key, page->index, page);
  129. cleancache_puts++;
  130. }
  131. }
  132. EXPORT_SYMBOL(__cleancache_put_page);
  133. /*
  134. * Flush any data from cleancache associated with the poolid and the
  135. * page's inode and page index so that a subsequent "get" will fail.
  136. */
  137. void __cleancache_flush_page(struct address_space *mapping, struct page *page)
  138. {
  139. /* careful... page->mapping is NULL sometimes when this is called */
  140. int pool_id = mapping->host->i_sb->cleancache_poolid;
  141. struct cleancache_filekey key = { .u.key = { 0 } };
  142. if (pool_id >= 0) {
  143. VM_BUG_ON(!PageLocked(page));
  144. if (cleancache_get_key(mapping->host, &key) >= 0) {
  145. (*cleancache_ops.flush_page)(pool_id, key, page->index);
  146. cleancache_flushes++;
  147. }
  148. }
  149. }
  150. EXPORT_SYMBOL(__cleancache_flush_page);
  151. /*
  152. * Flush all data from cleancache associated with the poolid and the
  153. * mappings's inode so that all subsequent gets to this poolid/inode
  154. * will fail.
  155. */
  156. void __cleancache_flush_inode(struct address_space *mapping)
  157. {
  158. int pool_id = mapping->host->i_sb->cleancache_poolid;
  159. struct cleancache_filekey key = { .u.key = { 0 } };
  160. if (pool_id >= 0 && cleancache_get_key(mapping->host, &key) >= 0)
  161. (*cleancache_ops.flush_inode)(pool_id, key);
  162. }
  163. EXPORT_SYMBOL(__cleancache_flush_inode);
  164. /*
  165. * Called by any cleancache-enabled filesystem at time of unmount;
  166. * note that pool_id is surrendered and may be reutrned by a subsequent
  167. * cleancache_init_fs or cleancache_init_shared_fs
  168. */
  169. void __cleancache_flush_fs(struct super_block *sb)
  170. {
  171. if (sb->cleancache_poolid >= 0) {
  172. int old_poolid = sb->cleancache_poolid;
  173. sb->cleancache_poolid = -1;
  174. (*cleancache_ops.flush_fs)(old_poolid);
  175. }
  176. }
  177. EXPORT_SYMBOL(__cleancache_flush_fs);
  178. #ifdef CONFIG_SYSFS
  179. /* see Documentation/ABI/xxx/sysfs-kernel-mm-cleancache */
  180. #define CLEANCACHE_SYSFS_RO(_name) \
  181. static ssize_t cleancache_##_name##_show(struct kobject *kobj, \
  182. struct kobj_attribute *attr, char *buf) \
  183. { \
  184. return sprintf(buf, "%lu\n", cleancache_##_name); \
  185. } \
  186. static struct kobj_attribute cleancache_##_name##_attr = { \
  187. .attr = { .name = __stringify(_name), .mode = 0444 }, \
  188. .show = cleancache_##_name##_show, \
  189. }
  190. CLEANCACHE_SYSFS_RO(succ_gets);
  191. CLEANCACHE_SYSFS_RO(failed_gets);
  192. CLEANCACHE_SYSFS_RO(puts);
  193. CLEANCACHE_SYSFS_RO(flushes);
  194. static struct attribute *cleancache_attrs[] = {
  195. &cleancache_succ_gets_attr.attr,
  196. &cleancache_failed_gets_attr.attr,
  197. &cleancache_puts_attr.attr,
  198. &cleancache_flushes_attr.attr,
  199. NULL,
  200. };
  201. static struct attribute_group cleancache_attr_group = {
  202. .attrs = cleancache_attrs,
  203. .name = "cleancache",
  204. };
  205. #endif /* CONFIG_SYSFS */
  206. static int __init init_cleancache(void)
  207. {
  208. #ifdef CONFIG_SYSFS
  209. int err;
  210. err = sysfs_create_group(mm_kobj, &cleancache_attr_group);
  211. #endif /* CONFIG_SYSFS */
  212. return 0;
  213. }
  214. module_init(init_cleancache)