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