lkml.org 
[lkml]   [2021]   [Oct]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[PATCH v2 20/53] fscache: Implement cookie invalidation
    From
    Date
    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)

    If there is one, any cached data for the specified cookie is 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 will be
    abandoned (writes) or reperformed (reads).

    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.

    Signed-off-by: David Howells <dhowells@redhat.com>
    cc: linux-cachefs@redhat.com
    ---

    fs/fscache/cookie.c | 72 +++++++++++++++++++++++++++++++++++++++-
    fs/fscache/internal.h | 2 +
    fs/fscache/stats.c | 5 +++
    include/linux/fscache-cache.h | 3 ++
    include/linux/fscache.h | 33 ++++++++++++++++++
    include/linux/netfs.h | 1 +
    include/trace/events/fscache.h | 25 ++++++++++++++
    7 files changed, 140 insertions(+), 1 deletion(-)

    diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c
    index cf987756534c..2ad889f20430 100644
    --- a/fs/fscache/cookie.c
    +++ b/fs/fscache/cookie.c
    @@ -20,6 +20,7 @@ static void fscache_cookie_lru_worker(struct work_struct *work);
    static void fscache_cookie_worker(struct work_struct *work);
    static void fscache_drop_cookie(struct fscache_cookie *cookie);
    static void fscache_lookup_cookie(struct fscache_cookie *cookie);
    +static void fscache_invalidate_cookie(struct fscache_cookie *cookie);

    #define fscache_cookie_hash_shift 15
    static struct hlist_bl_head fscache_cookie_hash[1 << fscache_cookie_hash_shift];
    @@ -29,7 +30,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_stages[FSCACHE_COOKIE_STAGE__NR] = "-LCAFMWRD";
    +static const char fscache_cookie_stages[FSCACHE_COOKIE_STAGE__NR] = "-LCAIFMWRD";
    unsigned int fscache_lru_cookie_timeout = 10 * HZ;

    void fscache_print_cookie(struct fscache_cookie *cookie, char prefix)
    @@ -504,6 +505,7 @@ void __fscache_use_cookie(struct fscache_cookie *cookie, bool will_modify)
    set_bit(FSCACHE_COOKIE_LOCAL_WRITE, &cookie->flags);
    break;
    case FSCACHE_COOKIE_STAGE_ACTIVE:
    + case FSCACHE_COOKIE_STAGE_INVALIDATING:
    if (will_modify &&
    !test_and_set_bit(FSCACHE_COOKIE_LOCAL_WRITE, &cookie->flags)) {
    set_bit(FSCACHE_COOKIE_DO_PREP_TO_WRITE, &cookie->flags);
    @@ -598,6 +600,10 @@ static void __fscache_cookie_worker(struct fscache_cookie *cookie)
    cookie->debug_id, cookie->stage);
    break;

    + case FSCACHE_COOKIE_STAGE_INVALIDATING:
    + fscache_invalidate_cookie(cookie);
    + goto again;
    +
    case FSCACHE_COOKIE_STAGE_FAILED:
    break;

    @@ -723,6 +729,70 @@ static void fscache_cookie_drop_from_lru(struct fscache_cookie *cookie)
    }
    }

    +/*
    + * Ask the cache to effect invalidation of a cookie.
    + */
    +static void fscache_invalidate_cookie(struct fscache_cookie *cookie)
    +{
    + cookie->volume->cache->ops->invalidate_cookie(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->stage) {
    + case FSCACHE_COOKIE_STAGE_INVALIDATING: /* is_still_valid will catch it */
    + default:
    + spin_unlock(&cookie->lock);
    + _leave(" [no %u]", cookie->stage);
    + return;
    +
    + case FSCACHE_COOKIE_STAGE_LOOKING_UP:
    + case FSCACHE_COOKIE_STAGE_CREATING:
    + spin_unlock(&cookie->lock);
    + _leave(" [look %x]", cookie->inval_counter);
    + return;
    +
    + case FSCACHE_COOKIE_STAGE_ACTIVE:
    + __fscache_set_cookie_stage(cookie, FSCACHE_COOKIE_STAGE_INVALIDATING);
    + is_caching = fscache_begin_cookie_access(
    + cookie, fscache_access_invalidate_cookie);
    + spin_unlock(&cookie->lock);
    + wake_up_cookie_stage(cookie);
    +
    + if (is_caching)
    + fscache_queue_cookie(cookie, fscache_cookie_get_inval_work);
    + _leave(" [inv]");
    + return;
    + }
    +}
    +EXPORT_SYMBOL(__fscache_invalidate);
    +
    /*
    * Remove a cookie from the hash table.
    */
    diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h
    index 5aff9c143616..4c45d2af7160 100644
    --- a/fs/fscache/internal.h
    +++ b/fs/fscache/internal.h
    @@ -82,6 +82,8 @@ extern atomic_t fscache_n_acquires_no_cache;
    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;
    diff --git a/fs/fscache/stats.c b/fs/fscache/stats.c
    index 17bf57374595..45b7636c7737 100644
    --- a/fs/fscache/stats.c
    +++ b/fs/fscache/stats.c
    @@ -28,6 +28,8 @@ atomic_t fscache_n_acquires_no_cache;
    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);

    @@ -63,6 +65,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));

    diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h
    index a67c29207ad5..46d77a1840cd 100644
    --- a/include/linux/fscache-cache.h
    +++ b/include/linux/fscache-cache.h
    @@ -66,6 +66,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);
    };
    diff --git a/include/linux/fscache.h b/include/linux/fscache.h
    index df985507fa5e..0b01eaaef44c 100644
    --- a/include/linux/fscache.h
    +++ b/include/linux/fscache.h
    @@ -45,6 +45,8 @@ struct fscache_cookie;
    #define FSCACHE_ADV_WRITE_NOCACHE 0x02 /* Don't cache if written to locally */
    #define FSCACHE_ADV_FALLBACK_IO 0x04 /* Going to use the fallback I/O API (dangerous) */

    +#define FSCACHE_INVAL_DIO_WRITE 0x01 /* Invalidate due to DIO write */
    +
    /*
    * Data object state.
    */
    @@ -53,6 +55,7 @@ enum fscache_cookie_stage {
    FSCACHE_COOKIE_STAGE_LOOKING_UP, /* The cache object is being looked up */
    FSCACHE_COOKIE_STAGE_CREATING, /* The cache object is being created */
    FSCACHE_COOKIE_STAGE_ACTIVE, /* The cache is active, readable and writable */
    + FSCACHE_COOKIE_STAGE_INVALIDATING, /* The cache is being invalidated */
    FSCACHE_COOKIE_STAGE_FAILED, /* The cache failed, withdraw to clear */
    FSCACHE_COOKIE_STAGE_COMMITTING, /* The cookie is being committed */
    FSCACHE_COOKIE_STAGE_WITHDRAWING, /* The cookie is being withdrawn */
    @@ -158,6 +161,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
    @@ -325,4 +329,33 @@ 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. The object
    + * is then marked non-caching until such time as the invalidation is complete.
    + *
    + * FSCACHE_INVAL_LIGHT indicates that if the object has been invalidated and
    + * replaced by a temporary object, the temporary object need not be replaced
    + * again. This is primarily intended for use with FSCACHE_ADV_SINGLE_CHUNK.
    + *
    + * FSCACHE_INVAL_DIO_WRITE indicates that this is due to a direct I/O write and
    + * may cause caching to be suspended on this cookie.
    + *
    + * 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 */
    diff --git a/include/linux/netfs.h b/include/linux/netfs.h
    index 99137486d351..3c70eef56599 100644
    --- a/include/linux/netfs.h
    +++ b/include/linux/netfs.h
    @@ -103,6 +103,7 @@ struct netfs_cache_resources {
    void *cache_priv;
    void *cache_priv2;
    unsigned int debug_id; /* Cookie debug ID */
    + unsigned int inval_counter; /* object->inval_counter at begin_op */
    };

    /*
    diff --git a/include/trace/events/fscache.h b/include/trace/events/fscache.h
    index 2b31ef34efa2..b705ff36bddc 100644
    --- a/include/trace/events/fscache.h
    +++ b/include/trace/events/fscache.h
    @@ -50,6 +50,7 @@ enum fscache_cookie_trace {
    fscache_cookie_discard,
    fscache_cookie_get_end_access,
    fscache_cookie_get_hash_collision,
    + fscache_cookie_get_inval_work,
    fscache_cookie_get_lru,
    fscache_cookie_get_use_work,
    fscache_cookie_new_acquire,
    @@ -72,6 +73,8 @@ enum fscache_access_trace {
    fscache_access_acquire_volume_end,
    fscache_access_cache_pin,
    fscache_access_cache_unpin,
    + fscache_access_invalidate_cookie,
    + fscache_access_invalidate_cookie_end,
    fscache_access_lookup_cookie,
    fscache_access_lookup_cookie_end,
    fscache_access_relinquish_volume,
    @@ -113,6 +116,7 @@ enum fscache_access_trace {
    EM(fscache_cookie_discard, "DISCARD ") \
    EM(fscache_cookie_get_hash_collision, "GET hcoll") \
    EM(fscache_cookie_get_end_access, "GQ endac") \
    + EM(fscache_cookie_get_inval_work, "GQ inval") \
    EM(fscache_cookie_get_lru, "GET lru ") \
    EM(fscache_cookie_get_use_work, "GQ use ") \
    EM(fscache_cookie_new_acquire, "NEW acq ") \
    @@ -134,6 +138,8 @@ enum fscache_access_trace {
    EM(fscache_access_acquire_volume_end, "END acq_vol") \
    EM(fscache_access_cache_pin, "PIN cache ") \
    EM(fscache_access_cache_unpin, "UNPIN cache ") \
    + EM(fscache_access_invalidate_cookie, "BEGIN inval ") \
    + EM(fscache_access_invalidate_cookie_end,"END inval ") \
    EM(fscache_access_lookup_cookie, "BEGIN lookup ") \
    EM(fscache_access_lookup_cookie_end, "END lookup ") \
    EM(fscache_access_relinquish_volume, "BEGIN rlq_vol") \
    @@ -378,6 +384,25 @@ TRACE_EVENT(fscache_relinquish,
    __entry->n_active, __entry->flags, __entry->retire)
    );

    +TRACE_EVENT(fscache_invalidate,
    + TP_PROTO(struct fscache_cookie *cookie, loff_t new_size),
    +
    + TP_ARGS(cookie, new_size),
    +
    + TP_STRUCT__entry(
    + __field(unsigned int, cookie )
    + __field(loff_t, new_size )
    + ),
    +
    + TP_fast_assign(
    + __entry->cookie = cookie->debug_id;
    + __entry->new_size = new_size;
    + ),
    +
    + TP_printk("c=%08x sz=%llx",
    + __entry->cookie, __entry->new_size)
    + );
    +
    #endif /* _TRACE_FSCACHE_H */

    /* This part must be outside protection */

    \
     
     \ /
      Last update: 2021-10-22 21:05    [W:6.685 / U:0.028 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site