Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5103e947 authored by Josef Bacik's avatar Josef Bacik Committed by Chris Mason
Browse files

xattr support for btrfs

parent 0591fb56
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@ obj-m := btrfs.o
btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
	   hash.o file-item.o inode-item.o inode-map.o disk-io.o \
	   transaction.o bit-radix.o inode.o file.o tree-defrag.o \
	   extent_map.o sysfs.o struct-funcs.o
	   extent_map.o sysfs.o struct-funcs.o xattr.o acl.o

#btrfs-y := ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \
#	  root-tree.o dir-item.o hash.o file-item.o inode-item.o \

fs/btrfs/acl.c

0 → 100644
+66 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2007 Red Hat.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License v2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 021110-1307, USA.
 */

#include <linux/fs.h>
#include <linux/string.h>
#include <linux/xattr.h>
#include <linux/posix_acl_xattr.h>
#include "ctree.h"
#include "xattr.h"

static int btrfs_xattr_acl_access_get(struct inode *inode, const char *name,
				      void *value, size_t size)
{
	return btrfs_xattr_get(inode, BTRFS_XATTR_INDEX_POSIX_ACL_ACCESS, name,
			       value, size);
}

static int btrfs_xattr_acl_access_set(struct inode *inode, const char *name,
				      const void *value, size_t size, int flags)
{
	return btrfs_xattr_set(inode, BTRFS_XATTR_INDEX_POSIX_ACL_ACCESS, name,
			       value, size, flags);
}

static int btrfs_xattr_acl_default_get(struct inode *inode, const char *name,
				       void *value, size_t size)
{
	return btrfs_xattr_get(inode, BTRFS_XATTR_INDEX_POSIX_ACL_DEFAULT,
			       name, value, size);
}

static int btrfs_xattr_acl_default_set(struct inode *inode, const char *name,
				       const void *value, size_t size, int flags)
{
	return btrfs_xattr_set(inode, BTRFS_XATTR_INDEX_POSIX_ACL_DEFAULT,
			       name, value, size, flags);
}

struct xattr_handler btrfs_xattr_acl_default_handler = {
	.prefix = POSIX_ACL_XATTR_DEFAULT,
	.list	= btrfs_xattr_generic_list,
	.get	= btrfs_xattr_acl_default_get,
	.set	= btrfs_xattr_acl_default_set,
};

struct xattr_handler btrfs_xattr_acl_access_handler = {
	.prefix = POSIX_ACL_XATTR_ACCESS,
	.list	= btrfs_xattr_generic_list,
	.get	= btrfs_xattr_acl_access_get,
	.set	= btrfs_xattr_acl_access_set,
};
+18 −4
Original line number Diff line number Diff line
@@ -63,7 +63,8 @@ extern struct kmem_cache *btrfs_path_cachep;
#define BTRFS_FT_FIFO		5
#define BTRFS_FT_SOCK		6
#define BTRFS_FT_SYMLINK	7
#define BTRFS_FT_MAX		8
#define BTRFS_FT_XATTR		8
#define BTRFS_FT_MAX		9

/*
 * the key defines the order in the tree, and so it also defines (optimal)
@@ -226,7 +227,7 @@ struct btrfs_inode_item {

struct btrfs_dir_item {
	struct btrfs_disk_key location;
	__le16 flags;
	__le16 data_len;
	__le16 name_len;
	u8 type;
} __attribute__ ((__packed__));
@@ -367,7 +368,7 @@ struct btrfs_root {
 * the FS
 */
#define BTRFS_INODE_ITEM_KEY		1

#define BTRFS_XATTR_ITEM_KEY		2
/* reserve 2-15 close to the inode for later flexibility */

/*
@@ -621,7 +622,7 @@ static inline void btrfs_set_item_key(struct extent_buffer *eb,
}

/* struct btrfs_dir_item */
BTRFS_SETGET_FUNCS(dir_flags, struct btrfs_dir_item, flags, 16);
BTRFS_SETGET_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16);
BTRFS_SETGET_FUNCS(dir_type, struct btrfs_dir_item, type, 8);
BTRFS_SETGET_FUNCS(dir_name_len, struct btrfs_dir_item, name_len, 16);

