diff options
Diffstat (limited to 'fs/cachefiles/xattr.c')
-rw-r--r-- | fs/cachefiles/xattr.c | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/fs/cachefiles/xattr.c b/fs/cachefiles/xattr.c new file mode 100644 index 000000000000..f3e7a0bf068b --- /dev/null +++ b/fs/cachefiles/xattr.c | |||
@@ -0,0 +1,291 @@ | |||
1 | /* CacheFiles extended attribute management | ||
2 | * | ||
3 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/file.h> | ||
15 | #include <linux/fs.h> | ||
16 | #include <linux/fsnotify.h> | ||
17 | #include <linux/quotaops.h> | ||
18 | #include <linux/xattr.h> | ||
19 | #include "internal.h" | ||
20 | |||
21 | static const char cachefiles_xattr_cache[] = | ||
22 | XATTR_USER_PREFIX "CacheFiles.cache"; | ||
23 | |||
24 | /* | ||
25 | * check the type label on an object | ||
26 | * - done using xattrs | ||
27 | */ | ||
28 | int cachefiles_check_object_type(struct cachefiles_object *object) | ||
29 | { | ||
30 | struct dentry *dentry = object->dentry; | ||
31 | char type[3], xtype[3]; | ||
32 | int ret; | ||
33 | |||
34 | ASSERT(dentry); | ||
35 | ASSERT(dentry->d_inode); | ||
36 | |||
37 | if (!object->fscache.cookie) | ||
38 | strcpy(type, "C3"); | ||
39 | else | ||
40 | snprintf(type, 3, "%02x", object->fscache.cookie->def->type); | ||
41 | |||
42 | _enter("%p{%s}", object, type); | ||
43 | |||
44 | /* attempt to install a type label directly */ | ||
45 | ret = vfs_setxattr(dentry, cachefiles_xattr_cache, type, 2, | ||
46 | XATTR_CREATE); | ||
47 | if (ret == 0) { | ||
48 | _debug("SET"); /* we succeeded */ | ||
49 | goto error; | ||
50 | } | ||
51 | |||
52 | if (ret != -EEXIST) { | ||
53 | kerror("Can't set xattr on %*.*s [%lu] (err %d)", | ||
54 | dentry->d_name.len, dentry->d_name.len, | ||
55 | dentry->d_name.name, dentry->d_inode->i_ino, | ||
56 | -ret); | ||
57 | goto error; | ||
58 | } | ||
59 | |||
60 | /* read the current type label */ | ||
61 | ret = vfs_getxattr(dentry, cachefiles_xattr_cache, xtype, 3); | ||
62 | if (ret < 0) { | ||
63 | if (ret == -ERANGE) | ||
64 | goto bad_type_length; | ||
65 | |||
66 | kerror("Can't read xattr on %*.*s [%lu] (err %d)", | ||
67 | dentry->d_name.len, dentry->d_name.len, | ||
68 | dentry->d_name.name, dentry->d_inode->i_ino, | ||
69 | -ret); | ||
70 | goto error; | ||
71 | } | ||
72 | |||
73 | /* check the type is what we're expecting */ | ||
74 | if (ret != 2) | ||
75 | goto bad_type_length; | ||
76 | |||
77 | if (xtype[0] != type[0] || xtype[1] != type[1]) | ||
78 | goto bad_type; | ||
79 | |||
80 | ret = 0; | ||
81 | |||
82 | error: | ||
83 | _leave(" = %d", ret); | ||
84 | return ret; | ||
85 | |||
86 | bad_type_length: | ||
87 | kerror("Cache object %lu type xattr length incorrect", | ||
88 | dentry->d_inode->i_ino); | ||
89 | ret = -EIO; | ||
90 | goto error; | ||
91 | |||
92 | bad_type: | ||
93 | xtype[2] = 0; | ||
94 | kerror("Cache object %*.*s [%lu] type %s not %s", | ||
95 | dentry->d_name.len, dentry->d_name.len, | ||
96 | dentry->d_name.name, dentry->d_inode->i_ino, | ||
97 | xtype, type); | ||
98 | ret = -EIO; | ||
99 | goto error; | ||
100 | } | ||
101 | |||
102 | /* | ||
103 | * set the state xattr on a cache file | ||
104 | */ | ||
105 | int cachefiles_set_object_xattr(struct cachefiles_object *object, | ||
106 | struct cachefiles_xattr *auxdata) | ||
107 | { | ||
108 | struct dentry *dentry = object->dentry; | ||
109 | int ret; | ||
110 | |||
111 | ASSERT(object->fscache.cookie); | ||
112 | ASSERT(dentry); | ||
113 | |||
114 | _enter("%p,#%d", object, auxdata->len); | ||
115 | |||
116 | /* attempt to install the cache metadata directly */ | ||
117 | _debug("SET %s #%u", object->fscache.cookie->def->name, auxdata->len); | ||
118 | |||
119 | ret = vfs_setxattr(dentry, cachefiles_xattr_cache, | ||
120 | &auxdata->type, auxdata->len, | ||
121 | XATTR_CREATE); | ||
122 | if (ret < 0 && ret != -ENOMEM) | ||
123 | cachefiles_io_error_obj( | ||
124 | object, | ||
125 | "Failed to set xattr with error %d", ret); | ||
126 | |||
127 | _leave(" = %d", ret); | ||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | * update the state xattr on a cache file | ||
133 | */ | ||
134 | int cachefiles_update_object_xattr(struct cachefiles_object *object, | ||
135 | struct cachefiles_xattr *auxdata) | ||
136 | { | ||
137 | struct dentry *dentry = object->dentry; | ||
138 | int ret; | ||
139 | |||
140 | ASSERT(object->fscache.cookie); | ||
141 | ASSERT(dentry); | ||
142 | |||
143 | _enter("%p,#%d", object, auxdata->len); | ||
144 | |||
145 | /* attempt to install the cache metadata directly */ | ||
146 | _debug("SET %s #%u", object->fscache.cookie->def->name, auxdata->len); | ||
147 | |||
148 | ret = vfs_setxattr(dentry, cachefiles_xattr_cache, | ||
149 | &auxdata->type, auxdata->len, | ||
150 | XATTR_REPLACE); | ||
151 | if (ret < 0 && ret != -ENOMEM) | ||
152 | cachefiles_io_error_obj( | ||
153 | object, | ||
154 | "Failed to update xattr with error %d", ret); | ||
155 | |||
156 | _leave(" = %d", ret); | ||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | /* | ||
161 | * check the state xattr on a cache file | ||
162 | * - return -ESTALE if the object should be deleted | ||
163 | */ | ||
164 | int cachefiles_check_object_xattr(struct cachefiles_object *object, | ||
165 | struct cachefiles_xattr *auxdata) | ||
166 | { | ||
167 | struct cachefiles_xattr *auxbuf; | ||
168 | struct dentry *dentry = object->dentry; | ||
169 | int ret; | ||
170 | |||
171 | _enter("%p,#%d", object, auxdata->len); | ||
172 | |||
173 | ASSERT(dentry); | ||
174 | ASSERT(dentry->d_inode); | ||
175 | |||
176 | auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, GFP_KERNEL); | ||
177 | if (!auxbuf) { | ||
178 | _leave(" = -ENOMEM"); | ||
179 | return -ENOMEM; | ||
180 | } | ||
181 | |||
182 | /* read the current type label */ | ||
183 | ret = vfs_getxattr(dentry, cachefiles_xattr_cache, | ||
184 | &auxbuf->type, 512 + 1); | ||
185 | if (ret < 0) { | ||
186 | if (ret == -ENODATA) | ||
187 | goto stale; /* no attribute - power went off | ||
188 | * mid-cull? */ | ||
189 | |||
190 | if (ret == -ERANGE) | ||
191 | goto bad_type_length; | ||
192 | |||
193 | cachefiles_io_error_obj(object, | ||
194 | "Can't read xattr on %lu (err %d)", | ||
195 | dentry->d_inode->i_ino, -ret); | ||
196 | goto error; | ||
197 | } | ||
198 | |||
199 | /* check the on-disk object */ | ||
200 | if (ret < 1) | ||
201 | goto bad_type_length; | ||
202 | |||
203 | if (auxbuf->type != auxdata->type) | ||
204 | goto stale; | ||
205 | |||
206 | auxbuf->len = ret; | ||
207 | |||
208 | /* consult the netfs */ | ||
209 | if (object->fscache.cookie->def->check_aux) { | ||
210 | enum fscache_checkaux result; | ||
211 | unsigned int dlen; | ||
212 | |||
213 | dlen = auxbuf->len - 1; | ||
214 | |||
215 | _debug("checkaux %s #%u", | ||
216 | object->fscache.cookie->def->name, dlen); | ||
217 | |||
218 | result = fscache_check_aux(&object->fscache, | ||
219 | &auxbuf->data, dlen); | ||
220 | |||
221 | switch (result) { | ||
222 | /* entry okay as is */ | ||
223 | case FSCACHE_CHECKAUX_OKAY: | ||
224 | goto okay; | ||
225 | |||
226 | /* entry requires update */ | ||
227 | case FSCACHE_CHECKAUX_NEEDS_UPDATE: | ||
228 | break; | ||
229 | |||
230 | /* entry requires deletion */ | ||
231 | case FSCACHE_CHECKAUX_OBSOLETE: | ||
232 | goto stale; | ||
233 | |||
234 | default: | ||
235 | BUG(); | ||
236 | } | ||
237 | |||
238 | /* update the current label */ | ||
239 | ret = vfs_setxattr(dentry, cachefiles_xattr_cache, | ||
240 | &auxdata->type, auxdata->len, | ||
241 | XATTR_REPLACE); | ||
242 | if (ret < 0) { | ||
243 | cachefiles_io_error_obj(object, | ||
244 | "Can't update xattr on %lu" | ||
245 | " (error %d)", | ||
246 | dentry->d_inode->i_ino, -ret); | ||
247 | goto error; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | okay: | ||
252 | ret = 0; | ||
253 | |||
254 | error: | ||
255 | kfree(auxbuf); | ||
256 | _leave(" = %d", ret); | ||
257 | return ret; | ||
258 | |||
259 | bad_type_length: | ||
260 | kerror("Cache object %lu xattr length incorrect", | ||
261 | dentry->d_inode->i_ino); | ||
262 | ret = -EIO; | ||
263 | goto error; | ||
264 | |||
265 | stale: | ||
266 | ret = -ESTALE; | ||
267 | goto error; | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * remove the object's xattr to mark it stale | ||
272 | */ | ||
273 | int cachefiles_remove_object_xattr(struct cachefiles_cache *cache, | ||
274 | struct dentry *dentry) | ||
275 | { | ||
276 | int ret; | ||
277 | |||
278 | ret = vfs_removexattr(dentry, cachefiles_xattr_cache); | ||
279 | if (ret < 0) { | ||
280 | if (ret == -ENOENT || ret == -ENODATA) | ||
281 | ret = 0; | ||
282 | else if (ret != -ENOMEM) | ||
283 | cachefiles_io_error(cache, | ||
284 | "Can't remove xattr from %lu" | ||
285 | " (error %d)", | ||
286 | dentry->d_inode->i_ino, -ret); | ||
287 | } | ||
288 | |||
289 | _leave(" = %d", ret); | ||
290 | return ret; | ||
291 | } | ||