[Btrfs-devel] [PATCH 1/2] small ea support for btrfs

Josef Bacik jbacik at redhat.com
Mon Sep 10 06:36:43 PDT 2007


Hello,

This patch adds small ea support for btrfs.  This handles EA's that will fit
inline in a dir item, so basically this works for SELinux and most everything
else.  I've tested it by doing random xattr stuff as well as turning SELinux on
and doing a bunch of labeling stuff and making sure SELinux did what it was
supposed to do.  I've added the ACL stuff in here simply so it will compile, ACL
support is by no means done, its just there and ready to be added, something I
will do in the near future hopefully.  I copied what ext3 does for the xattr
handling stuff so it should be relatively easy to follow.  I've also done the
necessary work in order to make adding support for EA's that wont fit inline
pretty easy, instead of bugging out when we try to insert a dir_item thats too
large we return ENOSPC so I can handle it appropriately.  Let me know what you
think.  Thank you,

Josef

diff -r 9cb5f0f5c713 Makefile
--- a/Makefile	Thu Aug 30 12:16:51 2007 -0400
+++ b/Makefile	Wed Sep 05 13:05:29 2007 -0400
@@ -5,7 +5,8 @@ btrfs-y := super.o ctree.o extent-tree.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
+	   extent_map.o sysfs.o xattr.o xattr_user.o xattr_security.o acl.o \
+	   xattr_trusted.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 \
diff -r 9cb5f0f5c713 acl.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/acl.c	Tue Sep 04 15:39:30 2007 -0400
@@ -0,0 +1,106 @@
+/*
+ * 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 size_t btrfs_xattr_acl_access_list(struct inode *inode, char *list,
+					  size_t list_size, const char *name,
+					  size_t name_len)
+{
+	const size_t prefix_len = sizeof(POSIX_ACL_XATTR_ACCESS)-1;
+	const size_t total_len = prefix_len + name_len + 1;
+
+	if (list && total_len <= list_size) {
+		memcpy(list, POSIX_ACL_XATTR_ACCESS, prefix_len);
+		memcpy(list+prefix_len, name, name_len);
+		list[prefix_len + name_len] = '\0';
+	}
+
+	return total_len;
+}
+
+static int btrfs_xattr_acl_access_get(struct inode *inode, const char *name,
+				      void *value, size_t size)
+{
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+	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)
+{
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+	return btrfs_xattr_set(inode, BTRFS_XATTR_INDEX_POSIX_ACL_ACCESS, name,
+			       value, size, flags);
+}
+
+static size_t btrfs_xattr_acl_default_list(struct inode *inode, char *list,
+					   size_t list_size, const char *name,
+					   size_t name_len)
+{
+	const size_t prefix_len = sizeof(POSIX_ACL_XATTR_DEFAULT)-1;
+	const size_t total_len = prefix_len + name_len + 1;
+
+	if (list && total_len <= list_size) {
+		memcpy(list, POSIX_ACL_XATTR_DEFAULT, prefix_len);
+		memcpy(list+prefix_len, name, name_len);
+		list[prefix_len + name_len] = '\0';
+	}
+
+	return total_len;
+}
+
+static int btrfs_xattr_acl_default_get(struct inode *inode, const char *name,
+				       void *value, size_t size)
+{
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+	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)
+{
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+	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_acl_default_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_acl_access_list,
+	.get	= btrfs_xattr_acl_access_get,
+	.set	= btrfs_xattr_acl_access_set,
+};
diff -r 9cb5f0f5c713 ctree.c
--- a/ctree.c	Thu Aug 30 12:16:51 2007 -0400
+++ b/ctree.c	Wed Sep 05 13:05:29 2007 -0400
@@ -1826,7 +1826,7 @@ int btrfs_extend_item(struct btrfs_trans
 	data_end = leaf_data_end(root, leaf);
 
 	if (btrfs_leaf_free_space(root, leaf) < data_size)
-		BUG();
+		return -ENOSPC;
 	slot = path->slots[0];
 	old_data = btrfs_item_end(leaf->items + slot);
 
@@ -1896,7 +1896,7 @@ int btrfs_insert_empty_item(struct btrfs
 
 	if (btrfs_leaf_free_space(root, leaf) <
 	    sizeof(struct btrfs_item) + data_size) {
-		BUG();
+		return -ENOSPC;
 	}
 	slot = path->slots[0];
 	BUG_ON(slot < 0);
diff -r 9cb5f0f5c713 ctree.h
--- a/ctree.h	Thu Aug 30 12:16:51 2007 -0400
+++ b/ctree.h	Wed Sep 05 13:05:29 2007 -0400
@@ -220,7 +220,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__));
@@ -358,7 +358,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 */
 
 /*
@@ -400,7 +400,6 @@ struct btrfs_root {
  * data in the FS
  */
 #define BTRFS_STRING_ITEM_KEY	253
