cache.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /* AFS caching stuff
  2. *
  3. * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
  4. * Written by David Howells (dhowells@redhat.com)
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the License, or (at your option) any later version.
  10. */
  11. #include <linux/slab.h>
  12. #include <linux/sched.h>
  13. #include "internal.h"
  14. static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data,
  15. void *buffer, uint16_t buflen);
  16. static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data,
  17. void *buffer, uint16_t buflen);
  18. static enum fscache_checkaux afs_cell_cache_check_aux(void *cookie_netfs_data,
  19. const void *buffer,
  20. uint16_t buflen);
  21. static uint16_t afs_vlocation_cache_get_key(const void *cookie_netfs_data,
  22. void *buffer, uint16_t buflen);
  23. static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data,
  24. void *buffer, uint16_t buflen);
  25. static enum fscache_checkaux afs_vlocation_cache_check_aux(
  26. void *cookie_netfs_data, const void *buffer, uint16_t buflen);
  27. static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data,
  28. void *buffer, uint16_t buflen);
  29. static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data,
  30. void *buffer, uint16_t buflen);
  31. static void afs_vnode_cache_get_attr(const void *cookie_netfs_data,
  32. uint64_t *size);
  33. static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data,
  34. void *buffer, uint16_t buflen);
  35. static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data,
  36. const void *buffer,
  37. uint16_t buflen);
  38. static void afs_vnode_cache_now_uncached(void *cookie_netfs_data);
  39. struct fscache_netfs afs_cache_netfs = {
  40. .name = "afs",
  41. .version = 0,
  42. };
  43. struct fscache_cookie_def afs_cell_cache_index_def = {
  44. .name = "AFS.cell",
  45. .type = FSCACHE_COOKIE_TYPE_INDEX,
  46. .get_key = afs_cell_cache_get_key,
  47. .get_aux = afs_cell_cache_get_aux,
  48. .check_aux = afs_cell_cache_check_aux,
  49. };
  50. struct fscache_cookie_def afs_vlocation_cache_index_def = {
  51. .name = "AFS.vldb",
  52. .type = FSCACHE_COOKIE_TYPE_INDEX,
  53. .get_key = afs_vlocation_cache_get_key,
  54. .get_aux = afs_vlocation_cache_get_aux,
  55. .check_aux = afs_vlocation_cache_check_aux,
  56. };
  57. struct fscache_cookie_def afs_volume_cache_index_def = {
  58. .name = "AFS.volume",
  59. .type = FSCACHE_COOKIE_TYPE_INDEX,
  60. .get_key = afs_volume_cache_get_key,
  61. };
  62. struct fscache_cookie_def afs_vnode_cache_index_def = {
  63. .name = "AFS.vnode",
  64. .type = FSCACHE_COOKIE_TYPE_DATAFILE,
  65. .get_key = afs_vnode_cache_get_key,
  66. .get_attr = afs_vnode_cache_get_attr,
  67. .get_aux = afs_vnode_cache_get_aux,
  68. .check_aux = afs_vnode_cache_check_aux,
  69. .now_uncached = afs_vnode_cache_now_uncached,
  70. };
  71. /*
  72. * set the key for the index entry
  73. */
  74. static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data,
  75. void *buffer, uint16_t bufmax)
  76. {
  77. const struct afs_cell *cell = cookie_netfs_data;
  78. uint16_t klen;
  79. _enter("%p,%p,%u", cell, buffer, bufmax);
  80. klen = strlen(cell->name);
  81. if (klen > bufmax)
  82. return 0;
  83. memcpy(buffer, cell->name, klen);
  84. return klen;
  85. }
  86. /*
  87. * provide new auxilliary cache data
  88. */
  89. static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data,
  90. void *buffer, uint16_t bufmax)
  91. {
  92. const struct afs_cell *cell = cookie_netfs_data;
  93. uint16_t dlen;
  94. _enter("%p,%p,%u", cell, buffer, bufmax);
  95. dlen = cell->vl_naddrs * sizeof(cell->vl_addrs[0]);
  96. dlen = min(dlen, bufmax);
  97. dlen &= ~(sizeof(cell->vl_addrs[0]) - 1);
  98. memcpy(buffer, cell->vl_addrs, dlen);
  99. return dlen;
  100. }
  101. /*
  102. * check that the auxilliary data indicates that the entry is still valid
  103. */
  104. static enum fscache_checkaux afs_cell_cache_check_aux(void *cookie_netfs_data,
  105. const void *buffer,
  106. uint16_t buflen)
  107. {
  108. _leave(" = OKAY");
  109. return FSCACHE_CHECKAUX_OKAY;
  110. }
  111. /*****************************************************************************/
  112. /*
  113. * set the key for the index entry
  114. */
  115. static uint16_t afs_vlocation_cache_get_key(const void *cookie_netfs_data,
  116. void *buffer, uint16_t bufmax)
  117. {
  118. const struct afs_vlocation *vlocation = cookie_netfs_data;
  119. uint16_t klen;
  120. _enter("{%s},%p,%u", vlocation->vldb.name, buffer, bufmax);
  121. klen = strnlen(vlocation->vldb.name, sizeof(vlocation->vldb.name));
  122. if (klen > bufmax)
  123. return 0;
  124. memcpy(buffer, vlocation->vldb.name, klen);
  125. _leave(" = %u", klen);
  126. return klen;
  127. }
  128. /*
  129. * provide new auxilliary cache data
  130. */
  131. static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data,
  132. void *buffer, uint16_t bufmax)
  133. {
  134. const struct afs_vlocation *vlocation = cookie_netfs_data;
  135. uint16_t dlen;
  136. _enter("{%s},%p,%u", vlocation->vldb.name, buffer, bufmax);
  137. dlen = sizeof(struct afs_cache_vlocation);
  138. dlen -= offsetof(struct afs_cache_vlocation, nservers);
  139. if (dlen > bufmax)
  140. return 0;
  141. memcpy(buffer, (uint8_t *)&vlocation->vldb.nservers, dlen);
  142. _leave(" = %u", dlen);
  143. return dlen;
  144. }
  145. /*
  146. * check that the auxilliary data indicates that the entry is still valid
  147. */
  148. static
  149. enum fscache_checkaux afs_vlocation_cache_check_aux(void *cookie_netfs_data,
  150. const void *buffer,
  151. uint16_t buflen)
  152. {
  153. const struct afs_cache_vlocation *cvldb;
  154. struct afs_vlocation *vlocation = cookie_netfs_data;
  155. uint16_t dlen;
  156. _enter("{%s},%p,%u", vlocation->vldb.name, buffer, buflen);
  157. /* check the size of the data is what we're expecting */
  158. dlen = sizeof(struct afs_cache_vlocation);
  159. dlen -= offsetof(struct afs_cache_vlocation, nservers);
  160. if (dlen != buflen)
  161. return FSCACHE_CHECKAUX_OBSOLETE;
  162. cvldb = container_of(buffer, struct afs_cache_vlocation, nservers);
  163. /* if what's on disk is more valid than what's in memory, then use the
  164. * VL record from the cache */
  165. if (!vlocation->valid || vlocation->vldb.rtime == cvldb->rtime) {
  166. memcpy((uint8_t *)&vlocation->vldb.nservers, buffer, dlen);
  167. vlocation->valid = 1;
  168. _leave(" = SUCCESS [c->m]");
  169. return FSCACHE_CHECKAUX_OKAY;
  170. }
  171. /* need to update the cache if the cached info differs */
  172. if (memcmp(&vlocation->vldb, buffer, dlen) != 0) {
  173. /* delete if the volume IDs for this name differ */
  174. if (memcmp(&vlocation->vldb.vid, &cvldb->vid,
  175. sizeof(cvldb->vid)) != 0
  176. ) {
  177. _leave(" = OBSOLETE");
  178. return FSCACHE_CHECKAUX_OBSOLETE;
  179. }
  180. _leave(" = UPDATE");
  181. return FSCACHE_CHECKAUX_NEEDS_UPDATE;
  182. }
  183. _leave(" = OKAY");
  184. return FSCACHE_CHECKAUX_OKAY;
  185. }
  186. /*****************************************************************************/
  187. /*
  188. * set the key for the volume index entry
  189. */
  190. static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data,
  191. void *buffer, uint16_t bufmax)
  192. {
  193. const struct afs_volume *volume = cookie_netfs_data;
  194. uint16_t klen;
  195. _enter("{%u},%p,%u", volume->type, buffer, bufmax);
  196. klen = sizeof(volume->type);
  197. if (klen > bufmax)
  198. return 0;
  199. memcpy(buffer, &volume->type, sizeof(volume->type));
  200. _leave(" = %u", klen);
  201. return klen;
  202. }
  203. /*****************************************************************************/
  204. /*
  205. * set the key for the index entry
  206. */
  207. static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data,
  208. void *buffer, uint16_t bufmax)
  209. {
  210. const struct afs_vnode *vnode = cookie_netfs_data;
  211. uint16_t klen;
  212. _enter("{%x,%x,%llx},%p,%u",
  213. vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
  214. buffer, bufmax);
  215. klen = sizeof(vnode->fid.vnode);
  216. if (klen > bufmax)
  217. return 0;
  218. memcpy(buffer, &vnode->fid.vnode, sizeof(vnode->fid.vnode));
  219. _leave(" = %u", klen);
  220. return klen;
  221. }
  222. /*
  223. * provide updated file attributes
  224. */
  225. static void afs_vnode_cache_get_attr(const void *cookie_netfs_data,
  226. uint64_t *size)
  227. {
  228. const struct afs_vnode *vnode = cookie_netfs_data;
  229. _enter("{%x,%x,%llx},",
  230. vnode->fid.vnode, vnode->fid.unique,
  231. vnode->status.data_version);
  232. *size = vnode->status.size;
  233. }
  234. /*
  235. * provide new auxilliary cache data
  236. */
  237. static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data,
  238. void *buffer, uint16_t bufmax)
  239. {
  240. const struct afs_vnode *vnode = cookie_netfs_data;
  241. uint16_t dlen;
  242. _enter("{%x,%x,%Lx},%p,%u",
  243. vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
  244. buffer, bufmax);
  245. dlen = sizeof(vnode->fid.unique) + sizeof(vnode->status.data_version);
  246. if (dlen > bufmax)
  247. return 0;
  248. memcpy(buffer, &vnode->fid.unique, sizeof(vnode->fid.unique));
  249. buffer += sizeof(vnode->fid.unique);
  250. memcpy(buffer, &vnode->status.data_version,
  251. sizeof(vnode->status.data_version));
  252. _leave(" = %u", dlen);
  253. return dlen;
  254. }
  255. /*
  256. * check that the auxilliary data indicates that the entry is still valid
  257. */
  258. static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data,
  259. const void *buffer,
  260. uint16_t buflen)
  261. {
  262. struct afs_vnode *vnode = cookie_netfs_data;
  263. uint16_t dlen;
  264. _enter("{%x,%x,%llx},%p,%u",
  265. vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
  266. buffer, buflen);
  267. /* check the size of the data is what we're expecting */
  268. dlen = sizeof(vnode->fid.unique) + sizeof(vnode->status.data_version);
  269. if (dlen != buflen) {
  270. _leave(" = OBSOLETE [len %hx != %hx]", dlen, buflen);
  271. return FSCACHE_CHECKAUX_OBSOLETE;
  272. }
  273. if (memcmp(buffer,
  274. &vnode->fid.unique,
  275. sizeof(vnode->fid.unique)
  276. ) != 0) {
  277. unsigned unique;
  278. memcpy(&unique, buffer, sizeof(unique));
  279. _leave(" = OBSOLETE [uniq %x != %x]",
  280. unique, vnode->fid.unique);
  281. return FSCACHE_CHECKAUX_OBSOLETE;
  282. }
  283. if (memcmp(buffer + sizeof(vnode->fid.unique),
  284. &vnode->status.data_version,
  285. sizeof(vnode->status.data_version)
  286. ) != 0) {
  287. afs_dataversion_t version;
  288. memcpy(&version, buffer + sizeof(vnode->fid.unique),
  289. sizeof(version));
  290. _leave(" = OBSOLETE [vers %llx != %llx]",
  291. version, vnode->status.data_version);
  292. return FSCACHE_CHECKAUX_OBSOLETE;
  293. }
  294. _leave(" = SUCCESS");
  295. return FSCACHE_CHECKAUX_OKAY;
  296. }
  297. /*
  298. * indication the cookie is no longer uncached
  299. * - this function is called when the backing store currently caching a cookie
  300. * is removed
  301. * - the netfs should use this to clean up any markers indicating cached pages
  302. * - this is mandatory for any object that may have data
  303. */
  304. static void afs_vnode_cache_now_uncached(void *cookie_netfs_data)
  305. {
  306. struct afs_vnode *vnode = cookie_netfs_data;
  307. struct pagevec pvec;
  308. pgoff_t first;
  309. int loop, nr_pages;
  310. _enter("{%x,%x,%Lx}",
  311. vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version);
  312. pagevec_init(&pvec, 0);
  313. first = 0;
  314. for (;;) {
  315. /* grab a bunch of pages to clean */
  316. nr_pages = pagevec_lookup(&pvec, vnode->vfs_inode.i_mapping,
  317. first,
  318. PAGEVEC_SIZE - pagevec_count(&pvec));
  319. if (!nr_pages)
  320. break;
  321. for (loop = 0; loop < nr_pages; loop++)
  322. ClearPageFsCache(pvec.pages[loop]);
  323. first = pvec.pages[nr_pages - 1]->index + 1;
  324. pvec.nr = nr_pages;
  325. pagevec_release(&pvec);
  326. cond_resched();
  327. }
  328. _leave("");
  329. }