Commit ef778e7a authored by David Howells's avatar David Howells

FS-Cache: Provide proper invalidation

Provide a proper invalidation method rather than relying on the netfs retiring
the cookie it has and getting a new one.  The problem with this is that isn't
easy for the netfs to make sure that it has completed/cancelled all its
outstanding storage and retrieval operations on the cookie it is retiring.

Instead, have the cache provide an invalidation method that will cancel or wait
for all currently outstanding operations before invalidating the cache, and
will cause new operations to queue up behind that.  Whilst invalidation is in
progress, some requests will be rejected until the cache can stack a barrier on
the operation queue to cause new operations to be deferred behind it.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent 9f10523f
...@@ -308,6 +308,18 @@ performed on the denizens of the cache. These are held in a structure of type: ...@@ -308,6 +308,18 @@ performed on the denizens of the cache. These are held in a structure of type:
obtained by calling object->cookie->def->get_aux()/get_attr(). obtained by calling object->cookie->def->get_aux()/get_attr().
(*) Invalidate data object [mandatory]:
int (*invalidate_object)(struct fscache_operation *op)
This is called to invalidate a data object (as pointed to by op->object).
All the data stored for this object should be discarded and an
attr_changed operation should be performed. The caller will follow up
with an object update operation.
fscache_op_complete() must be called on op before returning.
(*) Discard object [mandatory]: (*) Discard object [mandatory]:
void (*drop_object)(struct fscache_object *object) void (*drop_object)(struct fscache_object *object)
......
...@@ -35,8 +35,9 @@ This document contains the following sections: ...@@ -35,8 +35,9 @@ This document contains the following sections:
(12) Index and data file update (12) Index and data file update
(13) Miscellaneous cookie operations (13) Miscellaneous cookie operations
(14) Cookie unregistration (14) Cookie unregistration
(15) Index and data file invalidation (15) Index invalidation
(16) FS-Cache specific page flags. (16) Data file invalidation
(17) FS-Cache specific page flags.
============================= =============================
...@@ -767,13 +768,42 @@ the cookies for "child" indices, objects and pages have been relinquished ...@@ -767,13 +768,42 @@ the cookies for "child" indices, objects and pages have been relinquished
first. first.
================================ ==================
INDEX AND DATA FILE INVALIDATION INDEX INVALIDATION
================================ ==================
There is no direct way to invalidate an index subtree. To do this, the caller
should relinquish and retire the cookie they have, and then acquire a new one.
======================
DATA FILE INVALIDATION
======================
Sometimes it will be necessary to invalidate an object that contains data.
Typically this will be necessary when the server tells the netfs of a foreign
change - at which point the netfs has to throw away all the state it had for an
inode and reload from the server.
To indicate that a cache object should be invalidated, the following function
can be called:
void fscache_invalidate(struct fscache_cookie *cookie);
This can be called with spinlocks held as it defers the work to a thread pool.
All extant storage, retrieval and attribute change ops at this point are
cancelled and discarded. Some future operations will be rejected until the
cache has had a chance to insert a barrier in the operations queue. After
that, operations will be queued again behind the invalidation operation.
The invalidation operation will perform an attribute change operation and an
auxiliary data update operation as it is very likely these will have changed.
Using the following function, the netfs can wait for the invalidation operation
to have reached a point at which it can start submitting ordinary operations
once again:
There is no direct way to invalidate an index subtree or a data file. To do void fscache_wait_on_invalidate(struct fscache_cookie *cookie);
this, the caller should relinquish and retire the cookie they have, and then
acquire a new one.
=========================== ===========================
......
...@@ -216,7 +216,14 @@ servicing netfs requests: ...@@ -216,7 +216,14 @@ servicing netfs requests:
The normal running state. In this state, requests the netfs makes will be The normal running state. In this state, requests the netfs makes will be
passed on to the cache. passed on to the cache.
(6) State FSCACHE_OBJECT_UPDATING. (6) State FSCACHE_OBJECT_INVALIDATING.
The object is undergoing invalidation. When the state comes here, it
discards all pending read, write and attribute change operations as it is
going to clear out the cache entirely and reinitialise it. It will then
continue to the FSCACHE_OBJECT_UPDATING state.
(7) State FSCACHE_OBJECT_UPDATING.
The state machine comes here to update the object in the cache from the The state machine comes here to update the object in the cache from the
netfs's records. This involves updating the auxiliary data that is used netfs's records. This involves updating the auxiliary data that is used
...@@ -225,13 +232,13 @@ servicing netfs requests: ...@@ -225,13 +232,13 @@ servicing netfs requests:
And there are terminal states in which an object cleans itself up, deallocates And there are terminal states in which an object cleans itself up, deallocates
memory and potentially deletes stuff from disk: memory and potentially deletes stuff from disk:
(7) State FSCACHE_OBJECT_LC_DYING. (8) State FSCACHE_OBJECT_LC_DYING.
The object comes here if it is dying because of a lookup or creation The object comes here if it is dying because of a lookup or creation
error. This would be due to a disk error or system error of some sort. error. This would be due to a disk error or system error of some sort.
Temporary data is cleaned up, and the parent is released. Temporary data is cleaned up, and the parent is released.
(8) State FSCACHE_OBJECT_DYING. (9) State FSCACHE_OBJECT_DYING.
The object comes here if it is dying due to an error, because its parent The object comes here if it is dying due to an error, because its parent
cookie has been relinquished by the netfs or because the cache is being cookie has been relinquished by the netfs or because the cache is being
...@@ -241,27 +248,27 @@ memory and potentially deletes stuff from disk: ...@@ -241,27 +248,27 @@ memory and potentially deletes stuff from disk:
can destroy themselves. This object waits for all its children to go away can destroy themselves. This object waits for all its children to go away
before advancing to the next state. before advancing to the next state.
(9) State FSCACHE_OBJECT_ABORT_INIT. (10) State FSCACHE_OBJECT_ABORT_INIT.
The object comes to this state if it was waiting on its parent in The object comes to this state if it was waiting on its parent in
FSCACHE_OBJECT_INIT, but its parent died. The object will destroy itself FSCACHE_OBJECT_INIT, but its parent died. The object will destroy itself
so that the parent may proceed from the FSCACHE_OBJECT_DYING state. so that the parent may proceed from the FSCACHE_OBJECT_DYING state.
(10) State FSCACHE_OBJECT_RELEASING. (11) State FSCACHE_OBJECT_RELEASING.
(11) State FSCACHE_OBJECT_RECYCLING. (12) State FSCACHE_OBJECT_RECYCLING.
The object comes to one of these two states when dying once it is rid of The object comes to one of these two states when dying once it is rid of
all its children, if it is dying because the netfs relinquished its all its children, if it is dying because the netfs relinquished its
cookie. In the first state, the cached data is expected to persist, and cookie. In the first state, the cached data is expected to persist, and
in the second it will be deleted. in the second it will be deleted.
(12) State FSCACHE_OBJECT_WITHDRAWING. (13) State FSCACHE_OBJECT_WITHDRAWING.
The object transits to this state if the cache decides it wants to The object transits to this state if the cache decides it wants to
withdraw the object from service, perhaps to make space, but also due to withdraw the object from service, perhaps to make space, but also due to
error or just because the whole cache is being withdrawn. error or just because the whole cache is being withdrawn.
(13) State FSCACHE_OBJECT_DEAD. (14) State FSCACHE_OBJECT_DEAD.
The object transits to this state when the in-memory object record is The object transits to this state when the in-memory object record is
ready to be deleted. The object processor shouldn't ever see an object in ready to be deleted. The object processor shouldn't ever see an object in
......
...@@ -369,6 +369,66 @@ static int fscache_attach_object(struct fscache_cookie *cookie, ...@@ -369,6 +369,66 @@ static int fscache_attach_object(struct fscache_cookie *cookie,
return ret; return ret;
} }
/*
* Invalidate an object. Callable with spinlocks held.
*/
void __fscache_invalidate(struct fscache_cookie *cookie)
{
struct fscache_object *object;
_enter("{%s}", cookie->def->name);
fscache_stat(&fscache_n_invalidates);
/* Only permit invalidation of data files. Invalidating an index will
* require the caller to release all its attachments to the tree rooted
* there, and if it's doing that, it may as well just retire the
* cookie.
*/
ASSERTCMP(cookie->def->type, ==, FSCACHE_COOKIE_TYPE_DATAFILE);
/* We will be updating the cookie too. */
BUG_ON(!cookie->def->get_aux);
/* If there's an object, we tell the object state machine to handle the
* invalidation on our behalf, otherwise there's nothing to do.
*/
if (!hlist_empty(&cookie->backing_objects)) {
spin_lock(&cookie->lock);
if (!hlist_empty(&cookie->backing_objects) &&
!test_and_set_bit(FSCACHE_COOKIE_INVALIDATING,
&cookie->flags)) {
object = hlist_entry(cookie->backing_objects.first,
struct fscache_object,
cookie_link);
if (object->state < FSCACHE_OBJECT_DYING)
fscache_raise_event(
object, FSCACHE_OBJECT_EV_INVALIDATE);
}
spin_unlock(&cookie->lock);
}
_leave("");
}
EXPORT_SYMBOL(__fscache_invalidate);
/*
* Wait for object invalidation to complete.
*/
void __fscache_wait_on_invalidate(struct fscache_cookie *cookie)
{
_enter("%p", cookie);
wait_on_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING,
fscache_wait_bit_interruptible,
TASK_UNINTERRUPTIBLE);
_leave("");
}
EXPORT_SYMBOL(__fscache_wait_on_invalidate);
/* /*
* update the index entries backing a cookie * update the index entries backing a cookie
*/ */
......
...@@ -122,10 +122,16 @@ extern int fscache_submit_exclusive_op(struct fscache_object *, ...@@ -122,10 +122,16 @@ extern int fscache_submit_exclusive_op(struct fscache_object *,
extern int fscache_submit_op(struct fscache_object *, extern int fscache_submit_op(struct fscache_object *,
struct fscache_operation *); struct fscache_operation *);
extern int fscache_cancel_op(struct fscache_operation *); extern int fscache_cancel_op(struct fscache_operation *);
extern void fscache_cancel_all_ops(struct fscache_object *);
extern void fscache_abort_object(struct fscache_object *); extern void fscache_abort_object(struct fscache_object *);
extern void fscache_start_operations(struct fscache_object *); extern void fscache_start_operations(struct fscache_object *);
extern void fscache_operation_gc(struct work_struct *); extern void fscache_operation_gc(struct work_struct *);
/*
* page.c
*/
extern void fscache_invalidate_writes(struct fscache_cookie *);
/* /*
* proc.c * proc.c
*/ */
...@@ -205,6 +211,9 @@ extern atomic_t fscache_n_acquires_ok; ...@@ -205,6 +211,9 @@ extern atomic_t fscache_n_acquires_ok;
extern atomic_t fscache_n_acquires_nobufs; extern atomic_t fscache_n_acquires_nobufs;
extern atomic_t fscache_n_acquires_oom; extern atomic_t fscache_n_acquires_oom;
extern atomic_t fscache_n_invalidates;
extern atomic_t fscache_n_invalidates_run;
extern atomic_t fscache_n_updates; extern atomic_t fscache_n_updates;
extern atomic_t fscache_n_updates_null; extern atomic_t fscache_n_updates_null;
extern atomic_t fscache_n_updates_run; extern atomic_t fscache_n_updates_run;
...@@ -237,6 +246,7 @@ extern atomic_t fscache_n_cop_alloc_object; ...@@ -237,6 +246,7 @@ extern atomic_t fscache_n_cop_alloc_object;
extern atomic_t fscache_n_cop_lookup_object; extern atomic_t fscache_n_cop_lookup_object;
extern atomic_t fscache_n_cop_lookup_complete; extern atomic_t fscache_n_cop_lookup_complete;
extern atomic_t fscache_n_cop_grab_object; extern atomic_t fscache_n_cop_grab_object;
extern atomic_t fscache_n_cop_invalidate_object;
extern atomic_t fscache_n_cop_update_object; extern atomic_t fscache_n_cop_update_object;
extern atomic_t fscache_n_cop_drop_object; extern atomic_t fscache_n_cop_drop_object;
extern atomic_t fscache_n_cop_put_object; extern atomic_t fscache_n_cop_put_object;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#define FSCACHE_DEBUG_LEVEL COOKIE #define FSCACHE_DEBUG_LEVEL COOKIE
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h>
#include "internal.h" #include "internal.h"
const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = {
...@@ -22,6 +23,7 @@ const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { ...@@ -22,6 +23,7 @@ const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = {
[FSCACHE_OBJECT_CREATING] = "OBJECT_CREATING", [FSCACHE_OBJECT_CREATING] = "OBJECT_CREATING",
[FSCACHE_OBJECT_AVAILABLE] = "OBJECT_AVAILABLE", [FSCACHE_OBJECT_AVAILABLE] = "OBJECT_AVAILABLE",
[FSCACHE_OBJECT_ACTIVE] = "OBJECT_ACTIVE", [FSCACHE_OBJECT_ACTIVE] = "OBJECT_ACTIVE",
[FSCACHE_OBJECT_INVALIDATING] = "OBJECT_INVALIDATING",
[FSCACHE_OBJECT_UPDATING] = "OBJECT_UPDATING", [FSCACHE_OBJECT_UPDATING] = "OBJECT_UPDATING",
[FSCACHE_OBJECT_DYING] = "OBJECT_DYING", [FSCACHE_OBJECT_DYING] = "OBJECT_DYING",
[FSCACHE_OBJECT_LC_DYING] = "OBJECT_LC_DYING", [FSCACHE_OBJECT_LC_DYING] = "OBJECT_LC_DYING",
...@@ -39,6 +41,7 @@ const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = { ...@@ -39,6 +41,7 @@ const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = {
[FSCACHE_OBJECT_CREATING] = "CRTN", [FSCACHE_OBJECT_CREATING] = "CRTN",
[FSCACHE_OBJECT_AVAILABLE] = "AVBL", [FSCACHE_OBJECT_AVAILABLE] = "AVBL",
[FSCACHE_OBJECT_ACTIVE] = "ACTV", [FSCACHE_OBJECT_ACTIVE] = "ACTV",
[FSCACHE_OBJECT_INVALIDATING] = "INVL",
[FSCACHE_OBJECT_UPDATING] = "UPDT", [FSCACHE_OBJECT_UPDATING] = "UPDT",
[FSCACHE_OBJECT_DYING] = "DYNG", [FSCACHE_OBJECT_DYING] = "DYNG",
[FSCACHE_OBJECT_LC_DYING] = "LCDY", [FSCACHE_OBJECT_LC_DYING] = "LCDY",
...@@ -54,6 +57,7 @@ static void fscache_put_object(struct fscache_object *); ...@@ -54,6 +57,7 @@ static void fscache_put_object(struct fscache_object *);
static void fscache_initialise_object(struct fscache_object *); static void fscache_initialise_object(struct fscache_object *);
static void fscache_lookup_object(struct fscache_object *); static void fscache_lookup_object(struct fscache_object *);
static void fscache_object_available(struct fscache_object *); static void fscache_object_available(struct fscache_object *);
static void fscache_invalidate_object(struct fscache_object *);
static void fscache_release_object(struct fscache_object *); static void fscache_release_object(struct fscache_object *);
static void fscache_withdraw_object(struct fscache_object *); static void fscache_withdraw_object(struct fscache_object *);
static void fscache_enqueue_dependents(struct fscache_object *); static void fscache_enqueue_dependents(struct fscache_object *);
...@@ -78,6 +82,15 @@ static inline void fscache_done_parent_op(struct fscache_object *object) ...@@ -78,6 +82,15 @@ static inline void fscache_done_parent_op(struct fscache_object *object)
spin_unlock(&parent->lock); spin_unlock(&parent->lock);
} }
/*
* Notify netfs of invalidation completion.
*/
static inline void fscache_invalidation_complete(struct fscache_cookie *cookie)
{
if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags))
wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING);
}
/* /*
* process events that have been sent to an object's state machine * process events that have been sent to an object's state machine
* - initiates parent lookup * - initiates parent lookup
...@@ -125,6 +138,16 @@ static void fscache_object_state_machine(struct fscache_object *object) ...@@ -125,6 +138,16 @@ static void fscache_object_state_machine(struct fscache_object *object)
case FSCACHE_OBJECT_ACTIVE: case FSCACHE_OBJECT_ACTIVE:
goto active_transit; goto active_transit;
/* Invalidate an object on disk */
case FSCACHE_OBJECT_INVALIDATING:
clear_bit(FSCACHE_OBJECT_EV_INVALIDATE, &object->events);
fscache_stat(&fscache_n_invalidates_run);
fscache_stat(&fscache_n_cop_invalidate_object);
fscache_invalidate_object(object);
fscache_stat_d(&fscache_n_cop_invalidate_object);
fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE);
goto active_transit;
/* update the object metadata on disk */ /* update the object metadata on disk */
case FSCACHE_OBJECT_UPDATING: case FSCACHE_OBJECT_UPDATING:
clear_bit(FSCACHE_OBJECT_EV_UPDATE, &object->events); clear_bit(FSCACHE_OBJECT_EV_UPDATE, &object->events);
...@@ -275,6 +298,9 @@ static void fscache_object_state_machine(struct fscache_object *object) ...@@ -275,6 +298,9 @@ static void fscache_object_state_machine(struct fscache_object *object)
case FSCACHE_OBJECT_EV_ERROR: case FSCACHE_OBJECT_EV_ERROR:
new_state = FSCACHE_OBJECT_DYING; new_state = FSCACHE_OBJECT_DYING;
goto change_state; goto change_state;
case FSCACHE_OBJECT_EV_INVALIDATE:
new_state = FSCACHE_OBJECT_INVALIDATING;
goto change_state;
case FSCACHE_OBJECT_EV_UPDATE: case FSCACHE_OBJECT_EV_UPDATE:
new_state = FSCACHE_OBJECT_UPDATING; new_state = FSCACHE_OBJECT_UPDATING;
goto change_state; goto change_state;
...@@ -679,6 +705,7 @@ static void fscache_withdraw_object(struct fscache_object *object) ...@@ -679,6 +705,7 @@ static void fscache_withdraw_object(struct fscache_object *object)
if (object->cookie == cookie) { if (object->cookie == cookie) {
hlist_del_init(&object->cookie_link); hlist_del_init(&object->cookie_link);
object->cookie = NULL; object->cookie = NULL;
fscache_invalidation_complete(cookie);
detached = true; detached = true;
} }
spin_unlock(&cookie->lock); spin_unlock(&cookie->lock);
...@@ -888,3 +915,48 @@ enum fscache_checkaux fscache_check_aux(struct fscache_object *object, ...@@ -888,3 +915,48 @@ enum fscache_checkaux fscache_check_aux(struct fscache_object *object,
return result; return result;
} }
EXPORT_SYMBOL(fscache_check_aux); EXPORT_SYMBOL(fscache_check_aux);
/*
* Asynchronously invalidate an object.
*/
static void fscache_invalidate_object(struct fscache_object *object)
{
struct fscache_operation *op;
struct fscache_cookie *cookie = object->cookie;
_enter("{OBJ%x}", object->debug_id);
/* Reject any new read/write ops and abort any that are pending. */
fscache_invalidate_writes(cookie);
clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
fscache_cancel_all_ops(object);
/* Now we have to wait for in-progress reads and writes */
op = kzalloc(sizeof(*op), GFP_KERNEL);
if (!op) {
fscache_raise_event(object, FSCACHE_OBJECT_EV_ERROR);
_leave(" [ENOMEM]");
return;
}
fscache_operation_init(op, object->cache->ops->invalidate_object, NULL);
op->flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_EXCLUSIVE);
spin_lock(&cookie->lock);
if (fscache_submit_exclusive_op(object, op) < 0)
BUG();
spin_unlock(&cookie->lock);
fscache_put_operation(op);
/* Once we've completed the invalidation, we know there will be no data
* stored in the cache and thus we can reinstate the data-check-skip
* optimisation.
*/
set_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags);
/* We can allow read and write requests to come in once again. They'll
* queue up behind our exclusive invalidation operation.
*/
fscache_invalidation_complete(cookie);
_leave("");
}
...@@ -323,6 +323,38 @@ int fscache_cancel_op(struct fscache_operation *op) ...@@ -323,6 +323,38 @@ int fscache_cancel_op(struct fscache_operation *op)
return ret; return ret;
} }
/*
* Cancel all pending operations on an object
*/
void fscache_cancel_all_ops(struct fscache_object *object)
{
struct fscache_operation *op;
_enter("OBJ%x", object->debug_id);
spin_lock(&object->lock);
while (!list_empty(&object->pending_ops)) {
op = list_entry(object->pending_ops.next,
struct fscache_operation, pend_link);
fscache_stat(&fscache_n_op_cancelled);
list_del_init(&op->pend_link);
ASSERTCMP(op->state, ==, FSCACHE_OP_ST_PENDING);
op->state = FSCACHE_OP_ST_CANCELLED;
if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags))
object->n_exclusive--;
if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags))
wake_up_bit(&op->flags, FSCACHE_OP_WAITING);
fscache_put_operation(op);
cond_resched_lock(&object->lock);
}
spin_unlock(&object->lock);
_leave("");
}
/* /*
* Record the completion of an in-progress operation. * Record the completion of an in-progress operation.
*/ */
......
...@@ -361,6 +361,11 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, ...@@ -361,6 +361,11 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie,
if (hlist_empty(&cookie->backing_objects)) if (hlist_empty(&cookie->backing_objects))
goto nobufs; goto nobufs;
if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) {
_leave(" = -ENOBUFS [invalidating]");
return -ENOBUFS;
}
ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX);
ASSERTCMP(page, !=, NULL); ASSERTCMP(page, !=, NULL);
...@@ -483,6 +488,11 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, ...@@ -483,6 +488,11 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie,
if (hlist_empty(&cookie->backing_objects)) if (hlist_empty(&cookie->backing_objects))
goto nobufs; goto nobufs;
if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) {
_leave(" = -ENOBUFS [invalidating]");
return -ENOBUFS;
}
ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX);
ASSERTCMP(*nr_pages, >, 0); ASSERTCMP(*nr_pages, >, 0);
ASSERT(!list_empty(pages)); ASSERT(!list_empty(pages));
...@@ -591,6 +601,11 @@ int __fscache_alloc_page(struct fscache_cookie *cookie, ...@@ -591,6 +601,11 @@ int __fscache_alloc_page(struct fscache_cookie *cookie,
ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX);
ASSERTCMP(page, !=, NULL); ASSERTCMP(page, !=, NULL);
if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) {
_leave(" = -ENOBUFS [invalidating]");
return -ENOBUFS;
}
if (fscache_wait_for_deferred_lookup(cookie) < 0) if (fscache_wait_for_deferred_lookup(cookie) < 0)
return -ERESTARTSYS; return -ERESTARTSYS;
...@@ -730,6 +745,37 @@ static void fscache_write_op(struct fscache_operation *_op) ...@@ -730,6 +745,37 @@ static void fscache_write_op(struct fscache_operation *_op)
_leave(""); _leave("");
} }
/*
* Clear the pages pending writing for invalidation
*/
void fscache_invalidate_writes(struct fscache_cookie *cookie)
{
struct page *page;
void *results[16];
int n, i;
_enter("");
while (spin_lock(&cookie->stores_lock),
n = radix_tree_gang_lookup_tag(&cookie->stores, results, 0,
ARRAY_SIZE(results),
FSCACHE_COOKIE_PENDING_TAG),
n > 0) {
for (i = n - 1; i >= 0; i--) {
page = results[i];
radix_tree_delete(&cookie->stores, page->index);
}
spin_unlock(&cookie->stores_lock);
for (i = n - 1; i >= 0; i--)
page_cache_release(results[i]);
}
spin_unlock(&cookie->stores_lock);
_leave("");
}
/* /*
* request a page be stored in the cache * request a page be stored in the cache
* - returns: * - returns:
...@@ -776,6 +822,11 @@ int __fscache_write_page(struct fscache_cookie *cookie, ...@@ -776,6 +822,11 @@ int __fscache_write_page(struct fscache_cookie *cookie,
fscache_stat(&fscache_n_stores); fscache_stat(&fscache_n_stores);
if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) {
_leave(" = -ENOBUFS [invalidating]");
return -ENOBUFS;
}
op = kzalloc(sizeof(*op), GFP_NOIO | __GFP_NOMEMALLOC | __GFP_NORETRY); op = kzalloc(sizeof(*op), GFP_NOIO | __GFP_NOMEMALLOC | __GFP_NORETRY);
if (!op) if (!op)
goto nomem; goto nomem;
......
...@@ -80,6 +80,9 @@ atomic_t fscache_n_acquires_ok; ...@@ -80,6 +80,9 @@ atomic_t fscache_n_acquires_ok;
atomic_t fscache_n_acquires_nobufs; atomic_t fscache_n_acquires_nobufs;
atomic_t fscache_n_acquires_oom; atomic_t fscache_n_acquires_oom;
atomic_t fscache_n_invalidates;
atomic_t fscache_n_invalidates_run;
atomic_t fscache_n_updates; atomic_t fscache_n_updates;
atomic_t fscache_n_updates_null; atomic_t fscache_n_updates_null;
atomic_t fscache_n_updates_run; atomic_t fscache_n_updates_run;
...@@ -112,6 +115,7 @@ atomic_t fscache_n_cop_alloc_object; ...@@ -112,6 +115,7 @@ atomic_t fscache_n_cop_alloc_object;
atomic_t fscache_n_cop_lookup_object; atomic_t fscache_n_cop_lookup_object;
atomic_t fscache_n_cop_lookup_complete; atomic_t fscache_n_cop_lookup_complete;
atomic_t fscache_n_cop_grab_object; atomic_t fscache_n_cop_grab_object;
atomic_t fscache_n_cop_invalidate_object;
atomic_t fscache_n_cop_update_object; atomic_t fscache_n_cop_update_object;
atomic_t fscache_n_cop_drop_object; atomic_t fscache_n_cop_drop_object;
atomic_t fscache_n_cop_put_object; atomic_t fscache_n_cop_put_object;
...@@ -168,6 +172,10 @@ static int fscache_stats_show(struct seq_file *m, void *v) ...@@ -168,6 +172,10 @@ static int fscache_stats_show(struct seq_file *m, void *v)
atomic_read(&fscache_n_object_created), atomic_read(&fscache_n_object_created),
atomic_read(&fscache_n_object_lookups_timed_out)); atomic_read(&fscache_n_object_lookups_timed_out));
seq_printf(m, "Invals : n=%u run=%u\n",
atomic_read(&fscache_n_invalidates),
atomic_read(&fscache_n_invalidates_run));
seq_printf(m, "Updates: n=%u nul=%u run=%u\n", seq_printf(m, "Updates: n=%u nul=%u run=%u\n",
atomic_read(&fscache_n_updates), atomic_read(&fscache_n_updates),
atomic_read(&fscache_n_updates_null), atomic_read(&fscache_n_updates_null),
...@@ -246,7 +254,8 @@ static int fscache_stats_show(struct seq_file *m, void *v) ...@@ -246,7 +254,8 @@ static int fscache_stats_show(struct seq_file *m, void *v)
atomic_read(&fscache_n_cop_lookup_object), atomic_read(&fscache_n_cop_lookup_object),
atomic_read(&fscache_n_cop_lookup_complete), atomic_read(&fscache_n_cop_lookup_complete),
atomic_read(&fscache_n_cop_grab_object)); atomic_read(&fscache_n_cop_grab_object));
seq_printf(m, "CacheOp: upo=%d dro=%d pto=%d atc=%d syn=%d\n", seq_printf(m, "CacheOp: inv=%d upo=%d dro=%d pto=%d atc=%d syn=%d\n",
atomic_read(&fscache_n_cop_invalidate_object),
atomic_read(&fscache_n_cop_update_object), atomic_read(&fscache_n_cop_update_object),
atomic_read(&fscache_n_cop_drop_object), atomic_read(&fscache_n_cop_drop_object),
atomic_read(&fscache_n_cop_put_object), atomic_read(&fscache_n_cop_put_object),
......
...@@ -254,6 +254,9 @@ struct fscache_cache_ops { ...@@ -254,6 +254,9 @@ struct fscache_cache_ops {
/* store the updated auxiliary data on an object */ /* store the updated auxiliary data on an object */
void (*update_object)(struct fscache_object *object); void (*update_object)(struct fscache_object *object);
/* Invalidate an object */
void (*invalidate_object)(struct fscache_operation *op);
/* discard the resources pinned by an object and effect retirement if /* discard the resources pinned by an object and effect retirement if
* necessary */ * necessary */
void (*drop_object)(struct fscache_object *object); void (*drop_object)(struct fscache_object *object);
...@@ -329,6 +332,7 @@ struct fscache_cookie { ...@@ -329,6 +332,7 @@ struct fscache_cookie {
#define FSCACHE_COOKIE_FILLING 4 /* T if filling object incrementally */ #define FSCACHE_COOKIE_FILLING 4 /* T if filling object incrementally */
#define FSCACHE_COOKIE_UNAVAILABLE 5 /* T if cookie is unavailable (error, etc) */ #define FSCACHE_COOKIE_UNAVAILABLE 5 /* T if cookie is unavailable (error, etc) */
#define FSCACHE_COOKIE_WAITING_ON_READS 6 /* T if cookie is waiting on reads */ #define FSCACHE_COOKIE_WAITING_ON_READS 6 /* T if cookie is waiting on reads */
#define FSCACHE_COOKIE_INVALIDATING 7 /* T if cookie is being invalidated */
}; };
extern struct fscache_cookie fscache_fsdef_index; extern struct fscache_cookie fscache_fsdef_index;
...@@ -345,6 +349,7 @@ struct fscache_object { ...@@ -345,6 +349,7 @@ struct fscache_object {
/* active states */ /* active states */
FSCACHE_OBJECT_AVAILABLE, /* cleaning up object after creation */ FSCACHE_OBJECT_AVAILABLE, /* cleaning up object after creation */
FSCACHE_OBJECT_ACTIVE, /* object is usable */ FSCACHE_OBJECT_ACTIVE, /* object is usable */
FSCACHE_OBJECT_INVALIDATING, /* object is invalidating */
FSCACHE_OBJECT_UPDATING, /* object is updating */ FSCACHE_OBJECT_UPDATING, /* object is updating */
/* terminal states */ /* terminal states */
...@@ -378,7 +383,8 @@ struct fscache_object { ...@@ -378,7 +383,8 @@ struct fscache_object {
#define FSCACHE_OBJECT_EV_RELEASE 4 /* T if netfs requested object release */ #define FSCACHE_OBJECT_EV_RELEASE 4 /* T if netfs requested object release */
#define FSCACHE_OBJECT_EV_RETIRE 5 /* T if netfs requested object retirement */ #define FSCACHE_OBJECT_EV_RETIRE 5 /* T if netfs requested object retirement */
#define FSCACHE_OBJECT_EV_WITHDRAW 6 /* T if cache requested object withdrawal */ #define FSCACHE_OBJECT_EV_WITHDRAW 6 /* T if cache requested object withdrawal */
#define FSCACHE_OBJECT_EVENTS_MASK 0x7f /* mask of all events*/ #define FSCACHE_OBJECT_EV_INVALIDATE 7 /* T if cache requested object invalidation */
#define FSCACHE_OBJECT_EVENTS_MASK 0xff /* mask of all events*/
unsigned long flags; unsigned long flags;
#define FSCACHE_OBJECT_LOCK 0 /* T if object is busy being processed */ #define FSCACHE_OBJECT_LOCK 0 /* T if object is busy being processed */
......
...@@ -185,6 +185,8 @@ extern struct fscache_cookie *__fscache_acquire_cookie( ...@@ -185,6 +185,8 @@ extern struct fscache_cookie *__fscache_acquire_cookie(
extern void __fscache_relinquish_cookie(struct fscache_cookie *, int); extern void __fscache_relinquish_cookie(struct fscache_cookie *, int);
extern void __fscache_update_cookie(struct fscache_cookie *); extern void __fscache_update_cookie(struct fscache_cookie *);
extern int __fscache_attr_changed(struct fscache_cookie *); extern int __fscache_attr_changed(struct fscache_cookie *);
extern void __fscache_invalidate(struct fscache_cookie *);
extern void __fscache_wait_on_invalidate(struct fscache_cookie *);
extern int __fscache_read_or_alloc_page(struct fscache_cookie *, extern int __fscache_read_or_alloc_page(struct fscache_cookie *,
struct page *, struct page *,
fscache_rw_complete_t, fscache_rw_complete_t,
...@@ -389,6 +391,42 @@ int fscache_attr_changed(struct fscache_cookie *cookie) ...@@ -389,6 +391,42 @@ int fscache_attr_changed(struct fscache_cookie *cookie)
return -ENOBUFS; return -ENOBUFS;
} }
/**
* fscache_invalidate - Notify cache that an object needs invalidation
* @cookie: The cookie representing the cache object
*
* 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. The object
* is then marked non-caching until such time as the invalidation is complete.
*
* This can be called with spinlocks held.
*
* See Documentation/filesystems/caching/netfs-api.txt for a complete
* description.
*/
static inline
void fscache_invalidate(struct fscache_cookie *cookie)
{
if (fscache_cookie_valid(cookie))
__fscache_invalidate(cookie);
}
/**
* fscache_wait_on_invalidate - Wait for invalidation to complete
* @cookie: The cookie representing the cache object
*
* Wait for the invalidation of an object to complete.
*
* See Documentation/filesystems/caching/netfs-api.txt for a complete
* description.
*/
static inline
void fscache_wait_on_invalidate(struct fscache_cookie *cookie)
{
if (fscache_cookie_valid(cookie))
__fscache_wait_on_invalidate(cookie);
}
/** /**
* fscache_reserve_space - Reserve data space for a cached object * fscache_reserve_space - Reserve data space for a cached object
* @cookie: The cookie representing the cache object * @cookie: The cookie representing the cache object
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment