Commit | Line | Data |
---|---|---|
1bd9c4e4 DH |
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> | |
32759f7d | 9 | #include <linux/namei.h> |
1bd9c4e4 DH |
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, | |
08d7a6fb | 18 | struct inode *inode) |
1bd9c4e4 | 19 | { |
1bd9c4e4 DH |
20 | bool can_use = false; |
21 | ||
22 | if (!(inode->i_flags & S_KERNEL_FILE)) { | |
23 | inode->i_flags |= S_KERNEL_FILE; | |
24 | trace_cachefiles_mark_active(object, inode); | |
25 | can_use = true; | |
26 | } else { | |
b64a3314 | 27 | trace_cachefiles_mark_failed(object, inode); |
1bd9c4e4 DH |
28 | } |
29 | ||
30 | return can_use; | |
31 | } | |
32 | ||
169379ea | 33 | static bool cachefiles_mark_inode_in_use(struct cachefiles_object *object, |
08d7a6fb | 34 | struct inode *inode) |
169379ea | 35 | { |
169379ea DH |
36 | bool can_use; |
37 | ||
38 | inode_lock(inode); | |
08d7a6fb | 39 | can_use = __cachefiles_mark_inode_in_use(object, inode); |
169379ea DH |
40 | inode_unlock(inode); |
41 | return can_use; | |
42 | } | |
43 | ||
1bd9c4e4 DH |
44 | /* |
45 | * Unmark a backing inode. The caller must hold the inode lock. | |
46 | */ | |
47 | static void __cachefiles_unmark_inode_in_use(struct cachefiles_object *object, | |
08d7a6fb | 48 | struct inode *inode) |
1bd9c4e4 | 49 | { |
1bd9c4e4 DH |
50 | inode->i_flags &= ~S_KERNEL_FILE; |
51 | trace_cachefiles_mark_inactive(object, inode); | |
52 | } | |
32759f7d | 53 | |
ea5dc046 | 54 | static void cachefiles_do_unmark_inode_in_use(struct cachefiles_object *object, |
08d7a6fb | 55 | struct inode *inode) |
ea5dc046 | 56 | { |
ea5dc046 | 57 | inode_lock(inode); |
08d7a6fb | 58 | __cachefiles_unmark_inode_in_use(object, inode); |
ea5dc046 JX |
59 | inode_unlock(inode); |
60 | } | |
61 | ||
169379ea DH |
62 | /* |
63 | * Unmark a backing inode and tell cachefilesd that there's something that can | |
64 | * be culled. | |
65 | */ | |
66 | void cachefiles_unmark_inode_in_use(struct cachefiles_object *object, | |
67 | struct file *file) | |
68 | { | |
69 | struct cachefiles_cache *cache = object->volume->cache; | |
70 | struct inode *inode = file_inode(file); | |
71 | ||
08d7a6fb | 72 | cachefiles_do_unmark_inode_in_use(object, inode); |
169379ea | 73 | |
08d7a6fb MS |
74 | if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) { |
75 | atomic_long_add(inode->i_blocks, &cache->b_released); | |
76 | if (atomic_inc_return(&cache->f_released)) | |
77 | cachefiles_state_changed(cache); | |
169379ea DH |
78 | } |
79 | } | |
80 | ||
32759f7d DH |
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); | |
8c39b8bc | 104 | trace_cachefiles_lookup(NULL, dir, subdir); |
32759f7d DH |
105 | if (IS_ERR(subdir)) { |
106 | trace_cachefiles_vfs_error(NULL, d_backing_inode(dir), | |
107 | PTR_ERR(subdir), | |
108 | cachefiles_trace_lookup_error); | |
109 | if (PTR_ERR(subdir) == -ENOMEM) | |
110 | goto nomem_d_alloc; | |
111 | goto lookup_error; | |
112 | } | |
113 | ||
114 | _debug("subdir -> %pd %s", | |
115 | subdir, d_backing_inode(subdir) ? "positive" : "negative"); | |
116 | ||
117 | /* we need to create the subdir if it doesn't exist yet */ | |
118 | if (d_is_negative(subdir)) { | |
3929eca7 DH |
119 | ret = cachefiles_has_space(cache, 1, 0, |
120 | cachefiles_has_space_for_create); | |
32759f7d DH |
121 | if (ret < 0) |
122 | goto mkdir_error; | |
123 | ||
124 | _debug("attempt mkdir"); | |
125 | ||
126 | path.mnt = cache->mnt; | |
127 | path.dentry = dir; | |
128 | ret = security_path_mkdir(&path, subdir, 0700); | |
129 | if (ret < 0) | |
130 | goto mkdir_error; | |
131 | ret = cachefiles_inject_write_error(); | |
132 | if (ret == 0) | |
abf08576 | 133 | ret = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), subdir, 0700); |
32759f7d DH |
134 | if (ret < 0) { |
135 | trace_cachefiles_vfs_error(NULL, d_inode(dir), ret, | |
136 | cachefiles_trace_mkdir_error); | |
137 | goto mkdir_error; | |
138 | } | |
8c39b8bc | 139 | trace_cachefiles_mkdir(dir, subdir); |
32759f7d DH |
140 | |
141 | if (unlikely(d_unhashed(subdir))) { | |
142 | cachefiles_put_directory(subdir); | |
143 | goto retry; | |
144 | } | |
145 | ASSERT(d_backing_inode(subdir)); | |
146 | ||
147 | _debug("mkdir -> %pd{ino=%lu}", | |
148 | subdir, d_backing_inode(subdir)->i_ino); | |
149 | if (_is_new) | |
150 | *_is_new = true; | |
151 | } | |
152 | ||
153 | /* Tell rmdir() it's not allowed to delete the subdir */ | |
154 | inode_lock(d_inode(subdir)); | |
155 | inode_unlock(d_inode(dir)); | |
156 | ||
08d7a6fb MS |
157 | if (!__cachefiles_mark_inode_in_use(NULL, d_inode(subdir))) { |
158 | pr_notice("cachefiles: Inode already in use: %pd (B=%lx)\n", | |
159 | subdir, d_inode(subdir)->i_ino); | |
32759f7d | 160 | goto mark_error; |
08d7a6fb | 161 | } |
32759f7d DH |
162 | |
163 | inode_unlock(d_inode(subdir)); | |
164 | ||
165 | /* we need to make sure the subdir is a directory */ | |
166 | ASSERT(d_backing_inode(subdir)); | |
167 | ||
168 | if (!d_can_lookup(subdir)) { | |
169 | pr_err("%s is not a directory\n", dirname); | |
170 | ret = -EIO; | |
171 | goto check_error; | |
172 | } | |
173 | ||
174 | ret = -EPERM; | |
175 | if (!(d_backing_inode(subdir)->i_opflags & IOP_XATTR) || | |
176 | !d_backing_inode(subdir)->i_op->lookup || | |
177 | !d_backing_inode(subdir)->i_op->mkdir || | |
178 | !d_backing_inode(subdir)->i_op->rename || | |
179 | !d_backing_inode(subdir)->i_op->rmdir || | |
180 | !d_backing_inode(subdir)->i_op->unlink) | |
181 | goto check_error; | |
182 | ||
183 | _leave(" = [%lu]", d_backing_inode(subdir)->i_ino); | |
184 | return subdir; | |
185 | ||
186 | check_error: | |
187 | cachefiles_put_directory(subdir); | |
188 | _leave(" = %d [check]", ret); | |
189 | return ERR_PTR(ret); | |
190 | ||
191 | mark_error: | |
192 | inode_unlock(d_inode(subdir)); | |
193 | dput(subdir); | |
194 | return ERR_PTR(-EBUSY); | |
195 | ||
196 | mkdir_error: | |
197 | inode_unlock(d_inode(dir)); | |
198 | dput(subdir); | |
199 | pr_err("mkdir %s failed with error %d\n", dirname, ret); | |
200 | return ERR_PTR(ret); | |
201 | ||
202 | lookup_error: | |
203 | inode_unlock(d_inode(dir)); | |
204 | ret = PTR_ERR(subdir); | |
205 | pr_err("Lookup %s failed with error %d\n", dirname, ret); | |
206 | return ERR_PTR(ret); | |
207 | ||
208 | nomem_d_alloc: | |
209 | inode_unlock(d_inode(dir)); | |
210 | _leave(" = -ENOMEM"); | |
211 | return ERR_PTR(-ENOMEM); | |
212 | } | |
213 | ||
214 | /* | |
215 | * Put a subdirectory. | |
216 | */ | |
217 | void cachefiles_put_directory(struct dentry *dir) | |
218 | { | |
219 | if (dir) { | |
08d7a6fb | 220 | cachefiles_do_unmark_inode_in_use(NULL, d_inode(dir)); |
32759f7d DH |
221 | dput(dir); |
222 | } | |
223 | } | |
07a90e97 DH |
224 | |
225 | /* | |
226 | * Remove a regular file from the cache. | |
227 | */ | |
228 | static int cachefiles_unlink(struct cachefiles_cache *cache, | |
229 | struct cachefiles_object *object, | |
230 | struct dentry *dir, struct dentry *dentry, | |
231 | enum fscache_why_object_killed why) | |
232 | { | |
233 | struct path path = { | |
234 | .mnt = cache->mnt, | |
235 | .dentry = dir, | |
236 | }; | |
237 | int ret; | |
238 | ||
8c39b8bc | 239 | trace_cachefiles_unlink(object, d_inode(dentry)->i_ino, why); |
07a90e97 DH |
240 | ret = security_path_unlink(&path, dentry); |
241 | if (ret < 0) { | |
242 | cachefiles_io_error(cache, "Unlink security error"); | |
243 | return ret; | |
244 | } | |
245 | ||
246 | ret = cachefiles_inject_remove_error(); | |
247 | if (ret == 0) { | |
abf08576 | 248 | ret = vfs_unlink(&nop_mnt_idmap, d_backing_inode(dir), dentry, NULL); |
07a90e97 DH |
249 | if (ret == -EIO) |
250 | cachefiles_io_error(cache, "Unlink failed"); | |
251 | } | |
252 | if (ret != 0) | |
253 | trace_cachefiles_vfs_error(object, d_backing_inode(dir), ret, | |
254 | cachefiles_trace_unlink_error); | |
255 | return ret; | |
256 | } | |
257 | ||
258 | /* | |
259 | * Delete an object representation from the cache | |
260 | * - File backed objects are unlinked | |
261 | * - Directory backed objects are stuffed into the graveyard for userspace to | |
262 | * delete | |
263 | */ | |
264 | int cachefiles_bury_object(struct cachefiles_cache *cache, | |
265 | struct cachefiles_object *object, | |
266 | struct dentry *dir, | |
267 | struct dentry *rep, | |
268 | enum fscache_why_object_killed why) | |
269 | { | |
270 | struct dentry *grave, *trap; | |
271 | struct path path, path_to_graveyard; | |
272 | char nbuffer[8 + 8 + 1]; | |
273 | int ret; | |
274 | ||
275 | _enter(",'%pd','%pd'", dir, rep); | |
276 | ||
277 | if (rep->d_parent != dir) { | |
278 | inode_unlock(d_inode(dir)); | |
279 | _leave(" = -ESTALE"); | |
280 | return -ESTALE; | |
281 | } | |
282 | ||
283 | /* non-directories can just be unlinked */ | |
284 | if (!d_is_dir(rep)) { | |
285 | dget(rep); /* Stop the dentry being negated if it's only pinned | |
286 | * by a file struct. | |
287 | */ | |
288 | ret = cachefiles_unlink(cache, object, dir, rep, why); | |
289 | dput(rep); | |
290 | ||
291 | inode_unlock(d_inode(dir)); | |
292 | _leave(" = %d", ret); | |
293 | return ret; | |
294 | } | |
295 | ||
296 | /* directories have to be moved to the graveyard */ | |
297 | _debug("move stale object to graveyard"); | |
298 | inode_unlock(d_inode(dir)); | |
299 | ||
300 | try_again: | |
301 | /* first step is to make up a grave dentry in the graveyard */ | |
302 | sprintf(nbuffer, "%08x%08x", | |
303 | (uint32_t) ktime_get_real_seconds(), | |
304 | (uint32_t) atomic_inc_return(&cache->gravecounter)); | |
305 | ||
306 | /* do the multiway lock magic */ | |
307 | trap = lock_rename(cache->graveyard, dir); | |
308 | ||
309 | /* do some checks before getting the grave dentry */ | |
310 | if (rep->d_parent != dir || IS_DEADDIR(d_inode(rep))) { | |
311 | /* the entry was probably culled when we dropped the parent dir | |
312 | * lock */ | |
313 | unlock_rename(cache->graveyard, dir); | |
314 | _leave(" = 0 [culled?]"); | |
315 | return 0; | |
316 | } | |
317 | ||
318 | if (!d_can_lookup(cache->graveyard)) { | |
319 | unlock_rename(cache->graveyard, dir); | |
320 | cachefiles_io_error(cache, "Graveyard no longer a directory"); | |
321 | return -EIO; | |
322 | } | |
323 | ||
324 | if (trap == rep) { | |
325 | unlock_rename(cache->graveyard, dir); | |
326 | cachefiles_io_error(cache, "May not make directory loop"); | |
327 | return -EIO; | |
328 | } | |
329 | ||
330 | if (d_mountpoint(rep)) { | |
331 | unlock_rename(cache->graveyard, dir); | |
332 | cachefiles_io_error(cache, "Mountpoint in cache"); | |
333 | return -EIO; | |
334 | } | |
335 | ||
336 | grave = lookup_one_len(nbuffer, cache->graveyard, strlen(nbuffer)); | |
337 | if (IS_ERR(grave)) { | |
338 | unlock_rename(cache->graveyard, dir); | |
339 | trace_cachefiles_vfs_error(object, d_inode(cache->graveyard), | |
340 | PTR_ERR(grave), | |
341 | cachefiles_trace_lookup_error); | |
342 | ||
343 | if (PTR_ERR(grave) == -ENOMEM) { | |
344 | _leave(" = -ENOMEM"); | |
345 | return -ENOMEM; | |
346 | } | |
347 | ||
348 | cachefiles_io_error(cache, "Lookup error %ld", PTR_ERR(grave)); | |
349 | return -EIO; | |
350 | } | |
351 | ||
352 | if (d_is_positive(grave)) { | |
353 | unlock_rename(cache->graveyard, dir); | |
354 | dput(grave); | |
355 | grave = NULL; | |
356 | cond_resched(); | |
357 | goto try_again; | |
358 | } | |
359 | ||
360 | if (d_mountpoint(grave)) { | |
361 | unlock_rename(cache->graveyard, dir); | |
362 | dput(grave); | |
363 | cachefiles_io_error(cache, "Mountpoint in graveyard"); | |
364 | return -EIO; | |
365 | } | |
366 | ||
367 | /* target should not be an ancestor of source */ | |
368 | if (trap == grave) { | |
369 | unlock_rename(cache->graveyard, dir); | |
370 | dput(grave); | |
371 | cachefiles_io_error(cache, "May not make directory loop"); | |
372 | return -EIO; | |
373 | } | |
374 | ||
375 | /* attempt the rename */ | |
376 | path.mnt = cache->mnt; | |
377 | path.dentry = dir; | |
378 | path_to_graveyard.mnt = cache->mnt; | |
379 | path_to_graveyard.dentry = cache->graveyard; | |
380 | ret = security_path_rename(&path, rep, &path_to_graveyard, grave, 0); | |
381 | if (ret < 0) { | |
382 | cachefiles_io_error(cache, "Rename security error %d", ret); | |
383 | } else { | |
384 | struct renamedata rd = { | |
abf08576 | 385 | .old_mnt_idmap = &nop_mnt_idmap, |
07a90e97 DH |
386 | .old_dir = d_inode(dir), |
387 | .old_dentry = rep, | |
abf08576 | 388 | .new_mnt_idmap = &nop_mnt_idmap, |
07a90e97 DH |
389 | .new_dir = d_inode(cache->graveyard), |
390 | .new_dentry = grave, | |
391 | }; | |
8c39b8bc | 392 | trace_cachefiles_rename(object, d_inode(rep)->i_ino, why); |
07a90e97 DH |
393 | ret = cachefiles_inject_read_error(); |
394 | if (ret == 0) | |
395 | ret = vfs_rename(&rd); | |
396 | if (ret != 0) | |
397 | trace_cachefiles_vfs_error(object, d_inode(dir), ret, | |
398 | cachefiles_trace_rename_error); | |
399 | if (ret != 0 && ret != -ENOMEM) | |
400 | cachefiles_io_error(cache, | |
401 | "Rename failed with error %d", ret); | |
402 | } | |
403 | ||
08d7a6fb | 404 | __cachefiles_unmark_inode_in_use(object, d_inode(rep)); |
07a90e97 DH |
405 | unlock_rename(cache->graveyard, dir); |
406 | dput(grave); | |
407 | _leave(" = 0"); | |
408 | return 0; | |
409 | } | |
410 | ||
1f08c925 DH |
411 | /* |
412 | * Delete a cache file. | |
413 | */ | |
414 | int cachefiles_delete_object(struct cachefiles_object *object, | |
415 | enum fscache_why_object_killed why) | |
416 | { | |
417 | struct cachefiles_volume *volume = object->volume; | |
418 | struct dentry *dentry = object->file->f_path.dentry; | |
419 | struct dentry *fan = volume->fanout[(u8)object->cookie->key_hash]; | |
420 | int ret; | |
421 | ||
422 | _enter(",OBJ%x{%pD}", object->debug_id, object->file); | |
423 | ||
424 | /* Stop the dentry being negated if it's only pinned by a file struct. */ | |
425 | dget(dentry); | |
426 | ||
427 | inode_lock_nested(d_backing_inode(fan), I_MUTEX_PARENT); | |
428 | ret = cachefiles_unlink(volume->cache, object, fan, dentry, why); | |
429 | inode_unlock(d_backing_inode(fan)); | |
430 | dput(dentry); | |
431 | return ret; | |
432 | } | |
433 | ||
434 | /* | |
435 | * Create a temporary file and leave it unattached and un-xattr'd until the | |
436 | * time comes to discard the object from memory. | |
437 | */ | |
438 | struct file *cachefiles_create_tmpfile(struct cachefiles_object *object) | |
439 | { | |
440 | struct cachefiles_volume *volume = object->volume; | |
441 | struct cachefiles_cache *cache = volume->cache; | |
442 | const struct cred *saved_cred; | |
443 | struct dentry *fan = volume->fanout[(u8)object->cookie->key_hash]; | |
444 | struct file *file; | |
24a81759 | 445 | const struct path parentpath = { .mnt = cache->mnt, .dentry = fan }; |
c8383054 | 446 | uint64_t ni_size; |
1f08c925 DH |
447 | long ret; |
448 | ||
1f08c925 DH |
449 | |
450 | cachefiles_begin_secure(cache, &saved_cred); | |
451 | ||
1f08c925 | 452 | ret = cachefiles_inject_write_error(); |
38017d44 | 453 | if (ret == 0) { |
1f2300a7 LT |
454 | file = kernel_tmpfile_open(&nop_mnt_idmap, &parentpath, |
455 | S_IFREG | 0600, | |
d56e0ddb AG |
456 | O_RDWR | O_LARGEFILE | O_DIRECT, |
457 | cache->cache_cred); | |
24a81759 | 458 | ret = PTR_ERR_OR_ZERO(file); |
38017d44 MS |
459 | } |
460 | if (ret) { | |
461 | trace_cachefiles_vfs_error(object, d_inode(fan), ret, | |
1f08c925 | 462 | cachefiles_trace_tmpfile_error); |
38017d44 | 463 | if (ret == -EIO) |
1f08c925 | 464 | cachefiles_io_error_obj(object, "Failed to create tmpfile"); |
38017d44 | 465 | goto err; |
1f08c925 DH |
466 | } |
467 | ||
24a81759 | 468 | trace_cachefiles_tmpfile(object, file_inode(file)); |
1f08c925 | 469 | |
08d7a6fb | 470 | /* This is a newly created file with no other possible user */ |
24a81759 | 471 | if (!cachefiles_mark_inode_in_use(object, file_inode(file))) |
08d7a6fb | 472 | WARN_ON(1); |
1f08c925 | 473 | |
c8383054 | 474 | ret = cachefiles_ondemand_init_object(object); |
38017d44 MS |
475 | if (ret < 0) |
476 | goto err_unuse; | |
c8383054 JX |
477 | |
478 | ni_size = object->cookie->object_size; | |
479 | ni_size = round_up(ni_size, CACHEFILES_DIO_BLOCK_SIZE); | |
480 | ||
1f08c925 | 481 | if (ni_size > 0) { |
24a81759 | 482 | trace_cachefiles_trunc(object, file_inode(file), 0, ni_size, |
1f08c925 DH |
483 | cachefiles_trunc_expand_tmpfile); |
484 | ret = cachefiles_inject_write_error(); | |
485 | if (ret == 0) | |
24a81759 | 486 | ret = vfs_truncate(&file->f_path, ni_size); |
1f08c925 DH |
487 | if (ret < 0) { |
488 | trace_cachefiles_vfs_error( | |
24a81759 | 489 | object, file_inode(file), ret, |
1f08c925 | 490 | cachefiles_trace_trunc_error); |
38017d44 | 491 | goto err_unuse; |
1f08c925 DH |
492 | } |
493 | } | |
494 | ||
38017d44 | 495 | ret = -EINVAL; |
1f08c925 DH |
496 | if (unlikely(!file->f_op->read_iter) || |
497 | unlikely(!file->f_op->write_iter)) { | |
498 | fput(file); | |
499 | pr_notice("Cache does not support read_iter and write_iter\n"); | |
38017d44 | 500 | goto err_unuse; |
1f08c925 | 501 | } |
1f08c925 DH |
502 | out: |
503 | cachefiles_end_secure(cache, saved_cred); | |
504 | return file; | |
38017d44 MS |
505 | |
506 | err_unuse: | |
24a81759 MS |
507 | cachefiles_do_unmark_inode_in_use(object, file_inode(file)); |
508 | fput(file); | |
38017d44 MS |
509 | err: |
510 | file = ERR_PTR(ret); | |
511 | goto out; | |
1f08c925 DH |
512 | } |
513 | ||
514 | /* | |
515 | * Create a new file. | |
516 | */ | |
517 | static bool cachefiles_create_file(struct cachefiles_object *object) | |
518 | { | |
519 | struct file *file; | |
520 | int ret; | |
521 | ||
3929eca7 DH |
522 | ret = cachefiles_has_space(object->volume->cache, 1, 0, |
523 | cachefiles_has_space_for_create); | |
1f08c925 DH |
524 | if (ret < 0) |
525 | return false; | |
526 | ||
527 | file = cachefiles_create_tmpfile(object); | |
528 | if (IS_ERR(file)) | |
529 | return false; | |
530 | ||
531 | set_bit(FSCACHE_COOKIE_NEEDS_UPDATE, &object->cookie->flags); | |
532 | set_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags); | |
533 | _debug("create -> %pD{ino=%lu}", file, file_inode(file)->i_ino); | |
534 | object->file = file; | |
535 | return true; | |
536 | } | |
537 | ||
538 | /* | |
539 | * Open an existing file, checking its attributes and replacing it if it is | |
540 | * stale. | |
541 | */ | |
542 | static bool cachefiles_open_file(struct cachefiles_object *object, | |
543 | struct dentry *dentry) | |
544 | { | |
545 | struct cachefiles_cache *cache = object->volume->cache; | |
546 | struct file *file; | |
547 | struct path path; | |
548 | int ret; | |
549 | ||
550 | _enter("%pd", dentry); | |
551 | ||
08d7a6fb MS |
552 | if (!cachefiles_mark_inode_in_use(object, d_inode(dentry))) { |
553 | pr_notice("cachefiles: Inode already in use: %pd (B=%lx)\n", | |
554 | dentry, d_inode(dentry)->i_ino); | |
1f08c925 | 555 | return false; |
08d7a6fb | 556 | } |
1f08c925 DH |
557 | |
558 | /* We need to open a file interface onto a data file now as we can't do | |
559 | * it on demand because writeback called from do_exit() sees | |
560 | * current->fs == NULL - which breaks d_path() called from ext4 open. | |
561 | */ | |
562 | path.mnt = cache->mnt; | |
563 | path.dentry = dentry; | |
cbb0b9d4 AG |
564 | file = kernel_file_open(&path, O_RDWR | O_LARGEFILE | O_DIRECT, |
565 | d_backing_inode(dentry), cache->cache_cred); | |
1f08c925 DH |
566 | if (IS_ERR(file)) { |
567 | trace_cachefiles_vfs_error(object, d_backing_inode(dentry), | |
568 | PTR_ERR(file), | |
569 | cachefiles_trace_open_error); | |
570 | goto error; | |
571 | } | |
572 | ||
573 | if (unlikely(!file->f_op->read_iter) || | |
574 | unlikely(!file->f_op->write_iter)) { | |
575 | pr_notice("Cache does not support read_iter and write_iter\n"); | |
576 | goto error_fput; | |
577 | } | |
578 | _debug("file -> %pd positive", dentry); | |
579 | ||
c8383054 JX |
580 | ret = cachefiles_ondemand_init_object(object); |
581 | if (ret < 0) | |
582 | goto error_fput; | |
583 | ||
1f08c925 DH |
584 | ret = cachefiles_check_auxdata(object, file); |
585 | if (ret < 0) | |
586 | goto check_failed; | |
587 | ||
588 | object->file = file; | |
589 | ||
590 | /* Always update the atime on an object we've just looked up (this is | |
591 | * used to keep track of culling, and atimes are only updated by read, | |
592 | * write and readdir but not lookup or open). | |
593 | */ | |
594 | touch_atime(&file->f_path); | |
595 | dput(dentry); | |
596 | return true; | |
597 | ||
598 | check_failed: | |
599 | fscache_cookie_lookup_negative(object->cookie); | |
600 | cachefiles_unmark_inode_in_use(object, file); | |
ea5dc046 JX |
601 | fput(file); |
602 | dput(dentry); | |
603 | if (ret == -ESTALE) | |
1f08c925 | 604 | return cachefiles_create_file(object); |
ea5dc046 JX |
605 | return false; |
606 | ||
1f08c925 DH |
607 | error_fput: |
608 | fput(file); | |
609 | error: | |
08d7a6fb | 610 | cachefiles_do_unmark_inode_in_use(object, d_inode(dentry)); |
1f08c925 DH |
611 | dput(dentry); |
612 | return false; | |
613 | } | |
614 | ||
615 | /* | |
616 | * walk from the parent object to the child object through the backing | |
617 | * filesystem, creating directories as we go | |
618 | */ | |
619 | bool cachefiles_look_up_object(struct cachefiles_object *object) | |
620 | { | |
621 | struct cachefiles_volume *volume = object->volume; | |
622 | struct dentry *dentry, *fan = volume->fanout[(u8)object->cookie->key_hash]; | |
623 | int ret; | |
624 | ||
625 | _enter("OBJ%x,%s,", object->debug_id, object->d_name); | |
626 | ||
627 | /* Look up path "cache/vol/fanout/file". */ | |
628 | ret = cachefiles_inject_read_error(); | |
629 | if (ret == 0) | |
630 | dentry = lookup_positive_unlocked(object->d_name, fan, | |
631 | object->d_name_len); | |
632 | else | |
633 | dentry = ERR_PTR(ret); | |
8c39b8bc | 634 | trace_cachefiles_lookup(object, fan, dentry); |
1f08c925 DH |
635 | if (IS_ERR(dentry)) { |
636 | if (dentry == ERR_PTR(-ENOENT)) | |
637 | goto new_file; | |
638 | if (dentry == ERR_PTR(-EIO)) | |
639 | cachefiles_io_error_obj(object, "Lookup failed"); | |
640 | return false; | |
641 | } | |
642 | ||
643 | if (!d_is_reg(dentry)) { | |
644 | pr_err("%pd is not a file\n", dentry); | |
645 | inode_lock_nested(d_inode(fan), I_MUTEX_PARENT); | |
646 | ret = cachefiles_bury_object(volume->cache, object, fan, dentry, | |
647 | FSCACHE_OBJECT_IS_WEIRD); | |
648 | dput(dentry); | |
649 | if (ret < 0) | |
650 | return false; | |
651 | goto new_file; | |
652 | } | |
653 | ||
654 | if (!cachefiles_open_file(object, dentry)) | |
655 | return false; | |
656 | ||
657 | _leave(" = t [%lu]", file_inode(object->file)->i_ino); | |
658 | return true; | |
659 | ||
660 | new_file: | |
661 | fscache_cookie_lookup_negative(object->cookie); | |
662 | return cachefiles_create_file(object); | |
663 | } | |
664 | ||
665 | /* | |
666 | * Attempt to link a temporary file into its rightful place in the cache. | |
667 | */ | |
668 | bool cachefiles_commit_tmpfile(struct cachefiles_cache *cache, | |
669 | struct cachefiles_object *object) | |
670 | { | |
671 | struct cachefiles_volume *volume = object->volume; | |
672 | struct dentry *dentry, *fan = volume->fanout[(u8)object->cookie->key_hash]; | |
673 | bool success = false; | |
674 | int ret; | |
675 | ||
676 | _enter(",%pD", object->file); | |
677 | ||
678 | inode_lock_nested(d_inode(fan), I_MUTEX_PARENT); | |
679 | ret = cachefiles_inject_read_error(); | |
680 | if (ret == 0) | |
681 | dentry = lookup_one_len(object->d_name, fan, object->d_name_len); | |
682 | else | |
683 | dentry = ERR_PTR(ret); | |
684 | if (IS_ERR(dentry)) { | |
685 | trace_cachefiles_vfs_error(object, d_inode(fan), PTR_ERR(dentry), | |
686 | cachefiles_trace_lookup_error); | |
687 | _debug("lookup fail %ld", PTR_ERR(dentry)); | |
688 | goto out_unlock; | |
689 | } | |
690 | ||
691 | if (!d_is_negative(dentry)) { | |
692 | if (d_backing_inode(dentry) == file_inode(object->file)) { | |
693 | success = true; | |
694 | goto out_dput; | |
695 | } | |
696 | ||
697 | ret = cachefiles_unlink(volume->cache, object, fan, dentry, | |
698 | FSCACHE_OBJECT_IS_STALE); | |
699 | if (ret < 0) | |
700 | goto out_dput; | |
701 | ||
702 | dput(dentry); | |
703 | ret = cachefiles_inject_read_error(); | |
704 | if (ret == 0) | |
705 | dentry = lookup_one_len(object->d_name, fan, object->d_name_len); | |
706 | else | |
707 | dentry = ERR_PTR(ret); | |
708 | if (IS_ERR(dentry)) { | |
709 | trace_cachefiles_vfs_error(object, d_inode(fan), PTR_ERR(dentry), | |
710 | cachefiles_trace_lookup_error); | |
711 | _debug("lookup fail %ld", PTR_ERR(dentry)); | |
712 | goto out_unlock; | |
713 | } | |
714 | } | |
715 | ||
716 | ret = cachefiles_inject_read_error(); | |
717 | if (ret == 0) | |
abf08576 | 718 | ret = vfs_link(object->file->f_path.dentry, &nop_mnt_idmap, |
1f08c925 DH |
719 | d_inode(fan), dentry, NULL); |
720 | if (ret < 0) { | |
721 | trace_cachefiles_vfs_error(object, d_inode(fan), ret, | |
722 | cachefiles_trace_link_error); | |
723 | _debug("link fail %d", ret); | |
724 | } else { | |
725 | trace_cachefiles_link(object, file_inode(object->file)); | |
726 | spin_lock(&object->lock); | |
727 | /* TODO: Do we want to switch the file pointer to the new dentry? */ | |
728 | clear_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags); | |
729 | spin_unlock(&object->lock); | |
730 | success = true; | |
731 | } | |
732 | ||
733 | out_dput: | |
734 | dput(dentry); | |
735 | out_unlock: | |
736 | inode_unlock(d_inode(fan)); | |
737 | _leave(" = %u", success); | |
738 | return success; | |
739 | } | |
740 | ||
07a90e97 DH |
741 | /* |
742 | * Look up an inode to be checked or culled. Return -EBUSY if the inode is | |
743 | * marked in use. | |
744 | */ | |
745 | static struct dentry *cachefiles_lookup_for_cull(struct cachefiles_cache *cache, | |
746 | struct dentry *dir, | |
747 | char *filename) | |
748 | { | |
749 | struct dentry *victim; | |
750 | int ret = -ENOENT; | |
751 | ||
752 | inode_lock_nested(d_inode(dir), I_MUTEX_PARENT); | |
753 | ||
754 | victim = lookup_one_len(filename, dir, strlen(filename)); | |
755 | if (IS_ERR(victim)) | |
756 | goto lookup_error; | |
757 | if (d_is_negative(victim)) | |
758 | goto lookup_put; | |
759 | if (d_inode(victim)->i_flags & S_KERNEL_FILE) | |
760 | goto lookup_busy; | |
761 | return victim; | |
762 | ||
763 | lookup_busy: | |
764 | ret = -EBUSY; | |
765 | lookup_put: | |
766 | inode_unlock(d_inode(dir)); | |
767 | dput(victim); | |
768 | return ERR_PTR(ret); | |
769 | ||
770 | lookup_error: | |
771 | inode_unlock(d_inode(dir)); | |
772 | ret = PTR_ERR(victim); | |
773 | if (ret == -ENOENT) | |
774 | return ERR_PTR(-ESTALE); /* Probably got retired by the netfs */ | |
775 | ||
776 | if (ret == -EIO) { | |
777 | cachefiles_io_error(cache, "Lookup failed"); | |
778 | } else if (ret != -ENOMEM) { | |
779 | pr_err("Internal error: %d\n", ret); | |
780 | ret = -EIO; | |
781 | } | |
782 | ||
783 | return ERR_PTR(ret); | |
784 | } | |
785 | ||
786 | /* | |
787 | * Cull an object if it's not in use | |
788 | * - called only by cache manager daemon | |
789 | */ | |
790 | int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir, | |
791 | char *filename) | |
792 | { | |
793 | struct dentry *victim; | |
794 | struct inode *inode; | |
795 | int ret; | |
796 | ||
797 | _enter(",%pd/,%s", dir, filename); | |
798 | ||
799 | victim = cachefiles_lookup_for_cull(cache, dir, filename); | |
800 | if (IS_ERR(victim)) | |
801 | return PTR_ERR(victim); | |
802 | ||
803 | /* check to see if someone is using this object */ | |
804 | inode = d_inode(victim); | |
805 | inode_lock(inode); | |
806 | if (inode->i_flags & S_KERNEL_FILE) { | |
807 | ret = -EBUSY; | |
808 | } else { | |
809 | /* Stop the cache from picking it back up */ | |
810 | inode->i_flags |= S_KERNEL_FILE; | |
811 | ret = 0; | |
812 | } | |
813 | inode_unlock(inode); | |
814 | if (ret < 0) | |
815 | goto error_unlock; | |
816 | ||
817 | ret = cachefiles_bury_object(cache, NULL, dir, victim, | |
818 | FSCACHE_OBJECT_WAS_CULLED); | |
819 | if (ret < 0) | |
820 | goto error; | |
821 | ||
9f08ebc3 | 822 | fscache_count_culled(); |
07a90e97 DH |
823 | dput(victim); |
824 | _leave(" = 0"); | |
825 | return 0; | |
826 | ||
827 | error_unlock: | |
828 | inode_unlock(d_inode(dir)); | |
829 | error: | |
830 | dput(victim); | |
831 | if (ret == -ENOENT) | |
832 | return -ESTALE; /* Probably got retired by the netfs */ | |
833 | ||
834 | if (ret != -ENOMEM) { | |
835 | pr_err("Internal error: %d\n", ret); | |
836 | ret = -EIO; | |
837 | } | |
838 | ||
839 | _leave(" = %d", ret); | |
840 | return ret; | |
841 | } | |
842 | ||
843 | /* | |
844 | * Find out if an object is in use or not | |
845 | * - called only by cache manager daemon | |
846 | * - returns -EBUSY or 0 to indicate whether an object is in use or not | |
847 | */ | |
848 | int cachefiles_check_in_use(struct cachefiles_cache *cache, struct dentry *dir, | |
849 | char *filename) | |
850 | { | |
851 | struct dentry *victim; | |
852 | int ret = 0; | |
853 | ||
854 | victim = cachefiles_lookup_for_cull(cache, dir, filename); | |
855 | if (IS_ERR(victim)) | |
856 | return PTR_ERR(victim); | |
857 | ||
858 | inode_unlock(d_inode(dir)); | |
859 | dput(victim); | |
860 | return ret; | |
861 | } |