xref: /openbmc/linux/fs/cachefiles/namei.c (revision 169379ea)
1 // 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>
9 #include <linux/namei.h>
10 #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  */
17 static 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 static bool cachefiles_mark_inode_in_use(struct cachefiles_object *object,
35 					 struct dentry *dentry)
36 {
37 	struct inode *inode = d_backing_inode(dentry);
38 	bool can_use;
39 
40 	inode_lock(inode);
41 	can_use = __cachefiles_mark_inode_in_use(object, dentry);
42 	inode_unlock(inode);
43 	return can_use;
44 }
45 
46 /*
47  * Unmark a backing inode.  The caller must hold the inode lock.
48  */
49 static void __cachefiles_unmark_inode_in_use(struct cachefiles_object *object,
50 					     struct dentry *dentry)
51 {
52 	struct inode *inode = d_backing_inode(dentry);
53 
54 	inode->i_flags &= ~S_KERNEL_FILE;
55 	trace_cachefiles_mark_inactive(object, inode);
56 }
57 
58 /*
59  * Unmark a backing inode and tell cachefilesd that there's something that can
60  * be culled.
61  */
62 void cachefiles_unmark_inode_in_use(struct cachefiles_object *object,
63 				    struct file *file)
64 {
65 	struct cachefiles_cache *cache = object->volume->cache;
66 	struct inode *inode = file_inode(file);
67 
68 	if (inode) {
69 		inode_lock(inode);
70 		__cachefiles_unmark_inode_in_use(object, file->f_path.dentry);
71 		inode_unlock(inode);
72 
73 		if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) {
74 			atomic_long_add(inode->i_blocks, &cache->b_released);
75 			if (atomic_inc_return(&cache->f_released))
76 				cachefiles_state_changed(cache);
77 		}
78 	}
79 }
80 
81 /*
82  * get a subdirectory
83  */
84 struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
85 					struct dentry *dir,
86 					const char *dirname,
87 					bool *_is_new)
88 {
89 	struct dentry *subdir;
90 	struct path path;
91 	int ret;
92 
93 	_enter(",,%s", dirname);
94 
95 	/* search the current directory for the element name */
96 	inode_lock_nested(d_inode(dir), I_MUTEX_PARENT);
97 
98 retry:
99 	ret = cachefiles_inject_read_error();
100 	if (ret == 0)
101 		subdir = lookup_one_len(dirname, dir, strlen(dirname));
102 	else
103 		subdir = ERR_PTR(ret);
104 	if (IS_ERR(subdir)) {
105 		trace_cachefiles_vfs_error(NULL, d_backing_inode(dir),
106 					   PTR_ERR(subdir),
107 					   cachefiles_trace_lookup_error);
108 		if (PTR_ERR(subdir) == -ENOMEM)
109 			goto nomem_d_alloc;
110 		goto lookup_error;
111 	}
112 
113 	_debug("subdir -> %pd %s",
114 	       subdir, d_backing_inode(subdir) ? "positive" : "negative");
115 
116 	/* we need to create the subdir if it doesn't exist yet */
117 	if (d_is_negative(subdir)) {
118 		ret = cachefiles_has_space(cache, 1, 0);
119 		if (ret < 0)
120 			goto mkdir_error;
121 
122 		_debug("attempt mkdir");
123 
124 		path.mnt = cache->mnt;
125 		path.dentry = dir;
126 		ret = security_path_mkdir(&path, subdir, 0700);
127 		if (ret < 0)
128 			goto mkdir_error;
129 		ret = cachefiles_inject_write_error();
130 		if (ret == 0)
131 			ret = vfs_mkdir(&init_user_ns, d_inode(dir), subdir, 0700);
132 		if (ret < 0) {
133 			trace_cachefiles_vfs_error(NULL, d_inode(dir), ret,
134 						   cachefiles_trace_mkdir_error);
135 			goto mkdir_error;
136 		}
137 
138 		if (unlikely(d_unhashed(subdir))) {
139 			cachefiles_put_directory(subdir);
140 			goto retry;
141 		}
142 		ASSERT(d_backing_inode(subdir));
143 
144 		_debug("mkdir -> %pd{ino=%lu}",
145 		       subdir, d_backing_inode(subdir)->i_ino);
146 		if (_is_new)
147 			*_is_new = true;
148 	}
149 
150 	/* Tell rmdir() it's not allowed to delete the subdir */
151 	inode_lock(d_inode(subdir));
152 	inode_unlock(d_inode(dir));
153 
154 	if (!__cachefiles_mark_inode_in_use(NULL, subdir))
155 		goto mark_error;
156 
157 	inode_unlock(d_inode(subdir));
158 
159 	/* we need to make sure the subdir is a directory */
160 	ASSERT(d_backing_inode(subdir));
161 
162 	if (!d_can_lookup(subdir)) {
163 		pr_err("%s is not a directory\n", dirname);
164 		ret = -EIO;
165 		goto check_error;
166 	}
167 
168 	ret = -EPERM;
169 	if (!(d_backing_inode(subdir)->i_opflags & IOP_XATTR) ||
170 	    !d_backing_inode(subdir)->i_op->lookup ||
171 	    !d_backing_inode(subdir)->i_op->mkdir ||
172 	    !d_backing_inode(subdir)->i_op->rename ||
173 	    !d_backing_inode(subdir)->i_op->rmdir ||
174 	    !d_backing_inode(subdir)->i_op->unlink)
175 		goto check_error;
176 
177 	_leave(" = [%lu]", d_backing_inode(subdir)->i_ino);
178 	return subdir;
179 
180 check_error:
181 	cachefiles_put_directory(subdir);
182 	_leave(" = %d [check]", ret);
183 	return ERR_PTR(ret);
184 
185 mark_error:
186 	inode_unlock(d_inode(subdir));
187 	dput(subdir);
188 	return ERR_PTR(-EBUSY);
189 
190 mkdir_error:
191 	inode_unlock(d_inode(dir));
192 	dput(subdir);
193 	pr_err("mkdir %s failed with error %d\n", dirname, ret);
194 	return ERR_PTR(ret);
195 
196 lookup_error:
197 	inode_unlock(d_inode(dir));
198 	ret = PTR_ERR(subdir);
199 	pr_err("Lookup %s failed with error %d\n", dirname, ret);
200 	return ERR_PTR(ret);
201 
202 nomem_d_alloc:
203 	inode_unlock(d_inode(dir));
204 	_leave(" = -ENOMEM");
205 	return ERR_PTR(-ENOMEM);
206 }
207 
208 /*
209  * Put a subdirectory.
210  */
211 void cachefiles_put_directory(struct dentry *dir)
212 {
213 	if (dir) {
214 		inode_lock(dir->d_inode);
215 		__cachefiles_unmark_inode_in_use(NULL, dir);
216 		inode_unlock(dir->d_inode);
217 		dput(dir);
218 	}
219 }
220