[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