mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
cachefiles: Delete the cachefiles driver pending rewrite
Delete the code from the cachefiles driver to make it easier to rewrite and resubmit in a logical manner. 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/163819577641.215744.12718114397770666596.stgit@warthog.procyon.org.uk/ # v1 Link: https://lore.kernel.org/r/163906883770.143852.4149714614981373410.stgit@warthog.procyon.org.uk/ # v2 Link: https://lore.kernel.org/r/163967076066.1823006.7175712134577687753.stgit@warthog.procyon.org.uk/ # v3 Link: https://lore.kernel.org/r/164021483619.640689.7586546280515844702.stgit@warthog.procyon.org.uk/ # v4
This commit is contained in:
@@ -132,7 +132,6 @@ menu "Caches"
|
||||
|
||||
source "fs/netfs/Kconfig"
|
||||
source "fs/fscache/Kconfig"
|
||||
source "fs/cachefiles/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
|
||||
@@ -125,7 +125,6 @@ obj-$(CONFIG_AFS_FS) += afs/
|
||||
obj-$(CONFIG_NILFS2_FS) += nilfs2/
|
||||
obj-$(CONFIG_BEFS_FS) += befs/
|
||||
obj-$(CONFIG_HOSTFS) += hostfs/
|
||||
obj-$(CONFIG_CACHEFILES) += cachefiles/
|
||||
obj-$(CONFIG_DEBUG_FS) += debugfs/
|
||||
obj-$(CONFIG_TRACING) += tracefs/
|
||||
obj-$(CONFIG_OCFS2_FS) += ocfs2/
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
config CACHEFILES
|
||||
tristate "Filesystem caching on files"
|
||||
depends on FSCACHE && BLOCK
|
||||
help
|
||||
This permits use of a mounted filesystem as a cache for other
|
||||
filesystems - primarily networking filesystems - thus allowing fast
|
||||
local disk to enhance the speed of slower devices.
|
||||
|
||||
See Documentation/filesystems/caching/cachefiles.rst for more
|
||||
information.
|
||||
|
||||
config CACHEFILES_DEBUG
|
||||
bool "Debug CacheFiles"
|
||||
depends on CACHEFILES
|
||||
help
|
||||
This permits debugging to be dynamically enabled in the filesystem
|
||||
caching on files module. If this is set, the debugging output may be
|
||||
enabled by setting bits in /sys/modules/cachefiles/parameter/debug or
|
||||
by including a debugging specifier in /etc/cachefilesd.conf.
|
||||
@@ -1,18 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for caching in a mounted filesystem
|
||||
#
|
||||
|
||||
cachefiles-y := \
|
||||
bind.o \
|
||||
daemon.o \
|
||||
interface.o \
|
||||
io.o \
|
||||
key.o \
|
||||
main.o \
|
||||
namei.o \
|
||||
rdwr.o \
|
||||
security.o \
|
||||
xattr.o
|
||||
|
||||
obj-$(CONFIG_CACHEFILES) := cachefiles.o
|
||||
@@ -1,278 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* Bind and unbind a cache from the filesystem backing it
|
||||
*
|
||||
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/statfs.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/xattr.h>
|
||||
#include "internal.h"
|
||||
|
||||
static int cachefiles_daemon_add_cache(struct cachefiles_cache *caches);
|
||||
|
||||
/*
|
||||
* bind a directory as a cache
|
||||
*/
|
||||
int cachefiles_daemon_bind(struct cachefiles_cache *cache, char *args)
|
||||
{
|
||||
_enter("{%u,%u,%u,%u,%u,%u},%s",
|
||||
cache->frun_percent,
|
||||
cache->fcull_percent,
|
||||
cache->fstop_percent,
|
||||
cache->brun_percent,
|
||||
cache->bcull_percent,
|
||||
cache->bstop_percent,
|
||||
args);
|
||||
|
||||
/* start by checking things over */
|
||||
ASSERT(cache->fstop_percent >= 0 &&
|
||||
cache->fstop_percent < cache->fcull_percent &&
|
||||
cache->fcull_percent < cache->frun_percent &&
|
||||
cache->frun_percent < 100);
|
||||
|
||||
ASSERT(cache->bstop_percent >= 0 &&
|
||||
cache->bstop_percent < cache->bcull_percent &&
|
||||
cache->bcull_percent < cache->brun_percent &&
|
||||
cache->brun_percent < 100);
|
||||
|
||||
if (*args) {
|
||||
pr_err("'bind' command doesn't take an argument\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!cache->rootdirname) {
|
||||
pr_err("No cache directory specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* don't permit already bound caches to be re-bound */
|
||||
if (test_bit(CACHEFILES_READY, &cache->flags)) {
|
||||
pr_err("Cache already bound\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* make sure we have copies of the tag and dirname strings */
|
||||
if (!cache->tag) {
|
||||
/* the tag string is released by the fops->release()
|
||||
* function, so we don't release it on error here */
|
||||
cache->tag = kstrdup("CacheFiles", GFP_KERNEL);
|
||||
if (!cache->tag)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* add the cache */
|
||||
return cachefiles_daemon_add_cache(cache);
|
||||
}
|
||||
|
||||
/*
|
||||
* add a cache
|
||||
*/
|
||||
static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache)
|
||||
{
|
||||
struct cachefiles_object *fsdef;
|
||||
struct path path;
|
||||
struct kstatfs stats;
|
||||
struct dentry *graveyard, *cachedir, *root;
|
||||
const struct cred *saved_cred;
|
||||
int ret;
|
||||
|
||||
_enter("");
|
||||
|
||||
/* we want to work under the module's security ID */
|
||||
ret = cachefiles_get_security_ID(cache);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
cachefiles_begin_secure(cache, &saved_cred);
|
||||
|
||||
/* allocate the root index object */
|
||||
ret = -ENOMEM;
|
||||
|
||||
fsdef = kmem_cache_alloc(cachefiles_object_jar, GFP_KERNEL);
|
||||
if (!fsdef)
|
||||
goto error_root_object;
|
||||
|
||||
ASSERTCMP(fsdef->backer, ==, NULL);
|
||||
|
||||
atomic_set(&fsdef->usage, 1);
|
||||
fsdef->type = FSCACHE_COOKIE_TYPE_INDEX;
|
||||
|
||||
/* look up the directory at the root of the cache */
|
||||
ret = kern_path(cache->rootdirname, LOOKUP_DIRECTORY, &path);
|
||||
if (ret < 0)
|
||||
goto error_open_root;
|
||||
|
||||
cache->mnt = path.mnt;
|
||||
root = path.dentry;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (mnt_user_ns(path.mnt) != &init_user_ns) {
|
||||
pr_warn("File cache on idmapped mounts not supported");
|
||||
goto error_unsupported;
|
||||
}
|
||||
|
||||
/* check parameters */
|
||||
ret = -EOPNOTSUPP;
|
||||
if (d_is_negative(root) ||
|
||||
!d_backing_inode(root)->i_op->lookup ||
|
||||
!d_backing_inode(root)->i_op->mkdir ||
|
||||
!(d_backing_inode(root)->i_opflags & IOP_XATTR) ||
|
||||
!root->d_sb->s_op->statfs ||
|
||||
!root->d_sb->s_op->sync_fs)
|
||||
goto error_unsupported;
|
||||
|
||||
ret = -EROFS;
|
||||
if (sb_rdonly(root->d_sb))
|
||||
goto error_unsupported;
|
||||
|
||||
/* determine the security of the on-disk cache as this governs
|
||||
* security ID of files we create */
|
||||
ret = cachefiles_determine_cache_security(cache, root, &saved_cred);
|
||||
if (ret < 0)
|
||||
goto error_unsupported;
|
||||
|
||||
/* get the cache size and blocksize */
|
||||
ret = vfs_statfs(&path, &stats);
|
||||
if (ret < 0)
|
||||
goto error_unsupported;
|
||||
|
||||
ret = -ERANGE;
|
||||
if (stats.f_bsize <= 0)
|
||||
goto error_unsupported;
|
||||
|
||||
ret = -EOPNOTSUPP;
|
||||
if (stats.f_bsize > PAGE_SIZE)
|
||||
goto error_unsupported;
|
||||
|
||||
cache->bsize = stats.f_bsize;
|
||||
cache->bshift = 0;
|
||||
if (stats.f_bsize < PAGE_SIZE)
|
||||
cache->bshift = PAGE_SHIFT - ilog2(stats.f_bsize);
|
||||
|
||||
_debug("blksize %u (shift %u)",
|
||||
cache->bsize, cache->bshift);
|
||||
|
||||
_debug("size %llu, avail %llu",
|
||||
(unsigned long long) stats.f_blocks,
|
||||
(unsigned long long) stats.f_bavail);
|
||||
|
||||
/* set up caching limits */
|
||||
do_div(stats.f_files, 100);
|
||||
cache->fstop = stats.f_files * cache->fstop_percent;
|
||||
cache->fcull = stats.f_files * cache->fcull_percent;
|
||||
cache->frun = stats.f_files * cache->frun_percent;
|
||||
|
||||
_debug("limits {%llu,%llu,%llu} files",
|
||||
(unsigned long long) cache->frun,
|
||||
(unsigned long long) cache->fcull,
|
||||
(unsigned long long) cache->fstop);
|
||||
|
||||
stats.f_blocks >>= cache->bshift;
|
||||
do_div(stats.f_blocks, 100);
|
||||
cache->bstop = stats.f_blocks * cache->bstop_percent;
|
||||
cache->bcull = stats.f_blocks * cache->bcull_percent;
|
||||
cache->brun = stats.f_blocks * cache->brun_percent;
|
||||
|
||||
_debug("limits {%llu,%llu,%llu} blocks",
|
||||
(unsigned long long) cache->brun,
|
||||
(unsigned long long) cache->bcull,
|
||||
(unsigned long long) cache->bstop);
|
||||
|
||||
/* get the cache directory and check its type */
|
||||
cachedir = cachefiles_get_directory(cache, root, "cache");
|
||||
if (IS_ERR(cachedir)) {
|
||||
ret = PTR_ERR(cachedir);
|
||||
goto error_unsupported;
|
||||
}
|
||||
|
||||
fsdef->dentry = cachedir;
|
||||
fsdef->fscache.cookie = NULL;
|
||||
|
||||
ret = cachefiles_check_object_type(fsdef);
|
||||
if (ret < 0)
|
||||
goto error_unsupported;
|
||||
|
||||
/* get the graveyard directory */
|
||||
graveyard = cachefiles_get_directory(cache, root, "graveyard");
|
||||
if (IS_ERR(graveyard)) {
|
||||
ret = PTR_ERR(graveyard);
|
||||
goto error_unsupported;
|
||||
}
|
||||
|
||||
cache->graveyard = graveyard;
|
||||
|
||||
/* publish the cache */
|
||||
fscache_init_cache(&cache->cache,
|
||||
&cachefiles_cache_ops,
|
||||
"%s",
|
||||
fsdef->dentry->d_sb->s_id);
|
||||
|
||||
fscache_object_init(&fsdef->fscache, &fscache_fsdef_index,
|
||||
&cache->cache);
|
||||
|
||||
ret = fscache_add_cache(&cache->cache, &fsdef->fscache, cache->tag);
|
||||
if (ret < 0)
|
||||
goto error_add_cache;
|
||||
|
||||
/* done */
|
||||
set_bit(CACHEFILES_READY, &cache->flags);
|
||||
dput(root);
|
||||
|
||||
pr_info("File cache on %s registered\n", cache->cache.identifier);
|
||||
|
||||
/* check how much space the cache has */
|
||||
cachefiles_has_space(cache, 0, 0);
|
||||
cachefiles_end_secure(cache, saved_cred);
|
||||
return 0;
|
||||
|
||||
error_add_cache:
|
||||
dput(cache->graveyard);
|
||||
cache->graveyard = NULL;
|
||||
error_unsupported:
|
||||
mntput(cache->mnt);
|
||||
cache->mnt = NULL;
|
||||
dput(fsdef->dentry);
|
||||
fsdef->dentry = NULL;
|
||||
dput(root);
|
||||
error_open_root:
|
||||
kmem_cache_free(cachefiles_object_jar, fsdef);
|
||||
error_root_object:
|
||||
cachefiles_end_secure(cache, saved_cred);
|
||||
pr_err("Failed to register: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* unbind a cache on fd release
|
||||
*/
|
||||
void cachefiles_daemon_unbind(struct cachefiles_cache *cache)
|
||||
{
|
||||
_enter("");
|
||||
|
||||
if (test_bit(CACHEFILES_READY, &cache->flags)) {
|
||||
pr_info("File cache on %s unregistering\n",
|
||||
cache->cache.identifier);
|
||||
|
||||
fscache_withdraw_cache(&cache->cache);
|
||||
}
|
||||
|
||||
dput(cache->graveyard);
|
||||
mntput(cache->mnt);
|
||||
|
||||
kfree(cache->rootdirname);
|
||||
kfree(cache->secctx);
|
||||
kfree(cache->tag);
|
||||
|
||||
_leave("");
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,350 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* General netfs cache on cache files internal defs
|
||||
*
|
||||
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#ifdef pr_fmt
|
||||
#undef pr_fmt
|
||||
#endif
|
||||
|
||||
#define pr_fmt(fmt) "CacheFiles: " fmt
|
||||
|
||||
|
||||
#include <linux/fscache-cache.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/wait_bit.h>
|
||||
#include <linux/cred.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/security.h>
|
||||
|
||||
struct cachefiles_cache;
|
||||
struct cachefiles_object;
|
||||
|
||||
extern unsigned cachefiles_debug;
|
||||
#define CACHEFILES_DEBUG_KENTER 1
|
||||
#define CACHEFILES_DEBUG_KLEAVE 2
|
||||
#define CACHEFILES_DEBUG_KDEBUG 4
|
||||
|
||||
#define cachefiles_gfp (__GFP_RECLAIM | __GFP_NORETRY | __GFP_NOMEMALLOC)
|
||||
|
||||
/*
|
||||
* node records
|
||||
*/
|
||||
struct cachefiles_object {
|
||||
struct fscache_object fscache; /* fscache handle */
|
||||
struct cachefiles_lookup_data *lookup_data; /* cached lookup data */
|
||||
struct dentry *dentry; /* the file/dir representing this object */
|
||||
struct dentry *backer; /* backing file */
|
||||
loff_t i_size; /* object size */
|
||||
unsigned long flags;
|
||||
#define CACHEFILES_OBJECT_ACTIVE 0 /* T if marked active */
|
||||
atomic_t usage; /* object usage count */
|
||||
uint8_t type; /* object type */
|
||||
uint8_t new; /* T if object new */
|
||||
spinlock_t work_lock;
|
||||
struct rb_node active_node; /* link in active tree (dentry is key) */
|
||||
};
|
||||
|
||||
extern struct kmem_cache *cachefiles_object_jar;
|
||||
|
||||
/*
|
||||
* Cache files cache definition
|
||||
*/
|
||||
struct cachefiles_cache {
|
||||
struct fscache_cache cache; /* FS-Cache record */
|
||||
struct vfsmount *mnt; /* mountpoint holding the cache */
|
||||
struct dentry *graveyard; /* directory into which dead objects go */
|
||||
struct file *cachefilesd; /* manager daemon handle */
|
||||
const struct cred *cache_cred; /* security override for accessing cache */
|
||||
struct mutex daemon_mutex; /* command serialisation mutex */
|
||||
wait_queue_head_t daemon_pollwq; /* poll waitqueue for daemon */
|
||||
struct rb_root active_nodes; /* active nodes (can't be culled) */
|
||||
rwlock_t active_lock; /* lock for active_nodes */
|
||||
atomic_t gravecounter; /* graveyard uniquifier */
|
||||
atomic_t f_released; /* number of objects released lately */
|
||||
atomic_long_t b_released; /* number of blocks released lately */
|
||||
unsigned frun_percent; /* when to stop culling (% files) */
|
||||
unsigned fcull_percent; /* when to start culling (% files) */
|
||||
unsigned fstop_percent; /* when to stop allocating (% files) */
|
||||
unsigned brun_percent; /* when to stop culling (% blocks) */
|
||||
unsigned bcull_percent; /* when to start culling (% blocks) */
|
||||
unsigned bstop_percent; /* when to stop allocating (% blocks) */
|
||||
unsigned bsize; /* cache's block size */
|
||||
unsigned bshift; /* min(ilog2(PAGE_SIZE / bsize), 0) */
|
||||
uint64_t frun; /* when to stop culling */
|
||||
uint64_t fcull; /* when to start culling */
|
||||
uint64_t fstop; /* when to stop allocating */
|
||||
sector_t brun; /* when to stop culling */
|
||||
sector_t bcull; /* when to start culling */
|
||||
sector_t bstop; /* when to stop allocating */
|
||||
unsigned long flags;
|
||||
#define CACHEFILES_READY 0 /* T if cache prepared */
|
||||
#define CACHEFILES_DEAD 1 /* T if cache dead */
|
||||
#define CACHEFILES_CULLING 2 /* T if cull engaged */
|
||||
#define CACHEFILES_STATE_CHANGED 3 /* T if state changed (poll trigger) */
|
||||
char *rootdirname; /* name of cache root directory */
|
||||
char *secctx; /* LSM security context */
|
||||
char *tag; /* cache binding tag */
|
||||
};
|
||||
|
||||
/*
|
||||
* backing file read tracking
|
||||
*/
|
||||
struct cachefiles_one_read {
|
||||
wait_queue_entry_t monitor; /* link into monitored waitqueue */
|
||||
struct page *back_page; /* backing file page we're waiting for */
|
||||
struct page *netfs_page; /* netfs page we're going to fill */
|
||||
struct fscache_retrieval *op; /* retrieval op covering this */
|
||||
struct list_head op_link; /* link in op's todo list */
|
||||
};
|
||||
|
||||
/*
|
||||
* backing file write tracking
|
||||
*/
|
||||
struct cachefiles_one_write {
|
||||
struct page *netfs_page; /* netfs page to copy */
|
||||
struct cachefiles_object *object;
|
||||
struct list_head obj_link; /* link in object's lists */
|
||||
fscache_rw_complete_t end_io_func;
|
||||
void *context;
|
||||
};
|
||||
|
||||
/*
|
||||
* auxiliary data xattr buffer
|
||||
*/
|
||||
struct cachefiles_xattr {
|
||||
uint16_t len;
|
||||
uint8_t type;
|
||||
uint8_t data[];
|
||||
};
|
||||
|
||||
#include <trace/events/cachefiles.h>
|
||||
|
||||
/*
|
||||
* note change of state for daemon
|
||||
*/
|
||||
static inline void cachefiles_state_changed(struct cachefiles_cache *cache)
|
||||
{
|
||||
set_bit(CACHEFILES_STATE_CHANGED, &cache->flags);
|
||||
wake_up_all(&cache->daemon_pollwq);
|
||||
}
|
||||
|
||||
/*
|
||||
* bind.c
|
||||
*/
|
||||
extern int cachefiles_daemon_bind(struct cachefiles_cache *cache, char *args);
|
||||
extern void cachefiles_daemon_unbind(struct cachefiles_cache *cache);
|
||||
|
||||
/*
|
||||
* daemon.c
|
||||
*/
|
||||
extern const struct file_operations cachefiles_daemon_fops;
|
||||
|
||||
extern int cachefiles_has_space(struct cachefiles_cache *cache,
|
||||
unsigned fnr, unsigned bnr);
|
||||
|
||||
/*
|
||||
* interface.c
|
||||
*/
|
||||
extern const struct fscache_cache_ops cachefiles_cache_ops;
|
||||
|
||||
void cachefiles_put_object(struct fscache_object *_object,
|
||||
enum fscache_obj_ref_trace why);
|
||||
|
||||
/*
|
||||
* key.c
|
||||
*/
|
||||
extern char *cachefiles_cook_key(const u8 *raw, int keylen, uint8_t type);
|
||||
|
||||
/*
|
||||
* namei.c
|
||||
*/
|
||||
extern void cachefiles_mark_object_inactive(struct cachefiles_cache *cache,
|
||||
struct cachefiles_object *object,
|
||||
blkcnt_t i_blocks);
|
||||
extern int cachefiles_delete_object(struct cachefiles_cache *cache,
|
||||
struct cachefiles_object *object);
|
||||
extern int cachefiles_walk_to_object(struct cachefiles_object *parent,
|
||||
struct cachefiles_object *object,
|
||||
const char *key,
|
||||
struct cachefiles_xattr *auxdata);
|
||||
extern struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
|
||||
struct dentry *dir,
|
||||
const char *name);
|
||||
|
||||
extern int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir,
|
||||
char *filename);
|
||||
|
||||
extern int cachefiles_check_in_use(struct cachefiles_cache *cache,
|
||||
struct dentry *dir, char *filename);
|
||||
|
||||
/*
|
||||
* rdwr.c
|
||||
*/
|
||||
extern int cachefiles_read_or_alloc_page(struct fscache_retrieval *,
|
||||
struct page *, gfp_t);
|
||||
extern int cachefiles_read_or_alloc_pages(struct fscache_retrieval *,
|
||||
struct list_head *, unsigned *,
|
||||
gfp_t);
|
||||
extern int cachefiles_allocate_page(struct fscache_retrieval *, struct page *,
|
||||
gfp_t);
|
||||
extern int cachefiles_allocate_pages(struct fscache_retrieval *,
|
||||
struct list_head *, unsigned *, gfp_t);
|
||||
extern int cachefiles_write_page(struct fscache_storage *, struct page *);
|
||||
extern void cachefiles_uncache_page(struct fscache_object *, struct page *);
|
||||
|
||||
/*
|
||||
* rdwr2.c
|
||||
*/
|
||||
extern int cachefiles_begin_read_operation(struct netfs_read_request *,
|
||||
struct fscache_retrieval *);
|
||||
|
||||
/*
|
||||
* security.c
|
||||
*/
|
||||
extern int cachefiles_get_security_ID(struct cachefiles_cache *cache);
|
||||
extern int cachefiles_determine_cache_security(struct cachefiles_cache *cache,
|
||||
struct dentry *root,
|
||||
const struct cred **_saved_cred);
|
||||
|
||||
static inline void cachefiles_begin_secure(struct cachefiles_cache *cache,
|
||||
const struct cred **_saved_cred)
|
||||
{
|
||||
*_saved_cred = override_creds(cache->cache_cred);
|
||||
}
|
||||
|
||||
static inline void cachefiles_end_secure(struct cachefiles_cache *cache,
|
||||
const struct cred *saved_cred)
|
||||
{
|
||||
revert_creds(saved_cred);
|
||||
}
|
||||
|
||||
/*
|
||||
* xattr.c
|
||||
*/
|
||||
extern int cachefiles_check_object_type(struct cachefiles_object *object);
|
||||
extern int cachefiles_set_object_xattr(struct cachefiles_object *object,
|
||||
struct cachefiles_xattr *auxdata);
|
||||
extern int cachefiles_update_object_xattr(struct cachefiles_object *object,
|
||||
struct cachefiles_xattr *auxdata);
|
||||
extern int cachefiles_check_auxdata(struct cachefiles_object *object);
|
||||
extern int cachefiles_check_object_xattr(struct cachefiles_object *object,
|
||||
struct cachefiles_xattr *auxdata);
|
||||
extern int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
|
||||
struct dentry *dentry);
|
||||
|
||||
|
||||
/*
|
||||
* error handling
|
||||
*/
|
||||
|
||||
#define cachefiles_io_error(___cache, FMT, ...) \
|
||||
do { \
|
||||
pr_err("I/O Error: " FMT"\n", ##__VA_ARGS__); \
|
||||
fscache_io_error(&(___cache)->cache); \
|
||||
set_bit(CACHEFILES_DEAD, &(___cache)->flags); \
|
||||
} while (0)
|
||||
|
||||
#define cachefiles_io_error_obj(object, FMT, ...) \
|
||||
do { \
|
||||
struct cachefiles_cache *___cache; \
|
||||
\
|
||||
___cache = container_of((object)->fscache.cache, \
|
||||
struct cachefiles_cache, cache); \
|
||||
cachefiles_io_error(___cache, FMT, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/*
|
||||
* debug tracing
|
||||
*/
|
||||
#define dbgprintk(FMT, ...) \
|
||||
printk(KERN_DEBUG "[%-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__)
|
||||
|
||||
|
||||
#if defined(__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_CACHEFILES_DEBUG)
|
||||
#define _enter(FMT, ...) \
|
||||
do { \
|
||||
if (cachefiles_debug & CACHEFILES_DEBUG_KENTER) \
|
||||
kenter(FMT, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define _leave(FMT, ...) \
|
||||
do { \
|
||||
if (cachefiles_debug & CACHEFILES_DEBUG_KLEAVE) \
|
||||
kleave(FMT, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define _debug(FMT, ...) \
|
||||
do { \
|
||||
if (cachefiles_debug & CACHEFILES_DEBUG_KDEBUG) \
|
||||
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
|
||||
|
||||
#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
|
||||
@@ -1,420 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* kiocb-using read/write
|
||||
*
|
||||
* Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#include <linux/mount.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/sched/mm.h>
|
||||
#include <linux/netfs.h>
|
||||
#include "internal.h"
|
||||
|
||||
struct cachefiles_kiocb {
|
||||
struct kiocb iocb;
|
||||
refcount_t ki_refcnt;
|
||||
loff_t start;
|
||||
union {
|
||||
size_t skipped;
|
||||
size_t len;
|
||||
};
|
||||
netfs_io_terminated_t term_func;
|
||||
void *term_func_priv;
|
||||
bool was_async;
|
||||
};
|
||||
|
||||
static inline void cachefiles_put_kiocb(struct cachefiles_kiocb *ki)
|
||||
{
|
||||
if (refcount_dec_and_test(&ki->ki_refcnt)) {
|
||||
fput(ki->iocb.ki_filp);
|
||||
kfree(ki);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle completion of a read from the cache.
|
||||
*/
|
||||
static void cachefiles_read_complete(struct kiocb *iocb, long ret)
|
||||
{
|
||||
struct cachefiles_kiocb *ki = container_of(iocb, struct cachefiles_kiocb, iocb);
|
||||
|
||||
_enter("%ld", ret);
|
||||
|
||||
if (ki->term_func) {
|
||||
if (ret >= 0)
|
||||
ret += ki->skipped;
|
||||
ki->term_func(ki->term_func_priv, ret, ki->was_async);
|
||||
}
|
||||
|
||||
cachefiles_put_kiocb(ki);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initiate a read from the cache.
|
||||
*/
|
||||
static int cachefiles_read(struct netfs_cache_resources *cres,
|
||||
loff_t start_pos,
|
||||
struct iov_iter *iter,
|
||||
bool seek_data,
|
||||
netfs_io_terminated_t term_func,
|
||||
void *term_func_priv)
|
||||
{
|
||||
struct cachefiles_kiocb *ki;
|
||||
struct file *file = cres->cache_priv2;
|
||||
unsigned int old_nofs;
|
||||
ssize_t ret = -ENOBUFS;
|
||||
size_t len = iov_iter_count(iter), skipped = 0;
|
||||
|
||||
_enter("%pD,%li,%llx,%zx/%llx",
|
||||
file, file_inode(file)->i_ino, start_pos, len,
|
||||
i_size_read(file_inode(file)));
|
||||
|
||||
/* If the caller asked us to seek for data before doing the read, then
|
||||
* we should do that now. If we find a gap, we fill it with zeros.
|
||||
*/
|
||||
if (seek_data) {
|
||||
loff_t off = start_pos, off2;
|
||||
|
||||
off2 = vfs_llseek(file, off, SEEK_DATA);
|
||||
if (off2 < 0 && off2 >= (loff_t)-MAX_ERRNO && off2 != -ENXIO) {
|
||||
skipped = 0;
|
||||
ret = off2;
|
||||
goto presubmission_error;
|
||||
}
|
||||
|
||||
if (off2 == -ENXIO || off2 >= start_pos + len) {
|
||||
/* The region is beyond the EOF or there's no more data
|
||||
* in the region, so clear the rest of the buffer and
|
||||
* return success.
|
||||
*/
|
||||
iov_iter_zero(len, iter);
|
||||
skipped = len;
|
||||
ret = 0;
|
||||
goto presubmission_error;
|
||||
}
|
||||
|
||||
skipped = off2 - off;
|
||||
iov_iter_zero(skipped, iter);
|
||||
}
|
||||
|
||||
ret = -ENOBUFS;
|
||||
ki = kzalloc(sizeof(struct cachefiles_kiocb), GFP_KERNEL);
|
||||
if (!ki)
|
||||
goto presubmission_error;
|
||||
|
||||
refcount_set(&ki->ki_refcnt, 2);
|
||||
ki->iocb.ki_filp = file;
|
||||
ki->iocb.ki_pos = start_pos + skipped;
|
||||
ki->iocb.ki_flags = IOCB_DIRECT;
|
||||
ki->iocb.ki_hint = ki_hint_validate(file_write_hint(file));
|
||||
ki->iocb.ki_ioprio = get_current_ioprio();
|
||||
ki->skipped = skipped;
|
||||
ki->term_func = term_func;
|
||||
ki->term_func_priv = term_func_priv;
|
||||
ki->was_async = true;
|
||||
|
||||
if (ki->term_func)
|
||||
ki->iocb.ki_complete = cachefiles_read_complete;
|
||||
|
||||
get_file(ki->iocb.ki_filp);
|
||||
|
||||
old_nofs = memalloc_nofs_save();
|
||||
ret = vfs_iocb_iter_read(file, &ki->iocb, iter);
|
||||
memalloc_nofs_restore(old_nofs);
|
||||
switch (ret) {
|
||||
case -EIOCBQUEUED:
|
||||
goto in_progress;
|
||||
|
||||
case -ERESTARTSYS:
|
||||
case -ERESTARTNOINTR:
|
||||
case -ERESTARTNOHAND:
|
||||
case -ERESTART_RESTARTBLOCK:
|
||||
/* There's no easy way to restart the syscall since other AIO's
|
||||
* may be already running. Just fail this IO with EINTR.
|
||||
*/
|
||||
ret = -EINTR;
|
||||
fallthrough;
|
||||
default:
|
||||
ki->was_async = false;
|
||||
cachefiles_read_complete(&ki->iocb, ret);
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
in_progress:
|
||||
cachefiles_put_kiocb(ki);
|
||||
_leave(" = %zd", ret);
|
||||
return ret;
|
||||
|
||||
presubmission_error:
|
||||
if (term_func)
|
||||
term_func(term_func_priv, ret < 0 ? ret : skipped, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle completion of a write to the cache.
|
||||
*/
|
||||
static void cachefiles_write_complete(struct kiocb *iocb, long ret)
|
||||
{
|
||||
struct cachefiles_kiocb *ki = container_of(iocb, struct cachefiles_kiocb, iocb);
|
||||
struct inode *inode = file_inode(ki->iocb.ki_filp);
|
||||
|
||||
_enter("%ld", ret);
|
||||
|
||||
/* Tell lockdep we inherited freeze protection from submission thread */
|
||||
__sb_writers_acquired(inode->i_sb, SB_FREEZE_WRITE);
|
||||
__sb_end_write(inode->i_sb, SB_FREEZE_WRITE);
|
||||
|
||||
if (ki->term_func)
|
||||
ki->term_func(ki->term_func_priv, ret, ki->was_async);
|
||||
|
||||
cachefiles_put_kiocb(ki);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initiate a write to the cache.
|
||||
*/
|
||||
static int cachefiles_write(struct netfs_cache_resources *cres,
|
||||
loff_t start_pos,
|
||||
struct iov_iter *iter,
|
||||
netfs_io_terminated_t term_func,
|
||||
void *term_func_priv)
|
||||
{
|
||||
struct cachefiles_kiocb *ki;
|
||||
struct inode *inode;
|
||||
struct file *file = cres->cache_priv2;
|
||||
unsigned int old_nofs;
|
||||
ssize_t ret = -ENOBUFS;
|
||||
size_t len = iov_iter_count(iter);
|
||||
|
||||
_enter("%pD,%li,%llx,%zx/%llx",
|
||||
file, file_inode(file)->i_ino, start_pos, len,
|
||||
i_size_read(file_inode(file)));
|
||||
|
||||
ki = kzalloc(sizeof(struct cachefiles_kiocb), GFP_KERNEL);
|
||||
if (!ki)
|
||||
goto presubmission_error;
|
||||
|
||||
refcount_set(&ki->ki_refcnt, 2);
|
||||
ki->iocb.ki_filp = file;
|
||||
ki->iocb.ki_pos = start_pos;
|
||||
ki->iocb.ki_flags = IOCB_DIRECT | IOCB_WRITE;
|
||||
ki->iocb.ki_hint = ki_hint_validate(file_write_hint(file));
|
||||
ki->iocb.ki_ioprio = get_current_ioprio();
|
||||
ki->start = start_pos;
|
||||
ki->len = len;
|
||||
ki->term_func = term_func;
|
||||
ki->term_func_priv = term_func_priv;
|
||||
ki->was_async = true;
|
||||
|
||||
if (ki->term_func)
|
||||
ki->iocb.ki_complete = cachefiles_write_complete;
|
||||
|
||||
/* Open-code file_start_write here to grab freeze protection, which
|
||||
* will be released by another thread in aio_complete_rw(). Fool
|
||||
* lockdep by telling it the lock got released so that it doesn't
|
||||
* complain about the held lock when we return to userspace.
|
||||
*/
|
||||
inode = file_inode(file);
|
||||
__sb_start_write(inode->i_sb, SB_FREEZE_WRITE);
|
||||
__sb_writers_release(inode->i_sb, SB_FREEZE_WRITE);
|
||||
|
||||
get_file(ki->iocb.ki_filp);
|
||||
|
||||
old_nofs = memalloc_nofs_save();
|
||||
ret = vfs_iocb_iter_write(file, &ki->iocb, iter);
|
||||
memalloc_nofs_restore(old_nofs);
|
||||
switch (ret) {
|
||||
case -EIOCBQUEUED:
|
||||
goto in_progress;
|
||||
|
||||
case -ERESTARTSYS:
|
||||
case -ERESTARTNOINTR:
|
||||
case -ERESTARTNOHAND:
|
||||
case -ERESTART_RESTARTBLOCK:
|
||||
/* There's no easy way to restart the syscall since other AIO's
|
||||
* may be already running. Just fail this IO with EINTR.
|
||||
*/
|
||||
ret = -EINTR;
|
||||
fallthrough;
|
||||
default:
|
||||
ki->was_async = false;
|
||||
cachefiles_write_complete(&ki->iocb, ret);
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
in_progress:
|
||||
cachefiles_put_kiocb(ki);
|
||||
_leave(" = %zd", ret);
|
||||
return ret;
|
||||
|
||||
presubmission_error:
|
||||
if (term_func)
|
||||
term_func(term_func_priv, -ENOMEM, false);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare a read operation, shortening it to a cached/uncached
|
||||
* boundary as appropriate.
|
||||
*/
|
||||
static enum netfs_read_source cachefiles_prepare_read(struct netfs_read_subrequest *subreq,
|
||||
loff_t i_size)
|
||||
{
|
||||
struct fscache_retrieval *op = subreq->rreq->cache_resources.cache_priv;
|
||||
struct cachefiles_object *object;
|
||||
struct cachefiles_cache *cache;
|
||||
const struct cred *saved_cred;
|
||||
struct file *file = subreq->rreq->cache_resources.cache_priv2;
|
||||
loff_t off, to;
|
||||
|
||||
_enter("%zx @%llx/%llx", subreq->len, subreq->start, i_size);
|
||||
|
||||
object = container_of(op->op.object,
|
||||
struct cachefiles_object, fscache);
|
||||
cache = container_of(object->fscache.cache,
|
||||
struct cachefiles_cache, cache);
|
||||
|
||||
if (!file)
|
||||
goto cache_fail_nosec;
|
||||
|
||||
if (subreq->start >= i_size)
|
||||
return NETFS_FILL_WITH_ZEROES;
|
||||
|
||||
cachefiles_begin_secure(cache, &saved_cred);
|
||||
|
||||
off = vfs_llseek(file, subreq->start, SEEK_DATA);
|
||||
if (off < 0 && off >= (loff_t)-MAX_ERRNO) {
|
||||
if (off == (loff_t)-ENXIO)
|
||||
goto download_and_store;
|
||||
goto cache_fail;
|
||||
}
|
||||
|
||||
if (off >= subreq->start + subreq->len)
|
||||
goto download_and_store;
|
||||
|
||||
if (off > subreq->start) {
|
||||
off = round_up(off, cache->bsize);
|
||||
subreq->len = off - subreq->start;
|
||||
goto download_and_store;
|
||||
}
|
||||
|
||||
to = vfs_llseek(file, subreq->start, SEEK_HOLE);
|
||||
if (to < 0 && to >= (loff_t)-MAX_ERRNO)
|
||||
goto cache_fail;
|
||||
|
||||
if (to < subreq->start + subreq->len) {
|
||||
if (subreq->start + subreq->len >= i_size)
|
||||
to = round_up(to, cache->bsize);
|
||||
else
|
||||
to = round_down(to, cache->bsize);
|
||||
subreq->len = to - subreq->start;
|
||||
}
|
||||
|
||||
cachefiles_end_secure(cache, saved_cred);
|
||||
return NETFS_READ_FROM_CACHE;
|
||||
|
||||
download_and_store:
|
||||
if (cachefiles_has_space(cache, 0, (subreq->len + PAGE_SIZE - 1) / PAGE_SIZE) == 0)
|
||||
__set_bit(NETFS_SREQ_WRITE_TO_CACHE, &subreq->flags);
|
||||
cache_fail:
|
||||
cachefiles_end_secure(cache, saved_cred);
|
||||
cache_fail_nosec:
|
||||
return NETFS_DOWNLOAD_FROM_SERVER;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare for a write to occur.
|
||||
*/
|
||||
static int cachefiles_prepare_write(struct netfs_cache_resources *cres,
|
||||
loff_t *_start, size_t *_len, loff_t i_size)
|
||||
{
|
||||
loff_t start = *_start;
|
||||
size_t len = *_len, down;
|
||||
|
||||
/* Round to DIO size */
|
||||
down = start - round_down(start, PAGE_SIZE);
|
||||
*_start = start - down;
|
||||
*_len = round_up(down + len, PAGE_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up an operation.
|
||||
*/
|
||||
static void cachefiles_end_operation(struct netfs_cache_resources *cres)
|
||||
{
|
||||
struct fscache_retrieval *op = cres->cache_priv;
|
||||
struct file *file = cres->cache_priv2;
|
||||
|
||||
_enter("");
|
||||
|
||||
if (file)
|
||||
fput(file);
|
||||
if (op) {
|
||||
fscache_op_complete(&op->op, false);
|
||||
fscache_put_retrieval(op);
|
||||
}
|
||||
|
||||
_leave("");
|
||||
}
|
||||
|
||||
static const struct netfs_cache_ops cachefiles_netfs_cache_ops = {
|
||||
.end_operation = cachefiles_end_operation,
|
||||
.read = cachefiles_read,
|
||||
.write = cachefiles_write,
|
||||
.prepare_read = cachefiles_prepare_read,
|
||||
.prepare_write = cachefiles_prepare_write,
|
||||
};
|
||||
|
||||
/*
|
||||
* Open the cache file when beginning a cache operation.
|
||||
*/
|
||||
int cachefiles_begin_read_operation(struct netfs_read_request *rreq,
|
||||
struct fscache_retrieval *op)
|
||||
{
|
||||
struct cachefiles_object *object;
|
||||
struct cachefiles_cache *cache;
|
||||
struct path path;
|
||||
struct file *file;
|
||||
|
||||
_enter("");
|
||||
|
||||
object = container_of(op->op.object,
|
||||
struct cachefiles_object, fscache);
|
||||
cache = container_of(object->fscache.cache,
|
||||
struct cachefiles_cache, cache);
|
||||
|
||||
path.mnt = cache->mnt;
|
||||
path.dentry = object->backer;
|
||||
file = open_with_fake_path(&path, O_RDWR | O_LARGEFILE | O_DIRECT,
|
||||
d_inode(object->backer), cache->cache_cred);
|
||||
if (IS_ERR(file))
|
||||
return PTR_ERR(file);
|
||||
if (!S_ISREG(file_inode(file)->i_mode))
|
||||
goto error_file;
|
||||
if (unlikely(!file->f_op->read_iter) ||
|
||||
unlikely(!file->f_op->write_iter)) {
|
||||
pr_notice("Cache does not support read_iter and write_iter\n");
|
||||
goto error_file;
|
||||
}
|
||||
|
||||
fscache_get_retrieval(op);
|
||||
rreq->cache_resources.cache_priv = op;
|
||||
rreq->cache_resources.cache_priv2 = file;
|
||||
rreq->cache_resources.ops = &cachefiles_netfs_cache_ops;
|
||||
rreq->cache_resources.debug_id = object->fscache.debug_id;
|
||||
_leave("");
|
||||
return 0;
|
||||
|
||||
error_file:
|
||||
fput(file);
|
||||
return -EIO;
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* Key to pathname encoder
|
||||
*
|
||||
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include "internal.h"
|
||||
|
||||
static const char cachefiles_charmap[64] =
|
||||
"0123456789" /* 0 - 9 */
|
||||
"abcdefghijklmnopqrstuvwxyz" /* 10 - 35 */
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* 36 - 61 */
|
||||
"_-" /* 62 - 63 */
|
||||
;
|
||||
|
||||
static const char cachefiles_filecharmap[256] = {
|
||||
/* we skip space and tab and control chars */
|
||||
[33 ... 46] = 1, /* '!' -> '.' */
|
||||
/* we skip '/' as it's significant to pathwalk */
|
||||
[48 ... 127] = 1, /* '0' -> '~' */
|
||||
};
|
||||
|
||||
/*
|
||||
* turn the raw key into something cooked
|
||||
* - the raw key should include the length in the two bytes at the front
|
||||
* - the key may be up to 514 bytes in length (including the length word)
|
||||
* - "base64" encode the strange keys, mapping 3 bytes of raw to four of
|
||||
* cooked
|
||||
* - need to cut the cooked key into 252 char lengths (189 raw bytes)
|
||||
*/
|
||||
char *cachefiles_cook_key(const u8 *raw, int keylen, uint8_t type)
|
||||
{
|
||||
unsigned char csum, ch;
|
||||
unsigned int acc;
|
||||
char *key;
|
||||
int loop, len, max, seg, mark, print;
|
||||
|
||||
_enter(",%d", keylen);
|
||||
|
||||
BUG_ON(keylen < 2 || keylen > 514);
|
||||
|
||||
csum = raw[0] + raw[1];
|
||||
print = 1;
|
||||
for (loop = 2; loop < keylen; loop++) {
|
||||
ch = raw[loop];
|
||||
csum += ch;
|
||||
print &= cachefiles_filecharmap[ch];
|
||||
}
|
||||
|
||||
if (print) {
|
||||
/* if the path is usable ASCII, then we render it directly */
|
||||
max = keylen - 2;
|
||||
max += 2; /* two base64'd length chars on the front */
|
||||
max += 5; /* @checksum/M */
|
||||
max += 3 * 2; /* maximum number of segment dividers (".../M")
|
||||
* is ((514 + 251) / 252) = 3
|
||||
*/
|
||||
max += 1; /* NUL on end */
|
||||
} else {
|
||||
/* calculate the maximum length of the cooked key */
|
||||
keylen = (keylen + 2) / 3;
|
||||
|
||||
max = keylen * 4;
|
||||
max += 5; /* @checksum/M */
|
||||
max += 3 * 2; /* maximum number of segment dividers (".../M")
|
||||
* is ((514 + 188) / 189) = 3
|
||||
*/
|
||||
max += 1; /* NUL on end */
|
||||
}
|
||||
|
||||
max += 1; /* 2nd NUL on end */
|
||||
|
||||
_debug("max: %d", max);
|
||||
|
||||
key = kmalloc(max, cachefiles_gfp);
|
||||
if (!key)
|
||||
return NULL;
|
||||
|
||||
len = 0;
|
||||
|
||||
/* build the cooked key */
|
||||
sprintf(key, "@%02x%c+", (unsigned) csum, 0);
|
||||
len = 5;
|
||||
mark = len - 1;
|
||||
|
||||
if (print) {
|
||||
acc = *(uint16_t *) raw;
|
||||
raw += 2;
|
||||
|
||||
key[len + 1] = cachefiles_charmap[acc & 63];
|
||||
acc >>= 6;
|
||||
key[len] = cachefiles_charmap[acc & 63];
|
||||
len += 2;
|
||||
|
||||
seg = 250;
|
||||
for (loop = keylen; loop > 0; loop--) {
|
||||
if (seg <= 0) {
|
||||
key[len++] = '\0';
|
||||
mark = len;
|
||||
key[len++] = '+';
|
||||
seg = 252;
|
||||
}
|
||||
|
||||
key[len++] = *raw++;
|
||||
ASSERT(len < max);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case FSCACHE_COOKIE_TYPE_INDEX: type = 'I'; break;
|
||||
case FSCACHE_COOKIE_TYPE_DATAFILE: type = 'D'; break;
|
||||
default: type = 'S'; break;
|
||||
}
|
||||
} else {
|
||||
seg = 252;
|
||||
for (loop = keylen; loop > 0; loop--) {
|
||||
if (seg <= 0) {
|
||||
key[len++] = '\0';
|
||||
mark = len;
|
||||
key[len++] = '+';
|
||||
seg = 252;
|
||||
}
|
||||
|
||||
acc = *raw++;
|
||||
acc |= *raw++ << 8;
|
||||
acc |= *raw++ << 16;
|
||||
|
||||
_debug("acc: %06x", acc);
|
||||
|
||||
key[len++] = cachefiles_charmap[acc & 63];
|
||||
acc >>= 6;
|
||||
key[len++] = cachefiles_charmap[acc & 63];
|
||||
acc >>= 6;
|
||||
key[len++] = cachefiles_charmap[acc & 63];
|
||||
acc >>= 6;
|
||||
key[len++] = cachefiles_charmap[acc & 63];
|
||||
|
||||
ASSERT(len < max);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case FSCACHE_COOKIE_TYPE_INDEX: type = 'J'; break;
|
||||
case FSCACHE_COOKIE_TYPE_DATAFILE: type = 'E'; break;
|
||||
default: type = 'T'; break;
|
||||
}
|
||||
}
|
||||
|
||||
key[mark] = type;
|
||||
key[len++] = 0;
|
||||
key[len] = 0;
|
||||
|
||||
_leave(" = %s %d", key, len);
|
||||
return key;
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* Network filesystem caching backend to use cache files on a premounted
|
||||
* filesystem
|
||||
*
|
||||
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/statfs.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "internal.h"
|
||||
|
||||
unsigned cachefiles_debug;
|
||||
module_param_named(debug, cachefiles_debug, uint, S_IWUSR | S_IRUGO);
|
||||
MODULE_PARM_DESC(cachefiles_debug, "CacheFiles debugging mask");
|
||||
|
||||
MODULE_DESCRIPTION("Mounted-filesystem based cache");
|
||||
MODULE_AUTHOR("Red Hat, Inc.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
struct kmem_cache *cachefiles_object_jar;
|
||||
|
||||
static struct miscdevice cachefiles_dev = {
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.name = "cachefiles",
|
||||
.fops = &cachefiles_daemon_fops,
|
||||
};
|
||||
|
||||
static void cachefiles_object_init_once(void *_object)
|
||||
{
|
||||
struct cachefiles_object *object = _object;
|
||||
|
||||
memset(object, 0, sizeof(*object));
|
||||
spin_lock_init(&object->work_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* initialise the fs caching module
|
||||
*/
|
||||
static int __init cachefiles_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = misc_register(&cachefiles_dev);
|
||||
if (ret < 0)
|
||||
goto error_dev;
|
||||
|
||||
/* create an object jar */
|
||||
ret = -ENOMEM;
|
||||
cachefiles_object_jar =
|
||||
kmem_cache_create("cachefiles_object_jar",
|
||||
sizeof(struct cachefiles_object),
|
||||
0,
|
||||
SLAB_HWCACHE_ALIGN,
|
||||
cachefiles_object_init_once);
|
||||
if (!cachefiles_object_jar) {
|
||||
pr_notice("Failed to allocate an object jar\n");
|
||||
goto error_object_jar;
|
||||
}
|
||||
|
||||
pr_info("Loaded\n");
|
||||
return 0;
|
||||
|
||||
error_object_jar:
|
||||
misc_deregister(&cachefiles_dev);
|
||||
error_dev:
|
||||
pr_err("failed to register: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
fs_initcall(cachefiles_init);
|
||||
|
||||
/*
|
||||
* clean up on module removal
|
||||
*/
|
||||
static void __exit cachefiles_exit(void)
|
||||
{
|
||||
pr_info("Unloading\n");
|
||||
|
||||
kmem_cache_destroy(cachefiles_object_jar);
|
||||
misc_deregister(&cachefiles_dev);
|
||||
}
|
||||
|
||||
module_exit(cachefiles_exit);
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,112 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* CacheFiles security management
|
||||
*
|
||||
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cred.h>
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* determine the security context within which we access the cache from within
|
||||
* the kernel
|
||||
*/
|
||||
int cachefiles_get_security_ID(struct cachefiles_cache *cache)
|
||||
{
|
||||
struct cred *new;
|
||||
int ret;
|
||||
|
||||
_enter("{%s}", cache->secctx);
|
||||
|
||||
new = prepare_kernel_cred(current);
|
||||
if (!new) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (cache->secctx) {
|
||||
ret = set_security_override_from_ctx(new, cache->secctx);
|
||||
if (ret < 0) {
|
||||
put_cred(new);
|
||||
pr_err("Security denies permission to nominate security context: error %d\n",
|
||||
ret);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
cache->cache_cred = new;
|
||||
ret = 0;
|
||||
error:
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* see if mkdir and create can be performed in the root directory
|
||||
*/
|
||||
static int cachefiles_check_cache_dir(struct cachefiles_cache *cache,
|
||||
struct dentry *root)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = security_inode_mkdir(d_backing_inode(root), root, 0);
|
||||
if (ret < 0) {
|
||||
pr_err("Security denies permission to make dirs: error %d",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = security_inode_create(d_backing_inode(root), root, 0);
|
||||
if (ret < 0)
|
||||
pr_err("Security denies permission to create files: error %d",
|
||||
ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* check the security details of the on-disk cache
|
||||
* - must be called with security override in force
|
||||
* - must return with a security override in force - even in the case of an
|
||||
* error
|
||||
*/
|
||||
int cachefiles_determine_cache_security(struct cachefiles_cache *cache,
|
||||
struct dentry *root,
|
||||
const struct cred **_saved_cred)
|
||||
{
|
||||
struct cred *new;
|
||||
int ret;
|
||||
|
||||
_enter("");
|
||||
|
||||
/* duplicate the cache creds for COW (the override is currently in
|
||||
* force, so we can use prepare_creds() to do this) */
|
||||
new = prepare_creds();
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
cachefiles_end_secure(cache, *_saved_cred);
|
||||
|
||||
/* use the cache root dir's security context as the basis with
|
||||
* which create files */
|
||||
ret = set_create_files_as(new, d_backing_inode(root));
|
||||
if (ret < 0) {
|
||||
abort_creds(new);
|
||||
cachefiles_begin_secure(cache, _saved_cred);
|
||||
_leave(" = %d [cfa]", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
put_cred(cache->cache_cred);
|
||||
cache->cache_cred = new;
|
||||
|
||||
cachefiles_begin_secure(cache, _saved_cred);
|
||||
ret = cachefiles_check_cache_dir(cache, root);
|
||||
|
||||
if (ret == -EOPNOTSUPP)
|
||||
ret = 0;
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
}
|
||||
@@ -1,324 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* CacheFiles extended attribute management
|
||||
*
|
||||
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/quotaops.h>
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/slab.h>
|
||||
#include "internal.h"
|
||||
|
||||
static const char cachefiles_xattr_cache[] =
|
||||
XATTR_USER_PREFIX "CacheFiles.cache";
|
||||
|
||||
/*
|
||||
* check the type label on an object
|
||||
* - done using xattrs
|
||||
*/
|
||||
int cachefiles_check_object_type(struct cachefiles_object *object)
|
||||
{
|
||||
struct dentry *dentry = object->dentry;
|
||||
char type[3], xtype[3];
|
||||
int ret;
|
||||
|
||||
ASSERT(dentry);
|
||||
ASSERT(d_backing_inode(dentry));
|
||||
|
||||
if (!object->fscache.cookie)
|
||||
strcpy(type, "C3");
|
||||
else
|
||||
snprintf(type, 3, "%02x", object->fscache.cookie->def->type);
|
||||
|
||||
_enter("%x{%s}", object->fscache.debug_id, type);
|
||||
|
||||
/* attempt to install a type label directly */
|
||||
ret = vfs_setxattr(&init_user_ns, dentry, cachefiles_xattr_cache, type,
|
||||
2, XATTR_CREATE);
|
||||
if (ret == 0) {
|
||||
_debug("SET"); /* we succeeded */
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ret != -EEXIST) {
|
||||
pr_err("Can't set xattr on %pd [%lu] (err %d)\n",
|
||||
dentry, d_backing_inode(dentry)->i_ino,
|
||||
-ret);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* read the current type label */
|
||||
ret = vfs_getxattr(&init_user_ns, dentry, cachefiles_xattr_cache, xtype,
|
||||
3);
|
||||
if (ret < 0) {
|
||||
if (ret == -ERANGE)
|
||||
goto bad_type_length;
|
||||
|
||||
pr_err("Can't read xattr on %pd [%lu] (err %d)\n",
|
||||
dentry, d_backing_inode(dentry)->i_ino,
|
||||
-ret);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* check the type is what we're expecting */
|
||||
if (ret != 2)
|
||||
goto bad_type_length;
|
||||
|
||||
if (xtype[0] != type[0] || xtype[1] != type[1])
|
||||
goto bad_type;
|
||||
|
||||
ret = 0;
|
||||
|
||||
error:
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
|
||||
bad_type_length:
|
||||
pr_err("Cache object %lu type xattr length incorrect\n",
|
||||
d_backing_inode(dentry)->i_ino);
|
||||
ret = -EIO;
|
||||
goto error;
|
||||
|
||||
bad_type:
|
||||
xtype[2] = 0;
|
||||
pr_err("Cache object %pd [%lu] type %s not %s\n",
|
||||
dentry, d_backing_inode(dentry)->i_ino,
|
||||
xtype, type);
|
||||
ret = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* set the state xattr on a cache file
|
||||
*/
|
||||
int cachefiles_set_object_xattr(struct cachefiles_object *object,
|
||||
struct cachefiles_xattr *auxdata)
|
||||
{
|
||||
struct dentry *dentry = object->dentry;
|
||||
int ret;
|
||||
|
||||
ASSERT(dentry);
|
||||
|
||||
_enter("%p,#%d", object, auxdata->len);
|
||||
|
||||
/* attempt to install the cache metadata directly */
|
||||
_debug("SET #%u", auxdata->len);
|
||||
|
||||
clear_bit(FSCACHE_COOKIE_AUX_UPDATED, &object->fscache.cookie->flags);
|
||||
ret = vfs_setxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
|
||||
&auxdata->type, auxdata->len, XATTR_CREATE);
|
||||
if (ret < 0 && ret != -ENOMEM)
|
||||
cachefiles_io_error_obj(
|
||||
object,
|
||||
"Failed to set xattr with error %d", ret);
|
||||
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* update the state xattr on a cache file
|
||||
*/
|
||||
int cachefiles_update_object_xattr(struct cachefiles_object *object,
|
||||
struct cachefiles_xattr *auxdata)
|
||||
{
|
||||
struct dentry *dentry = object->dentry;
|
||||
int ret;
|
||||
|
||||
if (!dentry)
|
||||
return -ESTALE;
|
||||
|
||||
_enter("%x,#%d", object->fscache.debug_id, auxdata->len);
|
||||
|
||||
/* attempt to install the cache metadata directly */
|
||||
_debug("SET #%u", auxdata->len);
|
||||
|
||||
clear_bit(FSCACHE_COOKIE_AUX_UPDATED, &object->fscache.cookie->flags);
|
||||
ret = vfs_setxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
|
||||
&auxdata->type, auxdata->len, XATTR_REPLACE);
|
||||
if (ret < 0 && ret != -ENOMEM)
|
||||
cachefiles_io_error_obj(
|
||||
object,
|
||||
"Failed to update xattr with error %d", ret);
|
||||
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* check the consistency between the backing cache and the FS-Cache cookie
|
||||
*/
|
||||
int cachefiles_check_auxdata(struct cachefiles_object *object)
|
||||
{
|
||||
struct cachefiles_xattr *auxbuf;
|
||||
enum fscache_checkaux validity;
|
||||
struct dentry *dentry = object->dentry;
|
||||
ssize_t xlen;
|
||||
int ret;
|
||||
|
||||
ASSERT(dentry);
|
||||
ASSERT(d_backing_inode(dentry));
|
||||
ASSERT(object->fscache.cookie->def->check_aux);
|
||||
|
||||
auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, GFP_KERNEL);
|
||||
if (!auxbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
xlen = vfs_getxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
|
||||
&auxbuf->type, 512 + 1);
|
||||
ret = -ESTALE;
|
||||
if (xlen < 1 ||
|
||||
auxbuf->type != object->fscache.cookie->def->type)
|
||||
goto error;
|
||||
|
||||
xlen--;
|
||||
validity = fscache_check_aux(&object->fscache, &auxbuf->data, xlen,
|
||||
i_size_read(d_backing_inode(dentry)));
|
||||
if (validity != FSCACHE_CHECKAUX_OKAY)
|
||||
goto error;
|
||||
|
||||
ret = 0;
|
||||
error:
|
||||
kfree(auxbuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* check the state xattr on a cache file
|
||||
* - return -ESTALE if the object should be deleted
|
||||
*/
|
||||
int cachefiles_check_object_xattr(struct cachefiles_object *object,
|
||||
struct cachefiles_xattr *auxdata)
|
||||
{
|
||||
struct cachefiles_xattr *auxbuf;
|
||||
struct dentry *dentry = object->dentry;
|
||||
int ret;
|
||||
|
||||
_enter("%p,#%d", object, auxdata->len);
|
||||
|
||||
ASSERT(dentry);
|
||||
ASSERT(d_backing_inode(dentry));
|
||||
|
||||
auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, cachefiles_gfp);
|
||||
if (!auxbuf) {
|
||||
_leave(" = -ENOMEM");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* read the current type label */
|
||||
ret = vfs_getxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
|
||||
&auxbuf->type, 512 + 1);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENODATA)
|
||||
goto stale; /* no attribute - power went off
|
||||
* mid-cull? */
|
||||
|
||||
if (ret == -ERANGE)
|
||||
goto bad_type_length;
|
||||
|
||||
cachefiles_io_error_obj(object,
|
||||
"Can't read xattr on %lu (err %d)",
|
||||
d_backing_inode(dentry)->i_ino, -ret);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* check the on-disk object */
|
||||
if (ret < 1)
|
||||
goto bad_type_length;
|
||||
|
||||
if (auxbuf->type != auxdata->type)
|
||||
goto stale;
|
||||
|
||||
auxbuf->len = ret;
|
||||
|
||||
/* consult the netfs */
|
||||
if (object->fscache.cookie->def->check_aux) {
|
||||
enum fscache_checkaux result;
|
||||
unsigned int dlen;
|
||||
|
||||
dlen = auxbuf->len - 1;
|
||||
|
||||
_debug("checkaux %s #%u",
|
||||
object->fscache.cookie->def->name, dlen);
|
||||
|
||||
result = fscache_check_aux(&object->fscache,
|
||||
&auxbuf->data, dlen,
|
||||
i_size_read(d_backing_inode(dentry)));
|
||||
|
||||
switch (result) {
|
||||
/* entry okay as is */
|
||||
case FSCACHE_CHECKAUX_OKAY:
|
||||
goto okay;
|
||||
|
||||
/* entry requires update */
|
||||
case FSCACHE_CHECKAUX_NEEDS_UPDATE:
|
||||
break;
|
||||
|
||||
/* entry requires deletion */
|
||||
case FSCACHE_CHECKAUX_OBSOLETE:
|
||||
goto stale;
|
||||
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
/* update the current label */
|
||||
ret = vfs_setxattr(&init_user_ns, dentry,
|
||||
cachefiles_xattr_cache, &auxdata->type,
|
||||
auxdata->len, XATTR_REPLACE);
|
||||
if (ret < 0) {
|
||||
cachefiles_io_error_obj(object,
|
||||
"Can't update xattr on %lu"
|
||||
" (error %d)",
|
||||
d_backing_inode(dentry)->i_ino, -ret);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
okay:
|
||||
ret = 0;
|
||||
|
||||
error:
|
||||
kfree(auxbuf);
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
|
||||
bad_type_length:
|
||||
pr_err("Cache object %lu xattr length incorrect\n",
|
||||
d_backing_inode(dentry)->i_ino);
|
||||
ret = -EIO;
|
||||
goto error;
|
||||
|
||||
stale:
|
||||
ret = -ESTALE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* remove the object's xattr to mark it stale
|
||||
*/
|
||||
int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
|
||||
struct dentry *dentry)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = vfs_removexattr(&init_user_ns, dentry, cachefiles_xattr_cache);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOENT || ret == -ENODATA)
|
||||
ret = 0;
|
||||
else if (ret != -ENOMEM)
|
||||
cachefiles_io_error(cache,
|
||||
"Can't remove xattr from %lu"
|
||||
" (error %d)",
|
||||
d_backing_inode(dentry)->i_ino, -ret);
|
||||
}
|
||||
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
}
|
||||
@@ -1,321 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* CacheFiles tracepoints
|
||||
*
|
||||
* Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM cachefiles
|
||||
|
||||
#if !defined(_TRACE_CACHEFILES_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define _TRACE_CACHEFILES_H
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
/*
|
||||
* Define enums for tracing information.
|
||||
*/
|
||||
#ifndef __CACHEFILES_DECLARE_TRACE_ENUMS_ONCE_ONLY
|
||||
#define __CACHEFILES_DECLARE_TRACE_ENUMS_ONCE_ONLY
|
||||
|
||||
enum cachefiles_obj_ref_trace {
|
||||
cachefiles_obj_put_wait_retry = fscache_obj_ref__nr_traces,
|
||||
cachefiles_obj_put_wait_timeo,
|
||||
cachefiles_obj_ref__nr_traces
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define enum -> string mappings for display.
|
||||
*/
|
||||
#define cachefiles_obj_kill_traces \
|
||||
EM(FSCACHE_OBJECT_IS_STALE, "stale") \
|
||||
EM(FSCACHE_OBJECT_NO_SPACE, "no_space") \
|
||||
EM(FSCACHE_OBJECT_WAS_RETIRED, "was_retired") \
|
||||
E_(FSCACHE_OBJECT_WAS_CULLED, "was_culled")
|
||||
|
||||
#define cachefiles_obj_ref_traces \
|
||||
EM(fscache_obj_get_add_to_deps, "GET add_to_deps") \
|
||||
EM(fscache_obj_get_queue, "GET queue") \
|
||||
EM(fscache_obj_put_alloc_fail, "PUT alloc_fail") \
|
||||
EM(fscache_obj_put_attach_fail, "PUT attach_fail") \
|
||||
EM(fscache_obj_put_drop_obj, "PUT drop_obj") \
|
||||
EM(fscache_obj_put_enq_dep, "PUT enq_dep") \
|
||||
EM(fscache_obj_put_queue, "PUT queue") \
|
||||
EM(fscache_obj_put_work, "PUT work") \
|
||||
EM(cachefiles_obj_put_wait_retry, "PUT wait_retry") \
|
||||
E_(cachefiles_obj_put_wait_timeo, "PUT wait_timeo")
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
cachefiles_obj_kill_traces;
|
||||
cachefiles_obj_ref_traces;
|
||||
|
||||
/*
|
||||
* 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 }
|
||||
|
||||
|
||||
TRACE_EVENT(cachefiles_ref,
|
||||
TP_PROTO(struct cachefiles_object *obj,
|
||||
struct fscache_cookie *cookie,
|
||||
enum cachefiles_obj_ref_trace why,
|
||||
int usage),
|
||||
|
||||
TP_ARGS(obj, cookie, why, usage),
|
||||
|
||||
/* Note that obj may be NULL */
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, obj )
|
||||
__field(unsigned int, cookie )
|
||||
__field(enum cachefiles_obj_ref_trace, why )
|
||||
__field(int, usage )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->obj = obj->fscache.debug_id;
|
||||
__entry->cookie = cookie->debug_id;
|
||||
__entry->usage = usage;
|
||||
__entry->why = why;
|
||||
),
|
||||
|
||||
TP_printk("c=%08x o=%08x u=%d %s",
|
||||
__entry->cookie, __entry->obj, __entry->usage,
|
||||
__print_symbolic(__entry->why, cachefiles_obj_ref_traces))
|
||||
);
|
||||
|
||||
TRACE_EVENT(cachefiles_lookup,
|
||||
TP_PROTO(struct cachefiles_object *obj,
|
||||
struct dentry *de,
|
||||
struct inode *inode),
|
||||
|
||||
TP_ARGS(obj, de, inode),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, obj )
|
||||
__field(struct dentry *, de )
|
||||
__field(struct inode *, inode )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->obj = obj->fscache.debug_id;
|
||||
__entry->de = de;
|
||||
__entry->inode = inode;
|
||||
),
|
||||
|
||||
TP_printk("o=%08x d=%p i=%p",
|
||||
__entry->obj, __entry->de, __entry->inode)
|
||||
);
|
||||
|
||||
TRACE_EVENT(cachefiles_mkdir,
|
||||
TP_PROTO(struct cachefiles_object *obj,
|
||||
struct dentry *de, int ret),
|
||||
|
||||
TP_ARGS(obj, de, ret),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, obj )
|
||||
__field(struct dentry *, de )
|
||||
__field(int, ret )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->obj = obj->fscache.debug_id;
|
||||
__entry->de = de;
|
||||
__entry->ret = ret;
|
||||
),
|
||||
|
||||
TP_printk("o=%08x d=%p r=%u",
|
||||
__entry->obj, __entry->de, __entry->ret)
|
||||
);
|
||||
|
||||
TRACE_EVENT(cachefiles_create,
|
||||
TP_PROTO(struct cachefiles_object *obj,
|
||||
struct dentry *de, int ret),
|
||||
|
||||
TP_ARGS(obj, de, ret),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, obj )
|
||||
__field(struct dentry *, de )
|
||||
__field(int, ret )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->obj = obj->fscache.debug_id;
|
||||
__entry->de = de;
|
||||
__entry->ret = ret;
|
||||
),
|
||||
|
||||
TP_printk("o=%08x d=%p r=%u",
|
||||
__entry->obj, __entry->de, __entry->ret)
|
||||
);
|
||||
|
||||
TRACE_EVENT(cachefiles_unlink,
|
||||
TP_PROTO(struct cachefiles_object *obj,
|
||||
struct dentry *de,
|
||||
enum fscache_why_object_killed why),
|
||||
|
||||
TP_ARGS(obj, de, why),
|
||||
|
||||
/* Note that obj may be NULL */
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, obj )
|
||||
__field(struct dentry *, de )
|
||||
__field(enum fscache_why_object_killed, why )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->obj = obj ? obj->fscache.debug_id : UINT_MAX;
|
||||
__entry->de = de;
|
||||
__entry->why = why;
|
||||
),
|
||||
|
||||
TP_printk("o=%08x d=%p w=%s",
|
||||
__entry->obj, __entry->de,
|
||||
__print_symbolic(__entry->why, cachefiles_obj_kill_traces))
|
||||
);
|
||||
|
||||
TRACE_EVENT(cachefiles_rename,
|
||||
TP_PROTO(struct cachefiles_object *obj,
|
||||
struct dentry *de,
|
||||
struct dentry *to,
|
||||
enum fscache_why_object_killed why),
|
||||
|
||||
TP_ARGS(obj, de, to, why),
|
||||
|
||||
/* Note that obj may be NULL */
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, obj )
|
||||
__field(struct dentry *, de )
|
||||
__field(struct dentry *, to )
|
||||
__field(enum fscache_why_object_killed, why )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->obj = obj ? obj->fscache.debug_id : UINT_MAX;
|
||||
__entry->de = de;
|
||||
__entry->to = to;
|
||||
__entry->why = why;
|
||||
),
|
||||
|
||||
TP_printk("o=%08x d=%p t=%p w=%s",
|
||||
__entry->obj, __entry->de, __entry->to,
|
||||
__print_symbolic(__entry->why, cachefiles_obj_kill_traces))
|
||||
);
|
||||
|
||||
TRACE_EVENT(cachefiles_mark_active,
|
||||
TP_PROTO(struct cachefiles_object *obj,
|
||||
struct dentry *de),
|
||||
|
||||
TP_ARGS(obj, de),
|
||||
|
||||
/* Note that obj may be NULL */
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, obj )
|
||||
__field(struct dentry *, de )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->obj = obj->fscache.debug_id;
|
||||
__entry->de = de;
|
||||
),
|
||||
|
||||
TP_printk("o=%08x d=%p",
|
||||
__entry->obj, __entry->de)
|
||||
);
|
||||
|
||||
TRACE_EVENT(cachefiles_wait_active,
|
||||
TP_PROTO(struct cachefiles_object *obj,
|
||||
struct dentry *de,
|
||||
struct cachefiles_object *xobj),
|
||||
|
||||
TP_ARGS(obj, de, xobj),
|
||||
|
||||
/* Note that obj may be NULL */
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, obj )
|
||||
__field(unsigned int, xobj )
|
||||
__field(struct dentry *, de )
|
||||
__field(u16, flags )
|
||||
__field(u16, fsc_flags )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->obj = obj->fscache.debug_id;
|
||||
__entry->de = de;
|
||||
__entry->xobj = xobj->fscache.debug_id;
|
||||
__entry->flags = xobj->flags;
|
||||
__entry->fsc_flags = xobj->fscache.flags;
|
||||
),
|
||||
|
||||
TP_printk("o=%08x d=%p wo=%08x wf=%x wff=%x",
|
||||
__entry->obj, __entry->de, __entry->xobj,
|
||||
__entry->flags, __entry->fsc_flags)
|
||||
);
|
||||
|
||||
TRACE_EVENT(cachefiles_mark_inactive,
|
||||
TP_PROTO(struct cachefiles_object *obj,
|
||||
struct dentry *de,
|
||||
struct inode *inode),
|
||||
|
||||
TP_ARGS(obj, de, inode),
|
||||
|
||||
/* Note that obj may be NULL */
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, obj )
|
||||
__field(struct dentry *, de )
|
||||
__field(struct inode *, inode )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->obj = obj->fscache.debug_id;
|
||||
__entry->de = de;
|
||||
__entry->inode = inode;
|
||||
),
|
||||
|
||||
TP_printk("o=%08x d=%p i=%p",
|
||||
__entry->obj, __entry->de, __entry->inode)
|
||||
);
|
||||
|
||||
TRACE_EVENT(cachefiles_mark_buried,
|
||||
TP_PROTO(struct cachefiles_object *obj,
|
||||
struct dentry *de,
|
||||
enum fscache_why_object_killed why),
|
||||
|
||||
TP_ARGS(obj, de, why),
|
||||
|
||||
/* Note that obj may be NULL */
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, obj )
|
||||
__field(struct dentry *, de )
|
||||
__field(enum fscache_why_object_killed, why )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->obj = obj ? obj->fscache.debug_id : UINT_MAX;
|
||||
__entry->de = de;
|
||||
__entry->why = why;
|
||||
),
|
||||
|
||||
TP_printk("o=%08x d=%p w=%s",
|
||||
__entry->obj, __entry->de,
|
||||
__print_symbolic(__entry->why, cachefiles_obj_kill_traces))
|
||||
);
|
||||
|
||||
#endif /* _TRACE_CACHEFILES_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
#include <trace/define_trace.h>
|
||||
Reference in New Issue
Block a user