Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/fs/cachefiles/interface.c
48952 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* FS-Cache interface to CacheFiles
3
*
4
* Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
5
* Written by David Howells ([email protected])
6
*/
7
8
#include <linux/slab.h>
9
#include <linux/mount.h>
10
#include <linux/xattr.h>
11
#include <linux/file.h>
12
#include <linux/namei.h>
13
#include <linux/falloc.h>
14
#include <trace/events/fscache.h>
15
#include "internal.h"
16
17
static atomic_t cachefiles_object_debug_id;
18
19
/*
20
* Allocate a cache object record.
21
*/
22
static
23
struct cachefiles_object *cachefiles_alloc_object(struct fscache_cookie *cookie)
24
{
25
struct fscache_volume *vcookie = cookie->volume;
26
struct cachefiles_volume *volume = vcookie->cache_priv;
27
struct cachefiles_object *object;
28
29
_enter("{%s},%x,", vcookie->key, cookie->debug_id);
30
31
object = kmem_cache_zalloc(cachefiles_object_jar, GFP_KERNEL);
32
if (!object)
33
return NULL;
34
35
if (cachefiles_ondemand_init_obj_info(object, volume)) {
36
kmem_cache_free(cachefiles_object_jar, object);
37
return NULL;
38
}
39
40
refcount_set(&object->ref, 1);
41
42
spin_lock_init(&object->lock);
43
INIT_LIST_HEAD(&object->cache_link);
44
object->volume = volume;
45
object->debug_id = atomic_inc_return(&cachefiles_object_debug_id);
46
object->cookie = fscache_get_cookie(cookie, fscache_cookie_get_attach_object);
47
48
fscache_count_object(vcookie->cache);
49
trace_cachefiles_ref(object->debug_id, cookie->debug_id, 1,
50
cachefiles_obj_new);
51
return object;
52
}
53
54
/*
55
* Note that an object has been seen.
56
*/
57
void cachefiles_see_object(struct cachefiles_object *object,
58
enum cachefiles_obj_ref_trace why)
59
{
60
trace_cachefiles_ref(object->debug_id, object->cookie->debug_id,
61
refcount_read(&object->ref), why);
62
}
63
64
/*
65
* Increment the usage count on an object;
66
*/
67
struct cachefiles_object *cachefiles_grab_object(struct cachefiles_object *object,
68
enum cachefiles_obj_ref_trace why)
69
{
70
int r;
71
72
__refcount_inc(&object->ref, &r);
73
trace_cachefiles_ref(object->debug_id, object->cookie->debug_id, r, why);
74
return object;
75
}
76
77
/*
78
* dispose of a reference to an object
79
*/
80
void cachefiles_put_object(struct cachefiles_object *object,
81
enum cachefiles_obj_ref_trace why)
82
{
83
unsigned int object_debug_id = object->debug_id;
84
unsigned int cookie_debug_id = object->cookie->debug_id;
85
struct fscache_cache *cache;
86
bool done;
87
int r;
88
89
done = __refcount_dec_and_test(&object->ref, &r);
90
trace_cachefiles_ref(object_debug_id, cookie_debug_id, r, why);
91
if (done) {
92
_debug("- kill object OBJ%x", object_debug_id);
93
94
ASSERTCMP(object->file, ==, NULL);
95
96
kfree(object->d_name);
97
cachefiles_ondemand_deinit_obj_info(object);
98
cache = object->volume->cache->cache;
99
fscache_put_cookie(object->cookie, fscache_cookie_put_object);
100
object->cookie = NULL;
101
kmem_cache_free(cachefiles_object_jar, object);
102
fscache_uncount_object(cache);
103
}
104
105
_leave("");
106
}
107
108
/*
109
* Adjust the size of a cache file if necessary to match the DIO size. We keep
110
* the EOF marker a multiple of DIO blocks so that we don't fall back to doing
111
* non-DIO for a partial block straddling the EOF, but we also have to be
112
* careful of someone expanding the file and accidentally accreting the
113
* padding.
114
*/
115
static int cachefiles_adjust_size(struct cachefiles_object *object)
116
{
117
struct iattr newattrs;
118
struct file *file = object->file;
119
uint64_t ni_size;
120
loff_t oi_size;
121
int ret;
122
123
ni_size = object->cookie->object_size;
124
ni_size = round_up(ni_size, CACHEFILES_DIO_BLOCK_SIZE);
125
126
_enter("{OBJ%x},[%llu]",
127
object->debug_id, (unsigned long long) ni_size);
128
129
if (!file)
130
return -ENOBUFS;
131
132
oi_size = i_size_read(file_inode(file));
133
if (oi_size == ni_size)
134
return 0;
135
136
inode_lock(file_inode(file));
137
138
/* if there's an extension to a partial page at the end of the backing
139
* file, we need to discard the partial page so that we pick up new
140
* data after it */
141
if (oi_size & ~PAGE_MASK && ni_size > oi_size) {
142
_debug("discard tail %llx", oi_size);
143
newattrs.ia_valid = ATTR_SIZE;
144
newattrs.ia_size = oi_size & PAGE_MASK;
145
ret = cachefiles_inject_remove_error();
146
if (ret == 0)
147
ret = notify_change(&nop_mnt_idmap, file->f_path.dentry,
148
&newattrs, NULL);
149
if (ret < 0)
150
goto truncate_failed;
151
}
152
153
newattrs.ia_valid = ATTR_SIZE;
154
newattrs.ia_size = ni_size;
155
ret = cachefiles_inject_write_error();
156
if (ret == 0)
157
ret = notify_change(&nop_mnt_idmap, file->f_path.dentry,
158
&newattrs, NULL);
159
160
truncate_failed:
161
inode_unlock(file_inode(file));
162
163
if (ret < 0)
164
trace_cachefiles_io_error(NULL, file_inode(file), ret,
165
cachefiles_trace_notify_change_error);
166
if (ret == -EIO) {
167
cachefiles_io_error_obj(object, "Size set failed");
168
ret = -ENOBUFS;
169
}
170
171
_leave(" = %d", ret);
172
return ret;
173
}
174
175
/*
176
* Attempt to look up the nominated node in this cache
177
*/
178
static bool cachefiles_lookup_cookie(struct fscache_cookie *cookie)
179
{
180
struct cachefiles_object *object;
181
struct cachefiles_cache *cache = cookie->volume->cache->cache_priv;
182
const struct cred *saved_cred;
183
bool success;
184
185
object = cachefiles_alloc_object(cookie);
186
if (!object)
187
goto fail;
188
189
_enter("{OBJ%x}", object->debug_id);
190
191
if (!cachefiles_cook_key(object))
192
goto fail_put;
193
194
cookie->cache_priv = object;
195
196
cachefiles_begin_secure(cache, &saved_cred);
197
198
success = cachefiles_look_up_object(object);
199
if (!success)
200
goto fail_withdraw;
201
202
cachefiles_see_object(object, cachefiles_obj_see_lookup_cookie);
203
204
spin_lock(&cache->object_list_lock);
205
list_add(&object->cache_link, &cache->object_list);
206
spin_unlock(&cache->object_list_lock);
207
cachefiles_adjust_size(object);
208
209
cachefiles_end_secure(cache, saved_cred);
210
_leave(" = t");
211
return true;
212
213
fail_withdraw:
214
cachefiles_end_secure(cache, saved_cred);
215
cachefiles_see_object(object, cachefiles_obj_see_lookup_failed);
216
fscache_caching_failed(cookie);
217
_debug("failed c=%08x o=%08x", cookie->debug_id, object->debug_id);
218
/* The caller holds an access count on the cookie, so we need them to
219
* drop it before we can withdraw the object.
220
*/
221
return false;
222
223
fail_put:
224
cachefiles_put_object(object, cachefiles_obj_put_alloc_fail);
225
fail:
226
return false;
227
}
228
229
/*
230
* Shorten the backing object to discard any dirty data and free up
231
* any unused granules.
232
*/
233
static bool cachefiles_shorten_object(struct cachefiles_object *object,
234
struct file *file, loff_t new_size)
235
{
236
struct cachefiles_cache *cache = object->volume->cache;
237
struct inode *inode = file_inode(file);
238
loff_t i_size, dio_size;
239
int ret;
240
241
dio_size = round_up(new_size, CACHEFILES_DIO_BLOCK_SIZE);
242
i_size = i_size_read(inode);
243
244
trace_cachefiles_trunc(object, inode, i_size, dio_size,
245
cachefiles_trunc_shrink);
246
ret = cachefiles_inject_remove_error();
247
if (ret == 0)
248
ret = vfs_truncate(&file->f_path, dio_size);
249
if (ret < 0) {
250
trace_cachefiles_io_error(object, file_inode(file), ret,
251
cachefiles_trace_trunc_error);
252
cachefiles_io_error_obj(object, "Trunc-to-size failed %d", ret);
253
cachefiles_remove_object_xattr(cache, object, file->f_path.dentry);
254
return false;
255
}
256
257
if (new_size < dio_size) {
258
trace_cachefiles_trunc(object, inode, dio_size, new_size,
259
cachefiles_trunc_dio_adjust);
260
ret = cachefiles_inject_write_error();
261
if (ret == 0)
262
ret = vfs_fallocate(file, FALLOC_FL_ZERO_RANGE,
263
new_size, dio_size - new_size);
264
if (ret < 0) {
265
trace_cachefiles_io_error(object, file_inode(file), ret,
266
cachefiles_trace_fallocate_error);
267
cachefiles_io_error_obj(object, "Trunc-to-dio-size failed %d", ret);
268
cachefiles_remove_object_xattr(cache, object, file->f_path.dentry);
269
return false;
270
}
271
}
272
273
return true;
274
}
275
276
/*
277
* Resize the backing object.
278
*/
279
static void cachefiles_resize_cookie(struct netfs_cache_resources *cres,
280
loff_t new_size)
281
{
282
struct cachefiles_object *object = cachefiles_cres_object(cres);
283
struct cachefiles_cache *cache = object->volume->cache;
284
struct fscache_cookie *cookie = object->cookie;
285
const struct cred *saved_cred;
286
struct file *file = cachefiles_cres_file(cres);
287
loff_t old_size = cookie->object_size;
288
289
_enter("%llu->%llu", old_size, new_size);
290
291
if (new_size < old_size) {
292
cachefiles_begin_secure(cache, &saved_cred);
293
cachefiles_shorten_object(object, file, new_size);
294
cachefiles_end_secure(cache, saved_cred);
295
object->cookie->object_size = new_size;
296
return;
297
}
298
299
/* The file is being expanded. We don't need to do anything
300
* particularly. cookie->initial_size doesn't change and so the point
301
* at which we have to download before doesn't change.
302
*/
303
cookie->object_size = new_size;
304
}
305
306
/*
307
* Commit changes to the object as we drop it.
308
*/
309
static void cachefiles_commit_object(struct cachefiles_object *object,
310
struct cachefiles_cache *cache)
311
{
312
bool update = false;
313
314
if (test_and_clear_bit(FSCACHE_COOKIE_LOCAL_WRITE, &object->cookie->flags))
315
update = true;
316
if (test_and_clear_bit(FSCACHE_COOKIE_NEEDS_UPDATE, &object->cookie->flags))
317
update = true;
318
if (update)
319
cachefiles_set_object_xattr(object);
320
321
if (test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags))
322
cachefiles_commit_tmpfile(cache, object);
323
}
324
325
/*
326
* Finalise and object and close the VFS structs that we have.
327
*/
328
static void cachefiles_clean_up_object(struct cachefiles_object *object,
329
struct cachefiles_cache *cache)
330
{
331
struct file *file;
332
333
if (test_bit(FSCACHE_COOKIE_RETIRED, &object->cookie->flags)) {
334
if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) {
335
cachefiles_see_object(object, cachefiles_obj_see_clean_delete);
336
_debug("- inval object OBJ%x", object->debug_id);
337
cachefiles_delete_object(object, FSCACHE_OBJECT_WAS_RETIRED);
338
} else {
339
cachefiles_see_object(object, cachefiles_obj_see_clean_drop_tmp);
340
_debug("- inval object OBJ%x tmpfile", object->debug_id);
341
}
342
} else {
343
cachefiles_see_object(object, cachefiles_obj_see_clean_commit);
344
cachefiles_commit_object(object, cache);
345
}
346
347
cachefiles_unmark_inode_in_use(object, object->file);
348
349
spin_lock(&object->lock);
350
file = object->file;
351
object->file = NULL;
352
spin_unlock(&object->lock);
353
354
if (file)
355
fput(file);
356
}
357
358
/*
359
* Withdraw caching for a cookie.
360
*/
361
static void cachefiles_withdraw_cookie(struct fscache_cookie *cookie)
362
{
363
struct cachefiles_object *object = cookie->cache_priv;
364
struct cachefiles_cache *cache = object->volume->cache;
365
const struct cred *saved_cred;
366
367
_enter("o=%x", object->debug_id);
368
cachefiles_see_object(object, cachefiles_obj_see_withdraw_cookie);
369
370
if (!list_empty(&object->cache_link)) {
371
spin_lock(&cache->object_list_lock);
372
cachefiles_see_object(object, cachefiles_obj_see_withdrawal);
373
list_del_init(&object->cache_link);
374
spin_unlock(&cache->object_list_lock);
375
}
376
377
cachefiles_ondemand_clean_object(object);
378
379
if (object->file) {
380
cachefiles_begin_secure(cache, &saved_cred);
381
cachefiles_clean_up_object(object, cache);
382
cachefiles_end_secure(cache, saved_cred);
383
}
384
385
cookie->cache_priv = NULL;
386
cachefiles_put_object(object, cachefiles_obj_put_detach);
387
}
388
389
/*
390
* Invalidate the storage associated with a cookie.
391
*/
392
static bool cachefiles_invalidate_cookie(struct fscache_cookie *cookie)
393
{
394
struct cachefiles_object *object = cookie->cache_priv;
395
struct file *new_file, *old_file;
396
bool old_tmpfile;
397
398
_enter("o=%x,[%llu]", object->debug_id, object->cookie->object_size);
399
400
old_tmpfile = test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags);
401
402
if (!object->file) {
403
fscache_resume_after_invalidation(cookie);
404
_leave(" = t [light]");
405
return true;
406
}
407
408
new_file = cachefiles_create_tmpfile(object);
409
if (IS_ERR(new_file))
410
goto failed;
411
412
/* Substitute the VFS target */
413
_debug("sub");
414
spin_lock(&object->lock);
415
416
old_file = object->file;
417
object->file = new_file;
418
object->content_info = CACHEFILES_CONTENT_NO_DATA;
419
set_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags);
420
set_bit(FSCACHE_COOKIE_NEEDS_UPDATE, &object->cookie->flags);
421
422
spin_unlock(&object->lock);
423
_debug("subbed");
424
425
/* Allow I/O to take place again */
426
fscache_resume_after_invalidation(cookie);
427
428
if (old_file) {
429
if (!old_tmpfile) {
430
struct cachefiles_volume *volume = object->volume;
431
struct dentry *fan = volume->fanout[(u8)cookie->key_hash];
432
struct dentry *obj;
433
434
obj = start_removing_dentry(fan, old_file->f_path.dentry);
435
if (!IS_ERR(obj))
436
cachefiles_bury_object(volume->cache, object,
437
fan, obj,
438
FSCACHE_OBJECT_INVALIDATED);
439
}
440
fput(old_file);
441
}
442
443
_leave(" = t");
444
return true;
445
446
failed:
447
_leave(" = f");
448
return false;
449
}
450
451
const struct fscache_cache_ops cachefiles_cache_ops = {
452
.name = "cachefiles",
453
.acquire_volume = cachefiles_acquire_volume,
454
.free_volume = cachefiles_free_volume,
455
.lookup_cookie = cachefiles_lookup_cookie,
456
.withdraw_cookie = cachefiles_withdraw_cookie,
457
.invalidate_cookie = cachefiles_invalidate_cookie,
458
.begin_operation = cachefiles_begin_operation,
459
.resize_cookie = cachefiles_resize_cookie,
460
.prepare_to_write = cachefiles_prepare_to_write,
461
};
462
463