-
 
 static inline u64 btrfs_block_group_used(struct btrfs_block_group_item *bi)
 {
@@ -606,16 +605,6 @@ static inline void btrfs_set_item_size(s
 	item->size = cpu_to_le16(val);
 }
 
-static inline u16 btrfs_dir_flags(struct btrfs_dir_item *d)
-{
-	return le16_to_cpu(d->flags);
-}
-
-static inline void btrfs_set_dir_flags(struct btrfs_dir_item *d, u16 val)
-{
-	d->flags = cpu_to_le16(val);
-}
-
 static inline u8 btrfs_dir_type(struct btrfs_dir_item *d)
 {
 	return d->type;
@@ -634,6 +623,16 @@ static inline void btrfs_set_dir_name_le
 static inline void btrfs_set_dir_name_len(struct btrfs_dir_item *d, u16 val)
 {
 	d->name_len = cpu_to_le16(val);
+}
+
+static inline u16 btrfs_dir_data_len(struct btrfs_dir_item *d)
+{
+	return le16_to_cpu(d->data_len);
+}
+
+static inline void btrfs_set_dir_data_len(struct btrfs_dir_item *d, u16 val)
+{
+	d->data_len = cpu_to_le16(val);
 }
 
 static inline void btrfs_disk_key_to_cpu(struct btrfs_key *cpu,
@@ -1170,6 +1169,15 @@ int btrfs_delete_one_dir_name(struct btr
 			      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,
+			    int name_len, const void *data, int data_len,
+			    u64 dir, u8 type);
+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, int name_len,
+					  int mod);
 /* inode-map.c */
 int btrfs_find_free_objectid(struct btrfs_trans_handle *trans,
 			     struct btrfs_root *fs_root,
@@ -1251,4 +1259,11 @@ void btrfs_sysfs_del_root(struct btrfs_r
 void btrfs_sysfs_del_root(struct btrfs_root *root);
 void btrfs_sysfs_del_super(struct btrfs_fs_info *root);
 
+/* xattr.c */
+ssize_t btrfs_getxattr(struct dentry *dentry, const char *name, void *buffer,
+		       size_t size);
+int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
+		   size_t size, int flags);
+int btrfs_removexattr(struct dentry *dentry, const char *name);
+ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
 #endif
diff -r 9cb5f0f5c713 dir-item.c
--- a/dir-item.c	Thu Aug 30 12:16:51 2007 -0400
+++ b/dir-item.c	Wed Sep 05 13:05:29 2007 -0400
@@ -42,9 +42,6 @@ static struct btrfs_dir_item *insert_wit
 		if (di)
 			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);
@@ -55,6 +52,65 @@ static struct btrfs_dir_item *insert_wit
 	BUG_ON(data_size > btrfs_item_size(item));
 	ptr += btrfs_item_size(item) - data_size;
 	return (struct btrfs_dir_item *)ptr;
+}
+
+int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
+			    struct btrfs_root *root, const char *name,
+			    int name_len, const void *data, int data_len,
+			    u64 dir, u8 type)
+{
+	int ret = 0;
+	struct btrfs_path *path;
+	struct btrfs_dir_item *dir_item;
+	char *name_ptr, *data_ptr;
+	struct btrfs_key key;
+	struct btrfs_key location;
+	u32 data_size;
+
+	key.objectid = dir;
+	key.flags = 0;
+	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();
+	data_size = sizeof(*dir_item) + name_len + data_len;
+	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
+					name, name_len);
+	if (IS_ERR(dir_item)) {
+		ret = PTR_ERR(dir_item);
+
+		/* ok we can't embed this xattr into a dir item, plan b */
+		if (ret == -ENOSPC) {
+			data_size = sizeof(*dir_item) + name_len;
+			dir_item = insert_with_overflow(trans, root, path,
+							&key, data_size, name,
+							name_len);
+			if (IS_ERR(dir_item)) {
+				/* seriously now, wtf */
+				ret = PTR_ERR(dir_item);
+				goto out;
+			}
+			/* alright here is where we add a file for this */
+		}
+
+		goto out;
+	}
+
+	memset(&location, 0, sizeof(location));
+	btrfs_cpu_key_to_disk(&dir_item->location, &location);
+	btrfs_set_dir_type(dir_item, type);
+	btrfs_set_dir_name_len(dir_item, name_len);
+	btrfs_set_dir_data_len(dir_item, data_len);
+	name_ptr = (char *)(dir_item + 1);
+	data_ptr = (char *)(name_ptr + name_len);
+
+	btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
+	btrfs_memcpy(root, path->nodes[0]->b_data, data_ptr, data, data_len);
+	btrfs_mark_buffer_dirty(path->nodes[0]);
+
+out:
+	btrfs_free_path(path);
+	return ret;
 }
 
 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