@@ -962,6 +963,15 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
			      struct btrfs_root *root,
			      struct btrfs_path *path,
			      struct btrfs_dir_item *di);
int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
			    struct btrfs_root *root, const char *name,
			    u16 name_len, const void *data, u16 data_len,
			    u64 dir);
struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
					  struct btrfs_root *root,
					  struct btrfs_path *path, u64 dir,
					  const char *name, u16 name_len,
					  int mod);
/* inode-map.c */
int btrfs_find_free_objectid(struct btrfs_trans_handle *trans,
			     struct btrfs_root *fs_root,
@@ -1039,4 +1049,8 @@ int btrfs_sysfs_add_root(struct btrfs_root *root);
void btrfs_sysfs_del_root(struct btrfs_root *root);
void btrfs_sysfs_del_super(struct btrfs_fs_info *root);

/* xattr.c */
ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
int btrfs_delete_xattrs(struct btrfs_trans_handle *trans,
			struct btrfs_root *root, struct inode *inode);
#endif
+94 −6
Original line number Diff line number Diff line
@@ -43,8 +43,6 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
			return ERR_PTR(-EEXIST);
		ret = btrfs_extend_item(trans, root, path, data_size);
		WARN_ON(ret > 0);
		if (ret)
			return ERR_PTR(ret);
	}
	if (ret < 0)
		return ERR_PTR(ret);
@@ -57,6 +55,57 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
	return (struct btrfs_dir_item *)ptr;
}

int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
			    struct btrfs_root *root, const char *name,
			    u16 name_len, const void *data, u16 data_len,
			    u64 dir)
{
	int ret = 0;
	struct btrfs_path *path;
	struct btrfs_dir_item *dir_item;
	unsigned long name_ptr, data_ptr;
	struct btrfs_key key, location;
	struct btrfs_disk_key disk_key;
	struct extent_buffer *leaf;
	u32 data_size;

	key.objectid = dir;
	btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
	ret = btrfs_name_hash(name, name_len, &key.offset);
	BUG_ON(ret);
	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;

	data_size = sizeof(*dir_item) + name_len + data_len;
	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
					name, name_len);
	/*
	 * FIXME: at some point we should handle xattr's that are larger than
	 * what we can fit in our leaf.  We set location to NULL b/c we arent
	 * pointing at anything else, that will change if we store the xattr
	 * data in a separate inode.
	 */
	BUG_ON(IS_ERR(dir_item));
	memset(&location, 0, sizeof(location));

	leaf = path->nodes[0];
	btrfs_cpu_key_to_disk(&disk_key, &location);
	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
	btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR);
	btrfs_set_dir_name_len(leaf, dir_item, name_len);
	btrfs_set_dir_data_len(leaf, dir_item, data_len);
	name_ptr = (unsigned long)(dir_item + 1);
	data_ptr = (unsigned long)((char *)name_ptr + name_len);

	write_extent_buffer(leaf, name, name_ptr, name_len);
	write_extent_buffer(leaf, data, data_ptr, data_len);
	btrfs_mark_buffer_dirty(path->nodes[0]);

	btrfs_free_path(path);
	return ret;
}

int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
			  *root, const char *name, int name_len, u64 dir,
			  struct btrfs_key *location, u8 type)
@@ -90,7 +139,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
	btrfs_cpu_key_to_disk(&disk_key, location);
	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
	btrfs_set_dir_type(leaf, dir_item, type);
	btrfs_set_dir_flags(leaf, dir_item, 0);
	btrfs_set_dir_data_len(leaf, dir_item, 0);
	btrfs_set_dir_name_len(leaf, dir_item, name_len);
	name_ptr = (unsigned long)(dir_item + 1);

@@ -117,7 +166,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
	btrfs_cpu_key_to_disk(&disk_key, location);
	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
	btrfs_set_dir_type(leaf, dir_item, type);
	btrfs_set_dir_flags(leaf, dir_item, 0);
	btrfs_set_dir_data_len(leaf, dir_item, 0);
	btrfs_set_dir_name_len(leaf, dir_item, name_len);
	name_ptr = (unsigned long)(dir_item + 1);
	write_extent_buffer(leaf, name, name_ptr, name_len);
