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) { |
abf08576 | 454 | file = vfs_tmpfile_open(&nop_mnt_idmap, &parentpath, S_IFREG, |
24a81759 MS |
455 | O_RDWR | O_LARGEFILE | O_DIRECT, |
456 | cache->cache_cred); | |
457 | ret = PTR_ERR_OR_ZERO(file); | |
38017d44 MS |
458 | } |
459 | if (ret) { | |
460 | trace_cachefiles_vfs_error(object, d_inode(fan), ret, | |
1f08c925 | 461 | cachefiles_trace_tmpfile_error); |
38017d44 | 462 | if (ret == -EIO) |
1f08c925 | 463 | cachefiles_io_error_obj(object, "Failed to create tmpfile"); |
38017d44 | 464 | goto err; |
1f08c925 DH |
465 | } |
466 | ||
24a81759 | 467 | trace_cachefiles_tmpfile(object, file_inode(file)); |
1f08c925 | 468 | |
08d7a6fb | 469 | /* This is a newly created file with no other possible user */ |
24a81759 | 470 | if (!cachefiles_mark_inode_in_use(object, file_inode(file))) |
08d7a6fb | 471 | WARN_ON(1); |
1f08c925 | 472 | |
c8383054 | 473 | ret = cachefiles_ondemand_init_object(object); |
38017d44 MS |
474 | if (ret < 0) |
475 | goto err_unuse; | |
c8383054 JX |
476 | |
477 | ni_size = object->cookie->object_size; | |
478 | ni_size = round_up(ni_size, CACHEFILES_DIO_BLOCK_SIZE); | |
479 | ||
1f08c925 | 480 | if (ni_size > 0) { |
24a81759 | 481 | trace_cachefiles_trunc(object, file_inode(file), 0, ni_size, |
1f08c925 DH |
482 | cachefiles_trunc_expand_tmpfile); |
483 | ret = cachefiles_inject_write_error(); | |
484 | if (ret == 0) | |
24a81759 | 485 | ret = vfs_truncate(&file->f_path, ni_size); |
1f08c925 DH |
486 | if (ret < 0) { |
487 | trace_cachefiles_vfs_error( | |
24a81759 | 488 | object, file_inode(file), ret, |
1f08c925 | 489 | cachefiles_trace_trunc_error); |
38017d44 | 490 | goto err_unuse; |
1f08c925 DH |
491 | } |
492 | } | |
493 | ||
38017d44 | 494 | ret = -EINVAL; |
1f08c925 DH |
495 | if (unlikely(!file->f_op->read_iter) || |
496 | unlikely(!file->f_op->write_iter)) { | |
497 | fput(file); | |
498 | pr_notice("Cache does not support read_iter and write_iter\n"); | |
38017d44 | 499 | goto err_unuse; |
1f08c925 | 500 | } |
1f08c925 DH |
501 | out: |
502 | cachefiles_end_secure(cache, saved_cred); | |
503 | return file; | |
38017d44 MS |
504 | |
505 | err_unuse: | |
24a81759 MS |
506 | cachefiles_do_unmark_inode_in_use(object, file_inode(file)); |
507 | fput(file); | |
38017d44 MS |
508 | err: |
509 | file = ERR_PTR(ret); | |
510 | goto out; | |
1f08c925 DH |
511 | } |
512 | ||
513 | /* | |
514 | * Create a new file. | |
515 | */ | |
516 | static bool cachefiles_create_file(struct cachefiles_object *object) | |
517 | { | |
518 | struct file *file; | |
519 | int ret; | |
520 | ||
3929eca7 DH |
521 | ret = cachefiles_has_space(object->volume->cache, 1, 0, |
522 | cachefiles_has_space_for_create); | |
1f08c925 DH |
523 | if (ret < 0) |
524 | return false; | |
525 | ||
526 | file = cachefiles_create_tmpfile(object); | |
527 | if (IS_ERR(file)) | |
528 | return false; | |
529 | ||
530 | set_bit(FSCACHE_COOKIE_NEEDS_UPDATE, &object->cookie->flags); | |
531 | set_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags); | |
532 | _debug("create -> %pD{ino=%lu}", file, file_inode(file)->i_ino); | |
533 | object->file = file; | |
534 | return true; | |
535 | } | |
536 | ||
537 | /* | |
538 | * Open an existing file, checking its attributes and replacing it if it is | |
539 | * stale. | |
540 | */ | |
541 | static bool cachefiles_open_file(struct cachefiles_object *object, | |
542 | struct dentry *dentry) | |
543 | { | |
544 | struct cachefiles_cache *cache = object->volume->cache; | |
545 | struct file *file; | |
546 | struct path path; | |
547 | int ret; | |
548 | ||
549 | _enter("%pd", dentry); | |
550 | ||
08d7a6fb MS |
551 | if (!cachefiles_mark_inode_in_use(object, d_inode(dentry))) { |
552 | pr_notice("cachefiles: Inode already in use: %pd (B=%lx)\n", | |
553 | dentry, d_inode(dentry)->i_ino); | |
1f08c925 | 554 | return false; |
08d7a6fb | 555 | } |
1f08c925 DH |
556 | |
557 | /* We need to open a file interface onto a data file now as we can't do | |
558 | * it on demand because writeback called from do_exit() sees | |
559 | * current->fs == NULL - which breaks d_path() called from ext4 open. | |
560 | */ | |
561 | path.mnt = cache->mnt; | |
562 | path.dentry = dentry; | |
563 | file = open_with_fake_path(&path, O_RDWR | O_LARGEFILE | O_DIRECT, | |
564 | d_backing_inode(dentry), cache->cache_cred); | |
565 | if (IS_ERR(file)) { | |
566 | trace_cachefiles_vfs_error(object, d_backing_inode(dentry), | |
567 | PTR_ERR(file), | |
568 | cachefiles_trace_open_error); | |
569 | goto error; | |
570 | } | |
571 | ||
572 | if (unlikely(!file->f_op->read_iter) || | |
573 | unlikely(!file->f_op->write_iter)) { | |
574 | pr_notice("Cache does not support read_iter and write_iter\n"); | |
575 | goto error_fput; | |
576 | } | |
577 | _debug("file -> %pd positive", dentry); | |
578 | ||
c8383054 JX |
579 | ret = cachefiles_ondemand_init_object(object); |
580 | if (ret < 0) | |
581 | goto error_fput; | |
582 | ||
1f08c925 DH |
583 | ret = cachefiles_check_auxdata(object, file); |
584 | if (ret < 0) | |
585 | goto check_failed; | |
586 | ||
587 | object->file = file; | |
588 | ||
589 | /* Always update the atime on an object we've just looked up (this is | |
590 | * used to keep track of culling, and atimes are only updated by read, | |
591 | * write and readdir but not lookup or open). | |
592 | */ | |
593 | touch_atime(&file->f_path); | |
594 | dput(dentry); | |
595 | return true; | |
596 | ||
597 | check_failed: | |
598 | fscache_cookie_lookup_negative(object->cookie); | |
599 | cachefiles_unmark_inode_in_use(object, file); | |
ea5dc046 JX |
600 | fput(file); |
601 | dput(dentry); | |
602 | if (ret == -ESTALE) | |
1f08c925 | 603 | return cachefiles_create_file(object); |
ea5dc046 JX |
604 | return false; |
605 | ||
1f08c925 DH |
606 | error_fput: |
607 | fput(file); | |
608 | error: | |
08d7a6fb | 609 | cachefiles_do_unmark_inode_in_use(object, d_inode(dentry)); |
1f08c925 DH |
610 | dput(dentry); |
611 | return false; | |
612 | } | |
613 | ||
614 | /* | |
615 | * walk from the parent object to the child object through the backing | |
616 | * filesystem, creating directories as we go | |
617 | */ | |
618 | bool cachefiles_look_up_object(struct cachefiles_object *object) | |
619 | { | |
620 | struct cachefiles_volume *volume = object->volume; | |
621 | struct dentry *dentry, *fan = volume->fanout[(u8)object->cookie->key_hash]; | |
622 | int ret; | |
623 | ||
624 | _enter("OBJ%x,%s,", object->debug_id, object->d_name); | |
625 | ||
626 | /* Look up path "cache/vol/fanout/file". */ | |
627 | ret = cachefiles_inject_read_error(); | |
628 | if (ret == 0) | |
629 | dentry = lookup_positive_unlocked(object->d_name, fan, | |
630 | object->d_name_len); | |
631 | else | |
632 | dentry = ERR_PTR(ret); | |
8c39b8bc | 633 | trace_cachefiles_lookup(object, fan, dentry); |
1f08c925 DH |
634 | if (IS_ERR(dentry)) { |
635 | if (dentry == ERR_PTR(-ENOENT)) | |
636 | goto new_file; | |
637 | if (dentry == ERR_PTR(-EIO)) | |
638 | cachefiles_io_error_obj(object, "Lookup failed"); | |
639 | return false; | |
640 | } | |
641 | ||
642 | if (!d_is_reg(dentry)) { | |
643 | pr_err("%pd is not a file\n", dentry); | |
644 | inode_lock_nested(d_inode(fan), I_MUTEX_PARENT); | |
645 | ret = cachefiles_bury_object(volume->cache, object, fan, dentry, | |
646 | FSCACHE_OBJECT_IS_WEIRD); | |
647 | dput(dentry); | |
648 | if (ret < 0) | |
649 | return false; | |
650 | goto new_file; | |
651 | } | |
652 | ||
653 | if (!cachefiles_open_file(object, dentry)) | |
654 | return false; | |
655 | ||
656 | _leave(" = t [%lu]", file_inode(object->file)->i_ino); | |
657 | return true; | |
658 | ||
659 | new_file: | |
660 | fscache_cookie_lookup_negative(object->cookie); | |
661 | return cachefiles_create_file(object); | |
662 | } | |
663 | ||
664 | /* | |
665 | * Attempt to link a temporary file into its rightful place in the cache. | |
666 | */ | |
667 | bool cachefiles_commit_tmpfile(struct cachefiles_cache *cache, | |
668 | struct cachefiles_object *object) | |
669 | { | |
670 | struct cachefiles_volume *volume = object->volume; | |
671 | struct dentry *dentry, *fan = volume->fanout[(u8)object->cookie->key_hash]; | |
672 | bool success = false; | |
673 | int ret; | |
674 | ||
675 | _enter(",%pD", object->file); | |
676 | ||
677 | inode_lock_nested(d_inode(fan), I_MUTEX_PARENT); | |
678 | ret = cachefiles_inject_read_error(); | |
679 | if (ret == 0) | |
680 | dentry = lookup_one_len(object->d_name, fan, object->d_name_len); | |
681 | else | |
682 | dentry = ERR_PTR(ret); | |
683 | if (IS_ERR(dentry)) { | |
684 | trace_cachefiles_vfs_error(object, d_inode(fan), PTR_ERR(dentry), | |
685 | cachefiles_trace_lookup_error); | |
686 | _debug("lookup fail %ld", PTR_ERR(dentry)); | |
687 | goto out_unlock; | |
688 | } | |
689 | ||
690 | if (!d_is_negative(dentry)) { | |
691 | if (d_backing_inode(dentry) == file_inode(object->file)) { | |
692 | success = true; | |
693 | goto out_dput; | |
694 | } | |
695 | ||
696 | ret = cachefiles_unlink(volume->cache, object, fan, dentry, | |
697 | FSCACHE_OBJECT_IS_STALE); | |
698 | if (ret < 0) | |
699 | goto out_dput; | |
700 | ||
701 | dput(dentry); | |
702 | ret = cachefiles_inject_read_error(); | |
703 | if (ret == 0) | |
704 | dentry = lookup_one_len(object->d_name, fan, object->d_name_len); | |
705 | else | |
706 | dentry = ERR_PTR(ret); | |
707 | if (IS_ERR(dentry)) { | |
708 | trace_cachefiles_vfs_error(object, d_inode(fan), PTR_ERR(dentry), | |
709 | cachefiles_trace_lookup_error); | |
710 | _debug("lookup fail %ld", PTR_ERR(dentry)); | |
711 | goto out_unlock; | |
712 | } | |
713 | } | |
714 | ||
715 | ret = cachefiles_inject_read_error(); | |
716 | if (ret == 0) | |
abf08576 | 717 | ret = vfs_link(object->file->f_path.dentry, &nop_mnt_idmap, |
1f08c925 DH |
718 | d_inode(fan), dentry, NULL); |
719 | if (ret < 0) { | |
720 | trace_cachefiles_vfs_error(object, d_inode(fan), ret, | |
721 | cachefiles_trace_link_error); | |
722 | _debug("link fail %d", ret); | |
723 | } else { | |
724 | trace_cachefiles_link(object, file_inode(object->file)); | |
725 | spin_lock(&object->lock); | |
726 | /* TODO: Do we want to switch the file pointer to the new dentry? */ | |
727 | clear_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags); | |
728 | spin_unlock(&object->lock); | |
729 | success = true; | |
730 | } | |
731 | ||
732 | out_dput: | |
733 | dput(dentry); | |
734 | out_unlock: | |
735 | inode_unlock(d_inode(fan)); | |
736 | _leave(" = %u", success); | |
737 | return success; | |
738 | } | |
739 | ||
07a90e97 DH |
740 | /* |
741 | * Look up an inode to be checked or culled. Return -EBUSY if the inode is | |
742 | * marked in use. | |
743 | */ | |
744 | static struct dentry *cachefiles_lookup_for_cull(struct cachefiles_cache *cache, | |
745 | struct dentry *dir, | |
746 | char *filename) | |
747 | { | |
748 | struct dentry *victim; | |
749 | int ret = -ENOENT; | |
750 | ||
751 | inode_lock_nested(d_inode(dir), I_MUTEX_PARENT); | |
752 | ||
753 | victim = lookup_one_len(filename, dir, strlen(filename)); | |
754 | if (IS_ERR(victim)) | |
755 | goto lookup_error; | |
756 | if (d_is_negative(victim)) | |
757 | goto lookup_put; | |
758 | if (d_inode(victim)->i_flags & S_KERNEL_FILE) | |
759 | goto lookup_busy; | |
760 | return victim; | |
761 | ||
762 | lookup_busy: | |
763 | ret = -EBUSY; | |
764 | lookup_put: | |
765 | inode_unlock(d_inode(dir)); | |
766 | dput(victim); | |
767 | return ERR_PTR(ret); | |
768 | ||
769 | lookup_error: | |
770 | inode_unlock(d_inode(dir)); | |
771 | ret = PTR_ERR(victim); | |
772 | if (ret == -ENOENT) | |
773 | return ERR_PTR(-ESTALE); /* Probably got retired by the netfs */ | |
774 | ||
775 | if (ret == -EIO) { | |
776 | cachefiles_io_error(cache, "Lookup failed"); | |
777 | } else if (ret != -ENOMEM) { | |
778 | pr_err("Internal error: %d\n", ret); | |
779 | ret = -EIO; | |
780 | } | |
781 | ||
782 | return ERR_PTR(ret); | |
783 | } | |
784 | ||
785 | /* | |
786 | * Cull an object if it's not in use | |
787 | * - called only by cache manager daemon | |
788 | */ | |
789 | int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir, | |
790 | char *filename) | |
791 | { | |
792 | struct dentry *victim; | |
793 | struct inode *inode; | |
794 | int ret; | |
795 | ||
796 | _enter(",%pd/,%s", dir, filename); | |
797 | ||
798 | victim = cachefiles_lookup_for_cull(cache, dir, filename); | |
799 | if (IS_ERR(victim)) | |
800 | return PTR_ERR(victim); | |
801 | ||
802 | /* check to see if someone is using this object */ | |
803 | inode = d_inode(victim); | |
804 | inode_lock(inode); | |
805 | if (inode->i_flags & S_KERNEL_FILE) { | |
806 | ret = -EBUSY; | |
807 | } else { | |
808 | /* Stop the cache from picking it back up */ | |
809 | inode->i_flags |= S_KERNEL_FILE; | |
810 | ret = 0; | |
811 | } | |
812 | inode_unlock(inode); | |
813 | if (ret < 0) | |
814 | goto error_unlock; | |
815 | ||
816 | ret = cachefiles_bury_object(cache, NULL, dir, victim, | |
817 | FSCACHE_OBJECT_WAS_CULLED); | |
818 | if (ret < 0) | |
819 | goto error; | |
820 | ||
9f08ebc3 | 821 | fscache_count_culled(); |
07a90e97 DH |
822 | dput(victim); |
823 | _leave(" = 0"); | |
824 | return 0; | |
825 | ||
826 | error_unlock: | |
827 | inode_unlock(d_inode(dir)); | |
828 | error: | |
829 | dput(victim); | |
830 | if (ret == -ENOENT) | |
831 | return -ESTALE; /* Probably got retired by the netfs */ | |
832 | ||
833 | if (ret != -ENOMEM) { | |
834 | pr_err("Internal error: %d\n", ret); | |
835 | ret = -EIO; | |
836 | } | |
837 | ||
838 | _leave(" = %d", ret); | |
839 | return ret; | |
840 | } | |
841 | ||
842 | /* | |
843 | * Find out if an object is in use or not | |
844 | * - called only by cache manager daemon | |
845 | * - returns -EBUSY or 0 to indicate whether an object is in use or not | |
846 | */ | |
847 | int cachefiles_check_in_use(struct cachefiles_cache *cache, struct dentry *dir, | |
848 | char *filename) | |
849 | { | |
850 | struct dentry *victim; | |
851 | int ret = 0; | |
852 | ||
853 | victim = cachefiles_lookup_for_cull(cache, dir, filename); | |
854 | if (IS_ERR(victim)) | |
855 | return PTR_ERR(victim); | |
856 | ||
857 | inode_unlock(d_inode(dir)); | |
858 | dput(victim); | |
859 | return ret; | |
860 | } |