/*
* linux/fs/reiserfs/xattr.c
*
* Copyright (c) 2002 by Jeff Mahoney, <jeffm@suse.com>
*
*/
/*
* In order to implement EA/ACLs in a clean, backwards compatible manner,
* they are implemented as files in a "private" directory.
* Each EA is in it's own file, with the directory layout like so (/ is assumed
* to be relative to fs root). Inside the /.reiserfs_priv/xattrs directory,
* directories named using the capital-hex form of the objectid and
* generation number are used. Inside each directory are individual files
* named with the name of the extended attribute.
*
* So, for objectid 12648430, we could have:
* /.reiserfs_priv/xattrs/C0FFEE.0/system.posix_acl_access
* /.reiserfs_priv/xattrs/C0FFEE.0/system.posix_acl_default
* /.reiserfs_priv/xattrs/C0FFEE.0/user.Content-Type
* .. or similar.
*
* The file contents are the text of the EA. The size is known based on the
* stat data describing the file.
*
* In the case of system.posix_acl_access and system.posix_acl_default, since
* these are special cases for filesystem ACLs, they are interpreted by the
* kernel, in addition, they are negatively and positively cached and attached
* to the inode so that unnecessary lookups are avoided.
*/
#include <linux/reiserfs_fs.h>
#include <linux/capability.h>
#include <linux/dcache.h>
#include <linux/namei.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/pagemap.h>
#include <linux/xattr.h>
#include <linux/reiserfs_xattr.h>
#include <linux/reiserfs_acl.h>
#include <asm/uaccess.h>
#include <net/checksum.h>
#include <linux/smp_lock.h>
#include <linux/stat.h>
#include <linux/quotaops.h>
#define PRIVROOT_NAME ".reiserfs_priv"
#define XAROOT_NAME "xattrs"
/* Helpers for inode ops. We do this so that we don't have all the VFS
* overhead and also for proper i_mutex annotation.
* dir->i_mutex must be held for all of them. */
static int xattr_create(struct inode *dir, struct dentry *dentry, int mode)
{
BUG_ON(!mutex_is_locked(&dir->i_mutex));
DQUOT_INIT(dir);
return dir->i_op->create(dir, dentry, mode, NULL);
}
static int xattr_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
BUG_ON(!mutex_is_locked(&dir->i_mutex));
DQUOT_INIT(dir);
return dir->i_op->mkdir(dir, dentry, mode);
}
/* We use I_MUTEX_CHILD here to silence lockdep. It's safe because xattr
* mutation ops aren't called during rename or splace, which are the
* only other users of I_MUTEX_CHILD. It violates the ordering, but that's
* better than allocating another subclass just for this code. */
static int xattr_unlink(struct inode *dir, struct dentry *dentry)
{
int error;
BUG_ON(!mutex_is_locked(&dir->i_mutex));
DQUOT_INIT(dir);
mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
error = dir->i_op->unlink(dir, dentry);
mutex_unlock(&dentry->d_inode->i_mutex);
if (!error)
d_delete(dentry);
return error;
}
static int xattr_rmdir(struct inode *dir, struct dentry *dentry)
{
int error;
BUG_ON(!mutex_is_locked(&dir->i_mutex));
DQUOT_INIT(dir);
mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
dentry_unhash(dentry);
error = dir->i_op->rmdir(dir, dentry);
if (!error)
dentry->d_inode->i_flags