Skip to content

Commit d24af13

Browse files
committed
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: David Howells <[email protected]> Reviewed-by: Jeff Layton <[email protected]> cc: [email protected] 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
1 parent 12bb21a commit d24af13

File tree

7 files changed

+155
-1
lines changed

7 files changed

+155
-1
lines changed

fs/fscache/cookie.c

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ static void fscache_cookie_lru_timed_out(struct timer_list *timer);
1919
static void fscache_cookie_lru_worker(struct work_struct *work);
2020
static void fscache_cookie_worker(struct work_struct *work);
2121
static void fscache_unhash_cookie(struct fscache_cookie *cookie);
22+
static void fscache_perform_invalidation(struct fscache_cookie *cookie);
2223

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

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

240+
/**
241+
* fscache_resume_after_invalidation - Allow I/O to resume after invalidation
242+
* @cookie: The cookie that was invalidated
243+
*
244+
* Tell fscache that invalidation is sufficiently complete that I/O can be
245+
* allowed again.
246+
*/
247+
void fscache_resume_after_invalidation(struct fscache_cookie *cookie)
248+
{
249+
fscache_set_cookie_state(cookie, FSCACHE_COOKIE_STATE_ACTIVE);
250+
}
251+
EXPORT_SYMBOL(fscache_resume_after_invalidation);
252+
239253
/**
240254
* fscache_caching_failed - Report that a failure stopped caching on a cookie
241255
* @cookie: The cookie that was affected
@@ -566,6 +580,7 @@ void __fscache_use_cookie(struct fscache_cookie *cookie, bool will_modify)
566580
set_bit(FSCACHE_COOKIE_LOCAL_WRITE, &cookie->flags);
567581
break;
568582
case FSCACHE_COOKIE_STATE_ACTIVE:
583+
case FSCACHE_COOKIE_STATE_INVALIDATING:
569584
if (will_modify &&
570585
!test_and_set_bit(FSCACHE_COOKIE_LOCAL_WRITE, &cookie->flags)) {
571586
set_bit(FSCACHE_COOKIE_DO_PREP_TO_WRITE, &cookie->flags);
@@ -671,6 +686,11 @@ static void fscache_cookie_state_machine(struct fscache_cookie *cookie)
671686
fscache_perform_lookup(cookie);
672687
goto again;
673688

689+
case FSCACHE_COOKIE_STATE_INVALIDATING:
690+
spin_unlock(&cookie->lock);
691+
fscache_perform_invalidation(cookie);
692+
goto again;
693+
674694
case FSCACHE_COOKIE_STATE_ACTIVE:
675695
if (test_and_clear_bit(FSCACHE_COOKIE_DO_PREP_TO_WRITE, &cookie->flags)) {
676696
spin_unlock(&cookie->lock);
@@ -962,6 +982,72 @@ struct fscache_cookie *fscache_get_cookie(struct fscache_cookie *cookie,
962982
}
963983
EXPORT_SYMBOL(fscache_get_cookie);
964984

985+
/*
986+
* Ask the cache to effect invalidation of a cookie.
987+
*/
988+
static void fscache_perform_invalidation(struct fscache_cookie *cookie)
989+
{
990+
if (!cookie->volume->cache->ops->invalidate_cookie(cookie))
991+
fscache_caching_failed(cookie);
992+
fscache_end_cookie_access(cookie, fscache_access_invalidate_cookie_end);
993+
}
994+
995+
/*
996+
* Invalidate an object.
997+
*/
998+
void __fscache_invalidate(struct fscache_cookie *cookie,
999+
const void *aux_data, loff_t new_size,
1000+
unsigned int flags)
1001+
{
1002+
bool is_caching;
1003+
1004+
_enter("c=%x", cookie->debug_id);
1005+
1006+
fscache_stat(&fscache_n_invalidates);
1007+
1008+
if (WARN(test_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags),
1009+
"Trying to invalidate relinquished cookie\n"))
1010+
return;
1011+
1012+
if ((flags & FSCACHE_INVAL_DIO_WRITE) &&
1013+
test_and_set_bit(FSCACHE_COOKIE_DISABLED, &cookie->flags))
1014+
return;
1015+
1016+
spin_lock(&cookie->lock);
1017+
set_bit(FSCACHE_COOKIE_NO_DATA_TO_READ, &cookie->flags);
1018+
fscache_update_aux(cookie, aux_data, &new_size);
1019+
cookie->inval_counter++;
1020+
trace_fscache_invalidate(cookie, new_size);
1021+
1022+
switch (cookie->state) {
1023+
case FSCACHE_COOKIE_STATE_INVALIDATING: /* is_still_valid will catch it */
1024+
default:
1025+
spin_unlock(&cookie->lock);
1026+
_leave(" [no %u]", cookie->state);
1027+
return;
1028+
1029+
case FSCACHE_COOKIE_STATE_LOOKING_UP:
1030+
case FSCACHE_COOKIE_STATE_CREATING:
1031+
spin_unlock(&cookie->lock);
1032+
_leave(" [look %x]", cookie->inval_counter);
1033+
return;
1034+
1035+
case FSCACHE_COOKIE_STATE_ACTIVE:
1036+
is_caching = fscache_begin_cookie_access(
1037+
cookie, fscache_access_invalidate_cookie);
1038+
if (is_caching)
1039+
__fscache_set_cookie_state(cookie, FSCACHE_COOKIE_STATE_INVALIDATING);
1040+
spin_unlock(&cookie->lock);
1041+
wake_up_cookie_state(cookie);
1042+
1043+
if (is_caching)
1044+
fscache_queue_cookie(cookie, fscache_cookie_get_inval_work);
1045+
_leave(" [inv]");
1046+
return;
1047+
}
1048+
}
1049+
EXPORT_SYMBOL(__fscache_invalidate);
1050+
9651051
/*
9661052
* Generate a list of extant cookies in /proc/fs/fscache/cookies
9671053
*/

