fscache: Introduce new driver
Introduce basic skeleton of the new, rewritten fscache driver. Changes ======= ver #3: - Use remove_proc_subtree(), not remove_proc_entry() to remove a populated dir. Signed-off-by: David Howells <dhowells@redhat.com> Reviewed-by: Jeff Layton <jlayton@kernel.org> cc: linux-cachefs@redhat.com Link: https://lore.kernel.org/r/163819584034.215744.4290533472390439030.stgit@warthog.procyon.org.uk/ # v1 Link: https://lore.kernel.org/r/163906887770.143852.3577888294989185666.stgit@warthog.procyon.org.uk/ # v2 Link: https://lore.kernel.org/r/163967080039.1823006.5702921801104057922.stgit@warthog.procyon.org.uk/ # v3 Link: https://lore.kernel.org/r/164021491014.640689.4292699878317589512.stgit@warthog.procyon.org.uk/ # v4
This commit is contained in:
parent
a39c41b853
commit
1e1236b841
@ -67,6 +67,7 @@ obj-$(CONFIG_DLM) += dlm/
|
||||
|
||||
# Do not add any filesystems before this line
|
||||
obj-$(CONFIG_NETFS_SUPPORT) += netfs/
|
||||
obj-$(CONFIG_FSCACHE) += fscache/
|
||||
obj-$(CONFIG_REISERFS_FS) += reiserfs/
|
||||
obj-$(CONFIG_EXT4_FS) += ext4/
|
||||
# We place ext4 before ext2 so that clean ext3 root fs's do NOT mount using the
|
||||
|
@ -1,4 +1,43 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
config FSCACHE
|
||||
tristate "General filesystem local caching manager"
|
||||
select NETFS_SUPPORT
|
||||
help
|
||||
This option enables a generic filesystem caching manager that can be
|
||||
used by various network and other filesystems to cache data locally.
|
||||
Different sorts of caches can be plugged in, depending on the
|
||||
resources available.
|
||||
|
||||
See Documentation/filesystems/caching/fscache.rst for more information.
|
||||
|
||||
config FSCACHE_STATS
|
||||
bool "Gather statistical information on local caching"
|
||||
depends on FSCACHE && PROC_FS
|
||||
select NETFS_STATS
|
||||
help
|
||||
This option causes statistical information to be gathered on local
|
||||
caching and exported through file:
|
||||
|
||||
/proc/fs/fscache/stats
|
||||
|
||||
The gathering of statistics adds a certain amount of overhead to
|
||||
execution as there are a quite a few stats gathered, and on a
|
||||
multi-CPU system these may be on cachelines that keep bouncing
|
||||
between CPUs. On the other hand, the stats are very useful for
|
||||
debugging purposes. Saying 'Y' here is recommended.
|
||||
|
||||
See Documentation/filesystems/caching/fscache.rst for more information.
|
||||
|
||||
config FSCACHE_DEBUG
|
||||
bool "Debug FS-Cache"
|
||||
depends on FSCACHE
|
||||
help
|
||||
This permits debugging to be dynamically enabled in the local caching
|
||||
management module. If this is set, the debugging output may be
|
||||
enabled by setting bits in /sys/modules/fscache/parameter/debug.
|
||||
|
||||
See Documentation/filesystems/caching/fscache.rst for more information.
|
||||
|
||||
config FSCACHE_OLD_API
|
||||
bool
|
||||
|
12
fs/fscache/Makefile
Normal file
12
fs/fscache/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for general filesystem caching code
|
||||
#
|
||||
|
||||
fscache-y := \
|
||||
main.o
|
||||
|
||||
fscache-$(CONFIG_PROC_FS) += proc.o
|
||||
fscache-$(CONFIG_FSCACHE_STATS) += stats.o
|
||||
|
||||
obj-$(CONFIG_FSCACHE) := fscache.o
|
183
fs/fscache/internal.h
Normal file
183
fs/fscache/internal.h
Normal file
@ -0,0 +1,183 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* Internal definitions for FS-Cache
|
||||
*
|
||||
* Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#ifdef pr_fmt
|
||||
#undef pr_fmt
|
||||
#endif
|
||||
|
||||
#define pr_fmt(fmt) "FS-Cache: " fmt
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fscache-cache.h>
|
||||
#include <trace/events/fscache.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
/*
|
||||
* main.c
|
||||
*/
|
||||
extern unsigned fscache_debug;
|
||||
|
||||
/*
|
||||
* proc.c
|
||||
*/
|
||||
#ifdef CONFIG_PROC_FS
|
||||
extern int __init fscache_proc_init(void);
|
||||
extern void fscache_proc_cleanup(void);
|
||||
#else
|
||||
#define fscache_proc_init() (0)
|
||||
#define fscache_proc_cleanup() do {} while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* stats.c
|
||||
*/
|
||||
#ifdef CONFIG_FSCACHE_STATS
|
||||
|
||||
static inline void fscache_stat(atomic_t *stat)
|
||||
{
|
||||
atomic_inc(stat);
|
||||
}
|
||||
|
||||
static inline void fscache_stat_d(atomic_t *stat)
|
||||
{
|
||||
atomic_dec(stat);
|
||||
}
|
||||
|
||||
#define __fscache_stat(stat) (stat)
|
||||
|
||||
int fscache_stats_show(struct seq_file *m, void *v);
|
||||
#else
|
||||
|
||||
#define __fscache_stat(stat) (NULL)
|
||||
#define fscache_stat(stat) do {} while (0)
|
||||
#define fscache_stat_d(stat) do {} while (0)
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* debug tracing
|
||||
*/
|
||||
#define dbgprintk(FMT, ...) \
|
||||
printk("[%-6.6s] "FMT"\n", current->comm, ##__VA_ARGS__)
|
||||
|
||||
#define kenter(FMT, ...) dbgprintk("==> %s("FMT")", __func__, ##__VA_ARGS__)
|
||||
#define kleave(FMT, ...) dbgprintk("<== %s()"FMT"", __func__, ##__VA_ARGS__)
|
||||
#define kdebug(FMT, ...) dbgprintk(FMT, ##__VA_ARGS__)
|
||||
|
||||
#define kjournal(FMT, ...) no_printk(FMT, ##__VA_ARGS__)
|
||||
|
||||
#ifdef __KDEBUG
|
||||
#define _enter(FMT, ...) kenter(FMT, ##__VA_ARGS__)
|
||||
#define _leave(FMT, ...) kleave(FMT, ##__VA_ARGS__)
|
||||
#define _debug(FMT, ...) kdebug(FMT, ##__VA_ARGS__)
|
||||
|
||||
#elif defined(CONFIG_FSCACHE_DEBUG)
|
||||
#define _enter(FMT, ...) \
|
||||
do { \
|
||||
if (__do_kdebug(ENTER)) \
|
||||
kenter(FMT, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define _leave(FMT, ...) \
|
||||
do { \
|
||||
if (__do_kdebug(LEAVE)) \
|
||||
kleave(FMT, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define _debug(FMT, ...) \
|
||||
do { \
|
||||
if (__do_kdebug(DEBUG)) \
|
||||
kdebug(FMT, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
#define _enter(FMT, ...) no_printk("==> %s("FMT")", __func__, ##__VA_ARGS__)
|
||||
#define _leave(FMT, ...) no_printk("<== %s()"FMT"", __func__, ##__VA_ARGS__)
|
||||
#define _debug(FMT, ...) no_printk(FMT, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* determine whether a particular optional debugging point should be logged
|
||||
* - we need to go through three steps to persuade cpp to correctly join the
|
||||
* shorthand in FSCACHE_DEBUG_LEVEL with its prefix
|
||||
*/
|
||||
#define ____do_kdebug(LEVEL, POINT) \
|
||||
unlikely((fscache_debug & \
|
||||
(FSCACHE_POINT_##POINT << (FSCACHE_DEBUG_ ## LEVEL * 3))))
|
||||
#define ___do_kdebug(LEVEL, POINT) \
|
||||
____do_kdebug(LEVEL, POINT)
|
||||
#define __do_kdebug(POINT) \
|
||||
___do_kdebug(FSCACHE_DEBUG_LEVEL, POINT)
|
||||
|
||||
#define FSCACHE_DEBUG_CACHE 0
|
||||
#define FSCACHE_DEBUG_COOKIE 1
|
||||
#define FSCACHE_DEBUG_OBJECT 2
|
||||
#define FSCACHE_DEBUG_OPERATION 3
|
||||
|
||||
#define FSCACHE_POINT_ENTER 1
|
||||
#define FSCACHE_POINT_LEAVE 2
|
||||
#define FSCACHE_POINT_DEBUG 4
|
||||
|
||||
#ifndef FSCACHE_DEBUG_LEVEL
|
||||
#define FSCACHE_DEBUG_LEVEL CACHE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* assertions
|
||||
*/
|
||||
#if 1 /* defined(__KDEBUGALL) */
|
||||
|
||||
#define ASSERT(X) \
|
||||
do { \
|
||||
if (unlikely(!(X))) { \
|
||||
pr_err("\n"); \
|
||||
pr_err("Assertion failed\n"); \
|
||||
BUG(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERTCMP(X, OP, Y) \
|
||||
do { \
|
||||
if (unlikely(!((X) OP (Y)))) { \
|
||||
pr_err("\n"); \
|
||||
pr_err("Assertion failed\n"); \
|
||||
pr_err("%lx " #OP " %lx is false\n", \
|
||||
(unsigned long)(X), (unsigned long)(Y)); \
|
||||
BUG(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERTIF(C, X) \
|
||||
do { \
|
||||
if (unlikely((C) && !(X))) { \
|
||||
pr_err("\n"); \
|
||||
pr_err("Assertion failed\n"); \
|
||||
BUG(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERTIFCMP(C, X, OP, Y) \
|
||||
do { \
|
||||
if (unlikely((C) && !((X) OP (Y)))) { \
|
||||
pr_err("\n"); \
|
||||
pr_err("Assertion failed\n"); \
|
||||
pr_err("%lx " #OP " %lx is false\n", \
|
||||
(unsigned long)(X), (unsigned long)(Y)); \
|
||||
BUG(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
#define ASSERT(X) do {} while (0)
|
||||
#define ASSERTCMP(X, OP, Y) do {} while (0)
|
||||
#define ASSERTIF(C, X) do {} while (0)
|
||||
#define ASSERTIFCMP(C, X, OP, Y) do {} while (0)
|
||||
|
||||
#endif /* assert or not */
|
65
fs/fscache/main.c
Normal file
65
fs/fscache/main.c
Normal file
@ -0,0 +1,65 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* General filesystem local caching manager
|
||||
*
|
||||
* Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#define FSCACHE_DEBUG_LEVEL CACHE
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "internal.h"
|
||||
|
||||
MODULE_DESCRIPTION("FS Cache Manager");
|
||||
MODULE_AUTHOR("Red Hat, Inc.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
unsigned fscache_debug;
|
||||
module_param_named(debug, fscache_debug, uint,
|
||||
S_IWUSR | S_IRUGO);
|
||||
MODULE_PARM_DESC(fscache_debug,
|
||||
"FS-Cache debugging mask");
|
||||
|
||||
struct workqueue_struct *fscache_wq;
|
||||
EXPORT_SYMBOL(fscache_wq);
|
||||
|
||||
/*
|
||||
* initialise the fs caching module
|
||||
*/
|
||||
static int __init fscache_init(void)
|
||||
{
|
||||
int ret = -ENOMEM;
|
||||
|
||||
fscache_wq = alloc_workqueue("fscache", WQ_UNBOUND | WQ_FREEZABLE, 0);
|
||||
if (!fscache_wq)
|
||||
goto error_wq;
|
||||
|
||||
ret = fscache_proc_init();
|
||||
if (ret < 0)
|
||||
goto error_proc;
|
||||
|
||||
pr_notice("Loaded\n");
|
||||
return 0;
|
||||
|
||||
error_proc:
|
||||
destroy_workqueue(fscache_wq);
|
||||
error_wq:
|
||||
return ret;
|
||||
}
|
||||
|
||||
fs_initcall(fscache_init);
|
||||
|
||||
/*
|
||||
* clean up on module removal
|
||||
*/
|
||||
static void __exit fscache_exit(void)
|
||||
{
|
||||
_enter("");
|
||||
|
||||
fscache_proc_cleanup();
|
||||
destroy_workqueue(fscache_wq);
|
||||
pr_notice("Unloaded\n");
|
||||
}
|
||||
|
||||
module_exit(fscache_exit);
|
42
fs/fscache/proc.c
Normal file
42
fs/fscache/proc.c
Normal file
@ -0,0 +1,42 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* FS-Cache statistics viewing interface
|
||||
*
|
||||
* Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#define FSCACHE_DEBUG_LEVEL CACHE
|
||||
#include <linux/module.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* initialise the /proc/fs/fscache/ directory
|
||||
*/
|
||||
int __init fscache_proc_init(void)
|
||||
{
|
||||
if (!proc_mkdir("fs/fscache", NULL))
|
||||
goto error_dir;
|
||||
|
||||
#ifdef CONFIG_FSCACHE_STATS
|
||||
if (!proc_create_single("fs/fscache/stats", S_IFREG | 0444, NULL,
|
||||
fscache_stats_show))
|
||||
goto error;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
remove_proc_entry("fs/fscache", NULL);
|
||||
error_dir:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* clean up the /proc/fs/fscache/ directory
|
||||
*/
|
||||
void fscache_proc_cleanup(void)
|
||||
{
|
||||
remove_proc_subtree("fs/fscache", NULL);
|
||||
}
|
22
fs/fscache/stats.c
Normal file
22
fs/fscache/stats.c
Normal file
@ -0,0 +1,22 @@
|
||||
// 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"
|
||||
|
||||
/*
|
||||
* display the general statistics
|
||||
*/
|
||||
int fscache_stats_show(struct seq_file *m, void *v)
|
||||
{
|
||||
seq_puts(m, "FS-Cache statistics\n");
|
||||
|
||||
netfs_stats_show(m);
|
||||
return 0;
|
||||
}
|
@ -16,4 +16,6 @@
|
||||
|
||||
#include <linux/fscache.h>
|
||||
|
||||
extern struct workqueue_struct *fscache_wq;
|
||||
|
||||
#endif /* _LINUX_FSCACHE_CACHE_H */
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* General filesystem caching interface
|
||||
*
|
||||
* Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved.
|
||||
* Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* NOTE!!! See:
|
||||
@ -18,9 +18,13 @@
|
||||
#include <linux/netfs.h>
|
||||
|
||||
#if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE)
|
||||
#define __fscache_available (1)
|
||||
#define fscache_available() (1)
|
||||
#define fscache_cookie_valid(cookie) (cookie)
|
||||
#define fscache_cookie_enabled(cookie) (cookie)
|
||||
#else
|
||||
#define __fscache_available (0)
|
||||
#define fscache_available() (0)
|
||||
#define fscache_cookie_valid(cookie) (0)
|
||||
#define fscache_cookie_enabled(cookie) (0)
|
||||
#endif
|
||||
|
49
include/trace/events/fscache.h
Normal file
49
include/trace/events/fscache.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* FS-Cache tracepoints
|
||||
*
|
||||
* Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM fscache
|
||||
|
||||
#if !defined(_TRACE_FSCACHE_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define _TRACE_FSCACHE_H
|
||||
|
||||
#include <linux/fscache.h>
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
/*
|
||||
* Define enums for tracing information.
|
||||
*/
|
||||
#ifndef __FSCACHE_DECLARE_TRACE_ENUMS_ONCE_ONLY
|
||||
#define __FSCACHE_DECLARE_TRACE_ENUMS_ONCE_ONLY
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Declare tracing information enums and their string mappings for display.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Export enum symbols via userspace.
|
||||
*/
|
||||
#undef EM
|
||||
#undef E_
|
||||
#define EM(a, b) TRACE_DEFINE_ENUM(a);
|
||||
#define E_(a, b) TRACE_DEFINE_ENUM(a);
|
||||
|
||||
/*
|
||||
* Now redefine the EM() and E_() macros to map the enums to the strings that
|
||||
* will be printed in the output.
|
||||
*/
|
||||
#undef EM
|
||||
#undef E_
|
||||
#define EM(a, b) { a, b },
|
||||
#define E_(a, b) { a, b }
|
||||
|
||||
|
||||
#endif /* _TRACE_FSCACHE_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
#include <trace/define_trace.h>
|
Loading…
Reference in New Issue
Block a user