Commit d24af13e authored by David Howells's avatar David Howells
Browse files

fscache: Implement cookie invalidation



Add a function to invalidate the cache behind a cookie:

	void fscache_invalidate(struct fscache_cookie *cookie,
				const void *aux_data,
				loff_t size,
				unsigned int flags)

This causes any cached data for the specified cookie to be discarded.  If
the cookie is marked as being in use, a new cache object will be created if
possible and future I/O will use that instead.  In-flight I/O should be
abandoned (writes) or reconsidered (reads).  Each time it is called
cookie->inval_counter is incremented and this can be used to detect
invalidation at the end of an I/O operation.

The coherency data attached to the cookie can be updated and the cookie
size should be reset.  One flag is available, FSCACHE_INVAL_DIO_WRITE,
which should be used to indicate invalidation due to a DIO write on a
file.  This will temporarily disable caching for this cookie.

Changes
=======
ver #2:
 - Should only change to inval state if can get access to cache.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
cc: linux-cachefs@redhat.com
Link: https://lore.kernel.org/r/163819602231.215744.11206598147269491575.stgit@warthog.procyon.org.uk/ # v1
Link: https://lore.kernel.org/r/163906909707.143852.18056070560477964891.stgit@warthog.procyon.org.uk/ # v2
Link: https://lore.kernel.org/r/163967107447.1823006.5945029409592119962.stgit@warthog.procyon.org.uk/ # v3
Link: https://lore.kernel.org/r/164021512640.640689.11418616313147754172.stgit@warthog.procyon.org.uk/ # v4
parent 12bb21a2
Loading
Loading
Loading
Loading
+87 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ static void fscache_cookie_lru_timed_out(struct timer_list *timer);
static void fscache_cookie_lru_worker(struct work_struct *work);
static void fscache_cookie_worker(struct work_struct *work);
static void fscache_unhash_cookie(struct fscache_cookie *cookie);
static void fscache_perform_invalidation(struct fscache_cookie *cookie);

#define fscache_cookie_hash_shift 15
static struct hlist_bl_head fscache_cookie_hash[1 << fscache_cookie_hash_shift];
@@ -28,7 +29,7 @@ static LIST_HEAD(fscache_cookie_lru);
static DEFINE_SPINLOCK(fscache_cookie_lru_lock);
DEFINE_TIMER(fscache_cookie_lru_timer, fscache_cookie_lru_timed_out);
static DECLARE_WORK(fscache_cookie_lru_work, fscache_cookie_lru_worker);
static const char fscache_cookie_states[FSCACHE_COOKIE_STATE__NR] = "-LCAFUWRD";
static const char fscache_cookie_states[FSCACHE_COOKIE_STATE__NR] = "-LCAIFUWRD";
unsigned int fscache_lru_cookie_timeout = 10 * HZ;

void fscache_print_cookie(struct fscache_cookie *cookie, char prefix)
@@ -236,6 +237,19 @@ void fscache_cookie_lookup_negative(struct fscache_cookie *cookie)
}
EXPORT_SYMBOL(fscache_cookie_lookup_negative);

/**
 * fscache_resume_after_invalidation - Allow I/O to resume after invalidation
 * @cookie: The cookie that was invalidated
 *
 * Tell fscache that invalidation is sufficiently complete that I/O can be
 * allowed again.
 */
void fscache_resume_after_invalidation(struct fscache_cookie *cookie)
{
	fscache_set_cookie_state(cookie, FSCACHE_COOKIE_STATE_ACTIVE);
}
EXPORT_SYMBOL(fscache_resume_after_invalidation);

