Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/fs/cachefiles/xattr.c
26282 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* CacheFiles extended attribute management
3
*
4
* Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
5
* Written by David Howells ([email protected])
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
#define CACHEFILES_COOKIE_TYPE_DATA 1
19
20
struct cachefiles_xattr {
21
__be64 object_size; /* Actual size of the object */
22
__be64 zero_point; /* Size after which server has no data not written by us */
23
__u8 type; /* Type of object */
24
__u8 content; /* Content presence (enum cachefiles_content) */
25
__u8 data[]; /* netfs coherency data */
26
} __packed;
27
28
static const char cachefiles_xattr_cache[] =
29
XATTR_USER_PREFIX "CacheFiles.cache";
30
31
struct cachefiles_vol_xattr {
32
__be32 reserved; /* Reserved, should be 0 */
33
__u8 data[]; /* netfs volume coherency data */
34
} __packed;
35
36
/*
37
* set the state xattr on a cache file
38
*/
39
int cachefiles_set_object_xattr(struct cachefiles_object *object)
40
{
41
struct cachefiles_xattr *buf;
42
struct dentry *dentry;
43
struct file *file = object->file;
44
unsigned int len = object->cookie->aux_len;
45
int ret;
46
47
if (!file)
48
return -ESTALE;
49
dentry = file->f_path.dentry;
50
51
_enter("%x,#%d", object->debug_id, len);
52
53
buf = kmalloc(sizeof(struct cachefiles_xattr) + len, GFP_KERNEL);
54
if (!buf)
55
return -ENOMEM;
56
57
buf->object_size = cpu_to_be64(object->cookie->object_size);
58
buf->zero_point = 0;
59
buf->type = CACHEFILES_COOKIE_TYPE_DATA;
60
buf->content = object->content_info;
61
if (test_bit(FSCACHE_COOKIE_LOCAL_WRITE, &object->cookie->flags))
62
buf->content = CACHEFILES_CONTENT_DIRTY;
63
if (len > 0)
64
memcpy(buf->data, fscache_get_aux(object->cookie), len);
65
66
ret = cachefiles_inject_write_error();
67
if (ret == 0) {
68
ret = mnt_want_write_file(file);
69
if (ret == 0) {
70
ret = vfs_setxattr(&nop_mnt_idmap, dentry,
71
cachefiles_xattr_cache, buf,
72
sizeof(struct cachefiles_xattr) + len, 0);
73
mnt_drop_write_file(file);
74
}
75
}
76
if (ret < 0) {
77
trace_cachefiles_vfs_error(object, file_inode(file), ret,
78
cachefiles_trace_setxattr_error);
79
trace_cachefiles_coherency(object, file_inode(file)->i_ino,
80
be64_to_cpup((__be64 *)buf->data),
81
buf->content,
82
cachefiles_coherency_set_fail);
83
if (ret != -ENOMEM)
84
cachefiles_io_error_obj(
85
object,
86
"Failed to set xattr with error %d", ret);
87
} else {
88
trace_cachefiles_coherency(object, file_inode(file)->i_ino,
89
be64_to_cpup((__be64 *)buf->data),
90
buf->content,
91
cachefiles_coherency_set_ok);
92
}
93
94
kfree(buf);
95
_leave(" = %d", ret);
96
return ret;
97
}
98
99
/*
100
* check the consistency between the backing cache and the FS-Cache cookie
101
*/
102
int cachefiles_check_auxdata(struct cachefiles_object *object, struct file *file)
103
{
104
struct cachefiles_xattr *buf;
105
struct dentry *dentry = file->f_path.dentry;
106
unsigned int len = object->cookie->aux_len, tlen;
107
const void *p = fscache_get_aux(object->cookie);
108
enum cachefiles_coherency_trace why;
109
ssize_t xlen;
110
int ret = -ESTALE;
111
112
tlen = sizeof(struct cachefiles_xattr) + len;
113
buf = kmalloc(tlen, GFP_KERNEL);
114
if (!buf)
115
return -ENOMEM;
116
117
xlen = cachefiles_inject_read_error();
118
if (xlen == 0)
119
xlen = vfs_getxattr(&nop_mnt_idmap, dentry, cachefiles_xattr_cache, buf, tlen);
120
if (xlen != tlen) {
121
if (xlen < 0) {
122
ret = xlen;
123
trace_cachefiles_vfs_error(object, file_inode(file), xlen,
124
cachefiles_trace_getxattr_error);
125
}
126
if (xlen == -EIO)
127
cachefiles_io_error_obj(
128
object,
129
"Failed to read aux with error %zd", xlen);
130
why = cachefiles_coherency_check_xattr;
131
goto out;
132
}
133
134
if (buf->type != CACHEFILES_COOKIE_TYPE_DATA) {
135
why = cachefiles_coherency_check_type;
136
} else if (memcmp(buf->data, p, len) != 0) {
137
why = cachefiles_coherency_check_aux;
138
} else if (be64_to_cpu(buf->object_size) != object->cookie->object_size) {
139
why = cachefiles_coherency_check_objsize;
140
} else if (buf->content == CACHEFILES_CONTENT_DIRTY) {
141
// TODO: Begin conflict resolution
142
pr_warn("Dirty object in cache\n");
143
why = cachefiles_coherency_check_dirty;
144
} else {
145
why = cachefiles_coherency_check_ok;
146
ret = 0;
147
}
148
149
out:
150
trace_cachefiles_coherency(object, file_inode(file)->i_ino,
151
be64_to_cpup((__be64 *)buf->data),
152
buf->content, why);
153
kfree(buf);
154
return ret;
155
}
156
157
/*
158
* remove the object's xattr to mark it stale
159
*/
160
int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
161
struct cachefiles_object *object,
162
struct dentry *dentry)
163
{
164
int ret;
165
166
ret = cachefiles_inject_remove_error();
167
if (ret == 0) {
168
ret = mnt_want_write(cache->mnt);
169
if (ret == 0) {
170
ret = vfs_removexattr(&nop_mnt_idmap, dentry,
171
cachefiles_xattr_cache);
172
mnt_drop_write(cache->mnt);
173
}
174
}
175
if (ret < 0) {
176
trace_cachefiles_vfs_error(object, d_inode(dentry), ret,
177
cachefiles_trace_remxattr_error);
178
if (ret == -ENOENT || ret == -ENODATA)
179
ret = 0;
180
else if (ret != -ENOMEM)
181
cachefiles_io_error(cache,
182
"Can't remove xattr from %lu"
183
" (error %d)",
184
d_backing_inode(dentry)->i_ino, -ret);
185
}
186
187
_leave(" = %d", ret);
188
return ret;
189
}
190
191
/*
192
* Stick a marker on the cache object to indicate that it's dirty.
193
*/
194
void cachefiles_prepare_to_write(struct fscache_cookie *cookie)
195
{
196
const struct cred *saved_cred;
197
struct cachefiles_object *object = cookie->cache_priv;
198
struct cachefiles_cache *cache = object->volume->cache;
199
200
_enter("c=%08x", object->cookie->debug_id);
201
202
if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) {
203
cachefiles_begin_secure(cache, &saved_cred);
204
cachefiles_set_object_xattr(object);
205
cachefiles_end_secure(cache, saved_cred);
206
}
207
}
208
209
/*
210
* Set the state xattr on a volume directory.
211
*/
212
bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume)
213
{
214
struct cachefiles_vol_xattr *buf;
215
unsigned int len = volume->vcookie->coherency_len;
216
const void *p = volume->vcookie->coherency;
217
struct dentry *dentry = volume->dentry;
218
int ret;
219
220
_enter("%x,#%d", volume->vcookie->debug_id, len);
221
222
len += sizeof(*buf);
223
buf = kmalloc(len, GFP_KERNEL);
224
if (!buf)
225
return false;
226
buf->reserved = cpu_to_be32(0);
227
memcpy(buf->data, p, volume->vcookie->coherency_len);
228
229
ret = cachefiles_inject_write_error();
230
if (ret == 0) {
231
ret = mnt_want_write(volume->cache->mnt);
232
if (ret == 0) {
233
ret = vfs_setxattr(&nop_mnt_idmap, dentry,
234
cachefiles_xattr_cache,
235
buf, len, 0);
236
mnt_drop_write(volume->cache->mnt);
237
}
238
}
239
if (ret < 0) {
240
trace_cachefiles_vfs_error(NULL, d_inode(dentry), ret,
241
cachefiles_trace_setxattr_error);
242
trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino,
243
cachefiles_coherency_vol_set_fail);
244
if (ret != -ENOMEM)
245
cachefiles_io_error(
246
volume->cache, "Failed to set xattr with error %d", ret);
247
} else {
248
trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino,
249
cachefiles_coherency_vol_set_ok);
250
}
251
252
kfree(buf);
253
_leave(" = %d", ret);
254
return ret == 0;
255
}
256
257
/*
258
* Check the consistency between the backing cache and the volume cookie.
259
*/
260
int cachefiles_check_volume_xattr(struct cachefiles_volume *volume)
261
{
262
struct cachefiles_vol_xattr *buf;
263
struct dentry *dentry = volume->dentry;
264
unsigned int len = volume->vcookie->coherency_len;
265
const void *p = volume->vcookie->coherency;
266
enum cachefiles_coherency_trace why;
267
ssize_t xlen;
268
int ret = -ESTALE;
269
270
_enter("");
271
272
len += sizeof(*buf);
273
buf = kmalloc(len, GFP_KERNEL);
274
if (!buf)
275
return -ENOMEM;
276
277
xlen = cachefiles_inject_read_error();
278
if (xlen == 0)
279
xlen = vfs_getxattr(&nop_mnt_idmap, dentry, cachefiles_xattr_cache, buf, len);
280
if (xlen != len) {
281
if (xlen < 0) {
282
ret = xlen;
283
trace_cachefiles_vfs_error(NULL, d_inode(dentry), xlen,
284
cachefiles_trace_getxattr_error);
285
if (xlen == -EIO)
286
cachefiles_io_error(
287
volume->cache,
288
"Failed to read xattr with error %zd", xlen);
289
}
290
why = cachefiles_coherency_vol_check_xattr;
291
} else if (buf->reserved != cpu_to_be32(0)) {
292
why = cachefiles_coherency_vol_check_resv;
293
} else if (memcmp(buf->data, p, len - sizeof(*buf)) != 0) {
294
why = cachefiles_coherency_vol_check_cmp;
295
} else {
296
why = cachefiles_coherency_vol_check_ok;
297
ret = 0;
298
}
299
300
trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino, why);
301
kfree(buf);
302
_leave(" = %d", ret);
303
return ret;
304
}
305
306