Commit 523d27cd authored by David Howells's avatar David Howells
Browse files

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: default avatarDavid Howells <dhowells@redhat.com>
Acked-by: default avatarJeff Layton <jlayton@kernel.org>
Tested-by: default avatar <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
parent 9f08ebc3
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ config AFS_DEBUG

config AFS_FSCACHE
	bool "Provide AFS client caching support"
	depends on AFS_FS=m && FSCACHE_OLD_API || AFS_FS=y && FSCACHE_OLD_API=y
	depends on AFS_FS=m && FSCACHE || AFS_FS=y && FSCACHE=y
	help
	  Say Y here if you want AFS data to be cached locally on disk through
	  the generic filesystem cache manager
+0 −3
Original line number Diff line number Diff line
@@ -3,10 +3,7 @@
# Makefile for Red Hat Linux AFS client.
#

afs-cache-$(CONFIG_AFS_FSCACHE) := cache.o

kafs-y := \
	$(afs-cache-y) \
	addr_list.o \
	callback.o \
	cell.o \

fs/afs/cache.c

deleted100644 → 0
+0 −68
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-or-later
/* AFS caching stuff
 *
 * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
 * Written by David Howells (dhowells@redhat.com)
 */

#include <linux/sched.h>
#include "internal.h"

static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data,
						       const void *buffer,
						       uint16_t buflen,
						       loff_t object_size);

struct fscache_netfs afs_cache_netfs = {
	.name			= "afs",
	.version		= 2,
};

struct fscache_cookie_def afs_cell_cache_index_def = {
	.name		= "AFS.cell",
	.type		= FSCACHE_COOKIE_TYPE_INDEX,
};

struct fscache_cookie_def afs_volume_cache_index_def = {
	.name		= "AFS.volume",
	.type		= FSCACHE_COOKIE_TYPE_INDEX,
};

struct fscache_cookie_def afs_vnode_cache_index_def = {
	.name		= "AFS.vnode",
	.type		= FSCACHE_COOKIE_TYPE_DATAFILE,
	.check_aux	= afs_vnode_cache_check_aux,
};

/*
 * check that the auxiliary data indicates that the entry is still valid
 */
static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data,
						       const void *buffer,
						       uint16_t buflen,
						       loff_t object_size)
{
	struct afs_vnode *vnode = cookie_netfs_data;
	struct afs_vnode_cache_aux aux;

	_enter("{%llx,%x,%llx},%p,%u",
	       vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
	       buffer, buflen);

	memcpy(&aux, buffer, sizeof(aux));

	/* check the size of the data is what we're expecting */
	if (buflen != sizeof(aux)) {
		_leave(" = OBSOLETE [len %hx != %zx]", buflen, sizeof(aux));
		return FSCACHE_CHECKAUX_OBSOLETE;
	}

	if (vnode->status.data_version != aux.data_version) {
		_leave(" = OBSOLETE [vers %llx != %llx]",
		       aux.data_version, vnode->status.data_version);
		return FSCACHE_CHECKAUX_OBSOLETE;
	}

	_leave(" = SUCCESS");
	return FSCACHE_CHECKAUX_OKAY;
}
+0 −12
Original line number Diff line number Diff line
@@ -680,13 +680,6 @@ static int afs_activate_cell(struct afs_net *net, struct afs_cell *cell)
			return ret;
	}

#ifdef CONFIG_AFS_FSCACHE
	cell->cache = fscache_acquire_cookie(afs_cache_netfs.primary_index,
					     &afs_cell_cache_index_def,
					     cell->name, strlen(cell->name),
					     NULL, 0,
					     cell, 0, true);
#endif
	ret = afs_proc_cell_setup(cell);
	if (ret < 0)
		return ret;
@@ -723,11 +716,6 @@ static void afs_deactivate_cell(struct afs_net *net, struct afs_cell *cell)
	afs_dynroot_rmdir(net, cell);
	mutex_unlock(&net->proc_cells_lock);

