[Ocfs2-tools-devel] [PATCH 8/9] ocfs2-tools: add xattr support in tunefs.ocfs2

Tiger Yang tiger.yang at oracle.com
Sat Jan 24 00:04:12 PST 2009


This patch add feature xattr in tunefs.ocfs2.
So you can enable or disable feature xattr on a ocfs2 volume.
Disable feature xattr will remove all xattrs which have already been set,
include acl, security xattrs.

Signed-off-by: Tiger Yang <tiger.yang at oracle.com>
---
 include/ocfs2/ocfs2.h        |   24 +++
 libocfs2/alloc.c             |   33 ++++
 libocfs2/extents.c           |   71 ++++++++
 libocfs2/truncate.c          |   32 ++++
 tunefs.ocfs2/Makefile        |    3 +-
 tunefs.ocfs2/feature_xattr.c |  404 ++++++++++++++++++++++++++++++++++++++++++
 tunefs.ocfs2/op_features.c   |    2 +
 7 files changed, 568 insertions(+), 1 deletions(-)
 create mode 100644 tunefs.ocfs2/feature_xattr.c

diff --git a/include/ocfs2/ocfs2.h b/include/ocfs2/ocfs2.h
index 4c8acab..4fd7e2c 100644
--- a/include/ocfs2/ocfs2.h
+++ b/include/ocfs2/ocfs2.h
@@ -966,6 +966,12 @@ static inline int ocfs2_meta_ecc(struct ocfs2_super_block *osb)
 	return 0;
 }
 
+static inline int ocfs2_support_xattr(struct ocfs2_super_block *osb)
+{
+	if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_XATTR)
+		return 1;
+	return 0;
+}
 
 /*
  * shamelessly lifted from the kernel
@@ -1107,5 +1113,23 @@ errcode_t ocfs2_xattr_get_rec(ocfs2_filesys *fs,
 			      uint64_t *p_blkno,
 			      uint32_t *e_cpos,
 			      uint32_t *num_clusters);
+errcode_t ocfs2_xattr_value_truncate(ocfs2_filesys *fs,
+				     struct ocfs2_xattr_value_root *xv);
+errcode_t ocfs2_xattr_tree_truncate(ocfs2_filesys *fs,
+				    struct ocfs2_xattr_tree_root *xt);
+errcode_t ocfs2_extent_iterate_xattr(ocfs2_filesys *fs,
+				     struct ocfs2_extent_list *el,
+				     uint64_t last_eb_blk,
+				     int flags,
+				     int (*func)(ocfs2_filesys *fs,
+						struct ocfs2_extent_rec *rec,
+						int tree_depth,
+						uint32_t ccount,
+						uint64_t ref_blkno,
+						int ref_recno,
+						void *priv_data),
+				     void *priv_data,
+				     int *changed);
+errcode_t ocfs2_delete_xattr_block(ocfs2_filesys *fs, uint64_t blkno);
 
 #endif  /* _FILESYS_H */
diff --git a/libocfs2/alloc.c b/libocfs2/alloc.c
index 4cc5759..e076bc5 100644
--- a/libocfs2/alloc.c
+++ b/libocfs2/alloc.c
@@ -416,6 +416,39 @@ out:
 	return ret;
 }
 
