Tiger Yang
2008-Jul-25 07:06 UTC
[Ocfs2-devel] [PATCH 1/2] ocfs2-tools: Add extended attribute support in mkfs.ocfs2
This patch add support for new feature xattr in mkfs.ocfs2. Signed-off-by: Tiger Yang <tiger.yang at oracle.com> --- include/ocfs2-kernel/ocfs2_fs.h | 89 ++++++++++++++++++++++++++++++++++---- include/ocfs2/ocfs2.h | 2 + libocfs2/Makefile | 3 +- libocfs2/feature_string.c | 9 ++++- libocfs2/inode.c | 7 +++ libocfs2/xattr.c | 37 ++++++++++++++++ mkfs.ocfs2/mkfs.c | 6 +++ mkfs.ocfs2/mkfs.ocfs2.8.in | 5 ++ sizetest/sizetest.c | 12 +++++- 9 files changed, 157 insertions(+), 13 deletions(-) create mode 100644 libocfs2/xattr.c diff --git a/include/ocfs2-kernel/ocfs2_fs.h b/include/ocfs2-kernel/ocfs2_fs.h index 0cfef2a..ade9ec1 100644 --- a/include/ocfs2-kernel/ocfs2_fs.h +++ b/include/ocfs2-kernel/ocfs2_fs.h @@ -64,6 +64,7 @@ #define OCFS2_INODE_SIGNATURE "INODE01" #define OCFS2_EXTENT_BLOCK_SIGNATURE "EXBLK01" #define OCFS2_GROUP_DESC_SIGNATURE "GROUP01" +#define OCFS2_XATTR_BLOCK_SIGNATURE "XATTR01" /* Compatibility flags */ #define OCFS2_HAS_COMPAT_FEATURE(sb,mask) \ @@ -89,7 +90,8 @@ #define OCFS2_FEATURE_INCOMPAT_SUPP (OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT \ | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC \ | OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP \ - | OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK) + | OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK \ + | OCFS2_FEATURE_INCOMPAT_XATTR) #define OCFS2_FEATURE_RO_COMPAT_SUPP OCFS2_FEATURE_RO_COMPAT_UNWRITTEN /* @@ -126,10 +128,6 @@ /* Support for data packed into inode blocks */ #define OCFS2_FEATURE_INCOMPAT_INLINE_DATA 0x0040 -/* Support for the extended slot map */ -#define OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP 0x100 - - /* * Support for alternate, userspace cluster stacks. If set, the superblock * field s_cluster_info contains a tag for the alternate stack in use as @@ -141,6 +139,12 @@ */ #define OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK 0x0080 +/* Support for the extended slot map */ +#define OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP 0x100 + +/* Support for extended attributes */ +#define OCFS2_FEATURE_INCOMPAT_XATTR 0x0200 + /* * backup superblock flag is used to indicate that this volume * has backup superblocks. @@ -554,7 +558,7 @@ struct ocfs2_super_block { /*40*/ __le16 s_max_slots; /* Max number of simultaneous mounts before tunefs required */ __le16 s_tunefs_flag; - __le32 s_reserved1; + __le32 s_uuid_hash; __le64 s_first_cluster_group; /* Block offset of 1st cluster * group header */ /*50*/ __u8 s_label[OCFS2_MAX_VOL_LABEL_LEN]; /* Label for mounting, etc. */ @@ -562,7 +566,11 @@ struct ocfs2_super_block { /*A0*/ struct ocfs2_cluster_info s_cluster_info; /* Selected userspace stack. Only valid with INCOMPAT flag. */ -/*B8*/ __le64 s_reserved2[17]; /* Fill out superblock */ +/*B8*/ __le16 s_xattr_inline_size; /* extended attribute inline size + for this fs*/ + __le16 s_reserved0; + __le32 s_reserved1; +/*C0*/ __le64 s_reserved2[16]; /* Fill out superblock */ /*140*/ /* @@ -612,7 +620,8 @@ struct ocfs2_dinode { belongs to */ __le16 i_suballoc_bit; /* Bit offset in suballocator block group */ -/*10*/ __le32 i_reserved0; +/*10*/ __le16 i_reserved0; + __le16 i_xattr_inline_size; __le32 i_clusters; /* Cluster count */ __le32 i_uid; /* Owner UID */ __le32 i_gid; /* Owning GID */ @@ -631,11 +640,12 @@ struct ocfs2_dinode { __le32 i_atime_nsec; __le32 i_ctime_nsec; __le32 i_mtime_nsec; - __le32 i_attr; +/*70*/ __le32 i_attr; __le16 i_orphaned_slot; /* Only valid when OCFS2_ORPHANED_FL was set in i_flags */ __le16 i_dyn_features; -/*70*/ __le64 i_reserved2[8]; + __le64 i_xattr_loc; +/*80*/ __le64 i_reserved2[7]; /*B8*/ union { __le64 i_pad1; /* Generic way to refer to this 64bit union */ @@ -706,6 +716,65 @@ struct ocfs2_group_desc /*40*/ __u8 bg_bitmap[0]; }; +/* + * On disk extended attribute structure for OCFS2 + * Include ocfs2_xattr_entry, ocfs2_xattr_header, ocfs2_xattr_value_root + * ocfs2_xattr_tree_root and ocfs2_xattr_block. + */ +#define OCFS2_XATTR_INDEXED 0x1 + +#define OCFS2_HASH_SHIFT 5 + +/* Inline extended attribute size (in bytes) */ +#define OCFS2_MIN_XATTR_INLINE_SIZE 256 + +struct ocfs2_xattr_entry { + __le32 xe_name_hash; + __le16 xe_name_offset; + __u8 xe_name_len; + __u8 xe_type : 7; + __u8 xe_local : 1; + __le64 xe_value_size; +}; + +struct ocfs2_xattr_header { + __le16 xh_count; + __le16 xh_reserved1; + __le32 xh_csum; + __le64 xh_reserved2; + struct ocfs2_xattr_entry xh_entries[0]; +}; + +struct ocfs2_xattr_value_root { +/*00*/ __le32 xr_clusters; + __le32 xr_reserved0; + __le64 xr_last_eb_blk; +/*10*/ struct ocfs2_extent_list xr_list; +}; + +struct ocfs2_xattr_tree_root { +/*00*/ __le32 xt_clusters; + __le32 xt_reserved0; + __le64 xt_last_eb_blk; +/*10*/ struct ocfs2_extent_list xt_list; +}; + +struct ocfs2_xattr_block { +/*00*/ __u8 xb_signature[8]; + __le16 xb_suballoc_slot; + __le16 xb_suballoc_bit; + __le32 xb_fs_generation; +/*10*/ __le32 xb_csum; + __le16 xb_flags; + __le16 xb_reserved0; + __le64 xb_blkno; +/*20*/ __le64 xb_reserved1[2]; +/*30*/ union { + struct ocfs2_xattr_header xb_header; + struct ocfs2_xattr_tree_root xb_root; + } xb_attrs; +}; + #ifdef __KERNEL__ static inline int ocfs2_fast_symlink_chars(struct super_block *sb) { diff --git a/include/ocfs2/ocfs2.h b/include/ocfs2/ocfs2.h index 642027e..1f81c47 100644 --- a/include/ocfs2/ocfs2.h +++ b/include/ocfs2/ocfs2.h @@ -941,4 +941,6 @@ errcode_t ocfs2_block_iterate_inode(ocfs2_filesys *fs, void *priv_data), void *priv_data); +uint32_t xattr_uuid_hash(unsigned char *uuid); + #endif /* _FILESYS_H */ diff --git a/libocfs2/Makefile b/libocfs2/Makefile index 5e12e7c..941688d 100644 --- a/libocfs2/Makefile +++ b/libocfs2/Makefile @@ -73,7 +73,8 @@ CFILES = \ lockid.c \ backup_super.c \ feature_string.c\ - image.c + image.c \ + xattr.c HFILES = \ bitmap.h \ diff --git a/libocfs2/feature_string.c b/libocfs2/feature_string.c index 4dc6a19..e4b914c 100644 --- a/libocfs2/feature_string.c +++ b/libocfs2/feature_string.c @@ -59,7 +59,8 @@ static ocfs2_fs_options feature_level_defaults[] = { {OCFS2_FEATURE_COMPAT_BACKUP_SB, OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC | - OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP, + OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP | + OCFS2_FEATURE_INCOMPAT_XATTR, OCFS2_FEATURE_RO_COMPAT_UNWRITTEN}, /* OCFS2_FEATURE_LEVEL_MAX_FEATURES */ }; @@ -91,6 +92,12 @@ static struct fs_feature_flags ocfs2_supported_features[] = { {0, OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP, 0}, }, { + "xattr", + {0, OCFS2_FEATURE_INCOMPAT_XATTR, 0}, + {0, OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC | + OCFS2_FEATURE_INCOMPAT_XATTR, 0}, + }, + { NULL, {0, 0, 0}, {0, 0, 0} diff --git a/libocfs2/inode.c b/libocfs2/inode.c index d556b38..cf8323e 100644 --- a/libocfs2/inode.c +++ b/libocfs2/inode.c @@ -127,7 +127,10 @@ static void ocfs2_swap_inode_second(struct ocfs2_dinode *di) sb->s_blocksize_bits = bswap_32(sb->s_blocksize_bits); sb->s_clustersize_bits = bswap_32(sb->s_clustersize_bits); sb->s_max_slots = bswap_16(sb->s_max_slots); + sb->s_tunefs_flag = bswap_16(sb->s_tunefs_flag); + sb->s_uuid_hash = bswap_32(sb->s_uuid_hash); sb->s_first_cluster_group = bswap_64(sb->s_first_cluster_group); + sb->s_xattr_inline_size = bswap_16(sb->s_xattr_inline_size); } else if (di->i_flags & OCFS2_LOCAL_ALLOC_FL) { struct ocfs2_local_alloc *la = &di->id2.i_lab; @@ -156,6 +159,7 @@ static void ocfs2_swap_inode_first(struct ocfs2_dinode *di) di->i_generation = bswap_32(di->i_generation); di->i_suballoc_slot = bswap_16(di->i_suballoc_slot); di->i_suballoc_bit = bswap_16(di->i_suballoc_bit); + di->i_xattr_inline_size = bswap_16(di->i_xattr_inline_size); di->i_clusters = bswap_32(di->i_clusters); di->i_uid = bswap_32(di->i_uid); di->i_gid = bswap_32(di->i_gid); @@ -174,6 +178,9 @@ static void ocfs2_swap_inode_first(struct ocfs2_dinode *di) di->i_ctime_nsec = bswap_32(di->i_ctime_nsec); di->i_mtime_nsec = bswap_32(di->i_mtime_nsec); di->i_attr = bswap_32(di->i_attr); + di->i_orphaned_slot = bswap_16(di->i_orphaned_slot); + di->i_dyn_features = bswap_16(di->i_dyn_features); + di->i_xattr_loc = bswap_64(di->i_xattr_loc); } static int has_extents(struct ocfs2_dinode *di) diff --git a/libocfs2/xattr.c b/libocfs2/xattr.c new file mode 100644 index 0000000..d198743 --- /dev/null +++ b/libocfs2/xattr.c @@ -0,0 +1,37 @@ +/* -*- mode: c; c-basic-offset: 8; -*- + * vim: noexpandtab sw=8 ts=8 sts=0: + * + * Copyright (C) 2004 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. + * + * 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 <string.h> +#include <inttypes.h> + +#include "ocfs2/byteorder.h" +#include "ocfs2/ocfs2.h" + +uint32_t xattr_uuid_hash(unsigned char *uuid) +{ + uint32_t i, hash = 0; + + for (i = 0; i < OCFS2_VOL_UUID_LEN; i++) { + hash = (hash << OCFS2_HASH_SHIFT) ^ + (hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT)) ^ + *uuid++; + } + return hash; +} + diff --git a/mkfs.ocfs2/mkfs.c b/mkfs.ocfs2/mkfs.c index dce7cab..8ce5651 100644 --- a/mkfs.ocfs2/mkfs.c +++ b/mkfs.ocfs2/mkfs.c @@ -1876,6 +1876,12 @@ format_superblock(State *s, SystemFileDiskRecord *rec, */ s->feature_flags.opt_compat &= !OCFS2_FEATURE_COMPAT_BACKUP_SB; + if (s->feature_flags.opt_incompat & OCFS2_FEATURE_INCOMPAT_XATTR) { + di->id2.i_super.s_xattr_inline_size + OCFS2_MIN_XATTR_INLINE_SIZE; + di->id2.i_super.s_uuid_hash = xattr_uuid_hash(s->uuid); + } + di->id2.i_super.s_feature_incompat = s->feature_flags.opt_incompat; di->id2.i_super.s_feature_compat = s->feature_flags.opt_compat; di->id2.i_super.s_feature_ro_compat = s->feature_flags.opt_ro_compat; diff --git a/mkfs.ocfs2/mkfs.ocfs2.8.in b/mkfs.ocfs2/mkfs.ocfs2.8.in index 6b553f8..cd36eea 100644 --- a/mkfs.ocfs2/mkfs.ocfs2.8.in +++ b/mkfs.ocfs2/mkfs.ocfs2.8.in @@ -108,6 +108,11 @@ Enable support for sparse files. With this, \fIOCFS2\fR can avoid allocating (an \fBunwritten\fR Enable unwritten extents support. With this turned on, an application can request that a range of clusters be pre-allocated within a file. \fIOCFS2\fR will mark those extents with a special flag so that expensive data zeroing doesn't have to be performed. Reads and writes to a pre-allocated region act as reads and writes to a hole, except a write will not fail due to lack of data allocation. This feature requires \fBsparse\fR file support to be turned on. Available with the file system bundled with Linux kernels 2.6.23 and later. .RE +.RS 1.2i +.TP +\fBxattr\fR +Enable support for extended attribute. +.RE .TP \fB\-\-fs\-feature\-level=\fR\fR\fIfeature\-level\fR diff --git a/sizetest/sizetest.c b/sizetest/sizetest.c index 35d85f0..fff0787 100644 --- a/sizetest/sizetest.c +++ b/sizetest/sizetest.c @@ -137,10 +137,15 @@ static void print_ocfs2_super_block(void) SHOW_OFFSET(struct ocfs2_super_block, s_clustersize_bits); SHOW_OFFSET(struct ocfs2_super_block, s_max_slots); SHOW_OFFSET(struct ocfs2_super_block, s_tunefs_flag); - SHOW_OFFSET(struct ocfs2_super_block, s_reserved1); + SHOW_OFFSET(struct ocfs2_super_block, s_uuid_hash); SHOW_OFFSET(struct ocfs2_super_block, s_first_cluster_group); SHOW_OFFSET(struct ocfs2_super_block, s_label); SHOW_OFFSET(struct ocfs2_super_block, s_uuid); + SHOW_OFFSET(struct ocfs2_super_block, s_cluster_info); + SHOW_OFFSET(struct ocfs2_super_block, s_xattr_inline_size); + SHOW_OFFSET(struct ocfs2_super_block, s_reserved0); + SHOW_OFFSET(struct ocfs2_super_block, s_reserved1); + SHOW_OFFSET(struct ocfs2_super_block, s_reserved2); END_TYPE(struct ocfs2_super_block); printf("\n"); @@ -169,6 +174,7 @@ static void print_ocfs2_dinode(void) SHOW_OFFSET(struct ocfs2_dinode, i_suballoc_slot); SHOW_OFFSET(struct ocfs2_dinode, i_suballoc_bit); SHOW_OFFSET(struct ocfs2_dinode, i_reserved0); + SHOW_OFFSET(struct ocfs2_dinode, i_xattr_inline_size); SHOW_OFFSET(struct ocfs2_dinode, i_clusters); SHOW_OFFSET(struct ocfs2_dinode, i_uid); SHOW_OFFSET(struct ocfs2_dinode, i_gid); @@ -187,7 +193,9 @@ static void print_ocfs2_dinode(void) SHOW_OFFSET(struct ocfs2_dinode, i_ctime_nsec); SHOW_OFFSET(struct ocfs2_dinode, i_mtime_nsec); SHOW_OFFSET(struct ocfs2_dinode, i_attr); + SHOW_OFFSET(struct ocfs2_dinode, i_orphaned_slot); SHOW_OFFSET(struct ocfs2_dinode, i_dyn_features); + SHOW_OFFSET(struct ocfs2_dinode, i_xattr_loc); SHOW_OFFSET(struct ocfs2_dinode, i_reserved2); SHOW_OFFSET(struct ocfs2_dinode, id1.i_pad1); @@ -201,6 +209,8 @@ static void print_ocfs2_dinode(void) SHOW_OFFSET(struct ocfs2_dinode, id2.i_lab); SHOW_OFFSET(struct ocfs2_dinode, id2.i_chain); SHOW_OFFSET(struct ocfs2_dinode, id2.i_list); + SHOW_OFFSET(struct ocfs2_dinode, id2.i_dealloc); + SHOW_OFFSET(struct ocfs2_dinode, id2.i_data); SHOW_OFFSET(struct ocfs2_dinode, id2.i_symlink); END_TYPE(struct ocfs2_dinode); -- 1.5.4.4
Tiger Yang
2008-Jul-25 07:06 UTC
[Ocfs2-devel] [PATCH 2/2] ocfs2-tools: Add extended attribute support in fsck.ocfs2
This patch will check all extended attribute associated with each inode, mark all xattr block as used. Signed-off-by: Tiger Yang <tiger.yang at oracle.com> --- fsck.ocfs2/Makefile | 3 +- fsck.ocfs2/extent.c | 17 +-- fsck.ocfs2/include/extent.h | 13 ++ fsck.ocfs2/include/xattr.h | 29 +++ fsck.ocfs2/pass1.c | 18 ++- fsck.ocfs2/xattr.c | 420 +++++++++++++++++++++++++++++++++++++++ include/ocfs2-kernel/ocfs2_fs.h | 7 + include/ocfs2/ocfs2.h | 6 + libocfs2/extend_file.c | 4 +- libocfs2/extent_map.c | 2 +- libocfs2/ocfs2_err.et | 3 + libocfs2/xattr.c | 110 ++++++++++ 12 files changed, 609 insertions(+), 23 deletions(-) create mode 100644 fsck.ocfs2/include/xattr.h create mode 100644 fsck.ocfs2/xattr.c diff --git a/fsck.ocfs2/Makefile b/fsck.ocfs2/Makefile index b804f67..f60515c 100644 --- a/fsck.ocfs2/Makefile +++ b/fsck.ocfs2/Makefile @@ -30,7 +30,8 @@ CFILES = fsck.c \ pass4.c \ problem.c \ strings.c \ - util.c + util.c \ + xattr.c HFILES = include/fsck.h \ include/dirblocks.h \ diff --git a/fsck.ocfs2/extent.c b/fsck.ocfs2/extent.c index 665704d..5f6639c 100644 --- a/fsck.ocfs2/extent.c +++ b/fsck.ocfs2/extent.c @@ -46,19 +46,6 @@ static const char *whoami = "extent.c"; -struct extent_info { - uint64_t ei_max_size; - uint64_t ei_clusters; - uint64_t ei_last_eb_blk; - uint16_t ei_expected_depth; - unsigned ei_expect_depth:1; -}; - -static errcode_t check_el(o2fsck_state *ost, struct extent_info *ei, - struct ocfs2_dinode *di, - struct ocfs2_extent_list *el, - uint16_t max_recs, int *changed); - static errcode_t check_eb(o2fsck_state *ost, struct extent_info *ei, struct ocfs2_dinode *di, uint64_t blkno, int *is_valid) @@ -233,7 +220,7 @@ out: return ret; } -static errcode_t check_el(o2fsck_state *ost, struct extent_info *ei, +errcode_t check_el(o2fsck_state *ost, struct extent_info *ei, struct ocfs2_dinode *di, struct ocfs2_extent_list *el, uint16_t max_recs, int *changed) @@ -373,4 +360,4 @@ errcode_t o2fsck_check_extents(o2fsck_state *ost, o2fsck_write_inode(ost, di->i_blkno, di); return ret; -} +} diff --git a/fsck.ocfs2/include/extent.h b/fsck.ocfs2/include/extent.h index 6fff28b..1266b7f 100644 --- a/fsck.ocfs2/include/extent.h +++ b/fsck.ocfs2/include/extent.h @@ -22,8 +22,21 @@ #include "fsck.h" +struct extent_info { + uint64_t ei_max_size; + uint64_t ei_clusters; + uint64_t ei_last_eb_blk; + uint16_t ei_expected_depth; + unsigned ei_expect_depth:1; +}; + errcode_t o2fsck_check_extents(o2fsck_state *ost, struct ocfs2_dinode *di); +errcode_t check_el(o2fsck_state *ost, struct extent_info *ei, + struct ocfs2_dinode *di, + struct ocfs2_extent_list *el, + uint16_t max_recs, int *changed); + #endif /* __O2FSCK_EXTENT_H__ */ diff --git a/fsck.ocfs2/include/xattr.h b/fsck.ocfs2/include/xattr.h new file mode 100644 index 0000000..49ad945 --- /dev/null +++ b/fsck.ocfs2/include/xattr.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2002 Oracle Corporation. 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 as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * 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. + */ + +#ifndef __O2FSCK_XATTR_H__ +#define __O2FSCK_XATTR_H__ + +#include "fsck.h" + +errcode_t o2fsck_check_xattr(o2fsck_state *ost, + struct ocfs2_dinode *di); + +#endif /* __O2FSCK_XATTR_H__ */ + diff --git a/fsck.ocfs2/pass1.c b/fsck.ocfs2/pass1.c index 70611b4..471a0be 100644 --- a/fsck.ocfs2/pass1.c +++ b/fsck.ocfs2/pass1.c @@ -59,6 +59,7 @@ #include "dirblocks.h" #include "dirparents.h" +#include "xattr.h" #include "extent.h" #include "icount.h" #include "fsck.h" @@ -758,13 +759,22 @@ static errcode_t o2fsck_check_blocks(ocfs2_filesys *fs, o2fsck_state *ost, .vb_di = di, }; + if (di->i_flags & (OCFS2_SUPER_BLOCK_FL | OCFS2_LOCAL_ALLOC_FL | + OCFS2_BITMAP_FL | OCFS2_CHAIN_FL | + OCFS2_DEALLOC_FL)) + return 0; + + ret = o2fsck_check_xattr(ost, di); + if (ret) { + com_err(whoami, ret, "while iterating over the xattr blocks " + "for inode %"PRIu64, di->i_blkno); + goto out; + } + /* don't bother to verify for inodes that don't have i_list, * we have to trust i_mode/i_clusters to tell us that a symlink * has put target data in the union instead of i_list */ - if ((di->i_flags & (OCFS2_SUPER_BLOCK_FL | OCFS2_LOCAL_ALLOC_FL | - OCFS2_BITMAP_FL | OCFS2_CHAIN_FL | - OCFS2_DEALLOC_FL)) || - (S_ISLNK(di->i_mode) && di->i_clusters == 0)) + if (S_ISLNK(di->i_mode) && di->i_clusters == 0) return 0; ret = o2fsck_check_extents(ost, di); diff --git a/fsck.ocfs2/xattr.c b/fsck.ocfs2/xattr.c new file mode 100644 index 0000000..15fa934 --- /dev/null +++ b/fsck.ocfs2/xattr.c @@ -0,0 +1,420 @@ +/* -*- mode: c; c-basic-offset: 8; -*- + * vim: noexpandtab sw=8 ts=8 sts=0: + * + * Copyright (C) 2004 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. + * + * 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 <string.h> +#include <inttypes.h> + +#include "ocfs2/byteorder.h" +#include "ocfs2/ocfs2.h" + +#include "xattr.h" +#include "extent.h" +#include "fsck.h" +#include "problem.h" +#include "util.h" + +static const char *whoami = "xattr.c"; + +static inline int ocfs2_xattr_extent_recs_per_inode(int blocksize) +{ + int size; + + size = blocksize - offsetof(struct ocfs2_xattr_block, + xb_attrs.xb_root.xt_list.l_recs); + + return (size / sizeof(struct ocfs2_extent_rec)); +} + +static inline uint16_t ocfs2_xattr_buckets_per_cluster(ocfs2_filesys *fs) +{ + return (fs->fs_clustersize / OCFS2_XATTR_BUCKET_SIZE); +} + +static inline uint16_t ocfs2_blocks_per_xattr_bucket(ocfs2_filesys *fs) +{ + return (OCFS2_XATTR_BUCKET_SIZE / fs->fs_blocksize); +} + +static errcode_t check_xattr(o2fsck_state *ost, + struct ocfs2_dinode *di, + struct ocfs2_xattr_header *xh, + int *changed) +{ + struct extent_info ei = {0, }; + int i; + errcode_t ret = 0; + + for (i = 0 ; i < xh->xh_count; i++) { + int change = 0; + struct ocfs2_xattr_entry *xe = &xh->xh_entries[i]; + + if (!xe->xe_local) { + struct ocfs2_xattr_value_root *xv + (struct ocfs2_xattr_value_root *) + ((void *)xh + xe->xe_name_offset + + OCFS2_XATTR_SIZE(xe->xe_name_len)); + struct ocfs2_extent_list *el = &xv->xr_list; + ret = check_el(ost, &ei, di, el, 1, &change); + if (ret) + break; + if (change) { + *changed = 1; + ocfs2_swap_extent_list_from_cpu(el); + } + } + } + + return ret; +} + +static errcode_t ocfs2_read_xattr_block(ocfs2_filesys *fs, + uint64_t blkno, + char *xb_buf) +{ + errcode_t ret = 0; + char *blk; + struct ocfs2_xattr_block *xb; + + if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) || + (blkno > fs->fs_blocks)) + return OCFS2_ET_BAD_BLKNO; + + ret = ocfs2_malloc_block(fs->fs_io, &blk); + if (ret) + return ret; + + ret = io_read_block(fs->fs_io, blkno, 1, blk); + if (ret) + goto out; + + xb = (struct ocfs2_xattr_block *)blk; + + if (memcmp(xb->xb_signature, OCFS2_XATTR_BLOCK_SIGNATURE, + strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { + ret = OCFS2_ET_BAD_XATTR_BLOCK_MAGIC; + goto out; + } + + memcpy(xb_buf, blk, fs->fs_blocksize); + + xb = (struct ocfs2_xattr_block *)xb_buf; + ocfs2_swap_xattr_block_to_cpu(xb); + +out: + ocfs2_free(&blk); + + return ret; +} + + +static errcode_t ocfs2_write_xattr_block(ocfs2_filesys *fs, + uint64_t blkno, + char *xb_buf) +{ + errcode_t ret = 0; + char *blk; + struct ocfs2_xattr_block *xb; + + if (!(fs->fs_flags & OCFS2_FLAG_RW)) + return OCFS2_ET_RO_FILESYS; + + if ((blkno < OCFS2_SUPER_BLOCK_BLKNO) || + (blkno > fs->fs_blocks)) + return OCFS2_ET_BAD_BLKNO; + + ret = ocfs2_malloc_block(fs->fs_io, &blk); + if (ret) + return ret; + + memcpy(blk, xb_buf, fs->fs_blocksize); + + xb = (struct ocfs2_xattr_block *)blk; + ocfs2_swap_xattr_block_from_cpu(xb); + + ret = io_write_block(fs->fs_io, blkno, 1, blk); + if (ret) + goto out; + + fs->fs_flags |= OCFS2_FLAG_CHANGED; + ret = 0; + +out: + ocfs2_free(&blk); + + return ret; +} + +static errcode_t ocfs2_xattr_get_rec(o2fsck_state *ost, + struct ocfs2_dinode *di, + uint32_t name_hash, + uint64_t *p_blkno, + uint32_t *e_cpos, + uint32_t *num_clusters, + struct ocfs2_extent_list *el) +{ + int i; + errcode_t ret = 0; + char *eb_buf = NULL; + struct ocfs2_extent_block *eb; + struct ocfs2_extent_rec *rec = NULL; + uint64_t e_blkno = 0; + + if (el->l_tree_depth) { + ret = ocfs2_find_leaf(ost->ost_fs, di, el, name_hash, &eb_buf); + if (ret) { + com_err(whoami, ret, "while finding leaf of xattr " + "tree"); + goto out; + } + + eb = (struct ocfs2_extent_block *) eb_buf; + el = &eb->h_list; + + if (el->l_tree_depth) { + ret = -1; + goto out; + } + } + + for (i = le16_to_cpu(el->l_next_free_rec) - 1; i >= 0; i--) { + rec = &el->l_recs[i]; + + if (le32_to_cpu(rec->e_cpos) <= name_hash) { + e_blkno = le64_to_cpu(rec->e_blkno); + break; + } + } + + if (!e_blkno) { + ret = -1; + goto out; + } + + *p_blkno = le64_to_cpu(rec->e_blkno); + *num_clusters = le16_to_cpu(rec->e_leaf_clusters); + if (e_cpos) + *e_cpos = le32_to_cpu(rec->e_cpos); +out: + if (eb_buf) + ocfs2_free(&eb_buf); + return ret; +} + +static errcode_t ocfs2_iterate_xattr_buckets(o2fsck_state *ost, + struct ocfs2_dinode *di, + uint64_t blkno, + uint32_t clusters) +{ + int i; + errcode_t ret = 0; + char *bucket = NULL; + struct ocfs2_xattr_header *xh; + int block_num = ocfs2_blocks_per_xattr_bucket(ost->ost_fs); + uint32_t bpc = ocfs2_xattr_buckets_per_cluster(ost->ost_fs); + uint32_t bucket_num = clusters * bpc; + char *bhs = NULL; + + + ret = ocfs2_malloc_blocks(ost->ost_fs->fs_io, block_num, &bhs); + if (ret) { + com_err(whoami, ret, "while allocating room to read bucket " + "of xattr data"); + goto out; + } + + for (i = 0; i < bucket_num; i++, blkno += block_num) { + int changed = 0; + + ret = io_read_block(ost->ost_fs->fs_io, blkno, block_num, bhs); + if (ret) { + com_err(whoami, ret, "while reading blocks of xattr " + "bucket"); + goto out; + } + + bucket = bhs; + + xh = (struct ocfs2_xattr_header *)bucket; + ocfs2_swap_xattr_header(xh); + ocfs2_swap_xattr_entries_to_cpu(xh); + /* + * The real bucket num in this series of blocks is stored + * in the 1st bucket. + */ + if (i == 0) + bucket_num = le16_to_cpu(xh->xh_reserved1); + + ret = check_xattr(ost, di, xh, &changed); + if (ret) + break; + if (changed) { + ocfs2_swap_xattr_entries_from_cpu(xh); + ocfs2_swap_xattr_header(xh); + io_write_block(ost->ost_fs->fs_io, blkno, block_num, + bhs); + } + } +out: + ocfs2_free(&bhs); + + return ret; +} + +static errcode_t o2fsck_check_xattr_index_block( + o2fsck_state *ost, + struct ocfs2_dinode *di, + struct ocfs2_xattr_tree_root *xt, + int *changed) +{ + struct ocfs2_extent_list *el = &xt->xt_list; + errcode_t ret = 0; + uint32_t name_hash = UINT_MAX, e_cpos = 0, num_clusters = 0; + uint64_t p_blkno = 0; + struct extent_info ei = {0, }; + + if (el->l_next_free_rec == 0) + return 0; + + ret = check_el(ost, &ei, di, el, + ocfs2_xattr_extent_recs_per_inode(ost->ost_fs->fs_blocksize), + changed); + if (ret) + return ret; + + while (name_hash > 0) { + ret = ocfs2_xattr_get_rec(ost, di, name_hash, &p_blkno, + &e_cpos, &num_clusters, el); + if (ret) { + com_err(whoami, ret, "while getting bucket record " + "of xattr data."); + goto out; + } + + ret = ocfs2_iterate_xattr_buckets(ost, di, p_blkno, + num_clusters); + if (ret) { + com_err(whoami, ret, "while iterating buckets " + "of xattr data."); + goto out; + } + + if (e_cpos == 0) + break; + + name_hash = e_cpos - 1; + } + if (*changed) + ocfs2_swap_extent_list_from_cpu(el); + +out: + return ret; +} + +static errcode_t o2fsck_check_xattr_ibody(o2fsck_state *ost, + struct ocfs2_dinode *di) +{ + errcode_t ret; + struct ocfs2_xattr_header *xh = NULL; + int changed = 0; + + xh = (struct ocfs2_xattr_header *) + ((void *)di + ost->ost_fs->fs_blocksize - + di->i_xattr_inline_size); + + ocfs2_swap_xattr_header(xh); + ocfs2_swap_xattr_entries_to_cpu(xh); + + ret = check_xattr(ost, di, xh, &changed); + + if (changed) { + ocfs2_swap_xattr_entries_from_cpu(xh); + ocfs2_swap_xattr_header(xh); + o2fsck_write_inode(ost, di->i_blkno, di); + } + return ret; +} + +static errcode_t o2fsck_check_xattr_block(o2fsck_state *ost, + struct ocfs2_dinode *di) +{ + errcode_t ret; + char *blk = NULL; + struct ocfs2_xattr_block *xb = NULL; + int changed = 0; + + o2fsck_mark_cluster_allocated(ost, + ocfs2_blocks_to_clusters(ost->ost_fs, di->i_xattr_loc)); + + ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &blk); + if (ret) { + com_err(whoami, ret, "while allocating room to read block " + "of xattr."); + return ret; + } + + ret = ocfs2_read_xattr_block(ost->ost_fs, di->i_xattr_loc, blk); + if (ret) { + com_err(whoami, ret, "while reading externel block of xattr."); + return ret; + } + + xb = (struct ocfs2_xattr_block *)blk; + + if (!(xb->xb_flags & OCFS2_XATTR_INDEXED)) { + struct ocfs2_xattr_header *xh = &xb->xb_attrs.xb_header; + + ret = check_xattr(ost, di, xh, &changed); + } else { + struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root; + + ret = o2fsck_check_xattr_index_block(ost, di, xt, &changed); + } + + if (changed) + ocfs2_write_xattr_block(ost->ost_fs, di->i_xattr_loc, blk); + + if (blk) + ocfs2_free(&blk); + + return ret; +} + +/* + * o2fsck_check_xattr + * + * Check extended attribute in inode block or external block. + */ +errcode_t o2fsck_check_xattr(o2fsck_state *ost, + struct ocfs2_dinode *di) +{ + errcode_t ret = 0; + + if (!(di->i_dyn_features & OCFS2_HAS_XATTR_FL)) + return 0; + + if (di->i_dyn_features & OCFS2_HAS_XATTR_FL) { + ret = o2fsck_check_xattr_ibody(ost, di); + if (ret) + return ret; + } + if (di->i_xattr_loc) + ret = o2fsck_check_xattr_block(ost, di); + + return ret; +} diff --git a/include/ocfs2-kernel/ocfs2_fs.h b/include/ocfs2-kernel/ocfs2_fs.h index ade9ec1..ee44be8 100644 --- a/include/ocfs2-kernel/ocfs2_fs.h +++ b/include/ocfs2-kernel/ocfs2_fs.h @@ -728,6 +728,13 @@ struct ocfs2_group_desc /* Inline extended attribute size (in bytes) */ #define OCFS2_MIN_XATTR_INLINE_SIZE 256 +#define OCFS2_XATTR_BUCKET_SIZE 4096 + +#define OCFS2_XATTR_ROUND 3 + +#define OCFS2_XATTR_SIZE(size) (((size) + OCFS2_XATTR_ROUND) & \ + ~(OCFS2_XATTR_ROUND)) + struct ocfs2_xattr_entry { __le32 xe_name_hash; __le16 xe_name_offset; diff --git a/include/ocfs2/ocfs2.h b/include/ocfs2/ocfs2.h index 1f81c47..6aadd46 100644 --- a/include/ocfs2/ocfs2.h +++ b/include/ocfs2/ocfs2.h @@ -291,6 +291,7 @@ errcode_t ocfs2_get_clusters(ocfs2_cached_inode *cinode, uint32_t *num_clusters, uint16_t *extent_flags); int ocfs2_find_leaf(ocfs2_filesys *fs, struct ocfs2_dinode *di, + struct ocfs2_extent_list *el, uint32_t cpos, char **leaf_buf); int ocfs2_search_extent_list(struct ocfs2_extent_list *el, uint32_t v_cluster); void ocfs2_swap_journal_superblock(journal_superblock_t *jsb); @@ -942,5 +943,10 @@ errcode_t ocfs2_block_iterate_inode(ocfs2_filesys *fs, void *priv_data); uint32_t xattr_uuid_hash(unsigned char *uuid); +void ocfs2_swap_xattr_entries_to_cpu(struct ocfs2_xattr_header *xh); +void ocfs2_swap_xattr_entries_from_cpu(struct ocfs2_xattr_header *xh); +void ocfs2_swap_xattr_header(struct ocfs2_xattr_header *xh); +void ocfs2_swap_xattr_block_from_cpu(struct ocfs2_xattr_block *xb); +void ocfs2_swap_xattr_block_to_cpu(struct ocfs2_xattr_block *xb); #endif /* _FILESYS_H */ diff --git a/libocfs2/extend_file.c b/libocfs2/extend_file.c index 1cb4a00..4cc7a94 100644 --- a/libocfs2/extend_file.c +++ b/libocfs2/extend_file.c @@ -997,16 +997,16 @@ static int ocfs2_find_path(ocfs2_filesys *fs, struct ocfs2_path *path, * This function doesn't handle non btree extent lists. */ int ocfs2_find_leaf(ocfs2_filesys *fs, struct ocfs2_dinode *di, + struct ocfs2_extent_list *el, uint32_t cpos, char **leaf_buf) { int ret; char *buf = NULL; struct ocfs2_path *path = NULL; - struct ocfs2_extent_list *el = &di->id2.i_list; assert(el->l_tree_depth > 0); - path = ocfs2_new_inode_path(fs, di); + path = ocfs2_new_path(fs, (char *)di, el); if (!path) { ret = OCFS2_ET_NO_MEMORY; goto out; diff --git a/libocfs2/extent_map.c b/libocfs2/extent_map.c index 7e5f8fe..dd081fc 100644 --- a/libocfs2/extent_map.c +++ b/libocfs2/extent_map.c @@ -147,7 +147,7 @@ errcode_t ocfs2_get_clusters(ocfs2_cached_inode *cinode, el = &di->id2.i_list; if (el->l_tree_depth) { - ret = ocfs2_find_leaf(fs, di, v_cluster, &eb_buf); + ret = ocfs2_find_leaf(fs, di, el, v_cluster, &eb_buf); if (ret) goto out; diff --git a/libocfs2/ocfs2_err.et b/libocfs2/ocfs2_err.et index 9b33a3b..88b3366 100644 --- a/libocfs2/ocfs2_err.et +++ b/libocfs2/ocfs2_err.et @@ -171,4 +171,7 @@ ec OCFS2_ET_NO_BACKUP_SUPER, ec OCFS2_ET_TOO_MANY_SLOTS, "Too many slots for slot map" +ec OCFS2_ET_BAD_XATTR_BLOCK_MAGIC, + "Bad magic number in xattr block" + end diff --git a/libocfs2/xattr.c b/libocfs2/xattr.c index d198743..767b333 100644 --- a/libocfs2/xattr.c +++ b/libocfs2/xattr.c @@ -35,3 +35,113 @@ uint32_t xattr_uuid_hash(unsigned char *uuid) return hash; } +static void ocfs2_swap_xattr_tree_root(struct ocfs2_xattr_tree_root *xt) +{ + xt->xt_clusters = bswap_16(xt->xt_clusters); + xt->xt_last_eb_blk = bswap_16(xt->xt_last_eb_blk); +} + +static void ocfs2_swap_xattr_value_root(struct ocfs2_xattr_value_root *xr) +{ + xr->xr_clusters = bswap_16(xr->xr_clusters); + xr->xr_last_eb_blk = bswap_16(xr->xr_last_eb_blk); +} + +static void ocfs2_swap_xattr_block_header(struct ocfs2_xattr_block *xb) +{ + xb->xb_suballoc_slot = bswap_16(xb->xb_suballoc_slot); + xb->xb_suballoc_bit = bswap_16(xb->xb_suballoc_bit); + xb->xb_fs_generation = bswap_32(xb->xb_fs_generation); + xb->xb_csum = bswap_32(xb->xb_csum); + xb->xb_flags = bswap_16(xb->xb_flags); + xb->xb_blkno = bswap_64(xb->xb_blkno); +} + +void ocfs2_swap_xattr_entries_to_cpu(struct ocfs2_xattr_header *xh) +{ + uint16_t i; + + if (cpu_is_little_endian) + return; + + for (i = 0; i < xh->xh_count; i++) { + struct ocfs2_xattr_entry *xe = &xh->xh_entries[i]; + + xe->xe_name_offset = bswap_16(xe->xe_name_offset); + xe->xe_value_size = bswap_64(xe->xe_value_size); + + if (!xe->xe_local) { + struct ocfs2_xattr_value_root *xr + (struct ocfs2_xattr_value_root *) + ((char *)xh + xe->xe_name_offset + + OCFS2_XATTR_SIZE(xe->xe_name_len)); + + ocfs2_swap_xattr_value_root(xr); + ocfs2_swap_extent_list_to_cpu(&xr->xr_list); + } + } +} + +void ocfs2_swap_xattr_entries_from_cpu(struct ocfs2_xattr_header *xh) +{ + uint16_t i; + + if (cpu_is_little_endian) + return; + + for (i = 0; i < xh->xh_count; i++) { + struct ocfs2_xattr_entry *xe = &xh->xh_entries[i]; + + if (!xe->xe_local) { + struct ocfs2_xattr_value_root *xr + (struct ocfs2_xattr_value_root *) + ((char *)xh + xe->xe_name_offset + + OCFS2_XATTR_SIZE(xe->xe_name_len)); + + ocfs2_swap_xattr_value_root(xr); + } + xe->xe_name_offset = bswap_16(xe->xe_name_offset); + xe->xe_value_size = bswap_64(xe->xe_value_size); + } +} + +void ocfs2_swap_xattr_header(struct ocfs2_xattr_header *xh) +{ + if (cpu_is_little_endian) + return; + + xh->xh_count = bswap_16(xh->xh_count); + xh->xh_reserved1 = bswap_16(xh->xh_reserved1); + xh->xh_csum = bswap_32(xh->xh_csum); +} + +void ocfs2_swap_xattr_block_from_cpu(struct ocfs2_xattr_block *xb) +{ + if (cpu_is_little_endian) + return; + + if (!(xb->xb_flags & OCFS2_XATTR_INDEXED)) { + ocfs2_swap_xattr_entries_from_cpu(&xb->xb_attrs.xb_header); + ocfs2_swap_xattr_header(&xb->xb_attrs.xb_header); + } else { + ocfs2_swap_xattr_tree_root(&xb->xb_attrs.xb_root); + } + + ocfs2_swap_xattr_block_header(xb); +} + +void ocfs2_swap_xattr_block_to_cpu(struct ocfs2_xattr_block *xb) +{ + if (cpu_is_little_endian) + return; + + ocfs2_swap_xattr_block_header(xb); + if (!(xb->xb_flags & OCFS2_XATTR_INDEXED)) { + ocfs2_swap_xattr_header(&xb->xb_attrs.xb_header); + ocfs2_swap_xattr_entries_to_cpu(&xb->xb_attrs.xb_header); + } else { + ocfs2_swap_xattr_tree_root(&xb->xb_attrs.xb_root); + ocfs2_swap_extent_list_to_cpu(&xb->xb_attrs.xb_root.xt_list); + } +} + -- 1.5.4.4
Joel Becker
2008-Jul-25 09:33 UTC
[Ocfs2-devel] [PATCH 1/2] ocfs2-tools: Add extended attribute support in mkfs.ocfs2
On Fri, Jul 25, 2008 at 03:06:38PM +0800, Tiger Yang wrote:> diff --git a/include/ocfs2-kernel/ocfs2_fs.h b/include/ocfs2-kernel/ocfs2_fs.h > index 0cfef2a..ade9ec1 100644 > --- a/include/ocfs2-kernel/ocfs2_fs.h > +++ b/include/ocfs2-kernel/ocfs2_fs.hYou've got an ancient version of the xattr ocfs2_fs.h here.> +struct ocfs2_xattr_entry { > + __le32 xe_name_hash; > + __le16 xe_name_offset; > + __u8 xe_name_len; > + __u8 xe_type : 7; > + __u8 xe_local : 1; > + __le64 xe_value_size; > +};We removed the bitfields.> +struct ocfs2_xattr_block { > +/*00*/ __u8 xb_signature[8]; > + __le16 xb_suballoc_slot; > + __le16 xb_suballoc_bit; > + __le32 xb_fs_generation; > +/*10*/ __le32 xb_csum; > + __le16 xb_flags; > + __le16 xb_reserved0; > + __le64 xb_blkno; > +/*20*/ __le64 xb_reserved1[2]; > +/*30*/ union { > + struct ocfs2_xattr_header xb_header; > + struct ocfs2_xattr_tree_root xb_root; > + } xb_attrs; > +};This got shuffled around for a 64bit checksum field. Etc. Can you sync up with Tao? Joel -- "The nice thing about egotists is that they don't talk about other people." - Lucille S. Harper Joel Becker Principal Software Developer Oracle E-mail: joel.becker at oracle.com Phone: (650) 506-8127
Tiger Yang
2008-Jul-29 05:49 UTC
[Ocfs2-devel] [PATCH 1/2] ocfs2-tools: Add extended attribute support in mkfs.ocfs2
Joel Becker wrote:>> +struct ocfs2_xattr_entry { >> + __le32 xe_name_hash; >> + __le16 xe_name_offset; >> + __u8 xe_name_len; >> + __u8 xe_type : 7; >> + __u8 xe_local : 1; >> + __le64 xe_value_size; >> +}; > > We removed the bitfields.Do we really remove the bitfields? We have no space for new u8 in xattr_entry. Mark said we just need change the bottom bit for xe_local.> > This got shuffled around for a 64bit checksum field. Etc. Can > you sync up with Tao? >sure. I will sync up those data struct with Tao. Thanks, tiger
Tao Ma
2008-Jul-29 07:09 UTC
[Ocfs2-devel] [PATCH 1/2] ocfs2-tools: Add extended attribute support in mkfs.ocfs2
Tiger Yang wrote:> Joel Becker wrote: > >>> +struct ocfs2_xattr_entry { >>> + __le32 xe_name_hash; >>> + __le16 xe_name_offset; >>> + __u8 xe_name_len; >>> + __u8 xe_type : 7; >>> + __u8 xe_local : 1; >>> + __le64 xe_value_size; >>> +}; >> We removed the bitfields. > > Do we really remove the bitfields? We have no space for new u8 in > xattr_entry. > Mark said we just need change the bottom bit for xe_local.Yes, tiger may be right. Here is the original mail link. http://oss.oracle.com/pipermail/ocfs2-devel/2008-July/002489.html FYI. Regards, Tao