#ifdef CONFIG_AFS_FSCACHE
	fscache_relinquish_cookie(cell->cache, NULL, false);
	cell->cache = NULL;
#endif

	_leave("");
}

+23 −6
Original line number Diff line number Diff line
@@ -159,6 +159,8 @@ int afs_open(struct inode *inode, struct file *file)
	if (file->f_flags & O_TRUNC)
		set_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags);

	fscache_use_cookie(afs_vnode_cache(vnode), file->f_mode & FMODE_WRITE);

	file->private_data = af;
	_leave(" = 0");
	return 0;
@@ -177,8 +179,10 @@ int afs_open(struct inode *inode, struct file *file)
 */
int afs_release(struct inode *inode, struct file *file)
{
	struct afs_vnode_cache_aux aux;
	struct afs_vnode *vnode = AFS_FS_I(inode);
	struct afs_file *af = file->private_data;
	loff_t i_size;
	int ret = 0;

	_enter("{%llx:%llu},", vnode->fid.vid, vnode->fid.vnode);
@@ -189,6 +193,15 @@ int afs_release(struct inode *inode, struct file *file)
	file->private_data = NULL;
	if (af->wb)
		afs_put_wb_key(af->wb);

	if ((file->f_mode & FMODE_WRITE)) {
		i_size = i_size_read(&vnode->vfs_inode);
		afs_set_cache_aux(vnode, &aux);
		fscache_unuse_cookie(afs_vnode_cache(vnode), &aux, &i_size);
	} else {
		fscache_unuse_cookie(afs_vnode_cache(vnode), NULL, NULL);
	}

	key_put(af->key);
	kfree(af);
	afs_prune_wb_keys(vnode);
@@ -352,7 +365,9 @@ static void afs_init_rreq(struct netfs_read_request *rreq, struct file *file)

static bool afs_is_cache_enabled(struct inode *inode)
{
	return fscache_cookie_enabled(afs_vnode_cache(AFS_FS_I(inode)));
	struct fscache_cookie *cookie = afs_vnode_cache(AFS_FS_I(inode));

	return fscache_cookie_enabled(cookie) && cookie->cache_priv;
}

static int afs_begin_cache_operation(struct netfs_read_request *rreq)
@@ -360,7 +375,8 @@ static int afs_begin_cache_operation(struct netfs_read_request *rreq)
#ifdef CONFIG_AFS_FSCACHE
	struct afs_vnode *vnode = AFS_FS_I(rreq->inode);

	return fscache_begin_read_operation(rreq, afs_vnode_cache(vnode));
	return fscache_begin_read_operation(&rreq->cache_resources,
					    afs_vnode_cache(vnode));
#else
	return -ENOBUFS;
#endif
@@ -482,23 +498,24 @@ static void afs_invalidatepage(struct page *page, unsigned int offset,
 * release a page and clean up its private state if it's not busy
 * - return true if the page can now be released, false if not
 */
static int afs_releasepage(struct page *page, gfp_t gfp_flags)
static int afs_releasepage(struct page *page, gfp_t gfp)
{
	struct folio *folio = page_folio(page);
	struct afs_vnode *vnode = AFS_FS_I(folio_inode(folio));

	_enter("{{%llx:%llu}[%lu],%lx},%x",
	       vnode->fid.vid, vnode->fid.vnode, folio_index(folio), folio->flags,
	       gfp_flags);
	       gfp);

	/* deny if page is being written to the cache and the caller hasn't
	 * elected to wait */
#ifdef CONFIG_AFS_FSCACHE
	if (folio_test_fscache(folio)) {
		if (!(gfp_flags & __GFP_DIRECT_RECLAIM) || !(gfp_flags & __GFP_FS))
		if (!gfpflags_allow_blocking(gfp) || !(gfp & __GFP_FS))
			return false;
		folio_wait_fscache(folio);
	}
	fscache_note_page_release(afs_vnode_cache(vnode));
#endif

	if (folio_test_private(folio)) {
Loading