/**
 * fscache_caching_failed - Report that a failure stopped caching on a cookie
 * @cookie: The cookie that was affected
@@ -566,6 +580,7 @@ void __fscache_use_cookie(struct fscache_cookie *cookie, bool will_modify)
			set_bit(FSCACHE_COOKIE_LOCAL_WRITE, &cookie->flags);
		break;
	case FSCACHE_COOKIE_STATE_ACTIVE:
	case FSCACHE_COOKIE_STATE_INVALIDATING:
		if (will_modify &&
		    !test_and_set_bit(FSCACHE_COOKIE_LOCAL_WRITE, &cookie->flags)) {
			set_bit(FSCACHE_COOKIE_DO_PREP_TO_WRITE, &cookie->flags);
@@ -671,6 +686,11 @@ static void fscache_cookie_state_machine(struct fscache_cookie *cookie)
		fscache_perform_lookup(cookie);
		goto again;

	case FSCACHE_COOKIE_STATE_INVALIDATING:
		spin_unlock(&cookie->lock);
		fscache_perform_invalidation(cookie);
		goto again;

	case FSCACHE_COOKIE_STATE_ACTIVE:
		if (test_and_clear_bit(FSCACHE_COOKIE_DO_PREP_TO_WRITE, &cookie->flags)) {
			spin_unlock(&cookie->lock);
@@ -962,6 +982,72 @@ struct fscache_cookie *fscache_get_cookie(struct fscache_cookie *cookie,
}
EXPORT_SYMBOL(fscache_get_cookie);

/*
 * Ask the cache to effect invalidation of a cookie.
 */
static void fscache_perform_invalidation(struct fscache_cookie *cookie)
{
	if (!cookie->volume->cache->ops->invalidate_cookie(cookie))
		fscache_caching_failed(cookie);
	fscache_end_cookie_access(cookie, fscache_access_invalidate_cookie_end);
}

/*
 * Invalidate an object.
 */
void __fscache_invalidate(struct fscache_cookie *cookie,
			  const void *aux_data, loff_t new_size,
			  unsigned int flags)
{
	bool is_caching;

	_enter("c=%x", cookie->debug_id);

	fscache_stat(&fscache_n_invalidates);

	if (WARN(test_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags),
		 "Trying to invalidate relinquished cookie\n"))
		return;

	if ((flags & FSCACHE_INVAL_DIO_WRITE) &&
	    test_and_set_bit(FSCACHE_COOKIE_DISABLED, &cookie->flags))
		return;

	spin_lock(&cookie->lock);
	set_bit(FSCACHE_COOKIE_NO_DATA_TO_READ, &cookie->flags);
	fscache_update_aux(cookie, aux_data, &new_size);
	cookie->inval_counter++;
	trace_fscache_invalidate(cookie, new_size);

	switch (cookie->state) {
	case FSCACHE_COOKIE_STATE_INVALIDATING: /* is_still_valid will catch it */
	default:
		spin_unlock(&cookie->lock);
		_leave(" [no %u]", cookie->state);
		return;

	case FSCACHE_COOKIE_STATE_LOOKING_UP:
	case FSCACHE_COOKIE_STATE_CREATING:
		spin_unlock(&cookie->lock);
		_leave(" [look %x]", cookie->inval_counter);
		return;

	case FSCACHE_COOKIE_STATE_ACTIVE:
		is_caching = fscache_begin_cookie_access(
			cookie, fscache_access_invalidate_cookie);
		if (is_caching)
			__fscache_set_cookie_state(cookie, FSCACHE_COOKIE_STATE_INVALIDATING);
		spin_unlock(&cookie->lock);
		wake_up_cookie_state(cookie);

		if (is_caching)
			fscache_queue_cookie(cookie, fscache_cookie_get_inval_work);
		_leave(" [inv]");
		return;
	}
}
EXPORT_SYMBOL(__fscache_invalidate);

/*
 * Generate a list of extant cookies in /proc/fs/fscache/cookies
 */
+2 −0
Original line number Diff line number Diff line
@@ -105,6 +105,8 @@ extern atomic_t fscache_n_acquires;
extern atomic_t fscache_n_acquires_ok;
extern atomic_t fscache_n_acquires_oom;

extern atomic_t fscache_n_invalidates;

extern atomic_t fscache_n_relinquishes;
extern atomic_t fscache_n_relinquishes_retire;
extern atomic_t fscache_n_relinquishes_dropped;
+5 −0
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ atomic_t fscache_n_acquires;
atomic_t fscache_n_acquires_ok;
atomic_t fscache_n_acquires_oom;

atomic_t fscache_n_invalidates;

atomic_t fscache_n_updates;
EXPORT_SYMBOL(fscache_n_updates);

@@ -59,6 +61,9 @@ int fscache_stats_show(struct seq_file *m, void *v)
		   timer_pending(&fscache_cookie_lru_timer) ?
		   fscache_cookie_lru_timer.expires - jiffies : 0);

	seq_printf(m, "Invals : n=%u\n",
		   atomic_read(&fscache_n_invalidates));

	seq_printf(m, "Updates: n=%u\n",
		   atomic_read(&fscache_n_updates));