@@ -194,6 +243,43 @@ btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
	return btrfs_match_dir_item_name(root, path, name, name_len);
}

struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
					  struct btrfs_root *root,
					  struct btrfs_path *path, u64 dir,
					  const char *name, u16 name_len,
					  int mod)
{
	int ret;
	struct btrfs_key key;
	int ins_len = mod < 0 ? -1 : 0;
	int cow = mod != 0;
	struct btrfs_key found_key;
	struct extent_buffer *leaf;

	key.objectid = dir;
	btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
	ret = btrfs_name_hash(name, name_len, &key.offset);
	BUG_ON(ret);
	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
	if (ret < 0)
		return ERR_PTR(ret);
	if (ret > 0) {
		if (path->slots[0] == 0)
			return NULL;
		path->slots[0]--;
	}

	leaf = path->nodes[0];
	btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);

	if (found_key.objectid != dir ||
	    btrfs_key_type(&found_key) != BTRFS_XATTR_ITEM_KEY ||
	    found_key.offset != key.offset)
		return NULL;

	return btrfs_match_dir_item_name(root, path, name, name_len);
}

struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
			      struct btrfs_path *path,
			      const char *name, int name_len)
@@ -210,7 +296,8 @@ struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
	total_len = btrfs_item_size_nr(leaf, path->slots[0]);
	while(cur < total_len) {
		this_len = sizeof(*dir_item) +
			btrfs_dir_name_len(leaf, dir_item);
			btrfs_dir_name_len(leaf, dir_item) +
			btrfs_dir_data_len(leaf, dir_item);
		name_ptr = (unsigned long)(dir_item + 1);

		if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
@@ -236,7 +323,8 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
	int ret = 0;

	leaf = path->nodes[0];
	sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di);
	sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) +
		btrfs_dir_data_len(leaf, di);
	item_len = btrfs_item_size_nr(leaf, path->slots[0]);
	if (sub_item_len == item_len) {
		ret = btrfs_del_item(trans, root, path);
+14 −1
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
#include <linux/compat.h>
#include <linux/bit_spinlock.h>
#include <linux/version.h>
#include <linux/xattr.h>
#include "ctree.h"
#include "disk-io.h"
#include "transaction.h"
@@ -839,6 +840,9 @@ void btrfs_delete_inode(struct inode *inode)

	btrfs_set_trans_block_group(trans, inode);
	ret = btrfs_truncate_in_trans(trans, root, inode);
	if (ret)
		goto no_delete_lock;
	ret = btrfs_delete_xattrs(trans, root, inode);
	if (ret)
		goto no_delete_lock;
	ret = btrfs_free_inode(trans, root, inode);
@@ -1110,7 +1114,8 @@ static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir)

			if (over)
				goto nopos;
			di_len = btrfs_dir_name_len(leaf, di) + sizeof(*di);
			di_len = btrfs_dir_name_len(leaf, di) +
				btrfs_dir_data_len(leaf, di) +sizeof(*di);
			di_cur += di_len;
			di = (struct btrfs_dir_item *)((char *)di + di_len);
		}
@@ -2519,6 +2524,10 @@ static struct inode_operations btrfs_dir_inode_operations = {
	.symlink	= btrfs_symlink,
	.setattr	= btrfs_setattr,
	.mknod		= btrfs_mknod,
	.setxattr	= generic_setxattr,
	.getxattr	= generic_getxattr,
	.listxattr	= btrfs_listxattr,
	.removexattr	= generic_removexattr,
};

static struct inode_operations btrfs_dir_ro_inode_operations = {
@@ -2567,6 +2576,10 @@ static struct inode_operations btrfs_file_inode_operations = {
	.truncate	= btrfs_truncate,
	.getattr	= btrfs_getattr,
	.setattr	= btrfs_setattr,
	.setxattr	= generic_setxattr,
	.getxattr	= generic_getxattr,
	.listxattr      = btrfs_listxattr,
	.removexattr	= generic_removexattr,
};

static struct inode_operations btrfs_special_inode_operations = {
Loading