Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /* CacheFiles extended attribute management
3 : : *
4 : : * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 : : * Written by David Howells (dhowells@redhat.com)
6 : : */
7 : :
8 : : #include <linux/module.h>
9 : : #include <linux/sched.h>
10 : : #include <linux/file.h>
11 : : #include <linux/fs.h>
12 : : #include <linux/fsnotify.h>
13 : : #include <linux/quotaops.h>
14 : : #include <linux/xattr.h>
15 : : #include <linux/slab.h>
16 : : #include "internal.h"
17 : :
18 : : static const char cachefiles_xattr_cache[] =
19 : : XATTR_USER_PREFIX "CacheFiles.cache";
20 : :
21 : : /*
22 : : * check the type label on an object
23 : : * - done using xattrs
24 : : */
25 : 0 : int cachefiles_check_object_type(struct cachefiles_object *object)
26 : : {
27 : 0 : struct dentry *dentry = object->dentry;
28 : : char type[3], xtype[3];
29 : : int ret;
30 : :
31 [ # # ]: 0 : ASSERT(dentry);
32 [ # # ]: 0 : ASSERT(d_backing_inode(dentry));
33 : :
34 [ # # ]: 0 : if (!object->fscache.cookie)
35 : 0 : strcpy(type, "C3");
36 : : else
37 : 0 : snprintf(type, 3, "%02x", object->fscache.cookie->def->type);
38 : :
39 : : _enter("%p{%s}", object, type);
40 : :
41 : : /* attempt to install a type label directly */
42 : 0 : ret = vfs_setxattr(dentry, cachefiles_xattr_cache, type, 2,
43 : : XATTR_CREATE);
44 [ # # ]: 0 : if (ret == 0) {
45 : : _debug("SET"); /* we succeeded */
46 : : goto error;
47 : : }
48 : :
49 [ # # ]: 0 : if (ret != -EEXIST) {
50 : 0 : pr_err("Can't set xattr on %pd [%lu] (err %d)\n",
51 : : dentry, d_backing_inode(dentry)->i_ino,
52 : : -ret);
53 : 0 : goto error;
54 : : }
55 : :
56 : : /* read the current type label */
57 : 0 : ret = vfs_getxattr(dentry, cachefiles_xattr_cache, xtype, 3);
58 [ # # ]: 0 : if (ret < 0) {
59 [ # # ]: 0 : if (ret == -ERANGE)
60 : : goto bad_type_length;
61 : :
62 : 0 : pr_err("Can't read xattr on %pd [%lu] (err %d)\n",
63 : : dentry, d_backing_inode(dentry)->i_ino,
64 : : -ret);
65 : 0 : goto error;
66 : : }
67 : :
68 : : /* check the type is what we're expecting */
69 [ # # ]: 0 : if (ret != 2)
70 : : goto bad_type_length;
71 : :
72 [ # # # # ]: 0 : if (xtype[0] != type[0] || xtype[1] != type[1])
73 : : goto bad_type;
74 : :
75 : : ret = 0;
76 : :
77 : : error:
78 : : _leave(" = %d", ret);
79 : 0 : return ret;
80 : :
81 : : bad_type_length:
82 : 0 : pr_err("Cache object %lu type xattr length incorrect\n",
83 : : d_backing_inode(dentry)->i_ino);
84 : : ret = -EIO;
85 : 0 : goto error;
86 : :
87 : : bad_type:
88 : 0 : xtype[2] = 0;
89 : 0 : pr_err("Cache object %pd [%lu] type %s not %s\n",
90 : : dentry, d_backing_inode(dentry)->i_ino,
91 : : xtype, type);
92 : : ret = -EIO;
93 : 0 : goto error;
94 : : }
95 : :
96 : : /*
97 : : * set the state xattr on a cache file
98 : : */
99 : 0 : int cachefiles_set_object_xattr(struct cachefiles_object *object,
100 : : struct cachefiles_xattr *auxdata)
101 : : {
102 : 0 : struct dentry *dentry = object->dentry;
103 : : int ret;
104 : :
105 [ # # ]: 0 : ASSERT(dentry);
106 : :
107 : : _enter("%p,#%d", object, auxdata->len);
108 : :
109 : : /* attempt to install the cache metadata directly */
110 : : _debug("SET #%u", auxdata->len);
111 : :
112 : 0 : clear_bit(FSCACHE_COOKIE_AUX_UPDATED, &object->fscache.cookie->flags);
113 : 0 : ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
114 : 0 : &auxdata->type, auxdata->len,
115 : : XATTR_CREATE);
116 [ # # ]: 0 : if (ret < 0 && ret != -ENOMEM)
117 : 0 : cachefiles_io_error_obj(
118 : : object,
119 : : "Failed to set xattr with error %d", ret);
120 : :
121 : : _leave(" = %d", ret);
122 : 0 : return ret;
123 : : }
124 : :
125 : : /*
126 : : * update the state xattr on a cache file
127 : : */
128 : 0 : int cachefiles_update_object_xattr(struct cachefiles_object *object,
129 : : struct cachefiles_xattr *auxdata)
130 : : {
131 : 0 : struct dentry *dentry = object->dentry;
132 : : int ret;
133 : :
134 [ # # ]: 0 : if (!dentry)
135 : : return -ESTALE;
136 : :
137 : : _enter("%p,#%d", object, auxdata->len);
138 : :
139 : : /* attempt to install the cache metadata directly */
140 : : _debug("SET #%u", auxdata->len);
141 : :
142 : 0 : clear_bit(FSCACHE_COOKIE_AUX_UPDATED, &object->fscache.cookie->flags);
143 : 0 : ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
144 : 0 : &auxdata->type, auxdata->len,
145 : : XATTR_REPLACE);
146 [ # # ]: 0 : if (ret < 0 && ret != -ENOMEM)
147 : 0 : cachefiles_io_error_obj(
148 : : object,
149 : : "Failed to update xattr with error %d", ret);
150 : :
151 : : _leave(" = %d", ret);
152 : 0 : return ret;
153 : : }
154 : :
155 : : /*
156 : : * check the consistency between the backing cache and the FS-Cache cookie
157 : : */
158 : 0 : int cachefiles_check_auxdata(struct cachefiles_object *object)
159 : : {
160 : : struct cachefiles_xattr *auxbuf;
161 : : enum fscache_checkaux validity;
162 : 0 : struct dentry *dentry = object->dentry;
163 : : ssize_t xlen;
164 : : int ret;
165 : :
166 [ # # ]: 0 : ASSERT(dentry);
167 [ # # ]: 0 : ASSERT(d_backing_inode(dentry));
168 [ # # ]: 0 : ASSERT(object->fscache.cookie->def->check_aux);
169 : :
170 : : auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, GFP_KERNEL);
171 [ # # ]: 0 : if (!auxbuf)
172 : : return -ENOMEM;
173 : :
174 : 0 : xlen = vfs_getxattr(dentry, cachefiles_xattr_cache,
175 : 0 : &auxbuf->type, 512 + 1);
176 : : ret = -ESTALE;
177 [ # # # # ]: 0 : if (xlen < 1 ||
178 : 0 : auxbuf->type != object->fscache.cookie->def->type)
179 : : goto error;
180 : :
181 : 0 : xlen--;
182 : 0 : validity = fscache_check_aux(&object->fscache, &auxbuf->data, xlen,
183 : : i_size_read(d_backing_inode(dentry)));
184 [ # # ]: 0 : if (validity != FSCACHE_CHECKAUX_OKAY)
185 : : goto error;
186 : :
187 : : ret = 0;
188 : : error:
189 : 0 : kfree(auxbuf);
190 : 0 : return ret;
191 : : }
192 : :
193 : : /*
194 : : * check the state xattr on a cache file
195 : : * - return -ESTALE if the object should be deleted
196 : : */
197 : 0 : int cachefiles_check_object_xattr(struct cachefiles_object *object,
198 : : struct cachefiles_xattr *auxdata)
199 : : {
200 : : struct cachefiles_xattr *auxbuf;
201 : 0 : struct dentry *dentry = object->dentry;
202 : : int ret;
203 : :
204 : : _enter("%p,#%d", object, auxdata->len);
205 : :
206 [ # # ]: 0 : ASSERT(dentry);
207 [ # # ]: 0 : ASSERT(d_backing_inode(dentry));
208 : :
209 : : auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, cachefiles_gfp);
210 [ # # ]: 0 : if (!auxbuf) {
211 : : _leave(" = -ENOMEM");
212 : : return -ENOMEM;
213 : : }
214 : :
215 : : /* read the current type label */
216 : 0 : ret = vfs_getxattr(dentry, cachefiles_xattr_cache,
217 : 0 : &auxbuf->type, 512 + 1);
218 [ # # ]: 0 : if (ret < 0) {
219 [ # # ]: 0 : if (ret == -ENODATA)
220 : : goto stale; /* no attribute - power went off
221 : : * mid-cull? */
222 : :
223 [ # # ]: 0 : if (ret == -ERANGE)
224 : : goto bad_type_length;
225 : :
226 : 0 : cachefiles_io_error_obj(object,
227 : : "Can't read xattr on %lu (err %d)",
228 : : d_backing_inode(dentry)->i_ino, -ret);
229 : 0 : goto error;
230 : : }
231 : :
232 : : /* check the on-disk object */
233 [ # # ]: 0 : if (ret < 1)
234 : : goto bad_type_length;
235 : :
236 [ # # ]: 0 : if (auxbuf->type != auxdata->type)
237 : : goto stale;
238 : :
239 : 0 : auxbuf->len = ret;
240 : :
241 : : /* consult the netfs */
242 [ # # ]: 0 : if (object->fscache.cookie->def->check_aux) {
243 : : enum fscache_checkaux result;
244 : : unsigned int dlen;
245 : :
246 : 0 : dlen = auxbuf->len - 1;
247 : :
248 : : _debug("checkaux %s #%u",
249 : : object->fscache.cookie->def->name, dlen);
250 : :
251 : 0 : result = fscache_check_aux(&object->fscache,
252 : 0 : &auxbuf->data, dlen,
253 : : i_size_read(d_backing_inode(dentry)));
254 : :
255 [ # # # # ]: 0 : switch (result) {
256 : : /* entry okay as is */
257 : : case FSCACHE_CHECKAUX_OKAY:
258 : : goto okay;
259 : :
260 : : /* entry requires update */
261 : : case FSCACHE_CHECKAUX_NEEDS_UPDATE:
262 : : break;
263 : :
264 : : /* entry requires deletion */
265 : : case FSCACHE_CHECKAUX_OBSOLETE:
266 : : goto stale;
267 : :
268 : : default:
269 : 0 : BUG();
270 : : }
271 : :
272 : : /* update the current label */
273 : 0 : ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
274 : 0 : &auxdata->type, auxdata->len,
275 : : XATTR_REPLACE);
276 [ # # ]: 0 : if (ret < 0) {
277 : 0 : cachefiles_io_error_obj(object,
278 : : "Can't update xattr on %lu"
279 : : " (error %d)",
280 : : d_backing_inode(dentry)->i_ino, -ret);
281 : 0 : goto error;
282 : : }
283 : : }
284 : :
285 : : okay:
286 : : ret = 0;
287 : :
288 : : error:
289 : 0 : kfree(auxbuf);
290 : : _leave(" = %d", ret);
291 : 0 : return ret;
292 : :
293 : : bad_type_length:
294 : 0 : pr_err("Cache object %lu xattr length incorrect\n",
295 : : d_backing_inode(dentry)->i_ino);
296 : : ret = -EIO;
297 : 0 : goto error;
298 : :
299 : : stale:
300 : : ret = -ESTALE;
301 : : goto error;
302 : : }
303 : :
304 : : /*
305 : : * remove the object's xattr to mark it stale
306 : : */
307 : 0 : int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
308 : : struct dentry *dentry)
309 : : {
310 : : int ret;
311 : :
312 : 0 : ret = vfs_removexattr(dentry, cachefiles_xattr_cache);
313 [ # # ]: 0 : if (ret < 0) {
314 [ # # ]: 0 : if (ret == -ENOENT || ret == -ENODATA)
315 : : ret = 0;
316 [ # # ]: 0 : else if (ret != -ENOMEM)
317 : 0 : cachefiles_io_error(cache,
318 : : "Can't remove xattr from %lu"
319 : : " (error %d)",
320 : : d_backing_inode(dentry)->i_ino, -ret);
321 : : }
322 : :
323 : : _leave(" = %d", ret);
324 : 0 : return ret;
325 : : }
|