From patchwork Wed Dec 22 23:13:56 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 12697380 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6A53EC433F5 for ; Wed, 22 Dec 2021 23:14:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242711AbhLVXOT (ORCPT ); Wed, 22 Dec 2021 18:14:19 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]:38691 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242579AbhLVXOQ (ORCPT ); Wed, 22 Dec 2021 18:14:16 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1640214855; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Pk5wbmEcoS5UMFpDxaU+VvgJBy9Wu8s4cvIp1AeoIcc=; b=h9k4Vih+h8rxTsArtmFEIM7IfK3NUmcf7lfH2gsR3n8JTiDIRr+wKR/RCGVxHAYj45TF4v 3sCNPtN8GVkl3ZTiay/ofjZgBS+p7YD3SSpVIKCpFmypJr+vc/Xa43Sva+mcO39x9ip+bL 7CunvoIHsEx9UzmkjC3e2/PbXQZiyJk= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-400-uXnCET9mOYm75-m_uUaqqw-1; Wed, 22 Dec 2021 18:14:12 -0500 X-MC-Unique: uXnCET9mOYm75-m_uUaqqw-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 4033D801ADB; Wed, 22 Dec 2021 23:14:10 +0000 (UTC) Received: from warthog.procyon.org.uk (unknown [10.33.36.165]) by smtp.corp.redhat.com (Postfix) with ESMTP id 173FA10911BA; Wed, 22 Dec 2021 23:13:56 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH v4 02/68] cachefiles: Delete the cachefiles driver pending rewrite From: David Howells To: linux-cachefs@redhat.com Cc: Jeff Layton , dhowells@redhat.com, Trond Myklebust , Anna Schumaker , Steve French , Dominique Martinet , Jeff Layton , Matthew Wilcox , Alexander Viro , Omar Sandoval , JeffleXu , Linus Torvalds , linux-afs@lists.infradead.org, linux-nfs@vger.kernel.org, linux-cifs@vger.kernel.org, ceph-devel@vger.kernel.org, v9fs-developer@lists.sourceforge.net, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Date: Wed, 22 Dec 2021 23:13:56 +0000 Message-ID: <164021483619.640689.7586546280515844702.stgit@warthog.procyon.org.uk> In-Reply-To: <164021479106.640689.17404516570194656552.stgit@warthog.procyon.org.uk> References: <164021479106.640689.17404516570194656552.stgit@warthog.procyon.org.uk> User-Agent: StGit/0.23 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org Delete the code from the cachefiles driver to make it easier to rewrite and resubmit in a logical manner. Signed-off-by: David Howells Reviewed-by: Jeff Layton 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 --- fs/Kconfig | 1 fs/Makefile | 1 fs/cachefiles/Kconfig | 21 - fs/cachefiles/Makefile | 18 - fs/cachefiles/bind.c | 278 ---------- fs/cachefiles/daemon.c | 748 --------------------------- fs/cachefiles/interface.c | 572 --------------------- fs/cachefiles/internal.h | 350 ------------- fs/cachefiles/io.c | 420 --------------- fs/cachefiles/key.c | 155 ------ fs/cachefiles/main.c | 95 --- fs/cachefiles/namei.c | 1018 ------------------------------------- fs/cachefiles/rdwr.c | 972 ----------------------------------- fs/cachefiles/security.c | 112 ---- fs/cachefiles/xattr.c | 324 ------------ include/trace/events/cachefiles.h | 321 ------------ 16 files changed, 5406 deletions(-) delete mode 100644 fs/cachefiles/Kconfig delete mode 100644 fs/cachefiles/Makefile delete mode 100644 fs/cachefiles/bind.c delete mode 100644 fs/cachefiles/daemon.c delete mode 100644 fs/cachefiles/interface.c delete mode 100644 fs/cachefiles/internal.h delete mode 100644 fs/cachefiles/io.c delete mode 100644 fs/cachefiles/key.c delete mode 100644 fs/cachefiles/main.c delete mode 100644 fs/cachefiles/namei.c delete mode 100644 fs/cachefiles/rdwr.c delete mode 100644 fs/cachefiles/security.c delete mode 100644 fs/cachefiles/xattr.c delete mode 100644 include/trace/events/cachefiles.h diff --git a/fs/Kconfig b/fs/Kconfig index a6313a969bc5..86e311377e6e 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -132,7 +132,6 @@ menu "Caches" source "fs/netfs/Kconfig" source "fs/fscache/Kconfig" -source "fs/cachefiles/Kconfig" endmenu diff --git a/fs/Makefile b/fs/Makefile index 84c5e4cdfee5..290815f3fd31 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -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/ diff --git a/fs/cachefiles/Kconfig b/fs/cachefiles/Kconfig deleted file mode 100644 index 6827b40f7ddc..000000000000 --- a/fs/cachefiles/Kconfig +++ /dev/null @@ -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. diff --git a/fs/cachefiles/Makefile b/fs/cachefiles/Makefile deleted file mode 100644 index 02fd17731769..000000000000 --- a/fs/cachefiles/Makefile +++ /dev/null @@ -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 diff --git a/fs/cachefiles/bind.c b/fs/cachefiles/bind.c deleted file mode 100644 index d463d89f5db8..000000000000 --- a/fs/cachefiles/bind.c +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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(""); -} diff --git a/fs/cachefiles/daemon.c b/fs/cachefiles/daemon.c deleted file mode 100644 index 752c1e43416f..000000000000 --- a/fs/cachefiles/daemon.c +++ /dev/null @@ -1,748 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* Daemon interface - * - * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -static int cachefiles_daemon_open(struct inode *, struct file *); -static int cachefiles_daemon_release(struct inode *, struct file *); -static ssize_t cachefiles_daemon_read(struct file *, char __user *, size_t, - loff_t *); -static ssize_t cachefiles_daemon_write(struct file *, const char __user *, - size_t, loff_t *); -static __poll_t cachefiles_daemon_poll(struct file *, - struct poll_table_struct *); -static int cachefiles_daemon_frun(struct cachefiles_cache *, char *); -static int cachefiles_daemon_fcull(struct cachefiles_cache *, char *); -static int cachefiles_daemon_fstop(struct cachefiles_cache *, char *); -static int cachefiles_daemon_brun(struct cachefiles_cache *, char *); -static int cachefiles_daemon_bcull(struct cachefiles_cache *, char *); -static int cachefiles_daemon_bstop(struct cachefiles_cache *, char *); -static int cachefiles_daemon_cull(struct cachefiles_cache *, char *); -static int cachefiles_daemon_debug(struct cachefiles_cache *, char *); -static int cachefiles_daemon_dir(struct cachefiles_cache *, char *); -static int cachefiles_daemon_inuse(struct cachefiles_cache *, char *); -static int cachefiles_daemon_secctx(struct cachefiles_cache *, char *); -static int cachefiles_daemon_tag(struct cachefiles_cache *, char *); - -static unsigned long cachefiles_open; - -const struct file_operations cachefiles_daemon_fops = { - .owner = THIS_MODULE, - .open = cachefiles_daemon_open, - .release = cachefiles_daemon_release, - .read = cachefiles_daemon_read, - .write = cachefiles_daemon_write, - .poll = cachefiles_daemon_poll, - .llseek = noop_llseek, -}; - -struct cachefiles_daemon_cmd { - char name[8]; - int (*handler)(struct cachefiles_cache *cache, char *args); -}; - -static const struct cachefiles_daemon_cmd cachefiles_daemon_cmds[] = { - { "bind", cachefiles_daemon_bind }, - { "brun", cachefiles_daemon_brun }, - { "bcull", cachefiles_daemon_bcull }, - { "bstop", cachefiles_daemon_bstop }, - { "cull", cachefiles_daemon_cull }, - { "debug", cachefiles_daemon_debug }, - { "dir", cachefiles_daemon_dir }, - { "frun", cachefiles_daemon_frun }, - { "fcull", cachefiles_daemon_fcull }, - { "fstop", cachefiles_daemon_fstop }, - { "inuse", cachefiles_daemon_inuse }, - { "secctx", cachefiles_daemon_secctx }, - { "tag", cachefiles_daemon_tag }, - { "", NULL } -}; - - -/* - * do various checks - */ -static int cachefiles_daemon_open(struct inode *inode, struct file *file) -{ - struct cachefiles_cache *cache; - - _enter(""); - - /* only the superuser may do this */ - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - /* the cachefiles device may only be open once at a time */ - if (xchg(&cachefiles_open, 1) == 1) - return -EBUSY; - - /* allocate a cache record */ - cache = kzalloc(sizeof(struct cachefiles_cache), GFP_KERNEL); - if (!cache) { - cachefiles_open = 0; - return -ENOMEM; - } - - mutex_init(&cache->daemon_mutex); - cache->active_nodes = RB_ROOT; - rwlock_init(&cache->active_lock); - init_waitqueue_head(&cache->daemon_pollwq); - - /* set default caching limits - * - limit at 1% free space and/or free files - * - cull below 5% free space and/or free files - * - cease culling above 7% free space and/or free files - */ - cache->frun_percent = 7; - cache->fcull_percent = 5; - cache->fstop_percent = 1; - cache->brun_percent = 7; - cache->bcull_percent = 5; - cache->bstop_percent = 1; - - file->private_data = cache; - cache->cachefilesd = file; - return 0; -} - -/* - * release a cache - */ -static int cachefiles_daemon_release(struct inode *inode, struct file *file) -{ - struct cachefiles_cache *cache = file->private_data; - - _enter(""); - - ASSERT(cache); - - set_bit(CACHEFILES_DEAD, &cache->flags); - - cachefiles_daemon_unbind(cache); - - ASSERT(!cache->active_nodes.rb_node); - - /* clean up the control file interface */ - cache->cachefilesd = NULL; - file->private_data = NULL; - cachefiles_open = 0; - - kfree(cache); - - _leave(""); - return 0; -} - -/* - * read the cache state - */ -static ssize_t cachefiles_daemon_read(struct file *file, char __user *_buffer, - size_t buflen, loff_t *pos) -{ - struct cachefiles_cache *cache = file->private_data; - unsigned long long b_released; - unsigned f_released; - char buffer[256]; - int n; - - //_enter(",,%zu,", buflen); - - if (!test_bit(CACHEFILES_READY, &cache->flags)) - return 0; - - /* check how much space the cache has */ - cachefiles_has_space(cache, 0, 0); - - /* summarise */ - f_released = atomic_xchg(&cache->f_released, 0); - b_released = atomic_long_xchg(&cache->b_released, 0); - clear_bit(CACHEFILES_STATE_CHANGED, &cache->flags); - - n = snprintf(buffer, sizeof(buffer), - "cull=%c" - " frun=%llx" - " fcull=%llx" - " fstop=%llx" - " brun=%llx" - " bcull=%llx" - " bstop=%llx" - " freleased=%x" - " breleased=%llx", - test_bit(CACHEFILES_CULLING, &cache->flags) ? '1' : '0', - (unsigned long long) cache->frun, - (unsigned long long) cache->fcull, - (unsigned long long) cache->fstop, - (unsigned long long) cache->brun, - (unsigned long long) cache->bcull, - (unsigned long long) cache->bstop, - f_released, - b_released); - - if (n > buflen) - return -EMSGSIZE; - - if (copy_to_user(_buffer, buffer, n) != 0) - return -EFAULT; - - return n; -} - -/* - * command the cache - */ -static ssize_t cachefiles_daemon_write(struct file *file, - const char __user *_data, - size_t datalen, - loff_t *pos) -{ - const struct cachefiles_daemon_cmd *cmd; - struct cachefiles_cache *cache = file->private_data; - ssize_t ret; - char *data, *args, *cp; - - //_enter(",,%zu,", datalen); - - ASSERT(cache); - - if (test_bit(CACHEFILES_DEAD, &cache->flags)) - return -EIO; - - if (datalen < 0 || datalen > PAGE_SIZE - 1) - return -EOPNOTSUPP; - - /* drag the command string into the kernel so we can parse it */ - data = memdup_user_nul(_data, datalen); - if (IS_ERR(data)) - return PTR_ERR(data); - - ret = -EINVAL; - if (memchr(data, '\0', datalen)) - goto error; - - /* strip any newline */ - cp = memchr(data, '\n', datalen); - if (cp) { - if (cp == data) - goto error; - - *cp = '\0'; - } - - /* parse the command */ - ret = -EOPNOTSUPP; - - for (args = data; *args; args++) - if (isspace(*args)) - break; - if (*args) { - if (args == data) - goto error; - *args = '\0'; - args = skip_spaces(++args); - } - - /* run the appropriate command handler */ - for (cmd = cachefiles_daemon_cmds; cmd->name[0]; cmd++) - if (strcmp(cmd->name, data) == 0) - goto found_command; - -error: - kfree(data); - //_leave(" = %zd", ret); - return ret; - -found_command: - mutex_lock(&cache->daemon_mutex); - - ret = -EIO; - if (!test_bit(CACHEFILES_DEAD, &cache->flags)) - ret = cmd->handler(cache, args); - - mutex_unlock(&cache->daemon_mutex); - - if (ret == 0) - ret = datalen; - goto error; -} - -/* - * poll for culling state - * - use EPOLLOUT to indicate culling state - */ -static __poll_t cachefiles_daemon_poll(struct file *file, - struct poll_table_struct *poll) -{ - struct cachefiles_cache *cache = file->private_data; - __poll_t mask; - - poll_wait(file, &cache->daemon_pollwq, poll); - mask = 0; - - if (test_bit(CACHEFILES_STATE_CHANGED, &cache->flags)) - mask |= EPOLLIN; - - if (test_bit(CACHEFILES_CULLING, &cache->flags)) - mask |= EPOLLOUT; - - return mask; -} - -/* - * give a range error for cache space constraints - * - can be tail-called - */ -static int cachefiles_daemon_range_error(struct cachefiles_cache *cache, - char *args) -{ - pr_err("Free space limits must be in range 0%%<=stop%" - */ -static int cachefiles_daemon_frun(struct cachefiles_cache *cache, char *args) -{ - unsigned long frun; - - _enter(",%s", args); - - if (!*args) - return -EINVAL; - - frun = simple_strtoul(args, &args, 10); - if (args[0] != '%' || args[1] != '\0') - return -EINVAL; - - if (frun <= cache->fcull_percent || frun >= 100) - return cachefiles_daemon_range_error(cache, args); - - cache->frun_percent = frun; - return 0; -} - -/* - * set the percentage of files at which to start culling - * - command: "fcull %" - */ -static int cachefiles_daemon_fcull(struct cachefiles_cache *cache, char *args) -{ - unsigned long fcull; - - _enter(",%s", args); - - if (!*args) - return -EINVAL; - - fcull = simple_strtoul(args, &args, 10); - if (args[0] != '%' || args[1] != '\0') - return -EINVAL; - - if (fcull <= cache->fstop_percent || fcull >= cache->frun_percent) - return cachefiles_daemon_range_error(cache, args); - - cache->fcull_percent = fcull; - return 0; -} - -/* - * set the percentage of files at which to stop allocating - * - command: "fstop %" - */ -static int cachefiles_daemon_fstop(struct cachefiles_cache *cache, char *args) -{ - unsigned long fstop; - - _enter(",%s", args); - - if (!*args) - return -EINVAL; - - fstop = simple_strtoul(args, &args, 10); - if (args[0] != '%' || args[1] != '\0') - return -EINVAL; - - if (fstop < 0 || fstop >= cache->fcull_percent) - return cachefiles_daemon_range_error(cache, args); - - cache->fstop_percent = fstop; - return 0; -} - -/* - * set the percentage of blocks at which to stop culling - * - command: "brun %" - */ -static int cachefiles_daemon_brun(struct cachefiles_cache *cache, char *args) -{ - unsigned long brun; - - _enter(",%s", args); - - if (!*args) - return -EINVAL; - - brun = simple_strtoul(args, &args, 10); - if (args[0] != '%' || args[1] != '\0') - return -EINVAL; - - if (brun <= cache->bcull_percent || brun >= 100) - return cachefiles_daemon_range_error(cache, args); - - cache->brun_percent = brun; - return 0; -} - -/* - * set the percentage of blocks at which to start culling - * - command: "bcull %" - */ -static int cachefiles_daemon_bcull(struct cachefiles_cache *cache, char *args) -{ - unsigned long bcull; - - _enter(",%s", args); - - if (!*args) - return -EINVAL; - - bcull = simple_strtoul(args, &args, 10); - if (args[0] != '%' || args[1] != '\0') - return -EINVAL; - - if (bcull <= cache->bstop_percent || bcull >= cache->brun_percent) - return cachefiles_daemon_range_error(cache, args); - - cache->bcull_percent = bcull; - return 0; -} - -/* - * set the percentage of blocks at which to stop allocating - * - command: "bstop %" - */ -static int cachefiles_daemon_bstop(struct cachefiles_cache *cache, char *args) -{ - unsigned long bstop; - - _enter(",%s", args); - - if (!*args) - return -EINVAL; - - bstop = simple_strtoul(args, &args, 10); - if (args[0] != '%' || args[1] != '\0') - return -EINVAL; - - if (bstop < 0 || bstop >= cache->bcull_percent) - return cachefiles_daemon_range_error(cache, args); - - cache->bstop_percent = bstop; - return 0; -} - -/* - * set the cache directory - * - command: "dir " - */ -static int cachefiles_daemon_dir(struct cachefiles_cache *cache, char *args) -{ - char *dir; - - _enter(",%s", args); - - if (!*args) { - pr_err("Empty directory specified\n"); - return -EINVAL; - } - - if (cache->rootdirname) { - pr_err("Second cache directory specified\n"); - return -EEXIST; - } - - dir = kstrdup(args, GFP_KERNEL); - if (!dir) - return -ENOMEM; - - cache->rootdirname = dir; - return 0; -} - -/* - * set the cache security context - * - command: "secctx " - */ -static int cachefiles_daemon_secctx(struct cachefiles_cache *cache, char *args) -{ - char *secctx; - - _enter(",%s", args); - - if (!*args) { - pr_err("Empty security context specified\n"); - return -EINVAL; - } - - if (cache->secctx) { - pr_err("Second security context specified\n"); - return -EINVAL; - } - - secctx = kstrdup(args, GFP_KERNEL); - if (!secctx) - return -ENOMEM; - - cache->secctx = secctx; - return 0; -} - -/* - * set the cache tag - * - command: "tag " - */ -static int cachefiles_daemon_tag(struct cachefiles_cache *cache, char *args) -{ - char *tag; - - _enter(",%s", args); - - if (!*args) { - pr_err("Empty tag specified\n"); - return -EINVAL; - } - - if (cache->tag) - return -EEXIST; - - tag = kstrdup(args, GFP_KERNEL); - if (!tag) - return -ENOMEM; - - cache->tag = tag; - return 0; -} - -/* - * request a node in the cache be culled from the current working directory - * - command: "cull " - */ -static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args) -{ - struct path path; - const struct cred *saved_cred; - int ret; - - _enter(",%s", args); - - if (strchr(args, '/')) - goto inval; - - if (!test_bit(CACHEFILES_READY, &cache->flags)) { - pr_err("cull applied to unready cache\n"); - return -EIO; - } - - if (test_bit(CACHEFILES_DEAD, &cache->flags)) { - pr_err("cull applied to dead cache\n"); - return -EIO; - } - - /* extract the directory dentry from the cwd */ - get_fs_pwd(current->fs, &path); - - if (!d_can_lookup(path.dentry)) - goto notdir; - - cachefiles_begin_secure(cache, &saved_cred); - ret = cachefiles_cull(cache, path.dentry, args); - cachefiles_end_secure(cache, saved_cred); - - path_put(&path); - _leave(" = %d", ret); - return ret; - -notdir: - path_put(&path); - pr_err("cull command requires dirfd to be a directory\n"); - return -ENOTDIR; - -inval: - pr_err("cull command requires dirfd and filename\n"); - return -EINVAL; -} - -/* - * set debugging mode - * - command: "debug " - */ -static int cachefiles_daemon_debug(struct cachefiles_cache *cache, char *args) -{ - unsigned long mask; - - _enter(",%s", args); - - mask = simple_strtoul(args, &args, 0); - if (args[0] != '\0') - goto inval; - - cachefiles_debug = mask; - _leave(" = 0"); - return 0; - -inval: - pr_err("debug command requires mask\n"); - return -EINVAL; -} - -/* - * find out whether an object in the current working directory is in use or not - * - command: "inuse " - */ -static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args) -{ - struct path path; - const struct cred *saved_cred; - int ret; - - //_enter(",%s", args); - - if (strchr(args, '/')) - goto inval; - - if (!test_bit(CACHEFILES_READY, &cache->flags)) { - pr_err("inuse applied to unready cache\n"); - return -EIO; - } - - if (test_bit(CACHEFILES_DEAD, &cache->flags)) { - pr_err("inuse applied to dead cache\n"); - return -EIO; - } - - /* extract the directory dentry from the cwd */ - get_fs_pwd(current->fs, &path); - - if (!d_can_lookup(path.dentry)) - goto notdir; - - cachefiles_begin_secure(cache, &saved_cred); - ret = cachefiles_check_in_use(cache, path.dentry, args); - cachefiles_end_secure(cache, saved_cred); - - path_put(&path); - //_leave(" = %d", ret); - return ret; - -notdir: - path_put(&path); - pr_err("inuse command requires dirfd to be a directory\n"); - return -ENOTDIR; - -inval: - pr_err("inuse command requires dirfd and filename\n"); - return -EINVAL; -} - -/* - * see if we have space for a number of pages and/or a number of files in the - * cache - */ -int cachefiles_has_space(struct cachefiles_cache *cache, - unsigned fnr, unsigned bnr) -{ - struct kstatfs stats; - struct path path = { - .mnt = cache->mnt, - .dentry = cache->mnt->mnt_root, - }; - int ret; - - //_enter("{%llu,%llu,%llu,%llu,%llu,%llu},%u,%u", - // (unsigned long long) cache->frun, - // (unsigned long long) cache->fcull, - // (unsigned long long) cache->fstop, - // (unsigned long long) cache->brun, - // (unsigned long long) cache->bcull, - // (unsigned long long) cache->bstop, - // fnr, bnr); - - /* find out how many pages of blockdev are available */ - memset(&stats, 0, sizeof(stats)); - - ret = vfs_statfs(&path, &stats); - if (ret < 0) { - if (ret == -EIO) - cachefiles_io_error(cache, "statfs failed"); - _leave(" = %d", ret); - return ret; - } - - stats.f_bavail >>= cache->bshift; - - //_debug("avail %llu,%llu", - // (unsigned long long) stats.f_ffree, - // (unsigned long long) stats.f_bavail); - - /* see if there is sufficient space */ - if (stats.f_ffree > fnr) - stats.f_ffree -= fnr; - else - stats.f_ffree = 0; - - if (stats.f_bavail > bnr) - stats.f_bavail -= bnr; - else - stats.f_bavail = 0; - - ret = -ENOBUFS; - if (stats.f_ffree < cache->fstop || - stats.f_bavail < cache->bstop) - goto begin_cull; - - ret = 0; - if (stats.f_ffree < cache->fcull || - stats.f_bavail < cache->bcull) - goto begin_cull; - - if (test_bit(CACHEFILES_CULLING, &cache->flags) && - stats.f_ffree >= cache->frun && - stats.f_bavail >= cache->brun && - test_and_clear_bit(CACHEFILES_CULLING, &cache->flags) - ) { - _debug("cease culling"); - cachefiles_state_changed(cache); - } - - //_leave(" = 0"); - return 0; - -begin_cull: - if (!test_and_set_bit(CACHEFILES_CULLING, &cache->flags)) { - _debug("### CULL CACHE ###"); - cachefiles_state_changed(cache); - } - - _leave(" = %d", ret); - return ret; -} diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c deleted file mode 100644 index da28ac1fa225..000000000000 --- a/fs/cachefiles/interface.c +++ /dev/null @@ -1,572 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* FS-Cache interface to CacheFiles - * - * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - */ - -#include -#include -#include "internal.h" - -struct cachefiles_lookup_data { - struct cachefiles_xattr *auxdata; /* auxiliary data */ - char *key; /* key path */ -}; - -static int cachefiles_attr_changed(struct fscache_object *_object); - -/* - * allocate an object record for a cookie lookup and prepare the lookup data - */ -static struct fscache_object *cachefiles_alloc_object( - struct fscache_cache *_cache, - struct fscache_cookie *cookie) -{ - struct cachefiles_lookup_data *lookup_data; - struct cachefiles_object *object; - struct cachefiles_cache *cache; - struct cachefiles_xattr *auxdata; - unsigned keylen, auxlen; - void *buffer, *p; - char *key; - - cache = container_of(_cache, struct cachefiles_cache, cache); - - _enter("{%s},%x,", cache->cache.identifier, cookie->debug_id); - - lookup_data = kmalloc(sizeof(*lookup_data), cachefiles_gfp); - if (!lookup_data) - goto nomem_lookup_data; - - /* create a new object record and a temporary leaf image */ - object = kmem_cache_alloc(cachefiles_object_jar, cachefiles_gfp); - if (!object) - goto nomem_object; - - ASSERTCMP(object->backer, ==, NULL); - - BUG_ON(test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)); - atomic_set(&object->usage, 1); - - fscache_object_init(&object->fscache, cookie, &cache->cache); - - object->type = cookie->def->type; - - /* get hold of the raw key - * - stick the length on the front and leave space on the back for the - * encoder - */ - buffer = kmalloc((2 + 512) + 3, cachefiles_gfp); - if (!buffer) - goto nomem_buffer; - - keylen = cookie->key_len; - if (keylen <= sizeof(cookie->inline_key)) - p = cookie->inline_key; - else - p = cookie->key; - memcpy(buffer + 2, p, keylen); - - *(uint16_t *)buffer = keylen; - ((char *)buffer)[keylen + 2] = 0; - ((char *)buffer)[keylen + 3] = 0; - ((char *)buffer)[keylen + 4] = 0; - - /* turn the raw key into something that can work with as a filename */ - key = cachefiles_cook_key(buffer, keylen + 2, object->type); - if (!key) - goto nomem_key; - - /* get hold of the auxiliary data and prepend the object type */ - auxdata = buffer; - auxlen = cookie->aux_len; - if (auxlen) { - if (auxlen <= sizeof(cookie->inline_aux)) - p = cookie->inline_aux; - else - p = cookie->aux; - memcpy(auxdata->data, p, auxlen); - } - - auxdata->len = auxlen + 1; - auxdata->type = cookie->type; - - lookup_data->auxdata = auxdata; - lookup_data->key = key; - object->lookup_data = lookup_data; - - _leave(" = %x [%p]", object->fscache.debug_id, lookup_data); - return &object->fscache; - -nomem_key: - kfree(buffer); -nomem_buffer: - BUG_ON(test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)); - kmem_cache_free(cachefiles_object_jar, object); - fscache_object_destroyed(&cache->cache); -nomem_object: - kfree(lookup_data); -nomem_lookup_data: - _leave(" = -ENOMEM"); - return ERR_PTR(-ENOMEM); -} - -/* - * attempt to look up the nominated node in this cache - * - return -ETIMEDOUT to be scheduled again - */ -static int cachefiles_lookup_object(struct fscache_object *_object) -{ - struct cachefiles_lookup_data *lookup_data; - struct cachefiles_object *parent, *object; - struct cachefiles_cache *cache; - const struct cred *saved_cred; - int ret; - - _enter("{OBJ%x}", _object->debug_id); - - cache = container_of(_object->cache, struct cachefiles_cache, cache); - parent = container_of(_object->parent, - struct cachefiles_object, fscache); - object = container_of(_object, struct cachefiles_object, fscache); - lookup_data = object->lookup_data; - - ASSERTCMP(lookup_data, !=, NULL); - - /* look up the key, creating any missing bits */ - cachefiles_begin_secure(cache, &saved_cred); - ret = cachefiles_walk_to_object(parent, object, - lookup_data->key, - lookup_data->auxdata); - cachefiles_end_secure(cache, saved_cred); - - /* polish off by setting the attributes of non-index files */ - if (ret == 0 && - object->fscache.cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) - cachefiles_attr_changed(&object->fscache); - - if (ret < 0 && ret != -ETIMEDOUT) { - if (ret != -ENOBUFS) - pr_warn("Lookup failed error %d\n", ret); - fscache_object_lookup_error(&object->fscache); - } - - _leave(" [%d]", ret); - return ret; -} - -/* - * indication of lookup completion - */ -static void cachefiles_lookup_complete(struct fscache_object *_object) -{ - struct cachefiles_object *object; - - object = container_of(_object, struct cachefiles_object, fscache); - - _enter("{OBJ%x,%p}", object->fscache.debug_id, object->lookup_data); - - if (object->lookup_data) { - kfree(object->lookup_data->key); - kfree(object->lookup_data->auxdata); - kfree(object->lookup_data); - object->lookup_data = NULL; - } -} - -/* - * increment the usage count on an inode object (may fail if unmounting) - */ -static -struct fscache_object *cachefiles_grab_object(struct fscache_object *_object, - enum fscache_obj_ref_trace why) -{ - struct cachefiles_object *object = - container_of(_object, struct cachefiles_object, fscache); - int u; - - _enter("{OBJ%x,%d}", _object->debug_id, atomic_read(&object->usage)); - -#ifdef CACHEFILES_DEBUG_SLAB - ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000); -#endif - - u = atomic_inc_return(&object->usage); - trace_cachefiles_ref(object, _object->cookie, - (enum cachefiles_obj_ref_trace)why, u); - return &object->fscache; -} - -/* - * update the auxiliary data for an object object on disk - */ -static void cachefiles_update_object(struct fscache_object *_object) -{ - struct cachefiles_object *object; - struct cachefiles_xattr *auxdata; - struct cachefiles_cache *cache; - struct fscache_cookie *cookie; - const struct cred *saved_cred; - const void *aux; - unsigned auxlen; - - _enter("{OBJ%x}", _object->debug_id); - - object = container_of(_object, struct cachefiles_object, fscache); - cache = container_of(object->fscache.cache, struct cachefiles_cache, - cache); - - if (!fscache_use_cookie(_object)) { - _leave(" [relinq]"); - return; - } - - cookie = object->fscache.cookie; - auxlen = cookie->aux_len; - - if (!auxlen) { - fscache_unuse_cookie(_object); - _leave(" [no aux]"); - return; - } - - auxdata = kmalloc(2 + auxlen + 3, cachefiles_gfp); - if (!auxdata) { - fscache_unuse_cookie(_object); - _leave(" [nomem]"); - return; - } - - aux = (auxlen <= sizeof(cookie->inline_aux)) ? - cookie->inline_aux : cookie->aux; - - memcpy(auxdata->data, aux, auxlen); - fscache_unuse_cookie(_object); - - auxdata->len = auxlen + 1; - auxdata->type = cookie->type; - - cachefiles_begin_secure(cache, &saved_cred); - cachefiles_update_object_xattr(object, auxdata); - cachefiles_end_secure(cache, saved_cred); - kfree(auxdata); - _leave(""); -} - -/* - * discard the resources pinned by an object and effect retirement if - * requested - */ -static void cachefiles_drop_object(struct fscache_object *_object) -{ - struct cachefiles_object *object; - struct cachefiles_cache *cache; - const struct cred *saved_cred; - struct inode *inode; - blkcnt_t i_blocks = 0; - - ASSERT(_object); - - object = container_of(_object, struct cachefiles_object, fscache); - - _enter("{OBJ%x,%d}", - object->fscache.debug_id, atomic_read(&object->usage)); - - cache = container_of(object->fscache.cache, - struct cachefiles_cache, cache); - -#ifdef CACHEFILES_DEBUG_SLAB - ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000); -#endif - - /* We need to tidy the object up if we did in fact manage to open it. - * It's possible for us to get here before the object is fully - * initialised if the parent goes away or the object gets retired - * before we set it up. - */ - if (object->dentry) { - /* delete retired objects */ - if (test_bit(FSCACHE_OBJECT_RETIRED, &object->fscache.flags) && - _object != cache->cache.fsdef - ) { - _debug("- retire object OBJ%x", object->fscache.debug_id); - inode = d_backing_inode(object->dentry); - if (inode) - i_blocks = inode->i_blocks; - - cachefiles_begin_secure(cache, &saved_cred); - cachefiles_delete_object(cache, object); - cachefiles_end_secure(cache, saved_cred); - } - - /* close the filesystem stuff attached to the object */ - if (object->backer != object->dentry) - dput(object->backer); - object->backer = NULL; - } - - /* note that the object is now inactive */ - if (test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)) - cachefiles_mark_object_inactive(cache, object, i_blocks); - - dput(object->dentry); - object->dentry = NULL; - - _leave(""); -} - -/* - * dispose of a reference to an object - */ -void cachefiles_put_object(struct fscache_object *_object, - enum fscache_obj_ref_trace why) -{ - struct cachefiles_object *object; - struct fscache_cache *cache; - int u; - - ASSERT(_object); - - object = container_of(_object, struct cachefiles_object, fscache); - - _enter("{OBJ%x,%d}", - object->fscache.debug_id, atomic_read(&object->usage)); - -#ifdef CACHEFILES_DEBUG_SLAB - ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000); -#endif - - ASSERTIFCMP(object->fscache.parent, - object->fscache.parent->n_children, >, 0); - - u = atomic_dec_return(&object->usage); - trace_cachefiles_ref(object, _object->cookie, - (enum cachefiles_obj_ref_trace)why, u); - ASSERTCMP(u, !=, -1); - if (u == 0) { - _debug("- kill object OBJ%x", object->fscache.debug_id); - - ASSERT(!test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)); - ASSERTCMP(object->fscache.parent, ==, NULL); - ASSERTCMP(object->backer, ==, NULL); - ASSERTCMP(object->dentry, ==, NULL); - ASSERTCMP(object->fscache.n_ops, ==, 0); - ASSERTCMP(object->fscache.n_children, ==, 0); - - if (object->lookup_data) { - kfree(object->lookup_data->key); - kfree(object->lookup_data->auxdata); - kfree(object->lookup_data); - object->lookup_data = NULL; - } - - cache = object->fscache.cache; - fscache_object_destroy(&object->fscache); - kmem_cache_free(cachefiles_object_jar, object); - fscache_object_destroyed(cache); - } - - _leave(""); -} - -/* - * sync a cache - */ -static void cachefiles_sync_cache(struct fscache_cache *_cache) -{ - struct cachefiles_cache *cache; - const struct cred *saved_cred; - int ret; - - _enter("%s", _cache->tag->name); - - cache = container_of(_cache, struct cachefiles_cache, cache); - - /* make sure all pages pinned by operations on behalf of the netfs are - * written to disc */ - cachefiles_begin_secure(cache, &saved_cred); - down_read(&cache->mnt->mnt_sb->s_umount); - ret = sync_filesystem(cache->mnt->mnt_sb); - up_read(&cache->mnt->mnt_sb->s_umount); - cachefiles_end_secure(cache, saved_cred); - - if (ret == -EIO) - cachefiles_io_error(cache, - "Attempt to sync backing fs superblock" - " returned error %d", - ret); -} - -/* - * check if the backing cache is updated to FS-Cache - * - called by FS-Cache when evaluates if need to invalidate the cache - */ -static int cachefiles_check_consistency(struct fscache_operation *op) -{ - struct cachefiles_object *object; - struct cachefiles_cache *cache; - const struct cred *saved_cred; - int ret; - - _enter("{OBJ%x}", op->object->debug_id); - - object = container_of(op->object, struct cachefiles_object, fscache); - cache = container_of(object->fscache.cache, - struct cachefiles_cache, cache); - - cachefiles_begin_secure(cache, &saved_cred); - ret = cachefiles_check_auxdata(object); - cachefiles_end_secure(cache, saved_cred); - - _leave(" = %d", ret); - return ret; -} - -/* - * notification the attributes on an object have changed - * - called with reads/writes excluded by FS-Cache - */ -static int cachefiles_attr_changed(struct fscache_object *_object) -{ - struct cachefiles_object *object; - struct cachefiles_cache *cache; - const struct cred *saved_cred; - struct iattr newattrs; - uint64_t ni_size; - loff_t oi_size; - int ret; - - ni_size = _object->store_limit_l; - - _enter("{OBJ%x},[%llu]", - _object->debug_id, (unsigned long long) ni_size); - - object = container_of(_object, struct cachefiles_object, fscache); - cache = container_of(object->fscache.cache, - struct cachefiles_cache, cache); - - if (ni_size == object->i_size) - return 0; - - if (!object->backer) - return -ENOBUFS; - - ASSERT(d_is_reg(object->backer)); - - fscache_set_store_limit(&object->fscache, ni_size); - - oi_size = i_size_read(d_backing_inode(object->backer)); - if (oi_size == ni_size) - return 0; - - cachefiles_begin_secure(cache, &saved_cred); - inode_lock(d_inode(object->backer)); - - /* if there's an extension to a partial page at the end of the backing - * file, we need to discard the partial page so that we pick up new - * data after it */ - if (oi_size & ~PAGE_MASK && ni_size > oi_size) { - _debug("discard tail %llx", oi_size); - newattrs.ia_valid = ATTR_SIZE; - newattrs.ia_size = oi_size & PAGE_MASK; - ret = notify_change(&init_user_ns, object->backer, &newattrs, NULL); - if (ret < 0) - goto truncate_failed; - } - - newattrs.ia_valid = ATTR_SIZE; - newattrs.ia_size = ni_size; - ret = notify_change(&init_user_ns, object->backer, &newattrs, NULL); - -truncate_failed: - inode_unlock(d_inode(object->backer)); - cachefiles_end_secure(cache, saved_cred); - - if (ret == -EIO) { - fscache_set_store_limit(&object->fscache, 0); - cachefiles_io_error_obj(object, "Size set failed"); - ret = -ENOBUFS; - } - - _leave(" = %d", ret); - return ret; -} - -/* - * Invalidate an object - */ -static void cachefiles_invalidate_object(struct fscache_operation *op) -{ - struct cachefiles_object *object; - struct cachefiles_cache *cache; - const struct cred *saved_cred; - struct path path; - uint64_t ni_size; - int ret; - - object = container_of(op->object, struct cachefiles_object, fscache); - cache = container_of(object->fscache.cache, - struct cachefiles_cache, cache); - - ni_size = op->object->store_limit_l; - - _enter("{OBJ%x},[%llu]", - op->object->debug_id, (unsigned long long)ni_size); - - if (object->backer) { - ASSERT(d_is_reg(object->backer)); - - fscache_set_store_limit(&object->fscache, ni_size); - - path.dentry = object->backer; - path.mnt = cache->mnt; - - cachefiles_begin_secure(cache, &saved_cred); - ret = vfs_truncate(&path, 0); - if (ret == 0) - ret = vfs_truncate(&path, ni_size); - cachefiles_end_secure(cache, saved_cred); - - if (ret != 0) { - fscache_set_store_limit(&object->fscache, 0); - if (ret == -EIO) - cachefiles_io_error_obj(object, - "Invalidate failed"); - } - } - - fscache_op_complete(op, true); - _leave(""); -} - -/* - * dissociate a cache from all the pages it was backing - */ -static void cachefiles_dissociate_pages(struct fscache_cache *cache) -{ - _enter(""); -} - -const struct fscache_cache_ops cachefiles_cache_ops = { - .name = "cachefiles", - .alloc_object = cachefiles_alloc_object, - .lookup_object = cachefiles_lookup_object, - .lookup_complete = cachefiles_lookup_complete, - .grab_object = cachefiles_grab_object, - .update_object = cachefiles_update_object, - .invalidate_object = cachefiles_invalidate_object, - .drop_object = cachefiles_drop_object, - .put_object = cachefiles_put_object, - .sync_cache = cachefiles_sync_cache, - .attr_changed = cachefiles_attr_changed, - .read_or_alloc_page = cachefiles_read_or_alloc_page, - .read_or_alloc_pages = cachefiles_read_or_alloc_pages, - .allocate_page = cachefiles_allocate_page, - .allocate_pages = cachefiles_allocate_pages, - .write_page = cachefiles_write_page, - .uncache_page = cachefiles_uncache_page, - .dissociate_pages = cachefiles_dissociate_pages, - .check_consistency = cachefiles_check_consistency, - .begin_read_operation = cachefiles_begin_read_operation, -}; diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h deleted file mode 100644 index 0a511c36dab8..000000000000 --- a/fs/cachefiles/internal.h +++ /dev/null @@ -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 -#include -#include -#include -#include -#include - -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 - -/* - * 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 diff --git a/fs/cachefiles/io.c b/fs/cachefiles/io.c deleted file mode 100644 index effe37ef8629..000000000000 --- a/fs/cachefiles/io.c +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#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; -} diff --git a/fs/cachefiles/key.c b/fs/cachefiles/key.c deleted file mode 100644 index 7f94efc97e23..000000000000 --- a/fs/cachefiles/key.c +++ /dev/null @@ -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 -#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; -} diff --git a/fs/cachefiles/main.c b/fs/cachefiles/main.c deleted file mode 100644 index 9c8d34c49b12..000000000000 --- a/fs/cachefiles/main.c +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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); diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c deleted file mode 100644 index a9aca5ab5970..000000000000 --- a/fs/cachefiles/namei.c +++ /dev/null @@ -1,1018 +0,0 @@ -// 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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=%x\n", - prefix, object->fscache.parent ? object->fscache.parent->debug_id : 0); - - spin_lock(&object->fscache.lock); - cookie = object->fscache.cookie; - if (cookie) { - pr_err("%scookie=%x [pr=%x nd=%p fl=%lx]\n", - prefix, - cookie->debug_id, - cookie->parent ? cookie->parent->debug_id : 0, - cookie->netfs_data, - 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] %pd", - 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, - struct cachefiles_object *object) -{ - struct cachefiles_object *xobject; - struct rb_node **_p, *_parent = NULL; - struct dentry *dentry; - - _enter(",%x", object->fscache.debug_id); - -try_again: - write_lock(&cache->active_lock); - - dentry = object->dentry; - trace_cachefiles_mark_active(object, dentry); - - if (test_and_set_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)) { - pr_err("Error: Object already active\n"); - cachefiles_printk_object(object, NULL); - BUG(); - } - - _p = &cache->active_nodes.rb_node; - while (*_p) { - _parent = *_p; - xobject = rb_entry(_parent, - struct cachefiles_object, active_node); - - ASSERT(xobject != object); - - if (xobject->dentry > dentry) - _p = &(*_p)->rb_left; - else if (xobject->dentry < dentry) - _p = &(*_p)->rb_right; - else - goto wait_for_old_object; - } - - rb_link_node(&object->active_node, _parent, _p); - rb_insert_color(&object->active_node, &cache->active_nodes); - - write_unlock(&cache->active_lock); - _leave(" = 0"); - return 0; - - /* an old object from a previous incarnation is hogging the slot - we - * need to wait for it to be destroyed */ -wait_for_old_object: - trace_cachefiles_wait_active(object, dentry, xobject); - clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); - - if (fscache_object_is_live(&xobject->fscache)) { - pr_err("\n"); - pr_err("Error: Unexpected object collision\n"); - cachefiles_printk_object(object, xobject); - } - atomic_inc(&xobject->usage); - write_unlock(&cache->active_lock); - - if (test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) { - wait_queue_head_t *wq; - - signed long timeout = 60 * HZ; - wait_queue_entry_t wait; - bool requeue; - - /* if the object we're waiting for is queued for processing, - * then just put ourselves on the queue behind it */ - if (work_pending(&xobject->fscache.work)) { - _debug("queue OBJ%x behind OBJ%x immediately", - object->fscache.debug_id, - xobject->fscache.debug_id); - goto requeue; - } - - /* otherwise we sleep until either the object we're waiting for - * is done, or the fscache_object is congested */ - wq = bit_waitqueue(&xobject->flags, CACHEFILES_OBJECT_ACTIVE); - init_wait(&wait); - requeue = false; - do { - prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); - if (!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) - break; - - requeue = fscache_object_sleep_till_congested(&timeout); - } while (timeout > 0 && !requeue); - finish_wait(wq, &wait); - - if (requeue && - test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) { - _debug("queue OBJ%x behind OBJ%x after wait", - object->fscache.debug_id, - xobject->fscache.debug_id); - goto requeue; - } - - if (timeout <= 0) { - pr_err("\n"); - pr_err("Error: Overlong wait for old active object to go away\n"); - cachefiles_printk_object(object, xobject); - goto requeue; - } - } - - ASSERT(!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)); - - cache->cache.ops->put_object(&xobject->fscache, - (enum fscache_obj_ref_trace)cachefiles_obj_put_wait_retry); - goto try_again; - -requeue: - cache->cache.ops->put_object(&xobject->fscache, - (enum fscache_obj_ref_trace)cachefiles_obj_put_wait_timeo); - _leave(" = -ETIMEDOUT"); - return -ETIMEDOUT; -} - -/* - * Mark an object as being inactive. - */ -void cachefiles_mark_object_inactive(struct cachefiles_cache *cache, - struct cachefiles_object *object, - blkcnt_t i_blocks) -{ - struct dentry *dentry = object->dentry; - struct inode *inode = d_backing_inode(dentry); - - trace_cachefiles_mark_inactive(object, dentry, inode); - - write_lock(&cache->active_lock); - rb_erase(&object->active_node, &cache->active_nodes); - clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); - write_unlock(&cache->active_lock); - - wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE); - - /* This object can now be culled, so we need to let the daemon know - * that there is something it can remove if it needs to. - */ - atomic_long_add(i_blocks, &cache->b_released); - if (atomic_inc_return(&cache->f_released)) - cachefiles_state_changed(cache); -} - -/* - * delete an object representation from the cache - * - file backed objects are unlinked - * - directory backed objects are stuffed into the graveyard for userspace to - * delete - * - unlocks the directory mutex - */ -static int cachefiles_bury_object(struct cachefiles_cache *cache, - struct cachefiles_object *object, - struct dentry *dir, - struct dentry *rep, - bool preemptive, - enum fscache_why_object_killed why) -{ - struct dentry *grave, *trap; - struct path path, path_to_graveyard; - char nbuffer[8 + 8 + 1]; - int ret; - - _enter(",'%pd','%pd'", dir, rep); - - /* non-directories can just be unlinked */ - if (!d_is_dir(rep)) { - _debug("unlink stale object"); - - path.mnt = cache->mnt; - path.dentry = dir; - ret = security_path_unlink(&path, rep); - if (ret < 0) { - cachefiles_io_error(cache, "Unlink security error"); - } else { - trace_cachefiles_unlink(object, rep, why); - ret = vfs_unlink(&init_user_ns, d_inode(dir), rep, - NULL); - - if (preemptive) - cachefiles_mark_object_buried(cache, rep, why); - } - - inode_unlock(d_inode(dir)); - - if (ret == -EIO) - cachefiles_io_error(cache, "Unlink failed"); - - _leave(" = %d", ret); - return ret; - } - - /* directories have to be moved to the graveyard */ - _debug("move stale object to graveyard"); - inode_unlock(d_inode(dir)); - -try_again: - /* first step is to make up a grave dentry in the graveyard */ - sprintf(nbuffer, "%08x%08x", - (uint32_t) ktime_get_real_seconds(), - (uint32_t) atomic_inc_return(&cache->gravecounter)); - - /* do the multiway lock magic */ - trap = lock_rename(cache->graveyard, dir); - - /* do some checks before getting the grave dentry */ - if (rep->d_parent != dir || IS_DEADDIR(d_inode(rep))) { - /* the entry was probably culled when we dropped the parent dir - * lock */ - unlock_rename(cache->graveyard, dir); - _leave(" = 0 [culled?]"); - return 0; - } - - if (!d_can_lookup(cache->graveyard)) { - unlock_rename(cache->graveyard, dir); - cachefiles_io_error(cache, "Graveyard no longer a directory"); - return -EIO; - } - - if (trap == rep) { - unlock_rename(cache->graveyard, dir); - cachefiles_io_error(cache, "May not make directory loop"); - return -EIO; - } - - if (d_mountpoint(rep)) { - unlock_rename(cache->graveyard, dir); - cachefiles_io_error(cache, "Mountpoint in cache"); - return -EIO; - } - - grave = lookup_one_len(nbuffer, cache->graveyard, strlen(nbuffer)); - if (IS_ERR(grave)) { - unlock_rename(cache->graveyard, dir); - - if (PTR_ERR(grave) == -ENOMEM) { - _leave(" = -ENOMEM"); - return -ENOMEM; - } - - cachefiles_io_error(cache, "Lookup error %ld", - PTR_ERR(grave)); - return -EIO; - } - - if (d_is_positive(grave)) { - unlock_rename(cache->graveyard, dir); - dput(grave); - grave = NULL; - cond_resched(); - goto try_again; - } - - if (d_mountpoint(grave)) { - unlock_rename(cache->graveyard, dir); - dput(grave); - cachefiles_io_error(cache, "Mountpoint in graveyard"); - return -EIO; - } - - /* target should not be an ancestor of source */ - if (trap == grave) { - unlock_rename(cache->graveyard, dir); - dput(grave); - cachefiles_io_error(cache, "May not make directory loop"); - return -EIO; - } - - /* attempt the rename */ - path.mnt = cache->mnt; - path.dentry = dir; - path_to_graveyard.mnt = cache->mnt; - path_to_graveyard.dentry = cache->graveyard; - ret = security_path_rename(&path, rep, &path_to_graveyard, grave, 0); - if (ret < 0) { - cachefiles_io_error(cache, "Rename security error %d", ret); - } else { - struct renamedata rd = { - .old_mnt_userns = &init_user_ns, - .old_dir = d_inode(dir), - .old_dentry = rep, - .new_mnt_userns = &init_user_ns, - .new_dir = d_inode(cache->graveyard), - .new_dentry = grave, - }; - trace_cachefiles_rename(object, rep, grave, why); - ret = vfs_rename(&rd); - if (ret != 0 && ret != -ENOMEM) - cachefiles_io_error(cache, - "Rename failed with error %d", ret); - - if (preemptive) - cachefiles_mark_object_buried(cache, rep, why); - } - - unlock_rename(cache->graveyard, dir); - dput(grave); - _leave(" = 0"); - return 0; -} - -/* - * delete an object representation from the cache - */ -int cachefiles_delete_object(struct cachefiles_cache *cache, - struct cachefiles_object *object) -{ - struct dentry *dir; - int ret; - - _enter(",OBJ%x{%pd}", object->fscache.debug_id, object->dentry); - - ASSERT(object->dentry); - ASSERT(d_backing_inode(object->dentry)); - ASSERT(object->dentry->d_parent); - - dir = dget_parent(object->dentry); - - inode_lock_nested(d_inode(dir), I_MUTEX_PARENT); - - if (test_bit(FSCACHE_OBJECT_KILLED_BY_CACHE, &object->fscache.flags)) { - /* object allocation for the same key preemptively deleted this - * object's file so that it could create its own file */ - _debug("object preemptively buried"); - inode_unlock(d_inode(dir)); - ret = 0; - } else { - /* we need to check that our parent is _still_ our parent - it - * may have been renamed */ - if (dir == object->dentry->d_parent) { - ret = cachefiles_bury_object(cache, object, dir, - object->dentry, false, - FSCACHE_OBJECT_WAS_RETIRED); - } else { - /* it got moved, presumably by cachefilesd culling it, - * so it's no longer in the key path and we can ignore - * it */ - inode_unlock(d_inode(dir)); - ret = 0; - } - } - - dput(dir); - _leave(" = %d", ret); - return ret; -} - -/* - * walk from the parent object to the child object through the backing - * filesystem, creating directories as we go - */ -int cachefiles_walk_to_object(struct cachefiles_object *parent, - struct cachefiles_object *object, - const char *key, - struct cachefiles_xattr *auxdata) -{ - struct cachefiles_cache *cache; - struct dentry *dir, *next = NULL; - struct inode *inode; - struct path path; - const char *name; - int ret, nlen; - - _enter("OBJ%x{%pd},OBJ%x,%s,", - parent->fscache.debug_id, parent->dentry, - object->fscache.debug_id, key); - - cache = container_of(parent->fscache.cache, - struct cachefiles_cache, cache); - path.mnt = cache->mnt; - - ASSERT(parent->dentry); - ASSERT(d_backing_inode(parent->dentry)); - - if (!(d_is_dir(parent->dentry))) { - // TODO: convert file to dir - _leave("looking up in none directory"); - return -ENOBUFS; - } - - dir = dget(parent->dentry); - -advance: - /* attempt to transit the first directory component */ - name = key; - nlen = strlen(key); - - /* key ends in a double NUL */ - key = key + nlen + 1; - if (!*key) - key = NULL; - -lookup_again: - /* search the current directory for the element name */ - _debug("lookup '%s'", name); - - inode_lock_nested(d_inode(dir), I_MUTEX_PARENT); - - next = lookup_one_len(name, dir, nlen); - if (IS_ERR(next)) { - trace_cachefiles_lookup(object, next, NULL); - goto lookup_error; - } - - inode = d_backing_inode(next); - trace_cachefiles_lookup(object, next, inode); - _debug("next -> %pd %s", next, inode ? "positive" : "negative"); - - if (!key) - object->new = !inode; - - /* if this element of the path doesn't exist, then the lookup phase - * failed, and we can release any readers in the certain knowledge that - * there's nothing for them to actually read */ - if (d_is_negative(next)) - fscache_object_lookup_negative(&object->fscache); - - /* we need to create the object if it's negative */ - if (key || object->type == FSCACHE_COOKIE_TYPE_INDEX) { - /* index objects and intervening tree levels must be subdirs */ - if (d_is_negative(next)) { - ret = cachefiles_has_space(cache, 1, 0); - if (ret < 0) - goto no_space_error; - - path.dentry = dir; - ret = security_path_mkdir(&path, next, 0); - if (ret < 0) - goto create_error; - ret = vfs_mkdir(&init_user_ns, d_inode(dir), next, 0); - if (!key) - trace_cachefiles_mkdir(object, next, ret); - if (ret < 0) - goto create_error; - - if (unlikely(d_unhashed(next))) { - dput(next); - inode_unlock(d_inode(dir)); - goto lookup_again; - } - ASSERT(d_backing_inode(next)); - - _debug("mkdir -> %pd{ino=%lu}", - next, d_backing_inode(next)->i_ino); - - } else if (!d_can_lookup(next)) { - pr_err("inode %lu is not a directory\n", - d_backing_inode(next)->i_ino); - ret = -ENOBUFS; - goto error; - } - - } else { - /* non-index objects start out life as files */ - if (d_is_negative(next)) { - ret = cachefiles_has_space(cache, 1, 0); - if (ret < 0) - goto no_space_error; - - path.dentry = dir; - ret = security_path_mknod(&path, next, S_IFREG, 0); - if (ret < 0) - goto create_error; - ret = vfs_create(&init_user_ns, d_inode(dir), next, - S_IFREG, true); - trace_cachefiles_create(object, next, ret); - if (ret < 0) - goto create_error; - - ASSERT(d_backing_inode(next)); - - _debug("create -> %pd{ino=%lu}", - next, d_backing_inode(next)->i_ino); - - } else if (!d_can_lookup(next) && - !d_is_reg(next) - ) { - pr_err("inode %lu is not a file or directory\n", - d_backing_inode(next)->i_ino); - ret = -ENOBUFS; - goto error; - } - } - - /* process the next component */ - if (key) { - _debug("advance"); - inode_unlock(d_inode(dir)); - dput(dir); - dir = next; - next = NULL; - goto advance; - } - - /* we've found the object we were looking for */ - object->dentry = next; - - /* if we've found that the terminal object exists, then we need to - * check its attributes and delete it if it's out of date */ - if (!object->new) { - _debug("validate '%pd'", next); - - ret = cachefiles_check_object_xattr(object, auxdata); - if (ret == -ESTALE) { - /* delete the object (the deleter drops the directory - * mutex) */ - object->dentry = NULL; - - ret = cachefiles_bury_object(cache, object, dir, next, - true, - FSCACHE_OBJECT_IS_STALE); - dput(next); - next = NULL; - - if (ret < 0) - goto delete_error; - - _debug("redo lookup"); - fscache_object_retrying_stale(&object->fscache); - goto lookup_again; - } - } - - /* note that we're now using this object */ - ret = cachefiles_mark_object_active(cache, object); - - inode_unlock(d_inode(dir)); - dput(dir); - dir = NULL; - - if (ret == -ETIMEDOUT) - goto mark_active_timed_out; - - _debug("=== OBTAINED_OBJECT ==="); - - if (object->new) { - /* attach data to a newly constructed terminal object */ - ret = cachefiles_set_object_xattr(object, auxdata); - if (ret < 0) - goto check_error; - } else { - /* always update the atime on an object we've just looked up - * (this is used to keep track of culling, and atimes are only - * updated by read, write and readdir but not lookup or - * open) */ - path.dentry = next; - touch_atime(&path); - } - - /* open a file interface onto a data file */ - if (object->type != FSCACHE_COOKIE_TYPE_INDEX) { - if (d_is_reg(object->dentry)) { - const struct address_space_operations *aops; - - ret = -EPERM; - aops = d_backing_inode(object->dentry)->i_mapping->a_ops; - if (!aops->bmap) - goto check_error; - if (object->dentry->d_sb->s_blocksize > PAGE_SIZE) - goto check_error; - - object->backer = object->dentry; - } else { - BUG(); // TODO: open file in data-class subdir - } - } - - object->new = 0; - fscache_obtained_object(&object->fscache); - - _leave(" = 0 [%lu]", d_backing_inode(object->dentry)->i_ino); - return 0; - -no_space_error: - fscache_object_mark_killed(&object->fscache, FSCACHE_OBJECT_NO_SPACE); -create_error: - _debug("create error %d", ret); - if (ret == -EIO) - cachefiles_io_error(cache, "Create/mkdir failed"); - goto error; - -mark_active_timed_out: - _debug("mark active timed out"); - goto release_dentry; - -check_error: - _debug("check error %d", ret); - cachefiles_mark_object_inactive( - cache, object, d_backing_inode(object->dentry)->i_blocks); -release_dentry: - dput(object->dentry); - object->dentry = NULL; - goto error_out; - -delete_error: - _debug("delete error %d", ret); - goto error_out2; - -lookup_error: - _debug("lookup error %ld", PTR_ERR(next)); - ret = PTR_ERR(next); - if (ret == -EIO) - cachefiles_io_error(cache, "Lookup failed"); - next = NULL; -error: - inode_unlock(d_inode(dir)); - dput(next); -error_out2: - dput(dir); -error_out: - _leave(" = error %d", -ret); - return ret; -} - -/* - * get a subdirectory - */ -struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache, - struct dentry *dir, - const char *dirname) -{ - struct dentry *subdir; - struct path path; - int ret; - - _enter(",,%s", dirname); - - /* search the current directory for the element name */ - inode_lock(d_inode(dir)); - -retry: - subdir = lookup_one_len(dirname, dir, strlen(dirname)); - if (IS_ERR(subdir)) { - if (PTR_ERR(subdir) == -ENOMEM) - goto nomem_d_alloc; - goto lookup_error; - } - - _debug("subdir -> %pd %s", - subdir, d_backing_inode(subdir) ? "positive" : "negative"); - - /* we need to create the subdir if it doesn't exist yet */ - if (d_is_negative(subdir)) { - ret = cachefiles_has_space(cache, 1, 0); - if (ret < 0) - goto mkdir_error; - - _debug("attempt mkdir"); - - path.mnt = cache->mnt; - path.dentry = dir; - ret = security_path_mkdir(&path, subdir, 0700); - if (ret < 0) - goto mkdir_error; - ret = vfs_mkdir(&init_user_ns, d_inode(dir), subdir, 0700); - if (ret < 0) - goto mkdir_error; - - if (unlikely(d_unhashed(subdir))) { - dput(subdir); - goto retry; - } - ASSERT(d_backing_inode(subdir)); - - _debug("mkdir -> %pd{ino=%lu}", - subdir, d_backing_inode(subdir)->i_ino); - } - - inode_unlock(d_inode(dir)); - - /* we need to make sure the subdir is a directory */ - ASSERT(d_backing_inode(subdir)); - - if (!d_can_lookup(subdir)) { - pr_err("%s is not a directory\n", dirname); - ret = -EIO; - goto check_error; - } - - ret = -EPERM; - if (!(d_backing_inode(subdir)->i_opflags & IOP_XATTR) || - !d_backing_inode(subdir)->i_op->lookup || - !d_backing_inode(subdir)->i_op->mkdir || - !d_backing_inode(subdir)->i_op->create || - !d_backing_inode(subdir)->i_op->rename || - !d_backing_inode(subdir)->i_op->rmdir || - !d_backing_inode(subdir)->i_op->unlink) - goto check_error; - - _leave(" = [%lu]", d_backing_inode(subdir)->i_ino); - return subdir; - -check_error: - dput(subdir); - _leave(" = %d [check]", ret); - return ERR_PTR(ret); - -mkdir_error: - inode_unlock(d_inode(dir)); - dput(subdir); - pr_err("mkdir %s failed with error %d\n", dirname, ret); - return ERR_PTR(ret); - -lookup_error: - inode_unlock(d_inode(dir)); - ret = PTR_ERR(subdir); - pr_err("Lookup %s failed with error %d\n", dirname, ret); - return ERR_PTR(ret); - -nomem_d_alloc: - inode_unlock(d_inode(dir)); - _leave(" = -ENOMEM"); - return ERR_PTR(-ENOMEM); -} - -/* - * find out if an object is in use or not - * - if finds object and it's not in use: - * - returns a pointer to the object and a reference on it - * - returns with the directory locked - */ -static struct dentry *cachefiles_check_active(struct cachefiles_cache *cache, - struct dentry *dir, - char *filename) -{ - struct cachefiles_object *object; - struct rb_node *_n; - struct dentry *victim; - int ret; - - //_enter(",%pd/,%s", - // dir, filename); - - /* look up the victim */ - inode_lock_nested(d_inode(dir), I_MUTEX_PARENT); - - victim = lookup_one_len(filename, dir, strlen(filename)); - if (IS_ERR(victim)) - goto lookup_error; - - //_debug("victim -> %pd %s", - // victim, d_backing_inode(victim) ? "positive" : "negative"); - - /* if the object is no longer there then we probably retired the object - * at the netfs's request whilst the cull was in progress - */ - if (d_is_negative(victim)) { - inode_unlock(d_inode(dir)); - dput(victim); - _leave(" = -ENOENT [absent]"); - return ERR_PTR(-ENOENT); - } - - /* check to see if we're using this object */ - read_lock(&cache->active_lock); - - _n = cache->active_nodes.rb_node; - - while (_n) { - object = rb_entry(_n, struct cachefiles_object, active_node); - - if (object->dentry > victim) - _n = _n->rb_left; - else if (object->dentry < victim) - _n = _n->rb_right; - else - goto object_in_use; - } - - read_unlock(&cache->active_lock); - - //_leave(" = %pd", victim); - return victim; - -object_in_use: - read_unlock(&cache->active_lock); - inode_unlock(d_inode(dir)); - dput(victim); - //_leave(" = -EBUSY [in use]"); - return ERR_PTR(-EBUSY); - -lookup_error: - inode_unlock(d_inode(dir)); - ret = PTR_ERR(victim); - if (ret == -ENOENT) { - /* file or dir now absent - probably retired by netfs */ - _leave(" = -ESTALE [absent]"); - return ERR_PTR(-ESTALE); - } - - if (ret == -EIO) { - cachefiles_io_error(cache, "Lookup failed"); - } else if (ret != -ENOMEM) { - pr_err("Internal error: %d\n", ret); - ret = -EIO; - } - - _leave(" = %d", ret); - return ERR_PTR(ret); -} - -/* - * cull an object if it's not in use - * - called only by cache manager daemon - */ -int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir, - char *filename) -{ - struct dentry *victim; - int ret; - - _enter(",%pd/,%s", dir, filename); - - victim = cachefiles_check_active(cache, dir, filename); - if (IS_ERR(victim)) - return PTR_ERR(victim); - - _debug("victim -> %pd %s", - victim, d_backing_inode(victim) ? "positive" : "negative"); - - /* okay... the victim is not being used so we can cull it - * - start by marking it as stale - */ - _debug("victim is cullable"); - - ret = cachefiles_remove_object_xattr(cache, victim); - if (ret < 0) - goto error_unlock; - - /* actually remove the victim (drops the dir mutex) */ - _debug("bury"); - - ret = cachefiles_bury_object(cache, NULL, dir, victim, false, - FSCACHE_OBJECT_WAS_CULLED); - if (ret < 0) - goto error; - - dput(victim); - _leave(" = 0"); - return 0; - -error_unlock: - inode_unlock(d_inode(dir)); -error: - dput(victim); - if (ret == -ENOENT) { - /* file or dir now absent - probably retired by netfs */ - _leave(" = -ESTALE [absent]"); - return -ESTALE; - } - - if (ret != -ENOMEM) { - pr_err("Internal error: %d\n", ret); - ret = -EIO; - } - - _leave(" = %d", ret); - return ret; -} - -/* - * find out if an object is in use or not - * - called only by cache manager daemon - * - returns -EBUSY or 0 to indicate whether an object is in use or not - */ -int cachefiles_check_in_use(struct cachefiles_cache *cache, struct dentry *dir, - char *filename) -{ - struct dentry *victim; - - //_enter(",%pd/,%s", - // dir, filename); - - victim = cachefiles_check_active(cache, dir, filename); - if (IS_ERR(victim)) - return PTR_ERR(victim); - - inode_unlock(d_inode(dir)); - dput(victim); - //_leave(" = 0"); - return 0; -} diff --git a/fs/cachefiles/rdwr.c b/fs/cachefiles/rdwr.c deleted file mode 100644 index fcf4f3b72923..000000000000 --- a/fs/cachefiles/rdwr.c +++ /dev/null @@ -1,972 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* Storage object read/write - * - * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - */ - -#include -#include -#include -#include -#include "internal.h" - -/* - * detect wake up events generated by the unlocking of pages in which we're - * interested - * - we use this to detect read completion of backing pages - * - the caller holds the waitqueue lock - */ -static int cachefiles_read_waiter(wait_queue_entry_t *wait, unsigned mode, - int sync, void *_key) -{ - struct cachefiles_one_read *monitor = - container_of(wait, struct cachefiles_one_read, monitor); - struct cachefiles_object *object; - struct fscache_retrieval *op = monitor->op; - struct wait_page_key *key = _key; - struct folio *folio = wait->private; - - ASSERT(key); - - _enter("{%lu},%u,%d,{%p,%u}", - monitor->netfs_page->index, mode, sync, - key->folio, key->bit_nr); - - if (key->folio != folio || key->bit_nr != PG_locked) - return 0; - - _debug("--- monitor %p %lx ---", folio, folio->flags); - - if (!folio_test_uptodate(folio) && !folio_test_error(folio)) { - /* unlocked, not uptodate and not erronous? */ - _debug("page probably truncated"); - } - - /* remove from the waitqueue */ - list_del(&wait->entry); - - /* move onto the action list and queue for FS-Cache thread pool */ - ASSERT(op); - - /* We need to temporarily bump the usage count as we don't own a ref - * here otherwise cachefiles_read_copier() may free the op between the - * monitor being enqueued on the op->to_do list and the op getting - * enqueued on the work queue. - */ - fscache_get_retrieval(op); - - object = container_of(op->op.object, struct cachefiles_object, fscache); - spin_lock(&object->work_lock); - list_add_tail(&monitor->op_link, &op->to_do); - fscache_enqueue_retrieval(op); - spin_unlock(&object->work_lock); - - fscache_put_retrieval(op); - return 0; -} - -/* - * handle a probably truncated page - * - check to see if the page is still relevant and reissue the read if - * possible - * - return -EIO on error, -ENODATA if the page is gone, -EINPROGRESS if we - * must wait again and 0 if successful - */ -static int cachefiles_read_reissue(struct cachefiles_object *object, - struct cachefiles_one_read *monitor) -{ - struct address_space *bmapping = d_backing_inode(object->backer)->i_mapping; - struct page *backpage = monitor->back_page, *backpage2; - int ret; - - _enter("{ino=%lx},{%lx,%lx}", - d_backing_inode(object->backer)->i_ino, - backpage->index, backpage->flags); - - /* skip if the page was truncated away completely */ - if (backpage->mapping != bmapping) { - _leave(" = -ENODATA [mapping]"); - return -ENODATA; - } - - backpage2 = find_get_page(bmapping, backpage->index); - if (!backpage2) { - _leave(" = -ENODATA [gone]"); - return -ENODATA; - } - - if (backpage != backpage2) { - put_page(backpage2); - _leave(" = -ENODATA [different]"); - return -ENODATA; - } - - /* the page is still there and we already have a ref on it, so we don't - * need a second */ - put_page(backpage2); - - INIT_LIST_HEAD(&monitor->op_link); - folio_add_wait_queue(page_folio(backpage), &monitor->monitor); - - if (trylock_page(backpage)) { - ret = -EIO; - if (PageError(backpage)) - goto unlock_discard; - ret = 0; - if (PageUptodate(backpage)) - goto unlock_discard; - - _debug("reissue read"); - ret = bmapping->a_ops->readpage(NULL, backpage); - if (ret < 0) - goto discard; - } - - /* but the page may have been read before the monitor was installed, so - * the monitor may miss the event - so we have to ensure that we do get - * one in such a case */ - if (trylock_page(backpage)) { - _debug("jumpstart %p {%lx}", backpage, backpage->flags); - unlock_page(backpage); - } - - /* it'll reappear on the todo list */ - _leave(" = -EINPROGRESS"); - return -EINPROGRESS; - -unlock_discard: - unlock_page(backpage); -discard: - spin_lock_irq(&object->work_lock); - list_del(&monitor->op_link); - spin_unlock_irq(&object->work_lock); - _leave(" = %d", ret); - return ret; -} - -/* - * copy data from backing pages to netfs pages to complete a read operation - * - driven by FS-Cache's thread pool - */ -static void cachefiles_read_copier(struct fscache_operation *_op) -{ - struct cachefiles_one_read *monitor; - struct cachefiles_object *object; - struct fscache_retrieval *op; - int error, max; - - op = container_of(_op, struct fscache_retrieval, op); - object = container_of(op->op.object, - struct cachefiles_object, fscache); - - _enter("{ino=%lu}", d_backing_inode(object->backer)->i_ino); - - max = 8; - spin_lock_irq(&object->work_lock); - - while (!list_empty(&op->to_do)) { - monitor = list_entry(op->to_do.next, - struct cachefiles_one_read, op_link); - list_del(&monitor->op_link); - - spin_unlock_irq(&object->work_lock); - - _debug("- copy {%lu}", monitor->back_page->index); - - recheck: - if (test_bit(FSCACHE_COOKIE_INVALIDATING, - &object->fscache.cookie->flags)) { - error = -ESTALE; - } else if (PageUptodate(monitor->back_page)) { - copy_highpage(monitor->netfs_page, monitor->back_page); - fscache_mark_page_cached(monitor->op, - monitor->netfs_page); - error = 0; - } else if (!PageError(monitor->back_page)) { - /* the page has probably been truncated */ - error = cachefiles_read_reissue(object, monitor); - if (error == -EINPROGRESS) - goto next; - goto recheck; - } else { - cachefiles_io_error_obj( - object, - "Readpage failed on backing file %lx", - (unsigned long) monitor->back_page->flags); - error = -EIO; - } - - put_page(monitor->back_page); - - fscache_end_io(op, monitor->netfs_page, error); - put_page(monitor->netfs_page); - fscache_retrieval_complete(op, 1); - fscache_put_retrieval(op); - kfree(monitor); - - next: - /* let the thread pool have some air occasionally */ - max--; - if (max < 0 || need_resched()) { - if (!list_empty(&op->to_do)) - fscache_enqueue_retrieval(op); - _leave(" [maxed out]"); - return; - } - - spin_lock_irq(&object->work_lock); - } - - spin_unlock_irq(&object->work_lock); - _leave(""); -} - -/* - * read the corresponding page to the given set from the backing file - * - an uncertain page is simply discarded, to be tried again another time - */ -static int cachefiles_read_backing_file_one(struct cachefiles_object *object, - struct fscache_retrieval *op, - struct page *netpage) -{ - struct cachefiles_one_read *monitor; - struct address_space *bmapping; - struct page *newpage, *backpage; - int ret; - - _enter(""); - - _debug("read back %p{%lu,%d}", - netpage, netpage->index, page_count(netpage)); - - monitor = kzalloc(sizeof(*monitor), cachefiles_gfp); - if (!monitor) - goto nomem; - - monitor->netfs_page = netpage; - monitor->op = fscache_get_retrieval(op); - - init_waitqueue_func_entry(&monitor->monitor, cachefiles_read_waiter); - - /* attempt to get hold of the backing page */ - bmapping = d_backing_inode(object->backer)->i_mapping; - newpage = NULL; - - for (;;) { - backpage = find_get_page(bmapping, netpage->index); - if (backpage) - goto backing_page_already_present; - - if (!newpage) { - newpage = __page_cache_alloc(cachefiles_gfp); - if (!newpage) - goto nomem_monitor; - } - - ret = add_to_page_cache_lru(newpage, bmapping, - netpage->index, cachefiles_gfp); - if (ret == 0) - goto installed_new_backing_page; - if (ret != -EEXIST) - goto nomem_page; - } - - /* we've installed a new backing page, so now we need to start - * it reading */ -installed_new_backing_page: - _debug("- new %p", newpage); - - backpage = newpage; - newpage = NULL; - -read_backing_page: - ret = bmapping->a_ops->readpage(NULL, backpage); - if (ret < 0) - goto read_error; - - /* set the monitor to transfer the data across */ -monitor_backing_page: - _debug("- monitor add"); - - /* install the monitor */ - get_page(monitor->netfs_page); - get_page(backpage); - monitor->back_page = backpage; - monitor->monitor.private = backpage; - folio_add_wait_queue(page_folio(backpage), &monitor->monitor); - monitor = NULL; - - /* but the page may have been read before the monitor was installed, so - * the monitor may miss the event - so we have to ensure that we do get - * one in such a case */ - if (trylock_page(backpage)) { - _debug("jumpstart %p {%lx}", backpage, backpage->flags); - unlock_page(backpage); - } - goto success; - - /* if the backing page is already present, it can be in one of - * three states: read in progress, read failed or read okay */ -backing_page_already_present: - _debug("- present"); - - if (newpage) { - put_page(newpage); - newpage = NULL; - } - - if (PageError(backpage)) - goto io_error; - - if (PageUptodate(backpage)) - goto backing_page_already_uptodate; - - if (!trylock_page(backpage)) - goto monitor_backing_page; - _debug("read %p {%lx}", backpage, backpage->flags); - goto read_backing_page; - - /* the backing page is already up to date, attach the netfs - * page to the pagecache and LRU and copy the data across */ -backing_page_already_uptodate: - _debug("- uptodate"); - - fscache_mark_page_cached(op, netpage); - - copy_highpage(netpage, backpage); - fscache_end_io(op, netpage, 0); - fscache_retrieval_complete(op, 1); - -success: - _debug("success"); - ret = 0; - -out: - if (backpage) - put_page(backpage); - if (monitor) { - fscache_put_retrieval(monitor->op); - kfree(monitor); - } - _leave(" = %d", ret); - return ret; - -read_error: - _debug("read error %d", ret); - if (ret == -ENOMEM) { - fscache_retrieval_complete(op, 1); - goto out; - } -io_error: - cachefiles_io_error_obj(object, "Page read error on backing file"); - fscache_retrieval_complete(op, 1); - ret = -ENOBUFS; - goto out; - -nomem_page: - put_page(newpage); -nomem_monitor: - fscache_put_retrieval(monitor->op); - kfree(monitor); -nomem: - fscache_retrieval_complete(op, 1); - _leave(" = -ENOMEM"); - return -ENOMEM; -} - -/* - * read a page from the cache or allocate a block in which to store it - * - cache withdrawal is prevented by the caller - * - returns -EINTR if interrupted - * - returns -ENOMEM if ran out of memory - * - returns -ENOBUFS if no buffers can be made available - * - returns -ENOBUFS if page is beyond EOF - * - if the page is backed by a block in the cache: - * - a read will be started which will call the callback on completion - * - 0 will be returned - * - else if the page is unbacked: - * - the metadata will be retained - * - -ENODATA will be returned - */ -int cachefiles_read_or_alloc_page(struct fscache_retrieval *op, - struct page *page, - gfp_t gfp) -{ - struct cachefiles_object *object; - struct cachefiles_cache *cache; - struct inode *inode; - sector_t block; - unsigned shift; - int ret, ret2; - - object = container_of(op->op.object, - struct cachefiles_object, fscache); - cache = container_of(object->fscache.cache, - struct cachefiles_cache, cache); - - _enter("{%p},{%lx},,,", object, page->index); - - if (!object->backer) - goto enobufs; - - inode = d_backing_inode(object->backer); - ASSERT(S_ISREG(inode->i_mode)); - - /* calculate the shift required to use bmap */ - shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; - - op->op.flags &= FSCACHE_OP_KEEP_FLAGS; - op->op.flags |= FSCACHE_OP_ASYNC; - op->op.processor = cachefiles_read_copier; - - /* we assume the absence or presence of the first block is a good - * enough indication for the page as a whole - * - TODO: don't use bmap() for this as it is _not_ actually good - * enough for this as it doesn't indicate errors, but it's all we've - * got for the moment - */ - block = page->index; - block <<= shift; - - ret2 = bmap(inode, &block); - ASSERT(ret2 == 0); - - _debug("%llx -> %llx", - (unsigned long long) (page->index << shift), - (unsigned long long) block); - - if (block) { - /* submit the apparently valid page to the backing fs to be - * read from disk */ - ret = cachefiles_read_backing_file_one(object, op, page); - } else if (cachefiles_has_space(cache, 0, 1) == 0) { - /* there's space in the cache we can use */ - fscache_mark_page_cached(op, page); - fscache_retrieval_complete(op, 1); - ret = -ENODATA; - } else { - goto enobufs; - } - - _leave(" = %d", ret); - return ret; - -enobufs: - fscache_retrieval_complete(op, 1); - _leave(" = -ENOBUFS"); - return -ENOBUFS; -} - -/* - * read the corresponding pages to the given set from the backing file - * - any uncertain pages are simply discarded, to be tried again another time - */ -static int cachefiles_read_backing_file(struct cachefiles_object *object, - struct fscache_retrieval *op, - struct list_head *list) -{ - struct cachefiles_one_read *monitor = NULL; - struct address_space *bmapping = d_backing_inode(object->backer)->i_mapping; - struct page *newpage = NULL, *netpage, *_n, *backpage = NULL; - int ret = 0; - - _enter(""); - - list_for_each_entry_safe(netpage, _n, list, lru) { - list_del(&netpage->lru); - - _debug("read back %p{%lu,%d}", - netpage, netpage->index, page_count(netpage)); - - if (!monitor) { - monitor = kzalloc(sizeof(*monitor), cachefiles_gfp); - if (!monitor) - goto nomem; - - monitor->op = fscache_get_retrieval(op); - init_waitqueue_func_entry(&monitor->monitor, - cachefiles_read_waiter); - } - - for (;;) { - backpage = find_get_page(bmapping, netpage->index); - if (backpage) - goto backing_page_already_present; - - if (!newpage) { - newpage = __page_cache_alloc(cachefiles_gfp); - if (!newpage) - goto nomem; - } - - ret = add_to_page_cache_lru(newpage, bmapping, - netpage->index, - cachefiles_gfp); - if (ret == 0) - goto installed_new_backing_page; - if (ret != -EEXIST) - goto nomem; - } - - /* we've installed a new backing page, so now we need - * to start it reading */ - installed_new_backing_page: - _debug("- new %p", newpage); - - backpage = newpage; - newpage = NULL; - - reread_backing_page: - ret = bmapping->a_ops->readpage(NULL, backpage); - if (ret < 0) - goto read_error; - - /* add the netfs page to the pagecache and LRU, and set the - * monitor to transfer the data across */ - monitor_backing_page: - _debug("- monitor add"); - - ret = add_to_page_cache_lru(netpage, op->mapping, - netpage->index, cachefiles_gfp); - if (ret < 0) { - if (ret == -EEXIST) { - put_page(backpage); - backpage = NULL; - put_page(netpage); - netpage = NULL; - fscache_retrieval_complete(op, 1); - continue; - } - goto nomem; - } - - /* install a monitor */ - get_page(netpage); - monitor->netfs_page = netpage; - - get_page(backpage); - monitor->back_page = backpage; - monitor->monitor.private = backpage; - folio_add_wait_queue(page_folio(backpage), &monitor->monitor); - monitor = NULL; - - /* but the page may have been read before the monitor was - * installed, so the monitor may miss the event - so we have to - * ensure that we do get one in such a case */ - if (trylock_page(backpage)) { - _debug("2unlock %p {%lx}", backpage, backpage->flags); - unlock_page(backpage); - } - - put_page(backpage); - backpage = NULL; - - put_page(netpage); - netpage = NULL; - continue; - - /* if the backing page is already present, it can be in one of - * three states: read in progress, read failed or read okay */ - backing_page_already_present: - _debug("- present %p", backpage); - - if (PageError(backpage)) - goto io_error; - - if (PageUptodate(backpage)) - goto backing_page_already_uptodate; - - _debug("- not ready %p{%lx}", backpage, backpage->flags); - - if (!trylock_page(backpage)) - goto monitor_backing_page; - - if (PageError(backpage)) { - _debug("error %lx", backpage->flags); - unlock_page(backpage); - goto io_error; - } - - if (PageUptodate(backpage)) - goto backing_page_already_uptodate_unlock; - - /* we've locked a page that's neither up to date nor erroneous, - * so we need to attempt to read it again */ - goto reread_backing_page; - - /* the backing page is already up to date, attach the netfs - * page to the pagecache and LRU and copy the data across */ - backing_page_already_uptodate_unlock: - _debug("uptodate %lx", backpage->flags); - unlock_page(backpage); - backing_page_already_uptodate: - _debug("- uptodate"); - - ret = add_to_page_cache_lru(netpage, op->mapping, - netpage->index, cachefiles_gfp); - if (ret < 0) { - if (ret == -EEXIST) { - put_page(backpage); - backpage = NULL; - put_page(netpage); - netpage = NULL; - fscache_retrieval_complete(op, 1); - continue; - } - goto nomem; - } - - copy_highpage(netpage, backpage); - - put_page(backpage); - backpage = NULL; - - fscache_mark_page_cached(op, netpage); - - /* the netpage is unlocked and marked up to date here */ - fscache_end_io(op, netpage, 0); - put_page(netpage); - netpage = NULL; - fscache_retrieval_complete(op, 1); - continue; - } - - netpage = NULL; - - _debug("out"); - -out: - /* tidy up */ - if (newpage) - put_page(newpage); - if (netpage) - put_page(netpage); - if (backpage) - put_page(backpage); - if (monitor) { - fscache_put_retrieval(op); - kfree(monitor); - } - - list_for_each_entry_safe(netpage, _n, list, lru) { - list_del(&netpage->lru); - put_page(netpage); - fscache_retrieval_complete(op, 1); - } - - _leave(" = %d", ret); - return ret; - -nomem: - _debug("nomem"); - ret = -ENOMEM; - goto record_page_complete; - -read_error: - _debug("read error %d", ret); - if (ret == -ENOMEM) - goto record_page_complete; -io_error: - cachefiles_io_error_obj(object, "Page read error on backing file"); - ret = -ENOBUFS; -record_page_complete: - fscache_retrieval_complete(op, 1); - goto out; -} - -/* - * read a list of pages from the cache or allocate blocks in which to store - * them - */ -int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op, - struct list_head *pages, - unsigned *nr_pages, - gfp_t gfp) -{ - struct cachefiles_object *object; - struct cachefiles_cache *cache; - struct list_head backpages; - struct pagevec pagevec; - struct inode *inode; - struct page *page, *_n; - unsigned shift, nrbackpages; - int ret, ret2, space; - - object = container_of(op->op.object, - struct cachefiles_object, fscache); - cache = container_of(object->fscache.cache, - struct cachefiles_cache, cache); - - _enter("{OBJ%x,%d},,%d,,", - object->fscache.debug_id, atomic_read(&op->op.usage), - *nr_pages); - - if (!object->backer) - goto all_enobufs; - - space = 1; - if (cachefiles_has_space(cache, 0, *nr_pages) < 0) - space = 0; - - inode = d_backing_inode(object->backer); - ASSERT(S_ISREG(inode->i_mode)); - - /* calculate the shift required to use bmap */ - shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; - - pagevec_init(&pagevec); - - op->op.flags &= FSCACHE_OP_KEEP_FLAGS; - op->op.flags |= FSCACHE_OP_ASYNC; - op->op.processor = cachefiles_read_copier; - - INIT_LIST_HEAD(&backpages); - nrbackpages = 0; - - ret = space ? -ENODATA : -ENOBUFS; - list_for_each_entry_safe(page, _n, pages, lru) { - sector_t block; - - /* we assume the absence or presence of the first block is a - * good enough indication for the page as a whole - * - TODO: don't use bmap() for this as it is _not_ actually - * good enough for this as it doesn't indicate errors, but - * it's all we've got for the moment - */ - block = page->index; - block <<= shift; - - ret2 = bmap(inode, &block); - ASSERT(ret2 == 0); - - _debug("%llx -> %llx", - (unsigned long long) (page->index << shift), - (unsigned long long) block); - - if (block) { - /* we have data - add it to the list to give to the - * backing fs */ - list_move(&page->lru, &backpages); - (*nr_pages)--; - nrbackpages++; - } else if (space && pagevec_add(&pagevec, page) == 0) { - fscache_mark_pages_cached(op, &pagevec); - fscache_retrieval_complete(op, 1); - ret = -ENODATA; - } else { - fscache_retrieval_complete(op, 1); - } - } - - if (pagevec_count(&pagevec) > 0) - fscache_mark_pages_cached(op, &pagevec); - - if (list_empty(pages)) - ret = 0; - - /* submit the apparently valid pages to the backing fs to be read from - * disk */ - if (nrbackpages > 0) { - ret2 = cachefiles_read_backing_file(object, op, &backpages); - if (ret2 == -ENOMEM || ret2 == -EINTR) - ret = ret2; - } - - _leave(" = %d [nr=%u%s]", - ret, *nr_pages, list_empty(pages) ? " empty" : ""); - return ret; - -all_enobufs: - fscache_retrieval_complete(op, *nr_pages); - return -ENOBUFS; -} - -/* - * allocate a block in the cache in which to store a page - * - cache withdrawal is prevented by the caller - * - returns -EINTR if interrupted - * - returns -ENOMEM if ran out of memory - * - returns -ENOBUFS if no buffers can be made available - * - returns -ENOBUFS if page is beyond EOF - * - otherwise: - * - the metadata will be retained - * - 0 will be returned - */ -int cachefiles_allocate_page(struct fscache_retrieval *op, - struct page *page, - gfp_t gfp) -{ - struct cachefiles_object *object; - struct cachefiles_cache *cache; - int ret; - - object = container_of(op->op.object, - struct cachefiles_object, fscache); - cache = container_of(object->fscache.cache, - struct cachefiles_cache, cache); - - _enter("%p,{%lx},", object, page->index); - - ret = cachefiles_has_space(cache, 0, 1); - if (ret == 0) - fscache_mark_page_cached(op, page); - else - ret = -ENOBUFS; - - fscache_retrieval_complete(op, 1); - _leave(" = %d", ret); - return ret; -} - -/* - * allocate blocks in the cache in which to store a set of pages - * - cache withdrawal is prevented by the caller - * - returns -EINTR if interrupted - * - returns -ENOMEM if ran out of memory - * - returns -ENOBUFS if some buffers couldn't be made available - * - returns -ENOBUFS if some pages are beyond EOF - * - otherwise: - * - -ENODATA will be returned - * - metadata will be retained for any page marked - */ -int cachefiles_allocate_pages(struct fscache_retrieval *op, - struct list_head *pages, - unsigned *nr_pages, - gfp_t gfp) -{ - struct cachefiles_object *object; - struct cachefiles_cache *cache; - struct pagevec pagevec; - struct page *page; - int ret; - - object = container_of(op->op.object, - struct cachefiles_object, fscache); - cache = container_of(object->fscache.cache, - struct cachefiles_cache, cache); - - _enter("%p,,,%d,", object, *nr_pages); - - ret = cachefiles_has_space(cache, 0, *nr_pages); - if (ret == 0) { - pagevec_init(&pagevec); - - list_for_each_entry(page, pages, lru) { - if (pagevec_add(&pagevec, page) == 0) - fscache_mark_pages_cached(op, &pagevec); - } - - if (pagevec_count(&pagevec) > 0) - fscache_mark_pages_cached(op, &pagevec); - ret = -ENODATA; - } else { - ret = -ENOBUFS; - } - - fscache_retrieval_complete(op, *nr_pages); - _leave(" = %d", ret); - return ret; -} - -/* - * request a page be stored in the cache - * - cache withdrawal is prevented by the caller - * - this request may be ignored if there's no cache block available, in which - * case -ENOBUFS will be returned - * - if the op is in progress, 0 will be returned - */ -int cachefiles_write_page(struct fscache_storage *op, struct page *page) -{ - struct cachefiles_object *object; - struct cachefiles_cache *cache; - struct file *file; - struct path path; - loff_t pos, eof; - size_t len; - void *data; - int ret = -ENOBUFS; - - ASSERT(op != NULL); - ASSERT(page != NULL); - - object = container_of(op->op.object, - struct cachefiles_object, fscache); - - _enter("%p,%p{%lx},,,", object, page, page->index); - - if (!object->backer) { - _leave(" = -ENOBUFS"); - return -ENOBUFS; - } - - ASSERT(d_is_reg(object->backer)); - - cache = container_of(object->fscache.cache, - struct cachefiles_cache, cache); - - pos = (loff_t)page->index << PAGE_SHIFT; - - /* We mustn't write more data than we have, so we have to beware of a - * partial page at EOF. - */ - eof = object->fscache.store_limit_l; - if (pos >= eof) - goto error; - - /* write the page to the backing filesystem and let it store it in its - * own time */ - path.mnt = cache->mnt; - path.dentry = object->backer; - file = dentry_open(&path, O_RDWR | O_LARGEFILE, cache->cache_cred); - if (IS_ERR(file)) { - ret = PTR_ERR(file); - goto error_2; - } - - len = PAGE_SIZE; - if (eof & ~PAGE_MASK) { - if (eof - pos < PAGE_SIZE) { - _debug("cut short %llx to %llx", - pos, eof); - len = eof - pos; - ASSERTCMP(pos + len, ==, eof); - } - } - - data = kmap(page); - ret = kernel_write(file, data, len, &pos); - kunmap(page); - fput(file); - if (ret != len) - goto error_eio; - - _leave(" = 0"); - return 0; - -error_eio: - ret = -EIO; -error_2: - if (ret == -EIO) - cachefiles_io_error_obj(object, - "Write page to backing file failed"); -error: - _leave(" = -ENOBUFS [%d]", ret); - return -ENOBUFS; -} - -/* - * detach a backing block from a page - * - cache withdrawal is prevented by the caller - */ -void cachefiles_uncache_page(struct fscache_object *_object, struct page *page) - __releases(&object->fscache.cookie->lock) -{ - struct cachefiles_object *object; - - object = container_of(_object, struct cachefiles_object, fscache); - - _enter("%p,{%lu}", object, page->index); - - spin_unlock(&object->fscache.cookie->lock); -} diff --git a/fs/cachefiles/security.c b/fs/cachefiles/security.c deleted file mode 100644 index aec13fd94692..000000000000 --- a/fs/cachefiles/security.c +++ /dev/null @@ -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 -#include -#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; -} diff --git a/fs/cachefiles/xattr.c b/fs/cachefiles/xattr.c deleted file mode 100644 index 9e82de668595..000000000000 --- a/fs/cachefiles/xattr.c +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#include -#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; -} diff --git a/include/trace/events/cachefiles.h b/include/trace/events/cachefiles.h deleted file mode 100644 index 920b6a303d60..000000000000 --- a/include/trace/events/cachefiles.h +++ /dev/null @@ -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 - -/* - * 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