Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

afs: Convert afs to use the new fscache API

Change the afs filesystem to support the new afs driver.

The following changes have been made:

(1) The fscache_netfs struct is no more, and there's no need to register
the filesystem as a whole. There's also no longer a cell cookie.

(2) The volume cookie is now an fscache_volume cookie, allocated with
fscache_acquire_volume(). This function takes three parameters: a
string representing the "volume" in the index, a string naming the
cache to use (or NULL) and a u64 that conveys coherency metadata for
the volume.

For afs, I've made it render the volume name string as:

"afs,<cell>,<volume_id>"

and the coherency data is currently 0.

(3) The fscache_cookie_def is no more and needed information is passed
directly to fscache_acquire_cookie(). The cache no longer calls back
into the filesystem, but rather metadata changes are indicated at
other times.

fscache_acquire_cookie() is passed the same keying and coherency
information as before, except that these are now stored in big endian
form instead of cpu endian. This makes the cache more copyable.

(4) fscache_use_cookie() and fscache_unuse_cookie() are called when a file
is opened or closed to prevent a cache file from being culled and to
keep resources to hand that are needed to do I/O.

fscache_use_cookie() is given an indication if the cache is likely to
be modified locally (e.g. the file is open for writing).

fscache_unuse_cookie() is given a coherency update if we had the file
open for writing and will update that.

(5) fscache_invalidate() is now given uptodate auxiliary data and a file
size. It can also take a flag to indicate if this was due to a DIO
write. This is wrapped into afs_fscache_invalidate() now for
convenience.

(6) fscache_resize() now gets called from the finalisation of
afs_setattr(), and afs_setattr() does use/unuse of the cookie around
the call to support this.

(7) fscache_note_page_release() is called from afs_release_page().

(8) Use a killable wait in nfs_vm_page_mkwrite() when waiting for
PG_fscache to be cleared.

Render the parts of the cookie key for an afs inode cookie as big endian.

Changes
=======
ver #2:
- Use gfpflags_allow_blocking() rather than using flag directly.
- fscache_acquire_volume() now returns errors.

Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Jeff Layton <jlayton@kernel.org>
Tested-by: kafs-testing@auristor.com
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
cc: linux-cachefs@redhat.com
Link: https://lore.kernel.org/r/163819661382.215744.1485608824741611837.stgit@warthog.procyon.org.uk/ # v1
Link: https://lore.kernel.org/r/163906970002.143852.17678518584089878259.stgit@warthog.procyon.org.uk/ # v2
Link: https://lore.kernel.org/r/163967174665.1823006.1301789965454084220.stgit@warthog.procyon.org.uk/ # v3
Link: https://lore.kernel.org/r/164021568841.640689.6684240152253400380.stgit@warthog.procyon.org.uk/ # v4

