 6ff66ac77a
			
		
	
	
	6ff66ac77a
	
	
	
		
			
			Commit 0227d6abb3 ("fs/cachefiles: replace kerror by pr_err") didn't
include newline featuring in original kerror definition
Signed-off-by: Fabian Frederick <fabf@skynet.be>
Reported-by: David Howells <dhowells@redhat.com>
Acked-by: David Howells <dhowells@redhat.com>
Cc: <stable@vger.kernel.org>	[3.16.x]
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
		
	
			
		
			
				
	
	
		
			327 lines
		
	
	
	
		
			7.1 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			327 lines
		
	
	
	
		
			7.1 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /* CacheFiles extended attribute management
 | |
|  *
 | |
|  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
 | |
|  * Written by David Howells (dhowells@redhat.com)
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU General Public Licence
 | |
|  * as published by the Free Software Foundation; either version
 | |
|  * 2 of the Licence, or (at your option) any later version.
 | |
|  */
 | |
| 
 | |
| #include <linux/module.h>
 | |
| #include <linux/sched.h>
 | |
| #include <linux/file.h>
 | |
| #include <linux/fs.h>
 | |
| #include <linux/fsnotify.h>
 | |
| #include <linux/quotaops.h>
 | |
| #include <linux/xattr.h>
 | |
| #include <linux/slab.h>
 | |
| #include "internal.h"
 | |
| 
 | |
| static const char cachefiles_xattr_cache[] =
 | |
| 	XATTR_USER_PREFIX "CacheFiles.cache";
 | |
| 
 | |
| /*
 | |
|  * check the type label on an object
 | |
|  * - done using xattrs
 | |
|  */
 | |
| int cachefiles_check_object_type(struct cachefiles_object *object)
 | |