+errcode_t ocfs2_delete_xattr_block(ocfs2_filesys *fs, uint64_t blkno)
+{
+	errcode_t ret;
+	char *buf;
+	int slot;
+	struct ocfs2_xattr_block *xb = NULL;
+
+	ret = ocfs2_malloc_block(fs->fs_io, &buf);
+	if (ret)
+		return ret;
+
+	ret = ocfs2_read_xattr_block(fs, blkno, buf);
+	if (ret)
+		goto out;
+
+	xb = (struct ocfs2_xattr_block *)buf;
+	slot = xb->xb_suballoc_slot;
+
+	ret = ocfs2_load_allocator(fs, EXTENT_ALLOC_SYSTEM_INODE, slot,
+				   &fs->fs_eb_allocs[slot]);
+	if (ret)
+		goto out;
+
+	ret = ocfs2_chain_free_with_io(fs, fs->fs_eb_allocs[slot], blkno);
+	if (ret)
+		goto out;
+
+out:
+	ocfs2_free(&buf);
+
+	return ret;
+}
+
 errcode_t ocfs2_delete_extent_block(ocfs2_filesys *fs, uint64_t blkno)
 {
 	errcode_t ret;
diff --git a/libocfs2/extents.c b/libocfs2/extents.c
index a014437..4b6808a 100644
--- a/libocfs2/extents.c
+++ b/libocfs2/extents.c
@@ -378,6 +378,77 @@ out:
 	return iret;
 }
 
+errcode_t ocfs2_extent_iterate_xattr(ocfs2_filesys *fs,
+				     struct ocfs2_extent_list *el,
+				     uint64_t last_eb_blk,
+				     int flags,
+				     int (*func)(ocfs2_filesys *fs,
+						struct ocfs2_extent_rec *rec,
+						int tree_depth,
+						uint32_t ccount,
+						uint64_t ref_blkno,
+						int ref_recno,
+						void *priv_data),
+				     void *priv_data,
+				     int *changed)
+{
+	int i;
+	int iret = 0;
+	errcode_t ret;
+	struct extent_context ctxt;
+
+	if (el->l_tree_depth) {
+		ret = ocfs2_malloc0(sizeof(char *) * el->l_tree_depth,
+				    &ctxt.eb_bufs);
+		if (ret)
+			goto out;
+
+		ret = ocfs2_malloc0(fs->fs_blocksize *
+				    el->l_tree_depth,
+				    &ctxt.eb_bufs[0]);
+		if (ret)
+			goto out_eb_bufs;
+
+		for (i = 1; i < el->l_tree_depth; i++) {
+			ctxt.eb_bufs[i] = ctxt.eb_bufs[0] +
+				i * fs->fs_blocksize;
+		}
+	} else
+		ctxt.eb_bufs = NULL;
+
+	ctxt.fs = fs;
+	ctxt.func = func;
+	ctxt.priv_data = priv_data;
+	ctxt.flags = flags;
+	ctxt.ccount = 0;
+	ctxt.last_eb_blkno = 0;
+	ctxt.last_eb_cpos = 0;
+
+	ret = 0;
+	iret |= extent_iterate_el(el, 0, &ctxt);
+	if (iret & OCFS2_EXTENT_ERROR)
+		ret = ctxt.errcode;
+
+	if (iret & OCFS2_EXTENT_ABORT)
+		goto out_abort;
+
+	if (last_eb_blk != ctxt.last_eb_blkno) {
+		last_eb_blk = ctxt.last_eb_blkno;
+		iret |= OCFS2_EXTENT_CHANGED;
+	}
+
+out_abort:
+	if (!ret && (iret & OCFS2_EXTENT_CHANGED))
+		*changed = 1;
+out_eb_bufs:
+	if (ctxt.eb_bufs) {
+		if (ctxt.eb_bufs[0])
+			ocfs2_free(&ctxt.eb_bufs[0]);
+		ocfs2_free(&ctxt.eb_bufs);
+	}
+out:
+	return ret;
+}
 
 errcode_t ocfs2_extent_iterate_inode(ocfs2_filesys *fs,
 				     struct ocfs2_dinode *inode,
diff --git a/libocfs2/truncate.c b/libocfs2/truncate.c
index e67f3b7..c18a247 100644
--- a/libocfs2/truncate.c
+++ b/libocfs2/truncate.c
@@ -261,6 +261,38 @@ out:
 	return ret;
 }
 
