diff options
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/fscache-index.c | 140 | ||||
-rw-r--r-- | fs/nfs/fscache.c | 83 | ||||
-rw-r--r-- | fs/nfs/fscache.h | 16 |
3 files changed, 94 insertions, 145 deletions
diff --git a/fs/nfs/fscache-index.c b/fs/nfs/fscache-index.c index 0ee4b93d36ea..6fd3679b7137 100644 --- a/fs/nfs/fscache-index.c +++ b/fs/nfs/fscache-index.c @@ -50,59 +50,6 @@ void nfs_fscache_unregister(void) } /* - * Layout of the key for an NFS server cache object. - */ -struct nfs_server_key { - uint16_t nfsversion; /* NFS protocol version */ - uint16_t family; /* address family */ - uint16_t port; /* IP port */ - union { - struct in_addr ipv4_addr; /* IPv4 address */ - struct in6_addr ipv6_addr; /* IPv6 address */ - } addr[0]; -}; - -/* - * Generate a key to describe a server in the main NFS index - * - We return the length of the key, or 0 if we can't generate one - */ -static uint16_t nfs_server_get_key(const void *cookie_netfs_data, - void *buffer, uint16_t bufmax) -{ - const struct nfs_client *clp = cookie_netfs_data; - const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &clp->cl_addr; - const struct sockaddr_in *sin = (struct sockaddr_in *) &clp->cl_addr; - struct nfs_server_key *key = buffer; - uint16_t len = sizeof(struct nfs_server_key); - - memset(key, 0, len); - key->nfsversion = clp->rpc_ops->version; - key->family = clp->cl_addr.ss_family; - - switch (clp->cl_addr.ss_family) { - case AF_INET: - key->port = sin->sin_port; - key->addr[0].ipv4_addr = sin->sin_addr; - len += sizeof(key->addr[0].ipv4_addr); - break; - - case AF_INET6: - key->port = sin6->sin6_port; - key->addr[0].ipv6_addr = sin6->sin6_addr; - len += sizeof(key->addr[0].ipv6_addr); - break; - - default: - printk(KERN_WARNING "NFS: Unknown network family '%d'\n", - clp->cl_addr.ss_family); - len = 0; - break; - } - - return len; -} - -/* * Define the server object for FS-Cache. This is used to describe a server * object to fscache_acquire_cookie(). It is keyed by the NFS protocol and * server address parameters. @@ -110,33 +57,9 @@ static uint16_t nfs_server_get_key(const void *cookie_netfs_data, const struct fscache_cookie_def nfs_fscache_server_index_def = { .name = "NFS.server", .type = FSCACHE_COOKIE_TYPE_INDEX, - .get_key = nfs_server_get_key, }; /* - * Generate a key to describe a superblock key in the main NFS index - */ -static uint16_t nfs_super_get_key(const void *cookie_netfs_data, - void *buffer, uint16_t bufmax) -{ - const struct nfs_fscache_key *key; - const struct nfs_server *nfss = cookie_netfs_data; - uint16_t len; - - key = nfss->fscache_key; - len = sizeof(key->key) + key->key.uniq_len; - if (len > bufmax) { - len = 0; - } else { - memcpy(buffer, &key->key, sizeof(key->key)); - memcpy(buffer + sizeof(key->key), - key->key.uniquifier, key->key.uniq_len); - } - - return len; -} - -/* * Define the superblock object for FS-Cache. This is used to describe a * superblock object to fscache_acquire_cookie(). It is keyed by all the NFS * parameters that might cause a separate superblock. @@ -144,41 +67,9 @@ static uint16_t nfs_super_get_key(const void *cookie_netfs_data, const struct fscache_cookie_def nfs_fscache_super_index_def = { .name = "NFS.super", .type = FSCACHE_COOKIE_TYPE_INDEX, - .get_key = nfs_super_get_key, }; /* - * Definition of the auxiliary data attached to NFS inode storage objects - * within the cache. - * - * The contents of this struct are recorded in the on-disk local cache in the - * auxiliary data attached to the data storage object backing an inode. This - * permits coherency to be managed when a new inode binds to an already extant - * cache object. - */ -struct nfs_fscache_inode_auxdata { - struct timespec mtime; - struct timespec ctime; - loff_t size; - u64 change_attr; -}; - -/* - * Generate a key to describe an NFS inode in an NFS server's index - */ -static uint16_t nfs_fscache_inode_get_key(const void *cookie_netfs_data, - void *buffer, uint16_t bufmax) -{ - const struct nfs_inode *nfsi = cookie_netfs_data; - uint16_t nsize; - - /* use the inode's NFS filehandle as the key */ - nsize = nfsi->fh.size; - memcpy(buffer, nfsi->fh.data, nsize); - return nsize; -} - -/* * Get certain file attributes from the netfs data * - This function can be absent for an index * - Not permitted to return an error @@ -193,35 +84,6 @@ static void nfs_fscache_inode_get_attr(const void *cookie_netfs_data, } /* - * Get the auxiliary data from netfs data - * - This function can be absent if the index carries no state data - * - Should store the auxiliary data in the buffer - * - Should return the amount of amount stored - * - Not permitted to return an error - * - The netfs data from the cookie being used as the source is presented - */ -static uint16_t nfs_fscache_inode_get_aux(const void *cookie_netfs_data, - void *buffer, uint16_t bufmax) -{ - struct nfs_fscache_inode_auxdata auxdata; - const struct nfs_inode *nfsi = cookie_netfs_data; - - memset(&auxdata, 0, sizeof(auxdata)); - auxdata.size = nfsi->vfs_inode.i_size; - auxdata.mtime = nfsi->vfs_inode.i_mtime; - auxdata.ctime = nfsi->vfs_inode.i_ctime; - - if (NFS_SERVER(&nfsi->vfs_inode)->nfs_client->rpc_ops->version == 4) - auxdata.change_attr = inode_peek_iversion_raw(&nfsi->vfs_inode); - - if (bufmax > sizeof(auxdata)) - bufmax = sizeof(auxdata); - - memcpy(buffer, &auxdata, bufmax); - return bufmax; -} - -/* * Consult the netfs about the state of an object * - This function can be absent if the index carries no state data * - The netfs data from the cookie being used as the target is @@ -288,9 +150,7 @@ static void nfs_fh_put_context(void *cookie_netfs_data, void *context) const struct fscache_cookie_def nfs_fscache_inode_object_def = { .name = "NFS.fh", .type = FSCACHE_COOKIE_TYPE_DATAFILE, - .get_key = nfs_fscache_inode_get_key, .get_attr = nfs_fscache_inode_get_attr, - .get_aux = nfs_fscache_inode_get_aux, .check_aux = nfs_fscache_inode_check_aux, .get_context = nfs_fh_get_context, .put_context = nfs_fh_put_context, diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c index d63bea8bbfbb..c45ba2691cee 100644 --- a/fs/nfs/fscache.c +++ b/fs/nfs/fscache.c @@ -18,6 +18,7 @@ #include <linux/in6.h> #include <linux/seq_file.h> #include <linux/slab.h> +#include <linux/iversion.h> #include "internal.h" #include "iostat.h" @@ -29,6 +30,21 @@ static struct rb_root nfs_fscache_keys = RB_ROOT; static DEFINE_SPINLOCK(nfs_fscache_keys_lock); /* + * Layout of the key for an NFS server cache object. + */ +struct nfs_server_key { + struct { + uint16_t nfsversion; /* NFS protocol version */ + uint16_t family; /* address family */ + __be16 port; /* IP port */ + } hdr; + union { + struct in_addr ipv4_addr; /* IPv4 address */ + struct in6_addr ipv6_addr; /* IPv6 address */ + }; +} __packed; + +/* * Get the per-client index cookie for an NFS client if the appropriate mount * flag was set * - We always try and get an index cookie for the client, but get filehandle @@ -36,9 +52,40 @@ static DEFINE_SPINLOCK(nfs_fscache_keys_lock); */ void nfs_fscache_get_client_cookie(struct nfs_client *clp) { + const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &clp->cl_addr; + const struct sockaddr_in *sin = (struct sockaddr_in *) &clp->cl_addr; + struct nfs_server_key key; + uint16_t len = sizeof(key.hdr); + + memset(&key, 0, sizeof(key)); + key.hdr.nfsversion = clp->rpc_ops->version; + key.hdr.family = clp->cl_addr.ss_family; + + switch (clp->cl_addr.ss_family) { + case AF_INET: + key.hdr.port = sin->sin_port; + key.ipv4_addr = sin->sin_addr; + len += sizeof(key.ipv4_addr); + break; + + case AF_INET6: + key.hdr.port = sin6->sin6_port; + key.ipv6_addr = sin6->sin6_addr; + len += sizeof(key.ipv6_addr); + break; + + default: + printk(KERN_WARNING "NFS: Unknown network family '%d'\n", + clp->cl_addr.ss_family); + clp->fscache = NULL; + return; + } + /* create a cache index for looking up filehandles */ clp->fscache = fscache_acquire_cookie(nfs_fscache_netfs.primary_index, &nfs_fscache_server_index_def, + &key, len, + NULL, 0, clp, true); dfprintk(FSCACHE, "NFS: get client cookie (0x%p/0x%p)\n", clp, clp->fscache); @@ -52,7 +99,7 @@ void nfs_fscache_release_client_cookie(struct nfs_client *clp) dfprintk(FSCACHE, "NFS: releasing client cookie (0x%p/0x%p)\n", clp, clp->fscache); - fscache_relinquish_cookie(clp->fscache, 0); + fscache_relinquish_cookie(clp->fscache, NULL, false); clp->fscache = NULL; } @@ -139,6 +186,8 @@ void nfs_fscache_get_super_cookie(struct super_block *sb, const char *uniq, int /* create a cache index for looking up filehandles */ nfss->fscache = fscache_acquire_cookie(nfss->nfs_client->fscache, &nfs_fscache_super_index_def, + key, sizeof(*key) + ulen, + NULL, 0, nfss, true); dfprintk(FSCACHE, "NFS: get superblock cookie (0x%p/0x%p)\n", nfss, nfss->fscache); @@ -163,7 +212,7 @@ void nfs_fscache_release_super_cookie(struct super_block *sb) dfprintk(FSCACHE, "NFS: releasing superblock cookie (0x%p/0x%p)\n", nfss, nfss->fscache); - fscache_relinquish_cookie(nfss->fscache, 0); + fscache_relinquish_cookie(nfss->fscache, NULL, false); nfss->fscache = NULL; if (nfss->fscache_key) { @@ -180,13 +229,25 @@ void nfs_fscache_release_super_cookie(struct super_block *sb) */ void nfs_fscache_init_inode(struct inode *inode) { + struct nfs_fscache_inode_auxdata auxdata; struct nfs_inode *nfsi = NFS_I(inode); nfsi->fscache = NULL; if (!S_ISREG(inode->i_mode)) return; + + memset(&auxdata, 0, sizeof(auxdata)); + auxdata.size = nfsi->vfs_inode.i_size; + auxdata.mtime = nfsi->vfs_inode.i_mtime; + auxdata.ctime = nfsi->vfs_inode.i_ctime; + + if (NFS_SERVER(&nfsi->vfs_inode)->nfs_client->rpc_ops->version == 4) + auxdata.change_attr = inode_peek_iversion_raw(&nfsi->vfs_inode); + nfsi->fscache = fscache_acquire_cookie(NFS_SB(inode->i_sb)->fscache, &nfs_fscache_inode_object_def, + nfsi->fh.data, nfsi->fh.size, + &auxdata, sizeof(auxdata), nfsi, false); } @@ -195,12 +256,17 @@ void nfs_fscache_init_inode(struct inode *inode) */ void nfs_fscache_clear_inode(struct inode *inode) { + struct nfs_fscache_inode_auxdata auxdata; struct nfs_inode *nfsi = NFS_I(inode); struct fscache_cookie *cookie = nfs_i_fscache(inode); dfprintk(FSCACHE, "NFS: clear cookie (0x%p/0x%p)\n", nfsi, cookie); - fscache_relinquish_cookie(cookie, false); + memset(&auxdata, 0, sizeof(auxdata)); + auxdata.size = nfsi->vfs_inode.i_size; + auxdata.mtime = nfsi->vfs_inode.i_mtime; + auxdata.ctime = nfsi->vfs_inode.i_ctime; + fscache_relinquish_cookie(cookie, &auxdata, false); nfsi->fscache = NULL; } @@ -232,20 +298,27 @@ static bool nfs_fscache_can_enable(void *data) */ void nfs_fscache_open_file(struct inode *inode, struct file *filp) { + struct nfs_fscache_inode_auxdata auxdata; struct nfs_inode *nfsi = NFS_I(inode); struct fscache_cookie *cookie = nfs_i_fscache(inode); if (!fscache_cookie_valid(cookie)) return; + memset(&auxdata, 0, sizeof(auxdata)); + auxdata.size = nfsi->vfs_inode.i_size; + auxdata.mtime = nfsi->vfs_inode.i_mtime; + auxdata.ctime = nfsi->vfs_inode.i_ctime; + if (inode_is_open_for_write(inode)) { dfprintk(FSCACHE, "NFS: nfsi 0x%p disabling cache\n", nfsi); clear_bit(NFS_INO_FSCACHE, &nfsi->flags); - fscache_disable_cookie(cookie, true); + fscache_disable_cookie(cookie, &auxdata, true); fscache_uncache_all_inode_pages(cookie, inode); } else { dfprintk(FSCACHE, "NFS: nfsi 0x%p enabling cache\n", nfsi); - fscache_enable_cookie(cookie, nfs_fscache_can_enable, inode); + fscache_enable_cookie(cookie, &auxdata, + nfs_fscache_can_enable, inode); if (fscache_cookie_enabled(cookie)) set_bit(NFS_INO_FSCACHE, &NFS_I(inode)->flags); } diff --git a/fs/nfs/fscache.h b/fs/nfs/fscache.h index d7fe3e799f2f..96e989f579d1 100644 --- a/fs/nfs/fscache.h +++ b/fs/nfs/fscache.h @@ -57,6 +57,22 @@ struct nfs_fscache_key { }; /* + * Definition of the auxiliary data attached to NFS inode storage objects + * within the cache. + * + * The contents of this struct are recorded in the on-disk local cache in the + * auxiliary data attached to the data storage object backing an inode. This + * permits coherency to be managed when a new inode binds to an already extant + * cache object. + */ +struct nfs_fscache_inode_auxdata { + struct timespec mtime; + struct timespec ctime; + loff_t size; + u64 change_attr; +}; + +/* * fscache-index.c */ extern struct fscache_netfs nfs_fscache_netfs; |