@@ -87,8 +143,8 @@ int btrfs_insert_dir_item(struct btrfs_t
 
 	btrfs_cpu_key_to_disk(&dir_item->location, location);
 	btrfs_set_dir_type(dir_item, type);
-	btrfs_set_dir_flags(dir_item, 0);
 	btrfs_set_dir_name_len(dir_item, name_len);
+	btrfs_set_dir_data_len(dir_item, 0);
 	name_ptr = (char *)(dir_item + 1);
 
 	btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
@@ -112,8 +168,8 @@ second_insert:
 	}
 	btrfs_cpu_key_to_disk(&dir_item->location, location);
 	btrfs_set_dir_type(dir_item, type);
-	btrfs_set_dir_flags(dir_item, 0);
 	btrfs_set_dir_name_len(dir_item, name_len);
+	btrfs_set_dir_data_len(dir_item, 0);
 	name_ptr = (char *)(dir_item + 1);
 	btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
 	btrfs_mark_buffer_dirty(path->nodes[0]);
@@ -185,6 +241,43 @@ btrfs_lookup_dir_index_item(struct btrfs
 		return ERR_PTR(ret);
 	if (ret > 0)
 		return ERR_PTR(-ENOENT);
+	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, int name_len,
+					  int mod)
+{
+	int ret;
+	struct btrfs_key key;
+	int ins_len = mod < 0 ? -1 : 0;
+	int cow = mod != 0;
+	struct btrfs_disk_key *found_key;
+	struct btrfs_leaf *leaf;
+
+	key.objectid = dir;
+	key.flags = 0;
+	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 = btrfs_buffer_leaf(path->nodes[0]);
+	found_key = &leaf->items[path->slots[0]].key;
+
+	if (btrfs_disk_key_objectid(found_key) != dir ||
+	    btrfs_disk_key_type(found_key) != BTRFS_XATTR_ITEM_KEY ||
+	    btrfs_disk_key_offset(found_key) != key.offset)
+		return NULL;
+
 	return btrfs_match_dir_item_name(root, path, name, name_len);
 }
 
