Skip to content

Commit 32e1500

Browse files
committed
fscache, cachefiles: Store the volume coherency data
Store the volume coherency data in an xattr and check it when we rebind the volume. If it doesn't match the cache volume is moved to the graveyard and rebuilt anew. Changes ======= ver #4: - Remove a couple of debugging prints. Signed-off-by: David Howells <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Link: https://lore.kernel.org/r/163967164397.1823006.2950539849831291830.stgit@warthog.procyon.org.uk/ # v3 Link: https://lore.kernel.org/r/164021563138.640689.15851092065380543119.stgit@warthog.procyon.org.uk/ # v4
1 parent 047487c commit 32e1500

File tree

6 files changed

+157
-6
lines changed

6 files changed

+157
-6
lines changed

fs/cachefiles/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,8 @@ extern int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
270270
struct cachefiles_object *object,
271271
struct dentry *dentry);
272272
extern void cachefiles_prepare_to_write(struct fscache_cookie *cookie);
273+
extern bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume);
274+
extern int cachefiles_check_volume_xattr(struct cachefiles_volume *volume);
273275

274276
/*
275277
* Error handling

fs/cachefiles/volume.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ void cachefiles_acquire_volume(struct fscache_volume *vcookie)
2222
struct dentry *vdentry, *fan;
2323
size_t len;
2424
char *name;
25-
int n_accesses, i;
25+
bool is_new = false;
26+
int ret, n_accesses, i;
2627

2728
_enter("");
2829

@@ -43,11 +44,29 @@ void cachefiles_acquire_volume(struct fscache_volume *vcookie)
4344
memcpy(name + 1, vcookie->key + 1, len);
4445
name[len + 1] = 0;
4546

46-
vdentry = cachefiles_get_directory(cache, cache->store, name, NULL);
47+
retry:
48+
vdentry = cachefiles_get_directory(cache, cache->store, name, &is_new);
4749
if (IS_ERR(vdentry))
4850
goto error_name;
4951
volume->dentry = vdentry;
5052

53+
if (is_new) {
54+
if (!cachefiles_set_volume_xattr(volume))
55+
goto error_dir;
56+
} else {
57+
ret = cachefiles_check_volume_xattr(volume);
58+
if (ret < 0) {
59+
if (ret != -ESTALE)
60+
goto error_dir;
61+
inode_lock_nested(d_inode(cache->store), I_MUTEX_PARENT);
62+
cachefiles_bury_object(cache, NULL, cache->store, vdentry,
63+
FSCACHE_VOLUME_IS_WEIRD);
64+
cachefiles_put_directory(volume->dentry);
65+
cond_resched();
66+
goto retry;
67+
}
68+
}
69+
5170
for (i = 0; i < 256; i++) {
5271
sprintf(name, "@%02x", i);
5372
fan = cachefiles_get_directory(cache, vdentry, name, NULL);
@@ -74,6 +93,7 @@ void cachefiles_acquire_volume(struct fscache_volume *vcookie)
7493
error_fan:
7594
for (i = 0; i < 256; i++)
7695
cachefiles_put_directory(volume->fanout[i]);
96+
error_dir:
7797
cachefiles_put_directory(volume->dentry);
7898
error_name:
7999
kfree(name);
@@ -114,5 +134,6 @@ void cachefiles_free_volume(struct fscache_volume *vcookie)
114134
void cachefiles_withdraw_volume(struct cachefiles_volume *volume)
115135
{
116136
fscache_withdraw_volume(volume->vcookie);
137+
cachefiles_set_volume_xattr(volume);
117138
__cachefiles_free_volume(volume);
118139
}

fs/cachefiles/xattr.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,81 @@ void cachefiles_prepare_to_write(struct fscache_cookie *cookie)
179179
cachefiles_end_secure(cache, saved_cred);
180180
}
181181
}
182+
183+
/*
184+
* Set the state xattr on a volume directory.
185+
*/
186+
bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume)
187+
{
188+
unsigned int len = volume->vcookie->coherency_len;
189+
const void *p = volume->vcookie->coherency;
190+
struct dentry *dentry = volume->dentry;
191+
int ret;
192+
193+
_enter("%x,#%d", volume->vcookie->debug_id, len);
194+
195+
ret = cachefiles_inject_write_error();
196+
if (ret == 0)
197+
ret = vfs_setxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
198+
p, len, 0);
199+
if (ret < 0) {
200+
trace_cachefiles_vfs_error(NULL, d_inode(dentry), ret,
201+
cachefiles_trace_setxattr_error);
202+
trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino,
203+
cachefiles_coherency_vol_set_fail);
204+
if (ret != -ENOMEM)
205+
cachefiles_io_error(
206+
volume->cache, "Failed to set xattr with error %d", ret);
207+
} else {
208+
trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino,
209+
cachefiles_coherency_vol_set_ok);
210+
}
211+
212+
_leave(" = %d", ret);
213+
return ret == 0;
214+
}
215+
216+
/*
217+
* Check the consistency between the backing cache and the volume cookie.
218+
*/
219+
int cachefiles_check_volume_xattr(struct cachefiles_volume *volume)
220+
{
221+
struct cachefiles_xattr *buf;
222+
struct dentry *dentry = volume->dentry;
223+
unsigned int len = volume->vcookie->coherency_len;
224+
const void *p = volume->vcookie->coherency;
225+
enum cachefiles_coherency_trace why;
226+
ssize_t xlen;
227+
int ret = -ESTALE;
228+
229+
_enter("");
230+
231+
buf = kmalloc(len, GFP_KERNEL);
232+
if (!buf)
233+
return -ENOMEM;
234+
235+
xlen = cachefiles_inject_read_error();
236+
if (xlen == 0)
237+
xlen = vfs_getxattr(&init_user_ns, dentry, cachefiles_xattr_cache, buf, len);
238+
if (xlen != len) {
239+
if (xlen < 0) {
240+
trace_cachefiles_vfs_error(NULL, d_inode(dentry), xlen,
241+
cachefiles_trace_getxattr_error);
242+
if (xlen == -EIO)
243+
cachefiles_io_error(
244+
volume->cache,
245+
"Failed to read xattr with error %zd", xlen);
246+
}
247+
why = cachefiles_coherency_vol_check_xattr;
248+
} else if (memcmp(buf->data, p, len) != 0) {
249+
why = cachefiles_coherency_vol_check_cmp;
250+
} else {
251+
why = cachefiles_coherency_vol_check_ok;
252+
ret = 0;
253+
}
254+
255+
trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino, why);
256+
kfree(buf);
257+
_leave(" = %d", ret);
258+
return ret;
259+
}

