mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-28 16:53:49 +00:00
92a714d727
An issue can occur between write-streaming (storing dirty data in partial non-uptodate pages) and a cachefiles object being culled to make space. The problem occurs because the cache object is only marked in use while there are files open using it. Once it has been released, it can be culled and the cookie marked disabled. At this point, a streaming write is permitted to occur (if the cache is active, we require pages to be prefetched and cached), but the cache can become active again before this gets flushed out - and then two effects can occur: (1) The cache may be asked to write out a region that's less than its DIO block size (assumed by cachefiles to be PAGE_SIZE) - and this causes one of two debugging statements to be emitted. (2) netfs_how_to_modify() gets confused because it sees a page that isn't allowed to be non-uptodate being uptodate and tries to prefetch it - leading to a warning that PG_fscache is set twice. Fix this by the following means: (1) Add a netfs_inode flag to disallow write-streaming to an inode and set it if we ever do local caching of that inode. It remains set for the lifetime of that inode - even if the cookie becomes disabled. (2) If the no-write-streaming flag is set, then make netfs_how_to_modify() always want to prefetch instead. (3) If netfs_how_to_modify() decides it wants to prefetch a folio, but that folio has write-streamed data in it, then it requires the folio be flushed first. (4) Export a counter of the number of times we wanted to prefetch a non-uptodate page, but found it had write-streamed data in it. (5) Export a counter of the number of times we cancelled a write to the cache because it didn't DIO align and remove the debug statements. Reported-by: Marc Dionne <marc.dionne@auristor.com> Signed-off-by: David Howells <dhowells@redhat.com> cc: Jeff Layton <jlayton@kernel.org> cc: linux-cachefs@redhat.com cc: linux-erofs@lists.ozlabs.org cc: linux-fsdevel@vger.kernel.org cc: linux-mm@kvack.org
104 lines
3.0 KiB
C
104 lines
3.0 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/* FS-Cache statistics
|
|
*
|
|
* Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
|
|
* Written by David Howells (dhowells@redhat.com)
|
|
*/
|
|
|
|
#define FSCACHE_DEBUG_LEVEL CACHE
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/seq_file.h>
|
|
#include "internal.h"
|
|
|
|
/*
|
|
* operation counters
|
|
*/
|
|
atomic_t fscache_n_volumes;
|
|
atomic_t fscache_n_volumes_collision;
|
|
atomic_t fscache_n_volumes_nomem;
|
|
atomic_t fscache_n_cookies;
|
|
atomic_t fscache_n_cookies_lru;
|
|
atomic_t fscache_n_cookies_lru_expired;
|
|
atomic_t fscache_n_cookies_lru_removed;
|
|
atomic_t fscache_n_cookies_lru_dropped;
|
|
|
|
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);
|
|
|
|
atomic_t fscache_n_relinquishes;
|
|
atomic_t fscache_n_relinquishes_retire;
|
|
atomic_t fscache_n_relinquishes_dropped;
|
|
|
|
atomic_t fscache_n_resizes;
|
|
atomic_t fscache_n_resizes_null;
|
|
|
|
atomic_t fscache_n_read;
|
|
EXPORT_SYMBOL(fscache_n_read);
|
|
atomic_t fscache_n_write;
|
|
EXPORT_SYMBOL(fscache_n_write);
|
|
atomic_t fscache_n_no_write_space;
|
|
EXPORT_SYMBOL(fscache_n_no_write_space);
|
|
atomic_t fscache_n_no_create_space;
|
|
EXPORT_SYMBOL(fscache_n_no_create_space);
|
|
atomic_t fscache_n_culled;
|
|
EXPORT_SYMBOL(fscache_n_culled);
|
|
atomic_t fscache_n_dio_misfit;
|
|
EXPORT_SYMBOL(fscache_n_dio_misfit);
|
|
|
|
/*
|
|
* display the general statistics
|
|
*/
|
|
int fscache_stats_show(struct seq_file *m)
|
|
{
|
|
seq_puts(m, "-- FS-Cache statistics --\n");
|
|
seq_printf(m, "Cookies: n=%d v=%d vcol=%u voom=%u\n",
|
|
atomic_read(&fscache_n_cookies),
|
|
atomic_read(&fscache_n_volumes),
|
|
atomic_read(&fscache_n_volumes_collision),
|
|
atomic_read(&fscache_n_volumes_nomem)
|
|
);
|
|
|
|
seq_printf(m, "Acquire: n=%u ok=%u oom=%u\n",
|
|
atomic_read(&fscache_n_acquires),
|
|
atomic_read(&fscache_n_acquires_ok),
|
|
atomic_read(&fscache_n_acquires_oom));
|
|
|
|
seq_printf(m, "LRU : n=%u exp=%u rmv=%u drp=%u at=%ld\n",
|
|
atomic_read(&fscache_n_cookies_lru),
|
|
atomic_read(&fscache_n_cookies_lru_expired),
|
|
atomic_read(&fscache_n_cookies_lru_removed),
|
|
atomic_read(&fscache_n_cookies_lru_dropped),
|
|
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 rsz=%u rsn=%u\n",
|
|
atomic_read(&fscache_n_updates),
|
|
atomic_read(&fscache_n_resizes),
|
|
atomic_read(&fscache_n_resizes_null));
|
|
|
|
seq_printf(m, "Relinqs: n=%u rtr=%u drop=%u\n",
|
|
atomic_read(&fscache_n_relinquishes),
|
|
atomic_read(&fscache_n_relinquishes_retire),
|
|
atomic_read(&fscache_n_relinquishes_dropped));
|
|
|
|
seq_printf(m, "NoSpace: nwr=%u ncr=%u cull=%u\n",
|
|
atomic_read(&fscache_n_no_write_space),
|
|
atomic_read(&fscache_n_no_create_space),
|
|
atomic_read(&fscache_n_culled));
|
|
|
|
seq_printf(m, "IO : rd=%u wr=%u mis=%u\n",
|
|
atomic_read(&fscache_n_read),
|
|
atomic_read(&fscache_n_write),
|
|
atomic_read(&fscache_n_dio_misfit));
|
|
return 0;
|
|
}
|