+errcode_t ocfs2_xattr_value_truncate(ocfs2_filesys *fs,
+				     struct ocfs2_xattr_value_root *xv)
+{
+	struct truncate_ctxt ctxt;
+	int changed;
+	struct ocfs2_extent_list *el = &xv->xr_list;
+
+	ctxt.new_i_clusters = xv->xr_clusters;
+	ctxt.new_size_in_clusters = 0;
+
+	return ocfs2_extent_iterate_xattr(fs, el, xv->xr_last_eb_blk,
+					OCFS2_EXTENT_FLAG_DEPTH_TRAVERSE,
+					truncate_iterate,
+					&ctxt, &changed);
+}
+
+errcode_t ocfs2_xattr_tree_truncate(ocfs2_filesys *fs,
+				    struct ocfs2_xattr_tree_root *xt)
+{
+	struct truncate_ctxt ctxt;
+	int changed;
+	struct ocfs2_extent_list *el = &xt->xt_list;
+
+	ctxt.new_i_clusters = xt->xt_clusters;
+	ctxt.new_size_in_clusters = 0;
+
+	return ocfs2_extent_iterate_xattr(fs, el, xt->xt_last_eb_blk,
+					OCFS2_EXTENT_FLAG_DEPTH_TRAVERSE,
+					truncate_iterate,
+					&ctxt, &changed);
+}
+
 #ifdef DEBUG_EXE
 #include <stdlib.h>
 #include <getopt.h>
diff --git a/tunefs.ocfs2/Makefile b/tunefs.ocfs2/Makefile
index b693e9c..fd244d8 100644
--- a/tunefs.ocfs2/Makefile
+++ b/tunefs.ocfs2/Makefile
@@ -23,7 +23,8 @@ OCFS2NE_FEATURES =			\
 	feature_local			\
 	feature_metaecc			\
 	feature_sparse_files		\
-	feature_unwritten_extents
+	feature_unwritten_extents	\
+	feature_xattr
 
 OCFS2NE_OPERATIONS =			\
 	op_cloned_volume		\