fs/fscache/volume.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,15 +205,22 @@ static struct fscache_volume *fscache_alloc_volume(const char *volume_key,
205205
size_t klen, hlen;
206206
char *key;
207207

208+
if (!coherency_data)
209+
coherency_len = 0;
210+
208211
cache = fscache_lookup_cache(cache_name, false);
209212
if (IS_ERR(cache))
210213
return NULL;
211214

212-
volume = kzalloc(sizeof(*volume), GFP_KERNEL);
215+
volume = kzalloc(struct_size(volume, coherency, coherency_len),
216+
GFP_KERNEL);
213217
if (!volume)
214218
goto err_cache;
215219

216220
volume->cache = cache;
221+
volume->coherency_len = coherency_len;
222+
if (coherency_data)
223+
memcpy(volume->coherency, coherency_data, coherency_len);
217224
INIT_LIST_HEAD(&volume->proc_link);
218225
INIT_WORK(&volume->work, fscache_create_volume_work);
219226
refcount_set(&volume->ref, 1);
@@ -421,8 +428,11 @@ void __fscache_relinquish_volume(struct fscache_volume *volume,
421428
if (WARN_ON(test_and_set_bit(FSCACHE_VOLUME_RELINQUISHED, &volume->flags)))
422429
return;
423430

424-
if (invalidate)
431+
if (invalidate) {
425432
set_bit(FSCACHE_VOLUME_INVALIDATE, &volume->flags);
433+
} else if (coherency_data) {
434+
memcpy(volume->coherency, coherency_data, volume->coherency_len);
435+
}
426436

427437
fscache_put_volume(volume, fscache_volume_put_relinquish);
428438
}

include/linux/fscache.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ struct fscache_volume {
8787
#define FSCACHE_VOLUME_COLLIDED_WITH 2 /* Volume was collided with */
8888
#define FSCACHE_VOLUME_ACQUIRE_PENDING 3 /* Volume is waiting to complete acquisition */
8989
#define FSCACHE_VOLUME_CREATING 4 /* Volume is being created on disk */
90+
u8 coherency_len; /* Length of the coherency data */
91+
u8 coherency[]; /* Coherency data */
9092
};
9193

9294
/*

include/trace/events/cachefiles.h

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ enum fscache_why_object_killed {
4040
FSCACHE_OBJECT_NO_SPACE,
4141
FSCACHE_OBJECT_WAS_RETIRED,
4242
FSCACHE_OBJECT_WAS_CULLED,
43+
FSCACHE_VOLUME_IS_WEIRD,
4344
};
4445

4546
enum cachefiles_coherency_trace {
@@ -53,6 +54,11 @@ enum cachefiles_coherency_trace {
5354
cachefiles_coherency_check_xattr,
5455
cachefiles_coherency_set_fail,
5556
cachefiles_coherency_set_ok,
57+
cachefiles_coherency_vol_check_cmp,
58+
cachefiles_coherency_vol_check_ok,
59+
cachefiles_coherency_vol_check_xattr,
60+
cachefiles_coherency_vol_set_fail,
61+
cachefiles_coherency_vol_set_ok,
5662
};
5763

5864
enum cachefiles_trunc_trace {
@@ -103,7 +109,8 @@ enum cachefiles_error_trace {
103109
EM(FSCACHE_OBJECT_INVALIDATED, "inval") \
104110
EM(FSCACHE_OBJECT_NO_SPACE, "no_space") \
105111
EM(FSCACHE_OBJECT_WAS_RETIRED, "was_retired") \
106-
E_(FSCACHE_OBJECT_WAS_CULLED, "was_culled")
112+
EM(FSCACHE_OBJECT_WAS_CULLED, "was_culled") \
113+
E_(FSCACHE_VOLUME_IS_WEIRD, "volume_weird")
107114

108115
#define cachefiles_obj_ref_traces \
109116
EM(cachefiles_obj_get_ioreq, "GET ioreq") \
@@ -129,7 +136,12 @@ enum cachefiles_error_trace {
129136
EM(cachefiles_coherency_check_type, "BAD type") \
130137
EM(cachefiles_coherency_check_xattr, "BAD xatt") \
131138
EM(cachefiles_coherency_set_fail, "SET fail") \
132-
E_(cachefiles_coherency_set_ok, "SET ok ")
139+
EM(cachefiles_coherency_set_ok, "SET ok ") \
140+
EM(cachefiles_coherency_vol_check_cmp, "VOL BAD cmp ") \
141+
EM(cachefiles_coherency_vol_check_ok, "VOL OK ") \
142+
EM(cachefiles_coherency_vol_check_xattr,"VOL BAD xatt") \
143+
EM(cachefiles_coherency_vol_set_fail, "VOL SET fail") \
144+
E_(cachefiles_coherency_vol_set_ok, "VOL SET ok ")
133145

134146
#define cachefiles_trunc_traces \
135147
EM(cachefiles_trunc_dio_adjust, "DIOADJ") \
@@ -365,6 +377,32 @@ TRACE_EVENT(cachefiles_coherency,
365377
__entry->content)
366378
);
367379

380+
TRACE_EVENT(cachefiles_vol_coherency,
381+
TP_PROTO(struct cachefiles_volume *volume,
382+
ino_t ino,
383+
enum cachefiles_coherency_trace why),
384+
385+
TP_ARGS(volume, ino, why),
386+
387+
/* Note that obj may be NULL */
388+
TP_STRUCT__entry(
389+
__field(unsigned int, vol )
390+
__field(enum cachefiles_coherency_trace, why )
391+
__field(u64, ino )
392+
),
393+
394+
TP_fast_assign(
395+
__entry->vol = volume->vcookie->debug_id;
396+
__entry->why = why;
397+
__entry->ino = ino;
398+
),
399+
400+
TP_printk("V=%08x %s i=%llx",
401+
__entry->vol,
402+
__print_symbolic(__entry->why, cachefiles_coherency_traces),
403+
__entry->ino)
404+
);
405+
368406
TRACE_EVENT(cachefiles_prep_read,
369407
TP_PROTO(struct netfs_read_subrequest *sreq,
370408
enum netfs_read_source source,

0 commit comments

Comments
 (0)