+4 −0
Original line number Diff line number Diff line
@@ -64,6 +64,9 @@ struct fscache_cache_ops {
	/* Withdraw an object without any cookie access counts held */
	void (*withdraw_cookie)(struct fscache_cookie *cookie);

	/* Invalidate an object */
	bool (*invalidate_cookie)(struct fscache_cookie *cookie);

	/* Prepare to write to a live cache object */
	void (*prepare_to_write)(struct fscache_cookie *cookie);
};
@@ -96,6 +99,7 @@ extern void fscache_put_cookie(struct fscache_cookie *cookie,
extern void fscache_end_cookie_access(struct fscache_cookie *cookie,
				      enum fscache_access_trace why);
extern void fscache_cookie_lookup_negative(struct fscache_cookie *cookie);
extern void fscache_resume_after_invalidation(struct fscache_cookie *cookie);
extern void fscache_caching_failed(struct fscache_cookie *cookie);

/**
+31 −0
Original line number Diff line number Diff line
@@ -39,6 +39,8 @@ struct fscache_cookie;
#define FSCACHE_ADV_WRITE_CACHE		0x00 /* Do cache if written to locally */
#define FSCACHE_ADV_WRITE_NOCACHE	0x02 /* Don't cache if written to locally */

#define FSCACHE_INVAL_DIO_WRITE		0x01 /* Invalidate due to DIO write */

/*
 * Data object state.
 */
@@ -47,6 +49,7 @@ enum fscache_cookie_state {
	FSCACHE_COOKIE_STATE_LOOKING_UP,	/* The cache object is being looked up */
	FSCACHE_COOKIE_STATE_CREATING,		/* The cache object is being created */
	FSCACHE_COOKIE_STATE_ACTIVE,		/* The cache is active, readable and writable */
	FSCACHE_COOKIE_STATE_INVALIDATING,	/* The cache is being invalidated */
	FSCACHE_COOKIE_STATE_FAILED,		/* The cache failed, withdraw to clear */
	FSCACHE_COOKIE_STATE_LRU_DISCARDING,	/* The cookie is being discarded by the LRU */
	FSCACHE_COOKIE_STATE_WITHDRAWING,	/* The cookie is being withdrawn */
@@ -153,6 +156,7 @@ extern struct fscache_cookie *__fscache_acquire_cookie(
extern void __fscache_use_cookie(struct fscache_cookie *, bool);
extern void __fscache_unuse_cookie(struct fscache_cookie *, const void *, const loff_t *);
extern void __fscache_relinquish_cookie(struct fscache_cookie *, bool);
extern void __fscache_invalidate(struct fscache_cookie *, const void *, loff_t, unsigned int);

/**
 * fscache_acquire_volume - Register a volume as desiring caching services
@@ -327,4 +331,31 @@ void __fscache_update_cookie(struct fscache_cookie *cookie, const void *aux_data
	set_bit(FSCACHE_COOKIE_NEEDS_UPDATE, &cookie->flags);
}

/**
 * fscache_invalidate - Notify cache that an object needs invalidation
 * @cookie: The cookie representing the cache object
 * @aux_data: The updated auxiliary data for the cookie (may be NULL)
 * @size: The revised size of the object.
 * @flags: Invalidation flags (FSCACHE_INVAL_*)
 *
 * Notify the cache that an object is needs to be invalidated and that it
 * should abort any retrievals or stores it is doing on the cache.  This
 * increments inval_counter on the cookie which can be used by the caller to
 * reconsider I/O requests as they complete.
 *
 * If @flags has FSCACHE_INVAL_DIO_WRITE set, this indicates that this is due
 * to a direct I/O write and will cause caching to be disabled on this cookie
 * until it is completely unused.
 *
 * See Documentation/filesystems/caching/netfs-api.rst for a complete
 * description.
 */
static inline
void fscache_invalidate(struct fscache_cookie *cookie,
			const void *aux_data, loff_t size, unsigned int flags)
{
	if (fscache_cookie_enabled(cookie))
		__fscache_invalidate(cookie, aux_data, size, flags);
}

#endif /* _LINUX_FSCACHE_H */
Loading