This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / fs / cachefiles / cf-xattr.c
1 /* cf-xattr.c: CacheFiles extended attribute management
2  *
3  * Copyright (C) 2006 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 License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, 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[] = XATTR_USER_PREFIX "CacheFiles.cache";
22
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         ASSERT(dentry->d_inode->i_op);
37         ASSERT(dentry->d_inode->i_op->setxattr);
38         ASSERT(dentry->d_inode->i_op->getxattr);
39
40         if (!object->fscache.cookie)
41                 strcpy(type, "C3");
42         else
43                 snprintf(type, 3, "%02x", object->fscache.cookie->def->type);
44
45         _enter("%p{%s}", object, type);
46
47         mutex_lock(&dentry->d_inode->i_mutex);
48
49         /* attempt to install a type label directly */
50         ret = dentry->d_inode->i_op->setxattr(dentry, cachefiles_xattr_cache,
51                                               type, 2, XATTR_CREATE);
52         if (ret == 0) {
53                 _debug("SET");
54                 fsnotify_xattr(dentry);
55                 mutex_unlock(&dentry->d_inode->i_mutex);
56                 goto error;
57         }
58
59         if (ret != -EEXIST) {
60                 kerror("Can't set xattr on %*.*s [%lu] (err %d)",
61                        dentry->d_name.len, dentry->d_name.len,
62                        dentry->d_name.name, dentry->d_inode->i_ino,
63                        -ret);
64                 goto error;
65         }
66
67         /* read the current type label */
68         ret = dentry->d_inode->i_op->getxattr(dentry, cachefiles_xattr_cache,
69                                               xtype, 3);
70         if (ret < 0) {
71                 if (ret == -ERANGE)
72                         goto bad_type_length;
73
74                 kerror("Can't read xattr on %*.*s [%lu] (err %d)",
75                        dentry->d_name.len, dentry->d_name.len,
76                        dentry->d_name.name, dentry->d_inode->i_ino,
77                        -ret);
78                 goto error;
79         }
80
81         /* check the type is what we're expecting */
82         if (ret != 2)
83                 goto bad_type_length;
84
85         if (xtype[0] != type[0] || xtype[1] != type[1])
86                 goto bad_type;
87
88         ret = 0;
89
90 error:
91         mutex_unlock(&dentry->d_inode->i_mutex);
92         _leave(" = %d", ret);
93         return ret;
94
95 bad_type_length:
96         kerror("Cache object %lu type xattr length incorrect",
97                dentry->d_inode->i_ino);
98         ret = -EIO;
99         goto error;
100
101 bad_type:
102         xtype[2] = 0;
103         kerror("Cache object %*.*s [%lu] type %s not %s",
104                dentry->d_name.len, dentry->d_name.len,
105                dentry->d_name.name, dentry->d_inode->i_ino,
106                xtype, type);
107         ret = -EIO;
108         goto error;
109 }
110
111 /*****************************************************************************/
112 /*
113  * set the state xattr on a cache file
114  */
115 int cachefiles_set_object_xattr(struct cachefiles_object *object,
116                                 struct cachefiles_xattr *auxdata)
117 {
118         struct dentry *dentry = object->dentry;
119         int ret;
120
121         ASSERT(object->fscache.cookie);
122         ASSERT(dentry);
123         ASSERT(dentry->d_inode->i_op->setxattr);
124
125         _enter("%p,#%d", object, auxdata->len);
126
127         /* attempt to install the cache metadata directly */
128         mutex_lock(&dentry->d_inode->i_mutex);
129
130         _debug("SET %s #%u",
131                object->fscache.cookie->def->name, auxdata->len);
132
133         ret = dentry->d_inode->i_op->setxattr(dentry, cachefiles_xattr_cache,
134                                               &auxdata->type, auxdata->len,
135                                               XATTR_CREATE);
136         if (ret == 0)
137                 fsnotify_xattr(dentry);
138         else if (ret != -ENOMEM)
139                 cachefiles_io_error_obj(object,
140                                         "Failed to set xattr with error %d",
141                                         ret);
142
143         mutex_unlock(&dentry->d_inode->i_mutex);
144         _leave(" = %d", ret);
145         return ret;
146 }
147
148 /*****************************************************************************/
149 /*
150  * check the state xattr on a cache file
151  * - return -ESTALE if the object should be deleted
152  */
153 int cachefiles_check_object_xattr(struct cachefiles_object *object,
154                                   struct cachefiles_xattr *auxdata)
155 {
156         struct cachefiles_xattr *auxbuf;
157         struct dentry *dentry = object->dentry;
158         int ret;
159
160         _enter("%p,#%d", object, auxdata->len);
161
162         ASSERT(dentry);
163         ASSERT(dentry->d_inode);
164         ASSERT(dentry->d_inode->i_op->setxattr);
165         ASSERT(dentry->d_inode->i_op->getxattr);
166
167         auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, GFP_KERNEL);
168         if (!auxbuf) {
169                 _leave(" = -ENOMEM");
170                 return -ENOMEM;
171         }
172
173         mutex_lock(&dentry->d_inode->i_mutex);
174
175         /* read the current type label */
176         ret = dentry->d_inode->i_op->getxattr(dentry, cachefiles_xattr_cache,
177                                               &auxbuf->type, 512 + 1);
178         if (ret < 0) {
179                 if (ret == -ENODATA)
180                         goto stale; /* no attribute - power went off
181                                      * mid-cull? */
182
183                 if (ret == -ERANGE)
184                         goto bad_type_length;
185
186                 cachefiles_io_error_obj(object,
187                                         "can't read xattr on %lu (err %d)",
188                                         dentry->d_inode->i_ino, -ret);
189                 goto error;
190         }
191
192         /* check the on-disk object */
193         if (ret < 1)
194                 goto bad_type_length;
195
196         if (auxbuf->type != auxdata->type)
197                 goto stale;
198
199         auxbuf->len = ret;
200
201         /* consult the netfs */
202         if (object->fscache.cookie->def->check_aux) {
203                 fscache_checkaux_t result;
204                 unsigned int dlen;
205
206                 dlen = auxbuf->len - 1;
207
208                 _debug("checkaux %s #%u",
209                        object->fscache.cookie->def->name, dlen);
210
211                 result = object->fscache.cookie->def->check_aux(
212                         object->fscache.cookie->netfs_data,
213                         &auxbuf->data, dlen);
214
215                 switch (result) {
216                         /* entry okay as is */
217                 case FSCACHE_CHECKAUX_OKAY:
218                         goto okay;
219
220                         /* entry requires update */
221                 case FSCACHE_CHECKAUX_NEEDS_UPDATE:
222                         break;
223
224                         /* entry requires deletion */
225                 case FSCACHE_CHECKAUX_OBSOLETE:
226                         goto stale;
227
228                 default:
229                         BUG();
230                 }
231
232                 /* update the current label */
233                 ret = dentry->d_inode->i_op->setxattr(dentry,
234                                                       cachefiles_xattr_cache,
235                                                       &auxdata->type,
236                                                       auxdata->len,
237                                                       XATTR_REPLACE);
238                 if (ret < 0) {
239                         cachefiles_io_error_obj(object,
240                                                 "Can't update xattr on %lu"
241                                                 " (error %d)",
242                                                 dentry->d_inode->i_ino, -ret);
243                         goto error;
244                 }
245         }
246
247 okay:
248         ret = 0;
249
250 error:
251         mutex_unlock(&dentry->d_inode->i_mutex);
252         kfree(auxbuf);
253         _leave(" = %d", ret);
254         return ret;
255
256 bad_type_length:
257         kerror("Cache object %lu xattr length incorrect",
258                dentry->d_inode->i_ino);
259         ret = -EIO;
260         goto error;
261
262 stale:
263         ret = -ESTALE;
264         goto error;
265 }
266
267 /*****************************************************************************/
268 /*
269  * remove the object's xattr to mark it stale
270  */
271 int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
272                                    struct dentry *dentry)
273 {
274         int ret;
275
276         mutex_lock(&dentry->d_inode->i_mutex);
277
278         ret = dentry->d_inode->i_op->removexattr(dentry,
279                                                  cachefiles_xattr_cache);
280
281         mutex_unlock(&dentry->d_inode->i_mutex);
282
283         if (ret < 0) {
284                 if (ret == -ENOENT || ret == -ENODATA)
285                         ret = 0;
286                 else if (ret != -ENOMEM)
287                         cachefiles_io_error(cache,
288                                             "Can't remove xattr from %lu"
289                                             " (error %d)",
290                                             dentry->d_inode->i_ino, -ret);
291         }
292
293         _leave(" = %d", ret);
294         return ret;
295 }