fs/fscache/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ extern atomic_t fscache_n_acquires;
105105
extern atomic_t fscache_n_acquires_ok;
106106
extern atomic_t fscache_n_acquires_oom;
107107

108+
extern atomic_t fscache_n_invalidates;
109+
108110
extern atomic_t fscache_n_relinquishes;
109111
extern atomic_t fscache_n_relinquishes_retire;
110112
extern atomic_t fscache_n_relinquishes_dropped;

fs/fscache/stats.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ atomic_t fscache_n_acquires;
2626
atomic_t fscache_n_acquires_ok;
2727
atomic_t fscache_n_acquires_oom;
2828

29+
atomic_t fscache_n_invalidates;
30+
2931
atomic_t fscache_n_updates;
3032
EXPORT_SYMBOL(fscache_n_updates);
3133

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

64+
seq_printf(m, "Invals : n=%u\n",
65+
atomic_read(&fscache_n_invalidates));
66+
6267
seq_printf(m, "Updates: n=%u\n",
6368
atomic_read(&fscache_n_updates));
6469

include/linux/fscache-cache.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ struct fscache_cache_ops {
6464
/* Withdraw an object without any cookie access counts held */
6565
void (*withdraw_cookie)(struct fscache_cookie *cookie);
6666

67+
/* Invalidate an object */
68+
bool (*invalidate_cookie)(struct fscache_cookie *cookie);
69+
6770
/* Prepare to write to a live cache object */
6871
void (*prepare_to_write)(struct fscache_cookie *cookie);
6972
};
@@ -96,6 +99,7 @@ extern void fscache_put_cookie(struct fscache_cookie *cookie,
9699
extern void fscache_end_cookie_access(struct fscache_cookie *cookie,
97100
enum fscache_access_trace why);
98101
extern void fscache_cookie_lookup_negative(struct fscache_cookie *cookie);
102+
extern void fscache_resume_after_invalidation(struct fscache_cookie *cookie);
99103
extern void fscache_caching_failed(struct fscache_cookie *cookie);
100104

101105
/**

include/linux/fscache.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ struct fscache_cookie;
3939
#define FSCACHE_ADV_WRITE_CACHE 0x00 /* Do cache if written to locally */
4040
#define FSCACHE_ADV_WRITE_NOCACHE 0x02 /* Don't cache if written to locally */
4141

42+
#define FSCACHE_INVAL_DIO_WRITE 0x01 /* Invalidate due to DIO write */
43+
4244
/*
4345
* Data object state.
4446
*/
@@ -47,6 +49,7 @@ enum fscache_cookie_state {
4749
FSCACHE_COOKIE_STATE_LOOKING_UP, /* The cache object is being looked up */
4850
FSCACHE_COOKIE_STATE_CREATING, /* The cache object is being created */
4951
FSCACHE_COOKIE_STATE_ACTIVE, /* The cache is active, readable and writable */
52+
FSCACHE_COOKIE_STATE_INVALIDATING, /* The cache is being invalidated */
5053
FSCACHE_COOKIE_STATE_FAILED, /* The cache failed, withdraw to clear */
5154
FSCACHE_COOKIE_STATE_LRU_DISCARDING, /* The cookie is being discarded by the LRU */
5255
FSCACHE_COOKIE_STATE_WITHDRAWING, /* The cookie is being withdrawn */
@@ -153,6 +156,7 @@ extern struct fscache_cookie *__fscache_acquire_cookie(
153156
extern void __fscache_use_cookie(struct fscache_cookie *, bool);
154157
extern void __fscache_unuse_cookie(struct fscache_cookie *, const void *, const loff_t *);
155158
extern void __fscache_relinquish_cookie(struct fscache_cookie *, bool);
159+
extern void __fscache_invalidate(struct fscache_cookie *, const void *, loff_t, unsigned int);
156160

157161
/**
158162
* 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
327331
set_bit(FSCACHE_COOKIE_NEEDS_UPDATE, &cookie->flags);
328332
}
329333

334+
/**
335+
* fscache_invalidate - Notify cache that an object needs invalidation
336+
* @cookie: The cookie representing the cache object
337+
* @aux_data: The updated auxiliary data for the cookie (may be NULL)
338+
* @size: The revised size of the object.
339+
* @flags: Invalidation flags (FSCACHE_INVAL_*)
340+
*
341+
* Notify the cache that an object is needs to be invalidated and that it
342+
* should abort any retrievals or stores it is doing on the cache. This
343+
* increments inval_counter on the cookie which can be used by the caller to
344+
* reconsider I/O requests as they complete.
345+
*
346+
* If @flags has FSCACHE_INVAL_DIO_WRITE set, this indicates that this is due
347+
* to a direct I/O write and will cause caching to be disabled on this cookie
348+
* until it is completely unused.
349+
*
350+
* See Documentation/filesystems/caching/netfs-api.rst for a complete
351+
* description.
352+
*/
353+
static inline
354+
void fscache_invalidate(struct fscache_cookie *cookie,
355+
const void *aux_data, loff_t size, unsigned int flags)
356+
{
357+
if (fscache_cookie_enabled(cookie))
358+
__fscache_invalidate(cookie, aux_data, size, flags);
359+
}
360+
330361
#endif /* _LINUX_FSCACHE_H */

include/linux/netfs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ struct netfs_cache_resources {
124124
void *cache_priv;
125125
void *cache_priv2;
126126
unsigned int debug_id; /* Cookie debug ID */
127+
unsigned int inval_counter; /* object->inval_counter at begin_op */
127128
};
128129

129130
/*

include/trace/events/fscache.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ enum fscache_cookie_trace {
5151
fscache_cookie_discard,
5252
fscache_cookie_get_end_access,
5353
fscache_cookie_get_hash_collision,
54+
fscache_cookie_get_inval_work,
5455
fscache_cookie_get_lru,
5556
fscache_cookie_get_use_work,
5657
fscache_cookie_new_acquire,
@@ -73,6 +74,8 @@ enum fscache_access_trace {
7374
fscache_access_acquire_volume_end,
7475
fscache_access_cache_pin,
7576
fscache_access_cache_unpin,
77+
fscache_access_invalidate_cookie,
78+
fscache_access_invalidate_cookie_end,
7679
fscache_access_lookup_cookie,
7780
fscache_access_lookup_cookie_end,
7881
fscache_access_lookup_cookie_end_failed,
@@ -116,6 +119,7 @@ enum fscache_access_trace {
116119
EM(fscache_cookie_discard, "DISCARD ") \
117120
EM(fscache_cookie_get_hash_collision, "GET hcoll") \
118121
EM(fscache_cookie_get_end_access, "GQ endac") \
122+
EM(fscache_cookie_get_inval_work, "GQ inval") \
119123
EM(fscache_cookie_get_lru, "GET lru ") \
120124
EM(fscache_cookie_get_use_work, "GQ use ") \
121125
EM(fscache_cookie_new_acquire, "NEW acq ") \
@@ -137,6 +141,8 @@ enum fscache_access_trace {
137141
EM(fscache_access_acquire_volume_end, "END acq_vol") \
138142
EM(fscache_access_cache_pin, "PIN cache ") \
139143
EM(fscache_access_cache_unpin, "UNPIN cache ") \
144+
EM(fscache_access_invalidate_cookie, "BEGIN inval ") \
145+
EM(fscache_access_invalidate_cookie_end,"END inval ") \
140146
EM(fscache_access_lookup_cookie, "BEGIN lookup ") \
141147
EM(fscache_access_lookup_cookie_end, "END lookup ") \
142148
EM(fscache_access_lookup_cookie_end_failed,"END lookupf") \
@@ -385,6 +391,25 @@ TRACE_EVENT(fscache_relinquish,
385391
__entry->n_active, __entry->flags, __entry->retire)
386392
);
387393

394+
TRACE_EVENT(fscache_invalidate,
395+
TP_PROTO(struct fscache_cookie *cookie, loff_t new_size),
396+
397+
TP_ARGS(cookie, new_size),
398+
399+
TP_STRUCT__entry(
400+
__field(unsigned int, cookie )
401+
__field(loff_t, new_size )
402+
),
403+
404+
TP_fast_assign(
405+
__entry->cookie = cookie->debug_id;
406+
__entry->new_size = new_size;
407+
),
408+
409+
TP_printk("c=%08x sz=%llx",
410+
__entry->cookie, __entry->new_size)
411+
);
412+
388413
#endif /* _TRACE_FSCACHE_H */
389414

390415
/* This part must be outside protection */

0 commit comments

Comments
 (0)