blob: 11a33209ab5fe062b09f0f45952bd5ac822b710d [file] [log] [blame]
David Howells1bd9c4e2021-11-18 08:58:08 +00001// SPDX-License-Identifier: GPL-2.0-or-later
2/* CacheFiles path walking and related routines
3 *
4 * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
6 */
7
8#include <linux/fs.h>
David Howells32759f72021-10-21 08:34:55 +01009#include <linux/namei.h>
David Howells1bd9c4e2021-11-18 08:58:08 +000010#include "internal.h"
11
12/*
13 * Mark the backing file as being a cache file if it's not already in use. The
14 * mark tells the culling request command that it's not allowed to cull the
15 * file or directory. The caller must hold the inode lock.
16 */
17static bool __cachefiles_mark_inode_in_use(struct cachefiles_object *object,
18 struct dentry *dentry)
19{
20 struct inode *inode = d_backing_inode(dentry);
21 bool can_use = false;
22
23 if (!(inode->i_flags & S_KERNEL_FILE)) {
24 inode->i_flags |= S_KERNEL_FILE;
25 trace_cachefiles_mark_active(object, inode);
26 can_use = true;
27 } else {
28 pr_notice("cachefiles: Inode already in use: %pd\n", dentry);
29 }
30
31 return can_use;
32}
33
34/*
35 * Unmark a backing inode. The caller must hold the inode lock.
36 */
37static void __cachefiles_unmark_inode_in_use(struct cachefiles_object *object,
38 struct dentry *dentry)
39{
40 struct inode *inode = d_backing_inode(dentry);
41
42 inode->i_flags &= ~S_KERNEL_FILE;
43 trace_cachefiles_mark_inactive(object, inode);
44}
David Howells32759f72021-10-21 08:34:55 +010045
46/*
47 * get a subdirectory
48 */
49struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
50 struct dentry *dir,
51 const char *dirname,
52 bool *_is_new)
53{
54 struct dentry *subdir;
55 struct path path;
56 int ret;
57
58 _enter(",,%s", dirname);
59
60 /* search the current directory for the element name */
61 inode_lock_nested(d_inode(dir), I_MUTEX_PARENT);
62
63retry:
64 ret = cachefiles_inject_read_error();
65 if (ret == 0)
66 subdir = lookup_one_len(dirname, dir, strlen(dirname));
67 else
68 subdir = ERR_PTR(ret);
69 if (IS_ERR(subdir)) {
70 trace_cachefiles_vfs_error(NULL, d_backing_inode(dir),
71 PTR_ERR(subdir),
72 cachefiles_trace_lookup_error);
73 if (PTR_ERR(subdir) == -ENOMEM)
74 goto nomem_d_alloc;
75 goto lookup_error;
76 }
77
78 _debug("subdir -> %pd %s",
79 subdir, d_backing_inode(subdir) ? "positive" : "negative");
80
81 /* we need to create the subdir if it doesn't exist yet */
82 if (d_is_negative(subdir)) {
83 ret = cachefiles_has_space(cache, 1, 0);
84 if (ret < 0)
85 goto mkdir_error;
86
87 _debug("attempt mkdir");
88
89 path.mnt = cache->mnt;
90 path.dentry = dir;
91 ret = security_path_mkdir(&path, subdir, 0700);
92 if (ret < 0)
93 goto mkdir_error;
94 ret = cachefiles_inject_write_error();
95 if (ret == 0)
96 ret = vfs_mkdir(&init_user_ns, d_inode(dir), subdir, 0700);
97 if (ret < 0) {
98 trace_cachefiles_vfs_error(NULL, d_inode(dir), ret,
99 cachefiles_trace_mkdir_error);
100 goto mkdir_error;
101 }
102
103 if (unlikely(d_unhashed(subdir))) {
104 cachefiles_put_directory(subdir);
105 goto retry;
106 }
107 ASSERT(d_backing_inode(subdir));
108
109 _debug("mkdir -> %pd{ino=%lu}",
110 subdir, d_backing_inode(subdir)->i_ino);
111 if (_is_new)
112 *_is_new = true;
113 }
114
115 /* Tell rmdir() it's not allowed to delete the subdir */
116 inode_lock(d_inode(subdir));
117 inode_unlock(d_inode(dir));
118
119 if (!__cachefiles_mark_inode_in_use(NULL, subdir))
120 goto mark_error;
121
122 inode_unlock(d_inode(subdir));
123
124 /* we need to make sure the subdir is a directory */
125 ASSERT(d_backing_inode(subdir));
126
127 if (!d_can_lookup(subdir)) {
128 pr_err("%s is not a directory\n", dirname);
129 ret = -EIO;
130 goto check_error;
131 }
132
133 ret = -EPERM;
134 if (!(d_backing_inode(subdir)->i_opflags & IOP_XATTR) ||
135 !d_backing_inode(subdir)->i_op->lookup ||
136 !d_backing_inode(subdir)->i_op->mkdir ||
137 !d_backing_inode(subdir)->i_op->rename ||
138 !d_backing_inode(subdir)->i_op->rmdir ||
139 !d_backing_inode(subdir)->i_op->unlink)
140 goto check_error;
141
142 _leave(" = [%lu]", d_backing_inode(subdir)->i_ino);
143 return subdir;
144
145check_error:
146 cachefiles_put_directory(subdir);
147 _leave(" = %d [check]", ret);
148 return ERR_PTR(ret);
149
150mark_error:
151 inode_unlock(d_inode(subdir));
152 dput(subdir);
153 return ERR_PTR(-EBUSY);
154
155mkdir_error:
156 inode_unlock(d_inode(dir));
157 dput(subdir);
158 pr_err("mkdir %s failed with error %d\n", dirname, ret);
159 return ERR_PTR(ret);
160
161lookup_error:
162 inode_unlock(d_inode(dir));
163 ret = PTR_ERR(subdir);
164 pr_err("Lookup %s failed with error %d\n", dirname, ret);
165 return ERR_PTR(ret);
166
167nomem_d_alloc:
168 inode_unlock(d_inode(dir));
169 _leave(" = -ENOMEM");
170 return ERR_PTR(-ENOMEM);
171}
172
173/*
174 * Put a subdirectory.
175 */
176void cachefiles_put_directory(struct dentry *dir)
177{
178 if (dir) {
179 inode_lock(dir->d_inode);
180 __cachefiles_unmark_inode_in_use(NULL, dir);
181 inode_unlock(dir->d_inode);
182 dput(dir);
183 }
184}