diff -r 9cb5f0f5c713 inode.c
--- a/inode.c	Thu Aug 30 12:16:51 2007 -0400
+++ b/inode.c	Wed Sep 05 13:05:29 2007 -0400
@@ -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"
@@ -2280,6 +2281,10 @@ static struct inode_operations btrfs_dir
 	.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 = {
@@ -2326,6 +2331,10 @@ static struct inode_operations btrfs_fil
 	.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 = {
diff -r 9cb5f0f5c713 print-tree.c
--- a/print-tree.c	Thu Aug 30 12:16:51 2007 -0400
+++ b/print-tree.c	Wed Sep 05 13:05:29 2007 -0400
@@ -56,10 +56,9 @@ void btrfs_print_leaf(struct btrfs_root 
 			break;
 		case BTRFS_DIR_ITEM_KEY:
 			di = btrfs_item_ptr(l, i, struct btrfs_dir_item);
-			printk("\t\tdir oid %llu flags %u type %u\n",
+			printk("\t\tdir oid %llu type %u\n",
 				(unsigned long long)btrfs_disk_key_objectid(
 							    &di->location),
-				btrfs_dir_flags(di),
 				btrfs_dir_type(di));
 			printk("\t\tname %.*s\n",
 			       btrfs_dir_name_len(di),(char *)(di + 1));
diff -r 9cb5f0f5c713 super.c
--- a/super.c	Thu Aug 30 12:16:51 2007 -0400
+++ b/super.c	Wed Sep 05 13:05:29 2007 -0400
@@ -40,6 +40,7 @@
 #include "btrfs_inode.h"
 #include "ioctl.h"
 #include "print-tree.h"
+#include "xattr.h"
 
 #define BTRFS_SUPER_MAGIC 0x9123682E
 
@@ -106,6 +107,7 @@ static int btrfs_fill_super(struct super
 	sb->s_maxbytes = MAX_LFS_FILESIZE;
 	sb->s_magic = BTRFS_SUPER_MAGIC;
 	sb->s_op = &btrfs_super_ops;
+	sb->s_xattr = btrfs_xattr_handlers;
 	sb->s_time_gran = 1;
 
 	tree_root = open_ctree(sb);
diff -r 9cb5f0f5c713 xattr.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xattr.c	Wed Sep 05 13:05:29 2007 -0400
@@ -0,0 +1,187 @@
+/*
+ * 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/init.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/rwsem.h>
+#include <linux/xattr.h>
+#include "ctree.h"
+#include "btrfs_inode.h"
+#include "transaction.h"
+#include "xattr.h"
+
+static struct xattr_handler *btrfs_xattr_handler_map[] = {
+	[BTRFS_XATTR_INDEX_USER]		= &btrfs_xattr_user_handler,
+	[BTRFS_XATTR_INDEX_POSIX_ACL_ACCESS]	= &btrfs_xattr_acl_access_handler,
+	[BTRFS_XATTR_INDEX_POSIX_ACL_DEFAULT]	= &btrfs_xattr_acl_default_handler,
+	[BTRFS_XATTR_INDEX_TRUSTED]		= &btrfs_xattr_trusted_handler,
+	[BTRFS_XATTR_INDEX_SECURITY]		= &btrfs_xattr_security_handler,
+};
+
+struct xattr_handler *btrfs_xattr_handlers[] = {
+	&btrfs_xattr_user_handler,
+	&btrfs_xattr_acl_access_handler,
+	&btrfs_xattr_acl_default_handler,
+	&btrfs_xattr_trusted_handler,
+	&btrfs_xattr_security_handler,
+	NULL
+};
+
+static inline struct xattr_handler *btrfs_xattr_handler(int name_index)
+{
+	struct xattr_handler *handler = NULL;
+
+	if (name_index > 0 && name_index < ARRAY_SIZE(btrfs_xattr_handler_map))
+		handler = btrfs_xattr_handler_map[name_index];
+
+	return handler;
+}
+
+static int check_prefix(const char *name, int name_index)
+{
+	struct xattr_handler *handler = btrfs_xattr_handler(name_index);
+	int name_len, prefix_len;
+
+	if (!handler)
+		return -EOPNOTSUPP;
+
+	prefix_len = sizeof(*handler->prefix)-1;
+	name_len = strlen(name);
+
+	if (name_len < prefix_len)
+		return -EOPNOTSUPP;
+
+	if (memcmp(name, handler->prefix, prefix_len) == 0)
+		return 0;
+
+	return -EOPNOTSUPP;
+}
+
+ssize_t btrfs_xattr_get(struct inode *inode, int name_index, const char *name,
+			void *buffer, size_t size)
+{
+	struct btrfs_dir_item *di;
+	struct btrfs_root *root = BTRFS_I(inode)->root;
+	struct btrfs_path *path;
+	int ret = 0;
+	char *data_ptr;
+
+	ret = check_prefix(name, name_index);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&root->fs_info->fs_mutex);
+	/* lookup the xattr by name */
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
+	di = btrfs_lookup_xattr(NULL, root, path, inode->i_ino, name,
+				strlen(name), 0);
+	if (!di || IS_ERR(di)) {
+		ret = -ENODATA;
+		goto out;
+	}
+
+	/* if size is 0, that means we want the size of the attr */
+	if (!size) {
+		ret = btrfs_dir_data_len(di);
+		goto out;
+	}
+
+	/* now get the data out of our dir_item */
+	if (btrfs_dir_data_len(di) > size) {
+		ret = -ERANGE;
+		goto out;
+	}
+	data_ptr = (char *)(di + 1) + btrfs_dir_name_len(di);
+	memcpy(buffer, data_ptr, btrfs_dir_data_len(di));
+	ret = btrfs_dir_data_len(di);
+
+out:
+	btrfs_free_path(path);
+	mutex_unlock(&root->fs_info->fs_mutex);
+	return ret;
+}
+
+int btrfs_xattr_set(struct inode *inode, int name_index, const char *name,
+		    const void *value, size_t size, int flags)
+{
+	struct btrfs_dir_item *di;
+	struct btrfs_root *root = BTRFS_I(inode)->root;
+	struct btrfs_trans_handle *trans;
+	struct btrfs_path *path;
+	int ret = 0;
+
+	ret = check_prefix(name, name_index);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&root->fs_info->fs_mutex);
+	trans = btrfs_start_transaction(root, 1);
+	btrfs_set_trans_block_group(trans, inode);
+
+	/* first lets see if we already have this xattr */
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
+	di = btrfs_lookup_xattr(trans, root, path, inode->i_ino, name,
+				strlen(name), 0);
+	if (IS_ERR(di)) {
+		ret = PTR_ERR(di);
+		goto out;
+	}
+
+	/* ok we already have this xattr, lets remove it */
+	if (di) {
+		/* if we want create only exit */
+		if (flags & XATTR_CREATE) {
+			ret = -EEXIST;
+			goto out;
+		}
+
+		ret = btrfs_del_item(trans, root, path);
+		if (ret)
+			goto out;
+		btrfs_release_path(root, path);
+	} else if (flags & XATTR_REPLACE) {
+		/* we couldn't find the attr to replace, so error out */
+		ret = -ENODATA;
+		goto out;
+	}
+
+	/* ok we have to create a completely new xattr */
+	ret = btrfs_insert_xattr_item(trans, root, name, strlen(name),
+				      value, size, inode->i_ino, 0);
+	if (ret)
+		goto out;
+
+out:
+	btrfs_free_path(path);
+	btrfs_end_transaction(trans, root);
+	mutex_unlock(&root->fs_info->fs_mutex);
+	return ret;
+}
+
+int btrfs_removexattr(struct dentry *dentry, const char *name)
+{
+	return 0;
+}
+
+ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
+{
+	return 0;
+}
diff -r 9cb5f0f5c713 xattr_security.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xattr_security.c	Wed Sep 05 13:05:29 2007 -0400
@@ -0,0 +1,64 @@
+/*
+ * 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 "ctree.h"
+#include "xattr.h"
+
+static size_t btrfs_xattr_security_list(struct inode *inode, char *list,
+					size_t list_size, const char *name,
+					size_t name_len)
+{
+	const size_t prefix_len = sizeof(XATTR_SECURITY_PREFIX)-1;
+	const size_t total_len = prefix_len + name_len + 1;
+
+	if (list && total_len <= list_size) {
+		memcpy(list, XATTR_SECURITY_PREFIX, prefix_len);
+		memcpy(list+prefix_len, name, name_len);
+		list[prefix_len + name_len] = '\0';
+	}
+
+	return total_len;
+}
+
+static int btrfs_xattr_security_get(struct inode *inode, const char *name,
+				    void *value, size_t size)
+{
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+	return btrfs_xattr_get(inode, BTRFS_XATTR_INDEX_SECURITY, name, value,
+			       size);
+}
+
+static int btrfs_xattr_security_set(struct inode *inode, const char *name,
+				    const void *value, size_t size, int flags)
+{
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+	return btrfs_xattr_set(inode, BTRFS_XATTR_INDEX_SECURITY, name, value,
+			       size, flags);
+}
+
+struct xattr_handler btrfs_xattr_security_handler = {
+	.prefix = XATTR_SECURITY_PREFIX,
+	.list	= btrfs_xattr_security_list,
+	.get	= btrfs_xattr_security_get,
+	.set	= btrfs_xattr_security_set,
+};
diff -r 9cb5f0f5c713 xattr_user.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xattr_user.c	Wed Sep 05 13:05:29 2007 -0400
@@ -0,0 +1,64 @@
+/*
+ * 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 "ctree.h"
+#include "xattr.h"
+
+static size_t btrfs_xattr_user_list(struct inode *inode, char *list,
+				    size_t list_size, const char *name,
+				    size_t name_len)
+{
+	const size_t prefix_len = sizeof(XATTR_USER_PREFIX)-1;
+	const size_t total_len = prefix_len + name_len + 1;
+
+	if (list && total_len <= list_size) {
+		memcpy(list, XATTR_USER_PREFIX, prefix_len);
+		memcpy(list+prefix_len, name, name_len);
+		list[prefix_len + name_len] = '\0';
+	}
+
+	return total_len;
+}
+
+static int btrfs_xattr_user_get(struct inode *inode, const char *name,
+				void *value, size_t size)
+{
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+	return btrfs_xattr_get(inode, BTRFS_XATTR_INDEX_USER, name, value,
+			       size);
+}
+
+static int btrfs_xattr_user_set(struct inode *inode, const char *name,
+				const void *value, size_t size, int flags)
+{
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+	return btrfs_xattr_set(inode, BTRFS_XATTR_INDEX_USER, name, value,
+			       size, flags);
+}
+
+struct xattr_handler btrfs_xattr_user_handler = {
+	.prefix = XATTR_USER_PREFIX,
+	.list	= btrfs_xattr_user_list,
+	.get	= btrfs_xattr_user_get,
+	.set	= btrfs_xattr_user_set,
+};



More information about the Btrfs-devel mailing list