fscache-index.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /* NFS FS-Cache index structure definition
  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 Licence
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the Licence, or (at your option) any later version.
  10. */
  11. #include <linux/init.h>
  12. #include <linux/kernel.h>
  13. #include <linux/sched.h>
  14. #include <linux/mm.h>
  15. #include <linux/nfs_fs.h>
  16. #include <linux/nfs_fs_sb.h>
  17. #include <linux/in6.h>
  18. #include "internal.h"
  19. #include "fscache.h"
  20. #define NFSDBG_FACILITY NFSDBG_FSCACHE
  21. /*
  22. * Define the NFS filesystem for FS-Cache. Upon registration FS-Cache sticks
  23. * the cookie for the top-level index object for NFS into here. The top-level
  24. * index can than have other cache objects inserted into it.
  25. */
  26. struct fscache_netfs nfs_fscache_netfs = {
  27. .name = "nfs",
  28. .version = 0,
  29. };
  30. /*
  31. * Register NFS for caching
  32. */
  33. int nfs_fscache_register(void)
  34. {
  35. return fscache_register_netfs(&nfs_fscache_netfs);
  36. }
  37. /*
  38. * Unregister NFS for caching
  39. */
  40. void nfs_fscache_unregister(void)
  41. {
  42. fscache_unregister_netfs(&nfs_fscache_netfs);
  43. }
  44. /*
  45. * Layout of the key for an NFS server cache object.
  46. */
  47. struct nfs_server_key {
  48. uint16_t nfsversion; /* NFS protocol version */
  49. uint16_t family; /* address family */
  50. uint16_t port; /* IP port */
  51. union {
  52. struct in_addr ipv4_addr; /* IPv4 address */
  53. struct in6_addr ipv6_addr; /* IPv6 address */
  54. } addr[0];
  55. };
  56. /*
  57. * Generate a key to describe a server in the main NFS index
  58. * - We return the length of the key, or 0 if we can't generate one
  59. */
  60. static uint16_t nfs_server_get_key(const void *cookie_netfs_data,
  61. void *buffer, uint16_t bufmax)
  62. {
  63. const struct nfs_client *clp = cookie_netfs_data;
  64. const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &clp->cl_addr;
  65. const struct sockaddr_in *sin = (struct sockaddr_in *) &clp->cl_addr;
  66. struct nfs_server_key *key = buffer;
  67. uint16_t len = sizeof(struct nfs_server_key);
  68. memset(key, 0, len);
  69. key->nfsversion = clp->rpc_ops->version;
  70. key->family = clp->cl_addr.ss_family;
  71. switch (clp->cl_addr.ss_family) {
  72. case AF_INET:
  73. key->port = sin->sin_port;
  74. key->addr[0].ipv4_addr = sin->sin_addr;
  75. len += sizeof(key->addr[0].ipv4_addr);
  76. break;
  77. case AF_INET6:
  78. key->port = sin6->sin6_port;
  79. key->addr[0].ipv6_addr = sin6->sin6_addr;
  80. len += sizeof(key->addr[0].ipv6_addr);
  81. break;
  82. default:
  83. printk(KERN_WARNING "NFS: Unknown network family '%d'\n",
  84. clp->cl_addr.ss_family);
  85. len = 0;
  86. break;
  87. }
  88. return len;
  89. }
  90. /*
  91. * Define the server object for FS-Cache. This is used to describe a server
  92. * object to fscache_acquire_cookie(). It is keyed by the NFS protocol and
  93. * server address parameters.
  94. */
  95. const struct fscache_cookie_def nfs_fscache_server_index_def = {
  96. .name = "NFS.server",
  97. .type = FSCACHE_COOKIE_TYPE_INDEX,
  98. .get_key = nfs_server_get_key,
  99. };
  100. /*
  101. * Generate a key to describe a superblock key in the main NFS index
  102. */
  103. static uint16_t nfs_super_get_key(const void *cookie_netfs_data,
  104. void *buffer, uint16_t bufmax)
  105. {
  106. const struct nfs_fscache_key *key;
  107. const struct nfs_server *nfss = cookie_netfs_data;
  108. uint16_t len;
  109. key = nfss->fscache_key;
  110. len = sizeof(key->key) + key->key.uniq_len;
  111. if (len > bufmax) {
  112. len = 0;
  113. } else {
  114. memcpy(buffer, &key->key, sizeof(key->key));
  115. memcpy(buffer + sizeof(key->key),
  116. key->key.uniquifier, key->key.uniq_len);
  117. }
  118. return len;
  119. }
  120. /*
  121. * Define the superblock object for FS-Cache. This is used to describe a
  122. * superblock object to fscache_acquire_cookie(). It is keyed by all the NFS
  123. * parameters that might cause a separate superblock.
  124. */
  125. const struct fscache_cookie_def nfs_fscache_super_index_def = {
  126. .name = "NFS.super",
  127. .type = FSCACHE_COOKIE_TYPE_INDEX,
  128. .get_key = nfs_super_get_key,
  129. };
  130. /*
  131. * Definition of the auxiliary data attached to NFS inode storage objects
  132. * within the cache.
  133. *
  134. * The contents of this struct are recorded in the on-disk local cache in the
  135. * auxiliary data attached to the data storage object backing an inode. This
  136. * permits coherency to be managed when a new inode binds to an already extant
  137. * cache object.
  138. */
  139. struct nfs_fscache_inode_auxdata {
  140. struct timespec mtime;
  141. struct timespec ctime;
  142. loff_t size;
  143. u64 change_attr;
  144. };
  145. /*
  146. * Generate a key to describe an NFS inode in an NFS server's index
  147. */
  148. static uint16_t nfs_fscache_inode_get_key(const void *cookie_netfs_data,
  149. void *buffer, uint16_t bufmax)
  150. {
  151. const struct nfs_inode *nfsi = cookie_netfs_data;
  152. uint16_t nsize;
  153. /* use the inode's NFS filehandle as the key */
  154. nsize = nfsi->fh.size;
  155. memcpy(buffer, nfsi->fh.data, nsize);
  156. return nsize;
  157. }
  158. /*
  159. * Get certain file attributes from the netfs data
  160. * - This function can be absent for an index
  161. * - Not permitted to return an error
  162. * - The netfs data from the cookie being used as the source is presented
  163. */
  164. static void nfs_fscache_inode_get_attr(const void *cookie_netfs_data,
  165. uint64_t *size)
  166. {
  167. const struct nfs_inode *nfsi = cookie_netfs_data;
  168. *size = nfsi->vfs_inode.i_size;
  169. }
  170. /*
  171. * Get the auxiliary data from netfs data
  172. * - This function can be absent if the index carries no state data
  173. * - Should store the auxiliary data in the buffer
  174. * - Should return the amount of amount stored
  175. * - Not permitted to return an error
  176. * - The netfs data from the cookie being used as the source is presented
  177. */
  178. static uint16_t nfs_fscache_inode_get_aux(const void *cookie_netfs_data,
  179. void *buffer, uint16_t bufmax)
  180. {
  181. struct nfs_fscache_inode_auxdata auxdata;
  182. const struct nfs_inode *nfsi = cookie_netfs_data;
  183. memset(&auxdata, 0, sizeof(auxdata));
  184. auxdata.size = nfsi->vfs_inode.i_size;
  185. auxdata.mtime = nfsi->vfs_inode.i_mtime;
  186. auxdata.ctime = nfsi->vfs_inode.i_ctime;
  187. if (NFS_SERVER(&nfsi->vfs_inode)->nfs_client->rpc_ops->version == 4)
  188. auxdata.change_attr = nfsi->vfs_inode.i_version;
  189. if (bufmax > sizeof(auxdata))
  190. bufmax = sizeof(auxdata);
  191. memcpy(buffer, &auxdata, bufmax);
  192. return bufmax;
  193. }
  194. /*
  195. * Consult the netfs about the state of an object
  196. * - This function can be absent if the index carries no state data
  197. * - The netfs data from the cookie being used as the target is
  198. * presented, as is the auxiliary data
  199. */
  200. static
  201. enum fscache_checkaux nfs_fscache_inode_check_aux(void *cookie_netfs_data,
  202. const void *data,
  203. uint16_t datalen)
  204. {
  205. struct nfs_fscache_inode_auxdata auxdata;
  206. struct nfs_inode *nfsi = cookie_netfs_data;
  207. if (datalen != sizeof(auxdata))
  208. return FSCACHE_CHECKAUX_OBSOLETE;
  209. memset(&auxdata, 0, sizeof(auxdata));
  210. auxdata.size = nfsi->vfs_inode.i_size;
  211. auxdata.mtime = nfsi->vfs_inode.i_mtime;
  212. auxdata.ctime = nfsi->vfs_inode.i_ctime;
  213. if (NFS_SERVER(&nfsi->vfs_inode)->nfs_client->rpc_ops->version == 4)
  214. auxdata.change_attr = nfsi->vfs_inode.i_version;
  215. if (memcmp(data, &auxdata, datalen) != 0)
  216. return FSCACHE_CHECKAUX_OBSOLETE;
  217. return FSCACHE_CHECKAUX_OKAY;
  218. }
  219. /*
  220. * Indication from FS-Cache that the cookie is no longer cached
  221. * - This function is called when the backing store currently caching a cookie
  222. * is removed
  223. * - The netfs should use this to clean up any markers indicating cached pages
  224. * - This is mandatory for any object that may have data
  225. */
  226. static void nfs_fscache_inode_now_uncached(void *cookie_netfs_data)
  227. {
  228. struct nfs_inode *nfsi = cookie_netfs_data;
  229. struct pagevec pvec;
  230. pgoff_t first;
  231. int loop, nr_pages;
  232. pagevec_init(&pvec, 0);
  233. first = 0;
  234. dprintk("NFS: nfs_inode_now_uncached: nfs_inode 0x%p\n", nfsi);
  235. for (;;) {
  236. /* grab a bunch of pages to unmark */
  237. nr_pages = pagevec_lookup(&pvec,
  238. nfsi->vfs_inode.i_mapping,
  239. first,
  240. PAGEVEC_SIZE - pagevec_count(&pvec));
  241. if (!nr_pages)
  242. break;
  243. for (loop = 0; loop < nr_pages; loop++)
  244. ClearPageFsCache(pvec.pages[loop]);
  245. first = pvec.pages[nr_pages - 1]->index + 1;
  246. pvec.nr = nr_pages;
  247. pagevec_release(&pvec);
  248. cond_resched();
  249. }
  250. }
  251. /*
  252. * Get an extra reference on a read context.
  253. * - This function can be absent if the completion function doesn't require a
  254. * context.
  255. * - The read context is passed back to NFS in the event that a data read on the
  256. * cache fails with EIO - in which case the server must be contacted to
  257. * retrieve the data, which requires the read context for security.
  258. */
  259. static void nfs_fh_get_context(void *cookie_netfs_data, void *context)
  260. {
  261. get_nfs_open_context(context);
  262. }
  263. /*
  264. * Release an extra reference on a read context.
  265. * - This function can be absent if the completion function doesn't require a
  266. * context.
  267. */
  268. static void nfs_fh_put_context(void *cookie_netfs_data, void *context)
  269. {
  270. if (context)
  271. put_nfs_open_context(context);
  272. }
  273. /*
  274. * Define the inode object for FS-Cache. This is used to describe an inode
  275. * object to fscache_acquire_cookie(). It is keyed by the NFS file handle for
  276. * an inode.
  277. *
  278. * Coherency is managed by comparing the copies of i_size, i_mtime and i_ctime
  279. * held in the cache auxiliary data for the data storage object with those in
  280. * the inode struct in memory.
  281. */
  282. const struct fscache_cookie_def nfs_fscache_inode_object_def = {
  283. .name = "NFS.fh",
  284. .type = FSCACHE_COOKIE_TYPE_DATAFILE,
  285. .get_key = nfs_fscache_inode_get_key,
  286. .get_attr = nfs_fscache_inode_get_attr,
  287. .get_aux = nfs_fscache_inode_get_aux,
  288. .check_aux = nfs_fscache_inode_check_aux,
  289. .now_uncached = nfs_fscache_inode_now_uncached,
  290. .get_context = nfs_fh_get_context,
  291. .put_context = nfs_fh_put_context,
  292. };