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 <linux/slab.h> 20#include "internal.h" 21 22static const char cachefiles_xattr_cache[] = 23 XATTR_USER_PREFIX "CacheFiles.cache"; 24 25/* 26 * check the type label on an object 27 * - done using xattrs 28 */ 29int cachefiles_check_object_type(struct cachefiles_object *object) 30{ 31 struct dentry *dentry = object->dentry; 32 char type[3], xtype[3]; 33 int ret; 34 35 ASSERT(dentry); 36 ASSERT(d_backing_inode(dentry)); 37 38 if (!object->fscache.cookie) 39 strcpy(type, "C3"); 40 else 41 snprintf(type, 3, "%02x", object->fscache.cookie->def->type); 42 43 _enter("%p{%s}", object, type); 44 45 /* attempt to install a type label directly */ 46 ret = vfs_setxattr(dentry, cachefiles_xattr_cache, type, 2, 47 XATTR_CREATE); 48 if (ret == 0) { 49 _debug("SET"); /* we succeeded */ 50 goto error; 51 } 52 53 if (ret != -EEXIST) { 54 pr_err("Can't set xattr on %pd [%lu] (err %d)\n", 55 dentry, d_backing_inode(dentry)->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 pr_err("Can't read xattr on %pd [%lu] (err %d)\n", 67 dentry, d_backing_inode(dentry)->i_ino, 68 -ret); 69 goto error; 70 } 71 72 /* check the type is what we're expecting */ 73 if (ret != 2) 74 goto bad_type_length; 75 76 if (xtype[0] != type[0] || xtype[1] != type[1]) 77 goto bad_type; 78 79 ret = 0; 80 81error: 82 _leave(" = %d", ret); 83 return ret; 84 85bad_type_length: 86 pr_err("Cache object %lu type xattr length incorrect\n", 87 d_backing_inode(dentry)->i_ino); 88 ret = -EIO; 89 goto error; 90 91bad_type: 92 xtype[2] = 0; 93 pr_err("Cache object %pd [%lu] type %s not %s\n", 94 dentry, d_backing_inode(dentry)->i_ino, 95 xtype, type); 96 ret = -EIO; 97 goto error; 98} 99 100/* 101 * set the state xattr on a cache file 102 */ 103int cachefiles_set_object_xattr(struct cachefiles_object *object, 104 struct cachefiles_xattr *auxdata) 105{ 106 struct dentry *dentry = object->dentry; 107 int ret; 108 109 ASSERT(dentry); 110 111 _enter("%p,#%d", object, auxdata->len); 112 113 /* attempt to install the cache metadata directly */ 114 _debug("SET #%u", auxdata->len); 115 116 ret = vfs_setxattr(dentry, cachefiles_xattr_cache, 117 &auxdata->type, auxdata->len, 118 XATTR_CREATE); 119 if (ret < 0 && ret != -ENOMEM) 120 cachefiles_io_error_obj( 121 object, 122 "Failed to set xattr with error %d", ret); 123 124 _leave(" = %d", ret); 125 return ret; 126} 127 128/* 129 * update the state xattr on a cache file 130 */ 131int cachefiles_update_object_xattr(struct cachefiles_object *object, 132 struct cachefiles_xattr *auxdata) 133{ 134 struct dentry *dentry = object->dentry; 135 int ret; 136 137 ASSERT(dentry); 138 139 _enter("%p,#%d", object, auxdata->len); 140 141 /* attempt to install the cache metadata directly */ 142 _debug("SET #%u", auxdata->len); 143 144 ret = vfs_setxattr(dentry, cachefiles_xattr_cache, 145 &auxdata->type, auxdata->len, 146 XATTR_REPLACE); 147 if (ret < 0 && ret != -ENOMEM) 148 cachefiles_io_error_obj( 149 object, 150 "Failed to update xattr with error %d", ret); 151 152 _leave(" = %d", ret); 153 return ret; 154} 155 156/* 157 * check the consistency between the backing cache and the FS-Cache cookie 158 */ 159int cachefiles_check_auxdata(struct cachefiles_object *object) 160{ 161 struct cachefiles_xattr *auxbuf; 162 enum fscache_checkaux validity; 163 struct dentry *dentry = object->dentry; 164 ssize_t xlen; 165 int ret; 166 167 ASSERT(dentry); 168 ASSERT(d_backing_inode(dentry)); 169 ASSERT(object->fscache.cookie->def->check_aux); 170 171 auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, GFP_KERNEL); 172 if (!auxbuf) 173 return -ENOMEM; 174 175 xlen = vfs_getxattr(dentry, cachefiles_xattr_cache, 176 &auxbuf->type, 512 + 1); 177 ret = -ESTALE; 178 if (xlen < 1 || 179 auxbuf->type != object->fscache.cookie->def->type) 180 goto error; 181 182 xlen--; 183 validity = fscache_check_aux(&object->fscache, &auxbuf->data, xlen); 184 if (validity != FSCACHE_CHECKAUX_OKAY) 185 goto error; 186 187 ret = 0; 188error: 189 kfree(auxbuf); 190 return ret; 191} 192 193/* 194 * check the state xattr on a cache file 195 * - return -ESTALE if the object should be deleted 196 */ 197int cachefiles_check_object_xattr(struct cachefiles_object *object, 198 struct cachefiles_xattr *auxdata) 199{ 200 struct cachefiles_xattr *auxbuf; 201 struct dentry *dentry = object->dentry; 202 int ret; 203 204 _enter("%p,#%d", object, auxdata->len); 205 206 ASSERT(dentry); 207 ASSERT(d_backing_inode(dentry)); 208 209 auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, cachefiles_gfp); 210 if (!auxbuf) { 211 _leave(" = -ENOMEM"); 212 return -ENOMEM; 213 } 214 215 /* read the current type label */ 216 ret = vfs_getxattr(dentry, cachefiles_xattr_cache, 217 &auxbuf->type, 512 + 1); 218 if (ret < 0) { 219 if (ret == -ENODATA) 220 goto stale; /* no attribute - power went off 221 * mid-cull? */ 222 223 if (ret == -ERANGE) 224 goto bad_type_length; 225 226 cachefiles_io_error_obj(object, 227 "Can't read xattr on %lu (err %d)", 228 d_backing_inode(dentry)->i_ino, -ret); 229 goto error; 230 } 231 232 /* check the on-disk object */ 233 if (ret < 1) 234 goto bad_type_length; 235 236 if (auxbuf->type != auxdata->type) 237 goto stale; 238 239 auxbuf->len = ret; 240 241 /* consult the netfs */ 242 if (object->fscache.cookie->def->check_aux) { 243 enum fscache_checkaux result; 244 unsigned int dlen; 245 246 dlen = auxbuf->len - 1; 247 248 _debug("checkaux %s #%u", 249 object->fscache.cookie->def->name, dlen); 250 251 result = fscache_check_aux(&object->fscache, 252 &auxbuf->data, dlen); 253 254 switch (result) { 255 /* entry okay as is */ 256 case FSCACHE_CHECKAUX_OKAY: 257 goto okay; 258 259 /* entry requires update */ 260 case FSCACHE_CHECKAUX_NEEDS_UPDATE: 261 break; 262 263 /* entry requires deletion */ 264 case FSCACHE_CHECKAUX_OBSOLETE: 265 goto stale; 266 267 default: 268 BUG(); 269 } 270 271 /* update the current label */ 272 ret = vfs_setxattr(dentry, cachefiles_xattr_cache, 273 &auxdata->type, auxdata->len, 274 XATTR_REPLACE); 275 if (ret < 0) { 276 cachefiles_io_error_obj(object, 277 "Can't update xattr on %lu" 278 " (error %d)", 279 d_backing_inode(dentry)->i_ino, -ret); 280 goto error; 281 } 282 } 283 284okay: 285 ret = 0; 286 287error: 288 kfree(auxbuf); 289 _leave(" = %d", ret); 290 return ret; 291 292bad_type_length: 293 pr_err("Cache object %lu xattr length incorrect\n", 294 d_backing_inode(dentry)->i_ino); 295 ret = -EIO; 296 goto error; 297 298stale: 299 ret = -ESTALE; 300 goto error; 301} 302 303/* 304 * remove the object's xattr to mark it stale 305 */ 306int cachefiles_remove_object_xattr(struct cachefiles_cache *cache, 307 struct dentry *dentry) 308{ 309 int ret; 310 311 ret = vfs_removexattr(dentry, cachefiles_xattr_cache); 312 if (ret < 0) { 313 if (ret == -ENOENT || ret == -ENODATA) 314 ret = 0; 315 else if (ret != -ENOMEM) 316 cachefiles_io_error(cache, 317 "Can't remove xattr from %lu" 318 " (error %d)", 319 d_backing_inode(dentry)->i_ino, -ret); 320 } 321 322 _leave(" = %d", ret); 323 return ret; 324} 325