diff options
Diffstat (limited to 'fs/fscache/object.c')
-rw-r--r-- | fs/fscache/object.c | 32 |
1 files changed, 30 insertions, 2 deletions
diff --git a/fs/fscache/object.c b/fs/fscache/object.c index 9e792e30f4db..7a182c87f378 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c | |||
@@ -30,6 +30,7 @@ static const struct fscache_state *fscache_look_up_object(struct fscache_object | |||
30 | static const struct fscache_state *fscache_object_available(struct fscache_object *, int); | 30 | static const struct fscache_state *fscache_object_available(struct fscache_object *, int); |
31 | static const struct fscache_state *fscache_parent_ready(struct fscache_object *, int); | 31 | static const struct fscache_state *fscache_parent_ready(struct fscache_object *, int); |
32 | static const struct fscache_state *fscache_update_object(struct fscache_object *, int); | 32 | static const struct fscache_state *fscache_update_object(struct fscache_object *, int); |
33 | static const struct fscache_state *fscache_object_dead(struct fscache_object *, int); | ||
33 | 34 | ||
34 | #define __STATE_NAME(n) fscache_osm_##n | 35 | #define __STATE_NAME(n) fscache_osm_##n |
35 | #define STATE(n) (&__STATE_NAME(n)) | 36 | #define STATE(n) (&__STATE_NAME(n)) |
@@ -91,7 +92,7 @@ static WORK_STATE(LOOKUP_FAILURE, "LCFL", fscache_lookup_failure); | |||
91 | static WORK_STATE(KILL_OBJECT, "KILL", fscache_kill_object); | 92 | static WORK_STATE(KILL_OBJECT, "KILL", fscache_kill_object); |
92 | static WORK_STATE(KILL_DEPENDENTS, "KDEP", fscache_kill_dependents); | 93 | static WORK_STATE(KILL_DEPENDENTS, "KDEP", fscache_kill_dependents); |
93 | static WORK_STATE(DROP_OBJECT, "DROP", fscache_drop_object); | 94 | static WORK_STATE(DROP_OBJECT, "DROP", fscache_drop_object); |
94 | static WORK_STATE(OBJECT_DEAD, "DEAD", (void*)2UL); | 95 | static WORK_STATE(OBJECT_DEAD, "DEAD", fscache_object_dead); |
95 | 96 | ||
96 | static WAIT_STATE(WAIT_FOR_INIT, "?INI", | 97 | static WAIT_STATE(WAIT_FOR_INIT, "?INI", |
97 | TRANSIT_TO(INIT_OBJECT, 1 << FSCACHE_OBJECT_EV_NEW_CHILD)); | 98 | TRANSIT_TO(INIT_OBJECT, 1 << FSCACHE_OBJECT_EV_NEW_CHILD)); |
@@ -229,6 +230,10 @@ execute_work_state: | |||
229 | event = -1; | 230 | event = -1; |
230 | if (new_state == NO_TRANSIT) { | 231 | if (new_state == NO_TRANSIT) { |
231 | _debug("{OBJ%x} %s notrans", object->debug_id, state->name); | 232 | _debug("{OBJ%x} %s notrans", object->debug_id, state->name); |
233 | if (unlikely(state == STATE(OBJECT_DEAD))) { | ||
234 | _leave(" [dead]"); | ||
235 | return; | ||
236 | } | ||
232 | fscache_enqueue_object(object); | 237 | fscache_enqueue_object(object); |
233 | event_mask = object->oob_event_mask; | 238 | event_mask = object->oob_event_mask; |
234 | goto unmask_events; | 239 | goto unmask_events; |
@@ -239,7 +244,7 @@ execute_work_state: | |||
239 | object->state = state = new_state; | 244 | object->state = state = new_state; |
240 | 245 | ||
241 | if (state->work) { | 246 | if (state->work) { |
242 | if (unlikely(state->work == ((void *)2UL))) { | 247 | if (unlikely(state == STATE(OBJECT_DEAD))) { |
243 | _leave(" [dead]"); | 248 | _leave(" [dead]"); |
244 | return; | 249 | return; |
245 | } | 250 | } |
@@ -645,6 +650,12 @@ static const struct fscache_state *fscache_kill_object(struct fscache_object *ob | |||
645 | fscache_mark_object_dead(object); | 650 | fscache_mark_object_dead(object); |
646 | object->oob_event_mask = 0; | 651 | object->oob_event_mask = 0; |
647 | 652 | ||
653 | if (test_bit(FSCACHE_OBJECT_RETIRED, &object->flags)) { | ||
654 | /* Reject any new read/write ops and abort any that are pending. */ | ||
655 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); | ||
656 | fscache_cancel_all_ops(object); | ||
657 | } | ||
658 | |||
648 | if (list_empty(&object->dependents) && | 659 | if (list_empty(&object->dependents) && |
649 | object->n_ops == 0 && | 660 | object->n_ops == 0 && |
650 | object->n_children == 0) | 661 | object->n_children == 0) |
@@ -1077,3 +1088,20 @@ void fscache_object_mark_killed(struct fscache_object *object, | |||
1077 | } | 1088 | } |
1078 | } | 1089 | } |
1079 | EXPORT_SYMBOL(fscache_object_mark_killed); | 1090 | EXPORT_SYMBOL(fscache_object_mark_killed); |
1091 | |||
1092 | /* | ||
1093 | * The object is dead. We can get here if an object gets queued by an event | ||
1094 | * that would lead to its death (such as EV_KILL) when the dispatcher is | ||
1095 | * already running (and so can be requeued) but hasn't yet cleared the event | ||
1096 | * mask. | ||
1097 | */ | ||
1098 | static const struct fscache_state *fscache_object_dead(struct fscache_object *object, | ||
1099 | int event) | ||
1100 | { | ||
1101 | if (!test_and_set_bit(FSCACHE_OBJECT_RUN_AFTER_DEAD, | ||
1102 | &object->flags)) | ||
1103 | return NO_TRANSIT; | ||
1104 | |||
1105 | WARN(true, "FS-Cache object redispatched after death"); | ||
1106 | return NO_TRANSIT; | ||
1107 | } | ||