+88 -150
+1 -1
fs/afs/Kconfig
··· 25 25 26 26 config AFS_FSCACHE 27 27 bool "Provide AFS client caching support" 28 - depends on AFS_FS=m && FSCACHE_OLD_API || AFS_FS=y && FSCACHE_OLD_API=y 28 + depends on AFS_FS=m && FSCACHE || AFS_FS=y && FSCACHE=y 29 29 help 30 30 Say Y here if you want AFS data to be cached locally on disk through 31 31 the generic filesystem cache manager
-3
fs/afs/Makefile
··· 3 3 # Makefile for Red Hat Linux AFS client. 4 4 # 5 5 6 - afs-cache-$(CONFIG_AFS_FSCACHE) := cache.o 7 - 8 6 kafs-y := \ 9 - $(afs-cache-y) \ 10 7 addr_list.o \ 11 8 callback.o \ 12 9 cell.o \
-68
fs/afs/cache.c
··· 1 - // SPDX-License-Identifier: GPL-2.0-or-later 2 - /* AFS caching stuff 3 - * 4 - * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. 5 - * Written by David Howells (dhowells@redhat.com) 6 - */ 7 - 8 - #include <linux/sched.h> 9 - #include "internal.h" 10 - 11 - static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data, 12 - const void *buffer, 13 - uint16_t buflen, 14 - loff_t object_size); 15 - 16 - struct fscache_netfs afs_cache_netfs = { 17 - .name = "afs", 18 - .version = 2, 19 - }; 20 - 21 - struct fscache_cookie_def afs_cell_cache_index_def = { 22 - .name = "AFS.cell", 23 - .type = FSCACHE_COOKIE_TYPE_INDEX, 24 - }; 25 - 26 - struct fscache_cookie_def afs_volume_cache_index_def = { 27 - .name = "AFS.volume", 28 - .type = FSCACHE_COOKIE_TYPE_INDEX, 29 - }; 30 - 31 - struct fscache_cookie_def afs_vnode_cache_index_def = { 32 - .name = "AFS.vnode", 33 - .type = FSCACHE_COOKIE_TYPE_DATAFILE, 34 - .check_aux = afs_vnode_cache_check_aux, 35 - }; 36 - 37 - /* 38 - * check that the auxiliary data indicates that the entry is still valid 39 - */ 40 - static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data, 41 - const void *buffer, 42 - uint16_t buflen, 43 - loff_t object_size) 44 - { 45 - struct afs_vnode *vnode = cookie_netfs_data; 46 - struct afs_vnode_cache_aux aux; 47 - 48 - _enter("{%llx,%x,%llx},%p,%u", 49 - vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version, 50 - buffer, buflen); 51 - 52 - memcpy(&aux, buffer, sizeof(aux)); 53 - 54 - /* check the size of the data is what we're expecting */ 55 - if (buflen != sizeof(aux)) { 56 - _leave(" = OBSOLETE [len %hx != %zx]", buflen, sizeof(aux)); 57 - return FSCACHE_CHECKAUX_OBSOLETE; 58 - } 59 - 60 - if (vnode->status.data_version != aux.data_version) { 61 - _leave(" = OBSOLETE [vers %llx != %llx]", 62 - aux.data_version, vnode->status.data_version); 63 - return FSCACHE_CHECKAUX_OBSOLETE; 64 - } 65 - 66 - _leave(" = SUCCESS"); 67 - return FSCACHE_CHECKAUX_OKAY; 68 - }
-12
fs/afs/cell.c
··· 680 680 return ret; 681 681 } 682 682 683 - #ifdef CONFIG_AFS_FSCACHE 684 - cell->cache = fscache_acquire_cookie(afs_cache_netfs.primary_index, 685 - &afs_cell_cache_index_def, 686 - cell->name, strlen(cell->name), 687 - NULL, 0, 688 - cell, 0, true); 689 - #endif 690 683 ret = afs_proc_cell_setup(cell); 691 684 if (ret < 0) 692 685 return ret; ··· 715 722 hlist_del_rcu(&cell->proc_link); 716 723 afs_dynroot_rmdir(net, cell); 717 724 mutex_unlock(&net->proc_cells_lock); 718 - 719 - #ifdef CONFIG_AFS_FSCACHE 720 - fscache_relinquish_cookie(cell->cache, NULL, false); 721 - cell->cache = NULL; 722 - #endif 723 725 724 726 _leave(""); 725 727 }
+23 -6
fs/afs/file.c
··· 158 158 159 159 if (file->f_flags & O_TRUNC) 160 160 set_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags); 161 - 161 + 162 + fscache_use_cookie(afs_vnode_cache(vnode), file->f_mode & FMODE_WRITE); 163 + 162 164 file->private_data = af; 163 165 _leave(" = 0"); 164 166 return 0; ··· 179 177 */ 180 178 int afs_release(struct inode *inode, struct file *file) 181 179 { 180 + struct afs_vnode_cache_aux aux; 182 181 struct afs_vnode *vnode = AFS_FS_I(inode); 183 182 struct afs_file *af = file->private_data; 183 + loff_t i_size; 184 184 int ret = 0; 185 185 186 186 _enter("{%llx:%llu},", vnode->fid.vid, vnode->fid.vnode); ··· 193 189 file->private_data = NULL; 194 190 if (af->wb) 195 191 afs_put_wb_key(af->wb); 192 + 193 + if ((file->f_mode & FMODE_WRITE)) { 194 + i_size = i_size_read(&vnode->vfs_inode); 195 + afs_set_cache_aux(vnode, &aux); 196 + fscache_unuse_cookie(afs_vnode_cache(vnode), &aux, &i_size); 197 + } else { 198 + fscache_unuse_cookie(afs_vnode_cache(vnode), NULL, NULL); 199 + } 200 + 196 201 key_put(af->key); 197 202 kfree(af); 198 203 afs_prune_wb_keys(vnode); ··· 365 352 366 353 static bool afs_is_cache_enabled(struct inode *inode) 367 354 { 368 - return fscache_cookie_enabled(afs_vnode_cache(AFS_FS_I(inode))); 355 + struct fscache_cookie *cookie = afs_vnode_cache(AFS_FS_I(inode)); 356 + 357 + return fscache_cookie_enabled(cookie) && cookie->cache_priv; 369 358 } 370 359 371 360 static int afs_begin_cache_operation(struct netfs_read_request *rreq) ··· 375 360 #ifdef CONFIG_AFS_FSCACHE 376 361 struct afs_vnode *vnode = AFS_FS_I(rreq->inode); 377 362 378 - return fscache_begin_read_operation(rreq, afs_vnode_cache(vnode)); 363 + return fscache_begin_read_operation(&rreq->cache_resources, 364 + afs_vnode_cache(vnode)); 379 365 #else 380 366 return -ENOBUFS; 381 367 #endif ··· 498 482 * release a page and clean up its private state if it's not busy 499 483 * - return true if the page can now be released, false if not 500 484 */ 501 - static int afs_releasepage(struct page *page, gfp_t gfp_flags) 485 + static int afs_releasepage(struct page *page, gfp_t gfp) 502 486 { 503 487 struct folio *folio = page_folio(page); 504 488 struct afs_vnode *vnode = AFS_FS_I(folio_inode(folio)); 505 489 506 490 _enter("{{%llx:%llu}[%lu],%lx},%x", 507 491 vnode->fid.vid, vnode->fid.vnode, folio_index(folio), folio->flags, 508 - gfp_flags); 492 + gfp); 509 493 510 494 /* deny if page is being written to the cache and the caller hasn't 511 495 * elected to wait */ 512 496 #ifdef CONFIG_AFS_FSCACHE 513 497 if (folio_test_fscache(folio)) { 514 - if (!(gfp_flags & __GFP_DIRECT_RECLAIM) || !(gfp_flags & __GFP_FS)) 498 + if (!gfpflags_allow_blocking(gfp) || !(gfp & __GFP_FS)) 515 499 return false; 516 500 folio_wait_fscache(folio); 517 501 } 502 + fscache_note_page_release(afs_vnode_cache(vnode)); 518 503 #endif 519 504 520 505 if (folio_test_private(folio)) {
+24 -24
fs/afs/inode.c
··· 413 413 { 414 414 #ifdef CONFIG_AFS_FSCACHE 415 415 struct { 416 - u32 vnode_id; 417 - u32 unique; 418 - u32 vnode_id_ext[2]; /* Allow for a 96-bit key */ 416 + __be32 vnode_id; 417 + __be32 unique; 418 + __be32 vnode_id_ext[2]; /* Allow for a 96-bit key */ 419 419 } __packed key; 420 420 struct afs_vnode_cache_aux aux; 421 421 ··· 424 424 return; 425 425 } 426 426 427 - key.vnode_id = vnode->fid.vnode; 428 - key.unique = vnode->fid.unique; 429 - key.vnode_id_ext[0] = vnode->fid.vnode >> 32; 430 - key.vnode_id_ext[1] = vnode->fid.vnode_hi; 431 - aux.data_version = vnode->status.data_version; 427 + key.vnode_id = htonl(vnode->fid.vnode); 428 + key.unique = htonl(vnode->fid.unique); 429 + key.vnode_id_ext[0] = htonl(vnode->fid.vnode >> 32); 430 + key.vnode_id_ext[1] = htonl(vnode->fid.vnode_hi); 431 + afs_set_cache_aux(vnode, &aux); 432 432 433 - vnode->cache = fscache_acquire_cookie(vnode->volume->cache, 434 - &afs_vnode_cache_index_def, 435 - &key, sizeof(key), 436 - &aux, sizeof(aux), 437 - vnode, vnode->status.size, true); 433 + vnode->cache = fscache_acquire_cookie( 434 + vnode->volume->cache, 435 + vnode->status.type == AFS_FTYPE_FILE ? 0 : FSCACHE_ADV_SINGLE_CHUNK, 436 + &key, sizeof(key), 437 + &aux, sizeof(aux), 438 + vnode->status.size); 438 439 #endif 439 440 } 440 441 ··· 564 563 { 565 564 _enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode); 566 565 567 - #ifdef CONFIG_AFS_FSCACHE 568 - fscache_invalidate(vnode->cache); 569 - #endif 566 + afs_invalidate_cache(vnode, 0); 570 567 571 568 /* nuke all the non-dirty pages that aren't locked, mapped or being 572 569 * written back in a regular file and completely discard the pages in a ··· 785 786 } 786 787 787 788 #ifdef CONFIG_AFS_FSCACHE 788 - { 789 - struct afs_vnode_cache_aux aux; 790 - 791 - aux.data_version = vnode->status.data_version; 792 - fscache_relinquish_cookie(vnode->cache, &aux, 793 - test_bit(AFS_VNODE_DELETED, &vnode->flags)); 794 - vnode->cache = NULL; 795 - } 789 + fscache_relinquish_cookie(vnode->cache, 790 + test_bit(AFS_VNODE_DELETED, &vnode->flags)); 791 + vnode->cache = NULL; 796 792 #endif 797 793 798 794 afs_prune_wb_keys(vnode); ··· 827 833 828 834 if (size < i_size) 829 835 truncate_pagecache(inode, size); 836 + if (size != i_size) 837 + fscache_resize_cookie(afs_vnode_cache(vp->vnode), 838 + vp->scb.status.size); 830 839 } 831 840 } 832 841 ··· 873 876 attr->ia_valid &= ~ATTR_SIZE; 874 877 } 875 878 879 + fscache_use_cookie(afs_vnode_cache(vnode), true); 880 + 876 881 /* flush any dirty data outstanding on a regular file */ 877 882 if (S_ISREG(vnode->vfs_inode.i_mode)) 878 883 filemap_write_and_wait(vnode->vfs_inode.i_mapping); ··· 906 907 907 908 out_unlock: 908 909 up_write(&vnode->validate_lock); 910 + fscache_unuse_cookie(afs_vnode_cache(vnode), NULL, NULL); 909 911 _leave(" = %d", ret); 910 912 return ret; 911 913 }
+18 -14
fs/afs/internal.h
··· 14 14 #include <linux/key.h> 15 15 #include <linux/workqueue.h> 16 16 #include <linux/sched.h> 17 - #define FSCACHE_USE_NEW_IO_API 18 17 #include <linux/fscache.h> 19 18 #include <linux/backing-dev.h> 20 19 #include <linux/uuid.h> ··· 363 364 struct key *anonymous_key; /* anonymous user key for this cell */ 364 365 struct work_struct manager; /* Manager for init/deinit/dns */ 365 366 struct hlist_node proc_link; /* /proc cell list link */ 366 - #ifdef CONFIG_AFS_FSCACHE 367 - struct fscache_cookie *cache; /* caching cookie */ 368 - #endif 369 367 time64_t dns_expiry; /* Time AFSDB/SRV record expires */ 370 368 time64_t last_inactive; /* Time of last drop of usage count */ 371 369 atomic_t ref; /* Struct refcount */ ··· 586 590 #define AFS_VOLUME_BUSY 5 /* - T if volume busy notice given */ 587 591 #define AFS_VOLUME_MAYBE_NO_IBULK 6 /* - T if some servers don't have InlineBulkStatus */ 588 592 #ifdef CONFIG_AFS_FSCACHE 589 - struct fscache_cookie *cache; /* caching cookie */ 593 + struct fscache_volume *cache; /* Caching cookie */ 590 594 #endif 591 595 struct afs_server_list __rcu *servers; /* List of servers on which volume resides */ 592 596 rwlock_t servers_lock; /* Lock for ->servers */ ··· 868 872 * Cache auxiliary data. 869 873 */ 870 874 struct afs_vnode_cache_aux { 871 - u64 data_version; 875 + __be64 data_version; 872 876 } __packed; 877 + 878 + static inline void afs_set_cache_aux(struct afs_vnode *vnode, 879 + struct afs_vnode_cache_aux *aux) 880 + { 881 + aux->data_version = cpu_to_be64(vnode->status.data_version); 882 + } 883 + 884 + static inline void afs_invalidate_cache(struct afs_vnode *vnode, unsigned int flags) 885 + { 886 + struct afs_vnode_cache_aux aux; 887 + 888 + afs_set_cache_aux(vnode, &aux); 889 + fscache_invalidate(afs_vnode_cache(vnode), &aux, 890 + i_size_read(&vnode->vfs_inode), flags); 891 + } 873 892 874 893 /* 875 894 * We use folio->private to hold the amount of the folio that we've written to, ··· 973 962 */ 974 963 #ifdef CONFIG_AFS_FSCACHE 975 964 extern struct fscache_netfs afs_cache_netfs; 976 - extern struct fscache_cookie_def afs_cell_cache_index_def; 977 - extern struct fscache_cookie_def afs_volume_cache_index_def; 978 - extern struct fscache_cookie_def afs_vnode_cache_index_def; 979 - #else 980 - #define afs_cell_cache_index_def (*(struct fscache_cookie_def *) NULL) 981 - #define afs_volume_cache_index_def (*(struct fscache_cookie_def *) NULL) 982 - #define afs_vnode_cache_index_def (*(struct fscache_cookie_def *) NULL) 983 965 #endif 984 966 985 967 /* ··· 1510 1506 * volume.c 1511 1507 */ 1512 1508 extern struct afs_volume *afs_create_volume(struct afs_fs_context *); 1513 - extern void afs_activate_volume(struct afs_volume *); 1509 + extern int afs_activate_volume(struct afs_volume *); 1514 1510 extern void afs_deactivate_volume(struct afs_volume *); 1515 1511 extern struct afs_volume *afs_get_volume(struct afs_volume *, enum afs_volume_trace); 1516 1512 extern void afs_put_volume(struct afs_net *, struct afs_volume *, enum afs_volume_trace);
-14
fs/afs/main.c
··· 186 186 if (!afs_lock_manager) 187 187 goto error_lockmgr; 188 188 189 - #ifdef CONFIG_AFS_FSCACHE 190 - /* we want to be able to cache */ 191 - ret = fscache_register_netfs(&afs_cache_netfs); 192 - if (ret < 0) 193 - goto error_cache; 194 - #endif 195 - 196 189 ret = register_pernet_device(&afs_net_ops); 197 190 if (ret < 0) 198 191 goto error_net; ··· 208 215 error_fs: 209 216 unregister_pernet_device(&afs_net_ops); 210 217 error_net: 211 - #ifdef CONFIG_AFS_FSCACHE 212 - fscache_unregister_netfs(&afs_cache_netfs); 213 - error_cache: 214 - #endif 215 218 destroy_workqueue(afs_lock_manager); 216 219 error_lockmgr: 217 220 destroy_workqueue(afs_async_calls); ··· 234 245 proc_remove(afs_proc_symlink); 235 246 afs_fs_exit(); 236 247 unregister_pernet_device(&afs_net_ops); 237 - #ifdef CONFIG_AFS_FSCACHE 238 - fscache_unregister_netfs(&afs_cache_netfs); 239 - #endif 240 248 destroy_workqueue(afs_lock_manager); 241 249 destroy_workqueue(afs_async_calls); 242 250 destroy_workqueue(afs_wq);
+22 -7
fs/afs/volume.c
··· 268 268 /* 269 269 * Activate a volume. 270 270 */ 271 - void afs_activate_volume(struct afs_volume *volume) 271 + int afs_activate_volume(struct afs_volume *volume) 272 272 { 273 273 #ifdef CONFIG_AFS_FSCACHE 274 - volume->cache = fscache_acquire_cookie(volume->cell->cache, 275 - &afs_volume_cache_index_def, 276 - &volume->vid, sizeof(volume->vid), 277 - NULL, 0, 278 - volume, 0, true); 274 + struct fscache_volume *vcookie; 275 + char *name; 276 + 277 + name = kasprintf(GFP_KERNEL, "afs,%s,%llx", 278 + volume->cell->name, volume->vid); 279 + if (!name) 280 + return -ENOMEM; 281 + 282 + vcookie = fscache_acquire_volume(name, NULL, NULL, 0); 283 + if (IS_ERR(vcookie)) { 284 + if (vcookie != ERR_PTR(-EBUSY)) { 285 + kfree(name); 286 + return PTR_ERR(vcookie); 287 + } 288 + pr_err("AFS: Cache volume key already in use (%s)\n", name); 289 + vcookie = NULL; 290 + } 291 + volume->cache = vcookie; 292 + kfree(name); 279 293 #endif 294 + return 0; 280 295 } 281 296 282 297 /* ··· 302 287 _enter("%s", volume->name); 303 288 304 289 #ifdef CONFIG_AFS_FSCACHE 305 - fscache_relinquish_cookie(volume->cache, NULL, 290 + fscache_relinquish_volume(volume->cache, NULL, 306 291 test_bit(AFS_VOLUME_DELETED, &volume->flags)); 307 292 volume->cache = NULL; 308 293 #endif
-1
fs/afs/write.c
··· 12 12 #include <linux/writeback.h> 13 13 #include <linux/pagevec.h> 14 14 #include <linux/netfs.h> 15 - #include <linux/fscache.h> 16 15 #include "internal.h" 17 16 18 17 /*