// SPDX-License-Identifier: GPL-2.0-or-later
/* CacheFiles path walking and related routines
*
* 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/mount.h>
#include <linux/namei.h>
#include <linux/security.h>
#include <linux/slab.h>
#include "internal.h"
#define CACHEFILES_KEYBUF_SIZE 512
/*
* dump debugging info about an object
*/
static noinline
void __cachefiles_printk_object(struct cachefiles_object *object,
const char *prefix)
{
struct fscache_cookie *cookie;
const u8 *k;
unsigned loop;
pr_err("%sobject: OBJ%x\n", prefix, object->fscache.debug_id);
pr_err("%sobjstate=%s fl=%lx wbusy=%x ev=%lx[%lx]\n",
prefix, object->fscache.state->name,
object->fscache.flags, work_busy(&object->fscache.work),
object->fscache.events, object->fscache.event_mask);
pr_err("%sops=%u inp=%u exc=%u\n",
prefix, object->fscache.n_ops, object->fscache.n_in_progress,
object->fscache.n_exclusive);
pr_err("%sparent=%p\n",
prefix, object->fscache.parent);
spin_lock(&object->fscache.lock);
cookie = object->fscache.cookie;
if (cookie) {
pr_err("%scookie=%p [pr=%p nd=%p fl=%lx]\n",
prefix,
object->fscache.cookie,
object->fscache.cookie->parent,
object->fscache.cookie->netfs_data,
object->fscache.cookie->flags);
pr_err("%skey=[%u] '", prefix, cookie->key_len);
k = (cookie->key_len <= sizeof(cookie->inline_key)) ?
cookie->inline_key : cookie->key;
for (loop = 0; loop < cookie->key_len; loop++)
pr_cont("%02x", k[loop]);
pr_cont("'\n");
} else {
pr_err("%scookie=NULL\n", prefix);
}
spin_unlock(&object->fscache.lock);
}
/*
* dump debugging info about a pair of objects
*/
static noinline void cachefiles_printk_object(struct cachefiles_object *object,
struct cachefiles_object *xobject)
{
if (object)
__cachefiles_printk_object(object, "");
if (xobject)
__cachefiles_printk_object(xobject, "x");
}
/*
* mark the owner of a dentry, if there is one, to indicate that that dentry
* has been preemptively deleted
* - the caller must hold the i_mutex on the dentry's parent as required to
* call vfs_unlink(), vfs_rmdir() or vfs_rename()
*/
static void cachefiles_mark_object_buried(struct cachefiles_cache *cache,
struct dentry *dentry,
enum fscache_why_object_killed why)
{
struct cachefiles_object *object;
struct rb_node *p;
_enter(",'%pd'", dentry);
write_lock(&cache->active_lock);
p = cache->active_nodes.rb_node;
while (p) {
object = rb_entry(p, struct cachefiles_object, active_node);
if (object->dentry > dentry)
p = p->rb_left;
else if (object->dentry < dentry)
p = p->rb_right;
else
goto found_dentry;
}
write_unlock(&cache->active_lock);
trace_cachefiles_mark_buried(NULL, dentry, why);
_leave(" [no owner]");
return;
/* found the dentry for */
found_dentry:
kdebug("preemptive burial: OBJ%x [%s] %p",
object->fscache.debug_id,
object->fscache.state->name,
dentry);
trace_cachefiles_mark_buried(object, dentry, why);
if (fscache_object_is_live(&object->fscache)) {
pr_err("\n");
pr_err("Error: Can't preemptively bury live object\n");
cachefiles_printk_object(object, NULL);
} else {
if (why != FSCACHE_OBJECT_IS_STALE)
fscache_object_mark_killed(&object->fscache, why);
}
write_unlock(&cache->active_lock);
_leave(" [owner marked]");
}
/*
* record the fact that an object is now active
*/
static int cachefiles_mark_object_active(struct cachefiles_cache *cache