diff options
author | Linus Torvalds | 2018-04-07 09:08:24 -0700 |
---|---|---|
committer | Linus Torvalds | 2018-04-07 09:08:24 -0700 |
commit | 62f8e6c5dcb6666e7da402aea28fcf846eea144c (patch) | |
tree | 2fb8ea1b55b4f0b0592fce715dc7816533609a23 /fs/cifs | |
parent | f605ba97fb80522656c7dce9825a908f1e765b57 (diff) | |
parent | ec0328e46d6e5d0f17372eb90ab8e333c2ac7ca9 (diff) |
Merge tag 'fscache-next-20180406' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs
Pull fscache updates from David Howells:
"Three patches that fix some of AFS's usage of fscache:
(1) Need to invalidate the cache if a foreign data change is detected
on the server.
(2) Move the vnode ID uniquifier (equivalent to i_generation) from
the auxiliary data to the index key to prevent a race between
file delete and a subsequent file create seeing the same index
key.
(3) Need to retire cookies that correspond to files that we think got
deleted on the server.
Four patches to fix some things in fscache and cachefiles:
(4) Fix a couple of checker warnings.
(5) Correctly indicate to the end-of-operation callback whether an
operation completed or was cancelled.
(6) Add a check for multiple cookie relinquishment.
(7) Fix a path through the asynchronous write that doesn't wake up a
waiter for a page if the cache decides not to write that page,
but discards it instead.
A couple of patches to add tracepoints to fscache and cachefiles:
(8) Add tracepoints for cookie operators, object state machine
execution, cachefiles object management and cachefiles VFS
operations.
(9) Add tracepoints for fscache operation management and page
wrangling.
And then three development patches:
(10) Attach the index key and auxiliary data to the cookie, pass this
information through various fscache-netfs API functions and get
rid of the callbacks to the netfs to get it.
This means that the cache can get at this information, even if
the netfs goes away. It also means that the cache can be lazy in
updating the coherency data.
(11) Pass the object data size through various fscache-netfs API
rather than calling back to the netfs for it, and store the value
in the object.
This makes it easier to correctly resize the object, as the size
is updated on writes to the cache, rather than calling back out
to the netfs.
(12) Maintain a catalogue of allocated cookies. This makes it possible
to catch cookie collision up front rather than down in the bowels
of the cache being run from a service thread from the object
state machine.
This will also make it possible in the future to reconnect to a
cookie that's not gone dead yet because it's waiting for
finalisation of the storage and also make it possible to bring
cookies online if the cache is added after the cookie has been
obtained"
* tag 'fscache-next-20180406' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
fscache: Maintain a catalogue of allocated cookies
fscache: Pass object size in rather than calling back for it
fscache: Attach the index key and aux data to the cookie
fscache: Add more tracepoints
fscache: Add tracepoints
fscache: Fix hanging wait on page discarded by writeback
fscache: Detect multiple relinquishment of a cookie
fscache: Pass the correct cancelled indications to fscache_op_complete()
fscache, cachefiles: Fix checker warnings
afs: Be more aggressive in retiring cached vnodes
afs: Use the vnode ID uniquifier in the cache key not the aux data
afs: Invalidate cache on server data change
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/cache.c | 168 | ||||
-rw-r--r-- | fs/cifs/fscache.c | 130 | ||||
-rw-r--r-- | fs/cifs/fscache.h | 13 |
3 files changed, 127 insertions, 184 deletions
diff --git a/fs/cifs/cache.c b/fs/cifs/cache.c index 2c14020e5e1d..edf5f40898bf 100644 --- a/fs/cifs/cache.c +++ b/fs/cifs/cache.c @@ -46,67 +46,11 @@ void cifs_fscache_unregister(void) } /* - * Key layout of CIFS server cache index object - */ -struct cifs_server_key { - uint16_t family; /* address family */ - __be16 port; /* IP port */ - union { - struct in_addr ipv4_addr; - struct in6_addr ipv6_addr; - } addr[0]; -}; - -/* - * Server object keyed by {IPaddress,port,family} tuple - */ -static uint16_t cifs_server_get_key(const void *cookie_netfs_data, - void *buffer, uint16_t maxbuf) -{ - const struct TCP_Server_Info *server = cookie_netfs_data; - const struct sockaddr *sa = (struct sockaddr *) &server->dstaddr; - const struct sockaddr_in *addr = (struct sockaddr_in *) sa; - const struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) sa; - struct cifs_server_key *key = buffer; - uint16_t key_len = sizeof(struct cifs_server_key); - - memset(key, 0, key_len); - - /* - * Should not be a problem as sin_family/sin6_family overlays - * sa_family field - */ - switch (sa->sa_family) { - case AF_INET: - key->family = sa->sa_family; - key->port = addr->sin_port; - key->addr[0].ipv4_addr = addr->sin_addr; - key_len += sizeof(key->addr[0].ipv4_addr); - break; - - case AF_INET6: - key->family = sa->sa_family; - key->port = addr6->sin6_port; - key->addr[0].ipv6_addr = addr6->sin6_addr; - key_len += sizeof(key->addr[0].ipv6_addr); - break; - - default: - cifs_dbg(VFS, "Unknown network family '%d'\n", sa->sa_family); - key_len = 0; - break; - } - - return key_len; -} - -/* * Server object for FS-Cache */ const struct fscache_cookie_def cifs_fscache_server_index_def = { .name = "CIFS.server", .type = FSCACHE_COOKIE_TYPE_INDEX, - .get_key = cifs_server_get_key, }; /* @@ -116,7 +60,7 @@ struct cifs_fscache_super_auxdata { u64 resource_id; /* unique server resource id */ }; -static char *extract_sharename(const char *treename) +char *extract_sharename(const char *treename) { const char *src; char *delim, *dst; @@ -140,56 +84,11 @@ static char *extract_sharename(const char *treename) return dst; } -/* - * Superblock object currently keyed by share name - */ -static uint16_t cifs_super_get_key(const void *cookie_netfs_data, void *buffer, - uint16_t maxbuf) -{ - const struct cifs_tcon *tcon = cookie_netfs_data; - char *sharename; - uint16_t len; - - sharename = extract_sharename(tcon->treeName); - if (IS_ERR(sharename)) { - cifs_dbg(FYI, "%s: couldn't extract sharename\n", __func__); - sharename = NULL; - return 0; - } - - len = strlen(sharename); - if (len > maxbuf) - return 0; - - memcpy(buffer, sharename, len); - - kfree(sharename); - - return len; -} - -static uint16_t -cifs_fscache_super_get_aux(const void *cookie_netfs_data, void *buffer, - uint16_t maxbuf) -{ - struct cifs_fscache_super_auxdata auxdata; - const struct cifs_tcon *tcon = cookie_netfs_data; - - memset(&auxdata, 0, sizeof(auxdata)); - auxdata.resource_id = tcon->resource_id; - - if (maxbuf > sizeof(auxdata)) - maxbuf = sizeof(auxdata); - - memcpy(buffer, &auxdata, maxbuf); - - return maxbuf; -} - static enum fscache_checkaux cifs_fscache_super_check_aux(void *cookie_netfs_data, const void *data, - uint16_t datalen) + uint16_t datalen, + loff_t object_size) { struct cifs_fscache_super_auxdata auxdata; const struct cifs_tcon *tcon = cookie_netfs_data; @@ -212,68 +111,14 @@ fscache_checkaux cifs_fscache_super_check_aux(void *cookie_netfs_data, const struct fscache_cookie_def cifs_fscache_super_index_def = { .name = "CIFS.super", .type = FSCACHE_COOKIE_TYPE_INDEX, - .get_key = cifs_super_get_key, - .get_aux = cifs_fscache_super_get_aux, .check_aux = cifs_fscache_super_check_aux, }; -/* - * Auxiliary data attached to CIFS inode within the cache - */ -struct cifs_fscache_inode_auxdata { - struct timespec last_write_time; - struct timespec last_change_time; - u64 eof; -}; - -static uint16_t cifs_fscache_inode_get_key(const void *cookie_netfs_data, - void *buffer, uint16_t maxbuf) -{ - const struct cifsInodeInfo *cifsi = cookie_netfs_data; - uint16_t keylen; - - /* use the UniqueId as the key */ - keylen = sizeof(cifsi->uniqueid); - if (keylen > maxbuf) - keylen = 0; - else - memcpy(buffer, &cifsi->uniqueid, keylen); - - return keylen; -} - -static void -cifs_fscache_inode_get_attr(const void *cookie_netfs_data, uint64_t *size) -{ - const struct cifsInodeInfo *cifsi = cookie_netfs_data; - - *size = cifsi->vfs_inode.i_size; -} - -static uint16_t -cifs_fscache_inode_get_aux(const void *cookie_netfs_data, void *buffer, - uint16_t maxbuf) -{ - struct cifs_fscache_inode_auxdata auxdata; - const struct cifsInodeInfo *cifsi = cookie_netfs_data; - - memset(&auxdata, 0, sizeof(auxdata)); - auxdata.eof = cifsi->server_eof; - auxdata.last_write_time = cifsi->vfs_inode.i_mtime; - auxdata.last_change_time = cifsi->vfs_inode.i_ctime; - - if (maxbuf > sizeof(auxdata)) - maxbuf = sizeof(auxdata); - - memcpy(buffer, &auxdata, maxbuf); - - return maxbuf; -} - static enum fscache_checkaux cifs_fscache_inode_check_aux(void *cookie_netfs_data, const void *data, - uint16_t datalen) + uint16_t datalen, + loff_t object_size) { struct cifs_fscache_inode_auxdata auxdata; struct cifsInodeInfo *cifsi = cookie_netfs_data; @@ -295,8 +140,5 @@ fscache_checkaux cifs_fscache_inode_check_aux(void *cookie_netfs_data, const struct fscache_cookie_def cifs_fscache_inode_object_def = { .name = "CIFS.uniqueid", .type = FSCACHE_COOKIE_TYPE_DATAFILE, - .get_key = cifs_fscache_inode_get_key, - .get_attr = cifs_fscache_inode_get_attr, - .get_aux = cifs_fscache_inode_get_aux, .check_aux = cifs_fscache_inode_check_aux, }; diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c index 8d4b7bc8ae91..25d3f66b2d50 100644 --- a/fs/cifs/fscache.c +++ b/fs/cifs/fscache.c @@ -23,11 +23,63 @@ #include "cifs_debug.h" #include "cifs_fs_sb.h" +/* + * Key layout of CIFS server cache index object + */ +struct cifs_server_key { + struct { + uint16_t family; /* address family */ + __be16 port; /* IP port */ + } hdr; + union { + struct in_addr ipv4_addr; + struct in6_addr ipv6_addr; + }; +} __packed; + +/* + * Get a cookie for a server object keyed by {IPaddress,port,family} tuple + */ void cifs_fscache_get_client_cookie(struct TCP_Server_Info *server) { + const struct sockaddr *sa = (struct sockaddr *) &server->dstaddr; + const struct sockaddr_in *addr = (struct sockaddr_in *) sa; + const struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) sa; + struct cifs_server_key key; + uint16_t key_len = sizeof(key.hdr); + + memset(&key, 0, sizeof(key)); + + /* + * Should not be a problem as sin_family/sin6_family overlays + * sa_family field + */ + key.hdr.family = sa->sa_family; + switch (sa->sa_family) { + case AF_INET: + key.hdr.port = addr->sin_port; + key.ipv4_addr = addr->sin_addr; + key_len += sizeof(key.ipv4_addr); + break; + + case AF_INET6: + key.hdr.port = addr6->sin6_port; + key.ipv6_addr = addr6->sin6_addr; + key_len += sizeof(key.ipv6_addr); + break; + + default: + cifs_dbg(VFS, "Unknown network family '%d'\n", sa->sa_family); + server->fscache = NULL; + return; + } + server->fscache = fscache_acquire_cookie(cifs_fscache_netfs.primary_index, - &cifs_fscache_server_index_def, server, true); + &cifs_fscache_server_index_def, + &key, key_len, + NULL, 0, + server, 0, true); cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", __func__, server, server->fscache); } @@ -36,17 +88,29 @@ void cifs_fscache_release_client_cookie(struct TCP_Server_Info *server) { cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", __func__, server, server->fscache); - fscache_relinquish_cookie(server->fscache, 0); + fscache_relinquish_cookie(server->fscache, NULL, false); server->fscache = NULL; } void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) { struct TCP_Server_Info *server = tcon->ses->server; + char *sharename; + + sharename = extract_sharename(tcon->treeName); + if (IS_ERR(sharename)) { + cifs_dbg(FYI, "%s: couldn't extract sharename\n", __func__); + tcon->fscache = NULL; + return; + } tcon->fscache = fscache_acquire_cookie(server->fscache, - &cifs_fscache_super_index_def, tcon, true); + &cifs_fscache_super_index_def, + sharename, strlen(sharename), + &tcon->resource_id, sizeof(tcon->resource_id), + tcon, 0, true); + kfree(sharename); cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", __func__, server->fscache, tcon->fscache); } @@ -54,10 +118,28 @@ void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) { cifs_dbg(FYI, "%s: (0x%p)\n", __func__, tcon->fscache); - fscache_relinquish_cookie(tcon->fscache, 0); + fscache_relinquish_cookie(tcon->fscache, &tcon->resource_id, false); tcon->fscache = NULL; } +static void cifs_fscache_acquire_inode_cookie(struct cifsInodeInfo *cifsi, + struct cifs_tcon *tcon) +{ + struct cifs_fscache_inode_auxdata auxdata; + + memset(&auxdata, 0, sizeof(auxdata)); + auxdata.eof = cifsi->server_eof; + auxdata.last_write_time = cifsi->vfs_inode.i_mtime; + auxdata.last_change_time = cifsi->vfs_inode.i_ctime; + + cifsi->fscache = + fscache_acquire_cookie(tcon->fscache, + &cifs_fscache_inode_object_def, + &cifsi->uniqueid, sizeof(cifsi->uniqueid), + &auxdata, sizeof(auxdata), + cifsi, cifsi->vfs_inode.i_size, true); +} + static void cifs_fscache_enable_inode_cookie(struct inode *inode) { struct cifsInodeInfo *cifsi = CIFS_I(inode); @@ -67,21 +149,28 @@ static void cifs_fscache_enable_inode_cookie(struct inode *inode) if (cifsi->fscache) return; - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) { - cifsi->fscache = fscache_acquire_cookie(tcon->fscache, - &cifs_fscache_inode_object_def, cifsi, true); - cifs_dbg(FYI, "%s: got FH cookie (0x%p/0x%p)\n", - __func__, tcon->fscache, cifsi->fscache); - } + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE)) + return; + + cifs_fscache_acquire_inode_cookie(cifsi, tcon); + + cifs_dbg(FYI, "%s: got FH cookie (0x%p/0x%p)\n", + __func__, tcon->fscache, cifsi->fscache); } void cifs_fscache_release_inode_cookie(struct inode *inode) { + struct cifs_fscache_inode_auxdata auxdata; struct cifsInodeInfo *cifsi = CIFS_I(inode); if (cifsi->fscache) { + memset(&auxdata, 0, sizeof(auxdata)); + auxdata.eof = cifsi->server_eof; + auxdata.last_write_time = cifsi->vfs_inode.i_mtime; + auxdata.last_change_time = cifsi->vfs_inode.i_ctime; + cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache); - fscache_relinquish_cookie(cifsi->fscache, 0); + fscache_relinquish_cookie(cifsi->fscache, &auxdata, false); cifsi->fscache = NULL; } } @@ -93,7 +182,7 @@ static void cifs_fscache_disable_inode_cookie(struct inode *inode) if (cifsi->fscache) { cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache); fscache_uncache_all_inode_pages(cifsi->fscache, inode); - fscache_relinquish_cookie(cifsi->fscache, 1); + fscache_relinquish_cookie(cifsi->fscache, NULL, true); cifsi->fscache = NULL; } } @@ -110,16 +199,14 @@ void cifs_fscache_reset_inode_cookie(struct inode *inode) { struct cifsInodeInfo *cifsi = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); + struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); struct fscache_cookie *old = cifsi->fscache; if (cifsi->fscache) { /* retire the current fscache cache and get a new one */ - fscache_relinquish_cookie(cifsi->fscache, 1); + fscache_relinquish_cookie(cifsi->fscache, NULL, true); - cifsi->fscache = fscache_acquire_cookie( - cifs_sb_master_tcon(cifs_sb)->fscache, - &cifs_fscache_inode_object_def, - cifsi, true); + cifs_fscache_acquire_inode_cookie(cifsi, tcon); cifs_dbg(FYI, "%s: new cookie 0x%p oldcookie 0x%p\n", __func__, cifsi->fscache, old); } @@ -214,13 +301,15 @@ int __cifs_readpages_from_fscache(struct inode *inode, void __cifs_readpage_to_fscache(struct inode *inode, struct page *page) { + struct cifsInodeInfo *cifsi = CIFS_I(inode); int ret; cifs_dbg(FYI, "%s: (fsc: %p, p: %p, i: %p)\n", - __func__, CIFS_I(inode)->fscache, page, inode); - ret = fscache_write_page(CIFS_I(inode)->fscache, page, GFP_KERNEL); + __func__, cifsi->fscache, page, inode); + ret = fscache_write_page(cifsi->fscache, page, + cifsi->vfs_inode.i_size, GFP_KERNEL); if (ret != 0) - fscache_uncache_page(CIFS_I(inode)->fscache, page); + fscache_uncache_page(cifsi->fscache, page); } void __cifs_fscache_readpages_cancel(struct inode *inode, struct list_head *pages) @@ -239,4 +328,3 @@ void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode) fscache_wait_on_page_write(cookie, page); fscache_uncache_page(cookie, page); } - diff --git a/fs/cifs/fscache.h b/fs/cifs/fscache.h index 24794b6cd8ec..c7e3ac251e16 100644 --- a/fs/cifs/fscache.h +++ b/fs/cifs/fscache.h @@ -27,6 +27,18 @@ #ifdef CONFIG_CIFS_FSCACHE +/* + * Auxiliary data attached to CIFS inode within the cache + */ +struct cifs_fscache_inode_auxdata { + struct timespec last_write_time; + struct timespec last_change_time; + u64 eof; +}; + +/* + * cache.c + */ extern struct fscache_netfs cifs_fscache_netfs; extern const struct fscache_cookie_def cifs_fscache_server_index_def; extern const struct fscache_cookie_def cifs_fscache_super_index_def; @@ -34,6 +46,7 @@ extern const struct fscache_cookie_def cifs_fscache_inode_object_def; extern int cifs_fscache_register(void); extern void cifs_fscache_unregister(void); +extern char *extract_sharename(const char *); /* * fscache.c |