diff --git a/tunefs.ocfs2/feature_xattr.c b/tunefs.ocfs2/feature_xattr.c
new file mode 100644
index 0000000..fa70c64
--- /dev/null
+++ b/tunefs.ocfs2/feature_xattr.c
@@ -0,0 +1,404 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * feature_xattr.c
+ *
+ * Copyright (C) 2004, 2008 Oracle.  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 version 2 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.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#include "ocfs2-kernel/kernel-list.h"
+#include "ocfs2/ocfs2.h"
+
+#include "libocfs2ne.h"
+
+struct xattr_inode {
+	struct list_head list;
+	uint64_t blkno;
+};
+
+struct xattr_context {
+	errcode_t ret;
+	struct list_head inodes;
+};
+
+static void empty_xattr_context(struct xattr_context *ctxt)
+{
+	struct list_head *pos, *n;
+	struct xattr_inode *xdi;
+
+	list_for_each_safe(pos, n, &ctxt->inodes) {
+		xdi = list_entry(pos, struct xattr_inode, list);
+		list_del(&xdi->list);
+		ocfs2_free(&xdi);
+	}
+}
+
+static errcode_t remove_xattr_entry(ocfs2_filesys *fs,
+				    struct ocfs2_xattr_header *xh)
+{
+	int i;
+	errcode_t ret = 0;
+
+	for (i = 0 ; i < xh->xh_count; i++) {
+		struct ocfs2_xattr_entry *xe = &xh->xh_entries[i];
+
+		if (!ocfs2_xattr_is_local(xe)) {
+			struct ocfs2_xattr_value_root *xv =
+				(struct ocfs2_xattr_value_root *)
+				((void *)xh + xe->xe_name_offset +
+				OCFS2_XATTR_SIZE(xe->xe_name_len));
+			ret = ocfs2_xattr_value_truncate(fs, xv);
+			if (ret)
+				break;
+		}
+	}
+
+	return ret;
+}
+
+static errcode_t remove_xattr_buckets(ocfs2_filesys *fs,
+				      uint64_t blkno,
+				      uint32_t clusters)
+{
+	int i;
+	errcode_t ret = 0;
+	char *bucket = NULL;
+	struct ocfs2_xattr_header *xh;
+	int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(fs);
+	uint32_t bpc = ocfs2_xattr_buckets_per_cluster(fs);
+	uint32_t num_buckets = clusters * bpc;
+
+	ret = ocfs2_malloc_blocks(fs->fs_io, blk_per_bucket, &bucket);
+	if (ret) {
+		tcom_err(ret, "while allocating room to read bucket "
+			 "of xattr data");
+		goto out;
+	}
+
+	for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) {
+
+		ret = io_read_block(fs->fs_io, blkno, blk_per_bucket, bucket);
+		if (ret) {
+			tcom_err(ret, "while reading blocks of xattr bucket");
+			goto out;
+		}
+
+		xh = (struct ocfs2_xattr_header *)bucket;
+		ocfs2_swap_xattrs_to_cpu(xh);
+		/*
+		 * The real bucket num in this series of blocks is stored
+		 * in the 1st bucket.
+		 */
+		if (i == 0)
+			num_buckets = xh->xh_num_buckets;
+
+		ret = remove_xattr_entry(fs, xh);
+		if (ret)
+			break;
+	}
+
+out:
+	ocfs2_free(&bucket);
+
+	return ret;
+}
+
+
+static errcode_t remove_xattr_index_block(ocfs2_filesys *fs,
+					  struct ocfs2_xattr_block *xb)
+{
+	struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list;
+	errcode_t ret = 0;
+	uint32_t name_hash = UINT_MAX, e_cpos = 0, num_clusters = 0;
+	uint64_t p_blkno = 0;
+
+	if (el->l_next_free_rec == 0)
+		return 0;
+
+	while (name_hash > 0) {
+		ret = ocfs2_xattr_get_rec(fs, xb, name_hash, &p_blkno,
+					  &e_cpos, &num_clusters);
+		if (ret) {
+			tcom_err(ret, "while getting bucket record "
+				 "of xattr data.");
+			goto out;
+		}
+
+		ret = remove_xattr_buckets(fs, p_blkno, num_clusters);
+		if (ret) {
+			tcom_err(ret, "while iterating buckets of xattr data");
+			goto out;
+		}
+
+		if (e_cpos == 0)
+			break;
+
+		name_hash = e_cpos - 1;
+	}
+
+out:
+	return ret;
+}
+
+static errcode_t remove_xattr_block(ocfs2_filesys *fs,
+				    struct ocfs2_dinode *di)
+{
+	errcode_t ret;
+	char *blk = NULL;
+	struct ocfs2_xattr_block *xb = NULL;
+
+	ret = ocfs2_malloc_block(fs->fs_io, &blk);
+	if (ret) {
+		tcom_err(ret, "while allocating room to read block "
+			 "of xattr.");
+		return ret;
+	}
+
+	ret = ocfs2_read_xattr_block(fs, di->i_xattr_loc, blk);
+	if (ret) {
+		tcom_err(ret, "while reading external block of xattr");
+		goto out;
+	}
+
+	xb = (struct ocfs2_xattr_block *)blk;
+
+	if (!(xb->xb_flags & OCFS2_XATTR_INDEXED)) {
+		struct ocfs2_xattr_header *xh = &xb->xb_attrs.xb_header;
+
+		ret = remove_xattr_entry(fs, xh);
+		if (ret) {
+			tcom_err(ret, "while trying to remove xattr in "
+			"external block");
+			goto out;
+		}
+	} else {
+		ret = remove_xattr_index_block(fs, xb);
+		if (ret) {
+			tcom_err(ret, "while trying to remove xattr in "
+			"index block");
+			goto out;
+		}
+		ret = ocfs2_xattr_tree_truncate(fs, &xb->xb_attrs.xb_root);
+		if (ret) {
+			tcom_err(ret, "while trying to remove xattr tree in "
+			"index block");
+			goto out;
+		}
+	}
+
+	/* release block*/
+	ret = ocfs2_delete_xattr_block(fs, di->i_xattr_loc);
+	if (ret)
+		goto out;
+	/* clean extended attributes */
+	memset(blk, 0, fs->fs_blocksize);
+
+out:
+	if (blk)
+		ocfs2_free(&blk);
+
+	return ret;
+}
+
+static errcode_t remove_xattr_ibody(ocfs2_filesys *fs,
+				    struct ocfs2_dinode *di)
+{
+	errcode_t ret;
+	struct ocfs2_xattr_header *xh = NULL;
+
+	xh = (struct ocfs2_xattr_header *)
+		 ((void *)di + fs->fs_blocksize -
+		  di->i_xattr_inline_size);
+
+	ocfs2_swap_xattrs_to_cpu(xh);
+
+	ret = remove_xattr_entry(fs, xh);
+	if (ret) {
+		tcom_err(ret, "while trying to remove xattr in ibody");
+		return ret;
+	}
+
+	/* clean inline extended attributs */
+	memset((char *)xh, 0, di->i_xattr_inline_size);
+
+	if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) {
+		struct ocfs2_inline_data *idata = &di->id2.i_data;
+		idata->id_count += di->i_xattr_inline_size;
+	} else if (!(S_ISLNK(di->i_mode) && di->i_clusters == 0)) {
+		struct ocfs2_extent_list *el = &di->id2.i_list;
+		el->l_count += (di->i_xattr_inline_size /
+				sizeof(struct ocfs2_extent_rec));
+	}
+	di->i_xattr_inline_size = 0;
+
+	return ret;
+}
+
+static errcode_t remove_xattr(ocfs2_filesys *fs,
+			      struct xattr_context *ctxt)
+{
+	errcode_t ret = 0;
+	struct list_head *pos;
+	struct xattr_inode *xdi;
+	struct ocfs2_dinode *di = NULL;
+	ocfs2_cached_inode *ci = NULL;
+
+	list_for_each(pos, &ctxt->inodes) {
+		xdi = list_entry(pos, struct xattr_inode, list);
+
+		ret = ocfs2_read_cached_inode(fs, xdi->blkno, &ci);
+		if (ret)
+			break;
+		di = ci->ci_inode;
+		if (di->i_dyn_features & OCFS2_INLINE_XATTR_FL) {
+			ret = remove_xattr_ibody(fs, di);
+			if (ret)
+				break;
+		}
+		if (di->i_xattr_loc)
+			ret = remove_xattr_block(fs, di);
+		di->i_xattr_loc = 0;
+		di->i_dyn_features &= ~(OCFS2_INLINE_XATTR_FL |
+					OCFS2_HAS_XATTR_FL);
+		ret = ocfs2_write_cached_inode(fs, ci);
+		ocfs2_free_cached_inode(fs, ci);
+		if (ret)
+			break;
+	}
+	return ret;
+}
+
+static errcode_t xattr_iterate(ocfs2_filesys *fs,
+			       struct ocfs2_dinode *di,
+			       void *user_data)
+{
+	errcode_t ret = 0;
+	struct xattr_inode *xdi = NULL;
+	struct xattr_context *ctxt = (struct xattr_context *)user_data;
+
+	if (!S_ISREG(di->i_mode) && !S_ISDIR(di->i_mode) &&
+	    !S_ISLNK(di->i_mode))
+		goto bail;
+
+	if (!(di->i_dyn_features & OCFS2_HAS_XATTR_FL))
+		goto bail;
+
+	ret = ocfs2_malloc0(sizeof(struct xattr_inode), &xdi);
+	if (ret)
+		goto bail;
+
+	xdi->blkno = di->i_blkno;
+	list_add_tail(&xdi->list, &ctxt->inodes);
+
+	return 0;
+bail:
+	return ret;
+}
+
+static int enable_xattr(ocfs2_filesys *fs, int flag)
+{
+	errcode_t ret = 0;
+	struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super);
+
+	if (ocfs2_support_xattr(super)) {
+		verbosef(VL_APP,
+			 "The extended attribute feature is already enabled; "
+			 "nothing to enable\n");
+		goto out;
+	}
+
+	if (!tools_interact("Enable the extended attribute feature on device "
+			     "\"%s\"? ",
+			     fs->fs_devname))
+		goto out;
+
+	super->s_uuid_hash = xattr_uuid_hash((unsigned char *)super->s_uuid);
+	super->s_xattr_inline_size = OCFS2_MIN_XATTR_INLINE_SIZE;
+	OCFS2_SET_INCOMPAT_FEATURE(super, OCFS2_FEATURE_INCOMPAT_XATTR);
+
+	tunefs_block_signals();
+	ret = ocfs2_write_super(fs);
+	tunefs_unblock_signals();
+	if (ret)
+		tcom_err(ret, "while writing out the superblock");
+
+out:
+	return ret;
+}
+
+static int disable_xattr(ocfs2_filesys *fs, int flag)
+{
+	errcode_t ret = 0;
+	struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super);
+	struct xattr_context ctxt;
+
+	if (!ocfs2_support_xattr(super)) {
+		verbosef(VL_APP,
+			 "The extended attribute feature is not enabled; "
+			 "nothing to disable\n");
+		goto out;
+	}
+
+	if (!tools_interact("Disable the extended attribute feature on device"
+			     " \"%s\"? ",
+			     fs->fs_devname))
+		goto out;
+
+	memset(&ctxt, 0, sizeof(struct xattr_context));
+	INIT_LIST_HEAD(&ctxt.inodes);
+	ret = tunefs_foreach_inode(fs, xattr_iterate, &ctxt);
+	if (ret) {
+		tcom_err(ret, "while trying to find files with xattr");
+		goto out_cleanup;
+	}
+
+	ret = remove_xattr(fs, &ctxt);
+	if (ret) {
+		tcom_err(ret, "while trying to remove xattr");
+		goto out_cleanup;
+	}
+
+	super->s_uuid_hash = 0;
+	super->s_xattr_inline_size = 0;
+	OCFS2_CLEAR_INCOMPAT_FEATURE(super, OCFS2_FEATURE_INCOMPAT_XATTR);
+
+	tunefs_block_signals();
+	ret = ocfs2_write_super(fs);
+	tunefs_unblock_signals();
+	if (ret)
+		tcom_err(ret, "while writing out the superblock");
+
+out_cleanup:
+	empty_xattr_context(&ctxt);
+out:
+	return ret;
+}
+
+DEFINE_TUNEFS_FEATURE_INCOMPAT(xattr,
+			       OCFS2_FEATURE_INCOMPAT_XATTR,
+			       TUNEFS_FLAG_RW | TUNEFS_FLAG_ALLOCATION,
+			       enable_xattr,
+			       disable_xattr);
+
+#ifdef DEBUG_EXE
+int main(int argc, char *argv[])
+{
+	return tunefs_feature_main(argc, argv, &xattr_feature);
+}
+#endif
diff --git a/tunefs.ocfs2/op_features.c b/tunefs.ocfs2/op_features.c
index b1424ee..ee9442e 100644
--- a/tunefs.ocfs2/op_features.c
+++ b/tunefs.ocfs2/op_features.c
@@ -40,6 +40,7 @@ extern struct tunefs_feature local_feature;
 extern struct tunefs_feature metaecc_feature;
 extern struct tunefs_feature sparse_files_feature;
 extern struct tunefs_feature unwritten_extents_feature;
+extern struct tunefs_feature xattr_feature;
 
 /* List of features supported by ocfs2ne */
 static struct tunefs_feature *features[] = {
@@ -50,6 +51,7 @@ static struct tunefs_feature *features[] = {
 	&metaecc_feature,
 	&sparse_files_feature,
 	&unwritten_extents_feature,
+	&xattr_feature,
 	NULL,
 };
 
-- 
1.5.4.4




More information about the Ocfs2-tools-devel mailing list