| {
 | |
| 	struct dentry *dentry = object->dentry;
 | |
| 	char type[3], xtype[3];
 | |
| 	int ret;
 | |
| 
 | |
| 	ASSERT(dentry);
 | |
| 	ASSERT(dentry->d_inode);
 | |
| 
 | |
| 	if (!object->fscache.cookie)
 | |
| 		strcpy(type, "C3");
 | |
| 	else
 | |
| 		snprintf(type, 3, "%02x", object->fscache.cookie->def->type);
 | |
| 
 | |
| 	_enter("%p{%s}", object, type);
 | |
| 
 | |
| 	/* attempt to install a type label directly */
 | |
| 	ret = vfs_setxattr(dentry, cachefiles_xattr_cache, type, 2,
 | |
| 			   XATTR_CREATE);
 | |
| 	if (ret == 0) {
 | |
| 		_debug("SET"); /* we succeeded */
 | |
| 		goto error;
 | |
| 	}
 | |
| 
 | |
| 	if (ret != -EEXIST) {
 | |
| 		pr_err("Can't set xattr on %*.*s [%lu] (err %d)\n",
 | |
| 		       dentry->d_name.len, dentry->d_name.len,
 | |
| 		       dentry->d_name.name, dentry->d_inode->i_ino,
 | |
| 		       -ret);
 | |
| 		goto error;
 | |
| 	}
 | |
| 
 | |
| 	/* read the current type label */
 | |
| 	ret = vfs_getxattr(dentry, cachefiles_xattr_cache, xtype, 3);
 | |
| 	if (ret < 0) {
 | |
| 		if (ret == -ERANGE)
 | |
| 			goto bad_type_length;
 | |
| 
 | |
| 		pr_err("Can't read xattr on %*.*s [%lu] (err %d)\n",
 | |
| 		       dentry->d_name.len, dentry->d_name.len,
 | |
| 		       dentry->d_name.name, dentry->d_inode->i_ino,
 | |
| 		       -ret);
 | |
| 		goto error;
 | |
| 	}
 | |
| 
 | |
| 	/* check the type is what we're expecting */
 | |
| 	if (ret != 2)
 | |
| 		goto bad_type_length;
 | |
| 
 | |
| 	if (xtype[0] != type[0] || xtype[1] != type[1])
 | |
| 		goto bad_type;
 | |
| 
 | |
| 	ret = 0;
 | |
| 
 | |
| error:
 | |
| 	_leave(" = %d", ret);
 | |
| 	return ret;
 | |
| 
 | |
| bad_type_length:
 | |
| 	pr_err("Cache object %lu type xattr length incorrect\n",
 | |
| 	       dentry->d_inode->i_ino);
 | |
| 	ret = -EIO;
 | |
| 	goto error;
 | |
| 
 | |
| bad_type:
 | |
| 	xtype[2] = 0;
 | |
| 	pr_err("Cache object %*.*s [%lu] type %s not %s\n",
 | |
| 	       dentry->d_name.len, dentry->d_name.len,
 | |
| 	       dentry->d_name.name, dentry->d_inode->i_ino,
 | |
| 	       xtype, type);
 | |
| 	ret = -EIO;
 | |
| 	goto error;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * set the state xattr on a cache file
 | |
|  */
 | |
| int cachefiles_set_object_xattr(struct cachefiles_object *object,
 | |
| 				struct cachefiles_xattr *auxdata)
 | |
| {
 | |
| 	struct dentry *dentry = object->dentry;
 | |
| 	int ret;
 | |
| 
 | |
| 	ASSERT(dentry);
 | |
| 
 | |
| 	_enter("%p,#%d", object, auxdata->len);
 | |
| 
 | |
| 	/* attempt to install the cache metadata directly */
 | |
| 	_debug("SET #%u", auxdata->len);
 | |
| 
 | |
| 	ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
 | |
| 			   &auxdata->type, auxdata->len,
 | |
| 			   XATTR_CREATE);
 | |
| 	if (ret < 0 && ret != -ENOMEM)
 | |
| 		cachefiles_io_error_obj(
 | |
| 			object,
 | |
| 			"Failed to set xattr with error %d", ret);
 | |
| 
 | |
| 	_leave(" = %d", ret);
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * update the state xattr on a cache file
 | |
|  */
 | |
| int cachefiles_update_object_xattr(struct cachefiles_object *object,
 | |
| 				   struct cachefiles_xattr *auxdata)
 | |
| {
 | |
| 	struct dentry *dentry = object->dentry;
 | |
| 	int ret;
 | |
| 
 | |
| 	ASSERT(dentry);
 | |
| 
 | |
| 	_enter("%p,#%d", object, auxdata->len);
 | |
| 
 | |
| 	/* attempt to install the cache metadata directly */
 | |
| 	_debug("SET #%u", auxdata->len);
 | |
| 
 | |
| 	ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
 | |
| 			   &auxdata->type, auxdata->len,
 | |
| 			   XATTR_REPLACE);
 | |
| 	if (ret < 0 && ret != -ENOMEM)
 | |
| 		cachefiles_io_error_obj(
 | |
| 			object,
 | |
| 			"Failed to update xattr with error %d", ret);
 | |
| 
 | |
| 	_leave(" = %d", ret);
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * check the consistency between the backing cache and the FS-Cache cookie
 | |
|  */
 | |
| int cachefiles_check_auxdata(struct cachefiles_object *object)
 | |
| {
 | |
| 	struct cachefiles_xattr *auxbuf;
 | |
| 	enum fscache_checkaux validity;
 | |
| 	struct dentry *dentry = object->dentry;
 | |
| 	ssize_t xlen;
 | |
| 	int ret;
 | |
| 
 | |
| 	ASSERT(dentry);
 | |
| 	ASSERT(dentry->d_inode);
 | |
| 	ASSERT(object->fscache.cookie->def->check_aux);
 | |
| 
 | |
| 	auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, GFP_KERNEL);
 | |
| 	if (!auxbuf)
 | |
| 		return -ENOMEM;
 | |
| 
 | |
| 	xlen = vfs_getxattr(dentry, cachefiles_xattr_cache,
 | |
| 			    &auxbuf->type, 512 + 1);
 | |
| 	ret = -ESTALE;
 | |
| 	if (xlen < 1 ||
 | |
| 	    auxbuf->type != object->fscache.cookie->def->type)
 | |
| 		goto error;
 | |
| 
 | |
| 	xlen--;
 | |
| 	validity = fscache_check_aux(&object->fscache, &auxbuf->data, xlen);
 | |
| 	if (validity != FSCACHE_CHECKAUX_OKAY)
 | |
| 		goto error;
 | |
| 
 | |
| 	ret = 0;
 | |
| error:
 | |
| 	kfree(auxbuf);
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * check the state xattr on a cache file
 | |
|  * - return -ESTALE if the object should be deleted
 | |
|  */
 | |
| int cachefiles_check_object_xattr(struct cachefiles_object *object,
 | |
| 				  struct cachefiles_xattr *auxdata)
 | |
| {
 | |
| 	struct cachefiles_xattr *auxbuf;
 | |
| 	struct dentry *dentry = object->dentry;
 | |
| 	int ret;
 | |
| 
 | |
| 	_enter("%p,#%d", object, auxdata->len);
 | |
| 
 | |
| 	ASSERT(dentry);
 | |
| 	ASSERT(dentry->d_inode);
 | |
| 
 | |
| 	auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, cachefiles_gfp);
 | |
| 	if (!auxbuf) {
 | |
| 		_leave(" = -ENOMEM");
 | |
| 		return -ENOMEM;
 | |
| 	}
 | |
| 
 | |
| 	/* read the current type label */
 | |
| 	ret = vfs_getxattr(dentry, cachefiles_xattr_cache,
 | |
| 			   &auxbuf->type, 512 + 1);
 | |
| 	if (ret < 0) {
 | |
| 		if (ret == -ENODATA)
 | |
| 			goto stale; /* no attribute - power went off
 | |
| 				     * mid-cull? */
 | |
| 
 | |
| 		if (ret == -ERANGE)
 | |
| 			goto bad_type_length;
 | |
| 
 | |
| 		cachefiles_io_error_obj(object,
 | |
| 					"Can't read xattr on %lu (err %d)",
 | |
| 					dentry->d_inode->i_ino, -ret);
 | |
| 		goto error;
 | |
| 	}
 | |
| 
 | |
| 	/* check the on-disk object */
 | |
| 	if (ret < 1)
 | |
| 		goto bad_type_length;
 | |
| 
 | |
| 	if (auxbuf->type != auxdata->type)
 | |
| 		goto stale;
 | |
| 
 | |
| 	auxbuf->len = ret;
 | |
| 
 | |
| 	/* consult the netfs */
 | |
| 	if (object->fscache.cookie->def->check_aux) {
 | |
| 		enum fscache_checkaux result;
 | |
| 		unsigned int dlen;
 | |
| 
 | |
| 		dlen = auxbuf->len - 1;
 | |
| 
 | |
| 		_debug("checkaux %s #%u",
 | |
| 		       object->fscache.cookie->def->name, dlen);
 | |
| 
 | |
| 		result = fscache_check_aux(&object->fscache,
 | |
| 					   &auxbuf->data, dlen);
 | |
| 
 | |
| 		switch (result) {
 | |
| 			/* entry okay as is */
 | |
| 		case FSCACHE_CHECKAUX_OKAY:
 | |
| 			goto okay;
 | |
| 
 | |
| 			/* entry requires update */
 | |
| 		case FSCACHE_CHECKAUX_NEEDS_UPDATE:
 | |
| 			break;
 | |
| 
 | |
| 			/* entry requires deletion */
 | |
| 		case FSCACHE_CHECKAUX_OBSOLETE:
 | |
| 			goto stale;
 | |
| 
 | |
| 		default:
 | |
| 			BUG();
 | |
| 		}
 | |
| 
 | |
| 		/* update the current label */
 | |
| 		ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
 | |
| 				   &auxdata->type, auxdata->len,
 | |
| 				   XATTR_REPLACE);
 | |
| 		if (ret < 0) {
 | |
| 			cachefiles_io_error_obj(object,
 | |
| 						"Can't update xattr on %lu"
 | |
| 						" (error %d)",
 | |
| 						dentry->d_inode->i_ino, -ret);
 | |
| 			goto error;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| okay:
 | |
| 	ret = 0;
 | |
| 
 | |
| error:
 | |
| 	kfree(auxbuf);
 | |
| 	_leave(" = %d", ret);
 | |
| 	return ret;
 | |
| 
 | |
| bad_type_length:
 | |
| 	pr_err("Cache object %lu xattr length incorrect\n",
 | |
| 	       dentry->d_inode->i_ino);
 | |
| 	ret = -EIO;
 | |
| 	goto error;
 | |
| 
 | |
| stale:
 | |
| 	ret = -ESTALE;
 | |
| 	goto error;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * remove the object's xattr to mark it stale
 | |
|  */
 | |
| int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
 | |
| 				   struct dentry *dentry)
 | |
| {
 | |
| 	int ret;
 | |
| 
 | |
| 	ret = vfs_removexattr(dentry, cachefiles_xattr_cache);
 | |
| 	if (ret < 0) {
 | |
| 		if (ret == -ENOENT || ret == -ENODATA)
 | |
| 			ret = 0;
 | |
| 		else if (ret != -ENOMEM)
 | |
| 			cachefiles_io_error(cache,
 | |
| 					    "Can't remove xattr from %lu"
 | |
| 					    " (error %d)",
 | |
| 					    dentry->d_inode->i_ino, -ret);
 | |
| 	}
 | |
| 
 | |
| 	_leave(" = %d", ret);
 | |
| 	return ret;
 | |
| }
 |