[Btrfs-devel] [PATCH 2/4] supporting code to add xattr support

Josef Bacik jbacik at redhat.com
Wed Nov 7 18:06:54 PST 2007


Hello,

This patch has all the supporting code that is required for xattr support.  This
adds the changes to the make file, changes to dir-item.c to handle xattr
dir_item's, and it adds something to btrfs_unlink_trans() so that it will remove
any/all xattrs associated with a file when it removes the file.  Thank you,

Josef

diff -r 9cb5f0f5c713 Makefile
--- a/Makefile	Thu Aug 30 12:16:51 2007 -0400
+++ b/Makefile	Tue Nov 06 21:31:20 2007 -0500
@@ -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 xattr_system.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 ctree.h
--- a/ctree.h	Thu Aug 30 12:16:51 2007 -0400
+++ b/ctree.h	Wed Nov 07 21:59:55 2007 -0500
@@ -61,6 +61,7 @@ extern struct kmem_cache *btrfs_path_cac
 #define BTRFS_FT_SOCK		6
 #define BTRFS_FT_SYMLINK	7
 #define BTRFS_FT_MAX		8
+#define BTRFS_FT_XATTR		9
 
 /*
  * the key defines the order in the tree, and so it also defines (optimal)
@@ -220,7 +221,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 +359,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 +401,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 +606,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 +624,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 +1170,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);
+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 +1260,13 @@ 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);
+int btrfs_delete_xattrs(struct btrfs_trans_handle *trans,
+			struct btrfs_root *root, struct inode *inode);
 #endif
diff -r 9cb5f0f5c713 dir-item.c
--- a/dir-item.c	Thu Aug 30 12:16:51 2007 -0400
+++ b/dir-item.c	Thu Nov 08 03:52:09 2007 -0500
@@ -43,8 +43,6 @@ static struct btrfs_dir_item *insert_wit
 			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 +53,51 @@ 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)
+{
+	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);
+	/*
+	 * FIXME: at some point we should handle xattr's that are larger than
+	 * what we can fit in our leaf
+	 */
+	BUG_ON(IS_ERR(dir_item));
+
+	memset(&location, 0, sizeof(location));
+	btrfs_cpu_key_to_disk(&dir_item->location, &location);
+	btrfs_set_dir_type(dir_item, BTRFS_FT_XATTR);
+	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 +130,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 +155,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]);
@@ -188,6 +231,43 @@ btrfs_lookup_dir_index_item(struct btrfs
 	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);
+}
+
 struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
 			      struct btrfs_path *path,
 			      const char *name, int name_len)
@@ -229,7 +309,7 @@ int btrfs_delete_one_dir_name(struct btr
 	int ret = 0;
 
 	leaf = btrfs_buffer_leaf(path->nodes[0]);
-	sub_item_len = sizeof(*di) + btrfs_dir_name_len(di);
+	sub_item_len = sizeof(*di) + btrfs_dir_name_len(di) + btrfs_dir_data_len(di);
 	item_len = btrfs_item_size(leaf->items + path->slots[0]);
 	if (sub_item_len == btrfs_item_size(leaf->items + path->slots[0])) {
 		ret = btrfs_del_item(trans, root, path);
diff -r 9cb5f0f5c713 inode.c
--- a/inode.c	Thu Aug 30 12:16:51 2007 -0400
+++ b/inode.c	Thu Nov 08 03:54:17 2007 -0500
@@ -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"
@@ -367,6 +368,10 @@ static int btrfs_unlink_trans(struct btr
 		goto err;
 	}
 	ret = btrfs_delete_one_dir_name(trans, root, path, di);
+	if (ret)
+		goto err;
+
+	ret = btrfs_delete_xattrs(trans, root, dentry->d_inode);
 
 	dentry->d_inode->i_ctime = dir->i_ctime;
 err:
@@ -2280,6 +2285,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 +2335,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 12:05:29 2007 -0500
@@ -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 12:05:29 2007 -0500
@@ -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);



More information about the Btrfs-devel mailing list