#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) \
| OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC \
| OCFS2_FEATURE_INCOMPAT_INLINE_DATA \
| 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
/*
/* 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
*/
#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.
*/
#define OCFS2_DEFAULT_LOCAL_ALLOC_SIZE 8
+/*
+ * Inline extended attribute size (in bytes)
+ * The value chosen should be aligned to 16 byte boundaries.
+ */
+#define OCFS2_MIN_XATTR_INLINE_SIZE 256
+
struct ocfs2_system_inode_info {
char *si_name;
int si_iflags;
/*40*/ __le16 s_max_slots; /* Max number of simultaneous mounts
before tunefs required */
__le16 s_tunefs_flag;
- __le32 s_reserved1;
+ __le32 s_uuid_hash; /* hash value of uuid */
__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. */
/*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*/
/*
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 */
__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 */
/*40*/ __u8 bg_bitmap[0];
};
+/*
+ * On disk extended attribute structure for OCFS2.
+ */
+
+/*
+ * ocfs2_xattr_entry indicates one extend attribute.
+ *
+ * Note that it can be stored in inode, one block or one xattr bucket.
+ */
+struct ocfs2_xattr_entry {
+ __le32 xe_name_hash; /* hash value of xattr prefix+suffix. */
+ __le16 xe_name_offset; /* byte offset from the 1st etnry in the local
+ local xattr storage(inode, xattr block or
+ xattr bucket). */
+ __u8 xe_name_len; /* xattr name len, does't include prefix. */
+ __u8 xe_type; /* the low 7 bits indicates the name prefix's
+ * type and the highest 1 bits indicate whether
+ * the EA is stored in the local storage. */
+ __le64 xe_value_size; /* real xattr value length. */
+};
+
+/*
+ * On disk structure for xattr header.
+ *
+ * One ocfs2_xattr_header describes how many ocfs2_xattr_entry records in
+ * the local xattr storage.
+ */
+struct ocfs2_xattr_header {
+ __le16 xh_count; /* contains the count of how
+ many records are in the
+ local xattr storage. */
+ __le16 xh_free_start; /* current offset for storing
+ xattr. */
+ __le16 xh_name_value_len; /* total length of name/value
+ length in this bucket. */
+ __le16 xh_num_buckets; /* bucket nums in one extent
+ record, only valid in the
+ first bucket. */
+ __le64 xh_csum;
+ struct ocfs2_xattr_entry xh_entries[0]; /* xattr entry list. */
+};
+
+/*
+ * On disk structure for xattr value root.
+ *
+ * It is used when one extended attribute's size is larger, and we will save it
+ * in an outside cluster. It will stored in a b-tree like file content.
+ */
+struct ocfs2_xattr_value_root {
+/*00*/ __le32 xr_clusters; /* clusters covered by xattr value. */
+ __le32 xr_reserved0;
+ __le64 xr_last_eb_blk; /* Pointer to last extent block */
+/*10*/ struct ocfs2_extent_list xr_list; /* Extent record list */
+};
+
+/*
+ * On disk structure for xattr tree root.
+ *
+ * It is used when there are too many extended attributes for one file. These
+ * attributes will be organized and stored in an indexed-btree.
+ */
+struct ocfs2_xattr_tree_root {
+/*00*/ __le32 xt_clusters; /* clusters covered by xattr. */
+ __le32 xt_reserved0;
+ __le64 xt_last_eb_blk; /* Pointer to last extent block */
+/*10*/ struct ocfs2_extent_list xt_list; /* Extent record list */
+};
+
+#define OCFS2_XATTR_INDEXED 0x1
+#define OCFS2_HASH_SHIFT 5
+#define OCFS2_XATTR_ROUND 3
+#define OCFS2_XATTR_SIZE(size) (((size) + OCFS2_XATTR_ROUND) & \
+ ~(OCFS2_XATTR_ROUND))
+
+#define OCFS2_XATTR_BUCKET_SIZE 4096
+#define OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET (OCFS2_XATTR_BUCKET_SIZE \
+ / OCFS2_MIN_BLOCKSIZE)
+
+/*
+ * On disk structure for xattr block.
+ */
+struct ocfs2_xattr_block {
+/*00*/ __u8 xb_signature[8]; /* Signature for verification */
+ __le16 xb_suballoc_slot; /* Slot suballocator this
+ block belongs to. */
+ __le16 xb_suballoc_bit; /* Bit offset in suballocator
+ block group */
+ __le32 xb_fs_generation; /* Must match super block */
+/*10*/ __le64 xb_blkno; /* Offset on disk, in blocks */
+ __le64 xb_csum;
+/*20*/ __le16 xb_flags; /* Indicates whether this block contains
+ real xattr or a xattr tree. */
+ __le16 xb_reserved0;
+ __le32 xb_reserved1;
+ __le64 xb_reserved2;
+/*30*/ union {
+ struct ocfs2_xattr_header xb_header; /* xattr header if this
+ block contains xattr */
+ struct ocfs2_xattr_tree_root xb_root;/* xattr tree root if this
+ block cotains xattr
+ tree. */
+ } xb_attrs;
+};
+
+#define OCFS2_XATTR_ENTRY_LOCAL 0x80
+#define OCFS2_XATTR_TYPE_MASK 0x7F
+static inline void ocfs2_xattr_set_local(struct ocfs2_xattr_entry *xe,
+ int local)
+{
+ if (local)
+ xe->xe_type |= OCFS2_XATTR_ENTRY_LOCAL;
+ else
+ xe->xe_type &= ~OCFS2_XATTR_ENTRY_LOCAL;
+}
+
+static inline int ocfs2_xattr_is_local(struct ocfs2_xattr_entry *xe)
+{
+ return xe->xe_type & OCFS2_XATTR_ENTRY_LOCAL;
+}
+
+static inline void ocfs2_xattr_set_type(struct ocfs2_xattr_entry *xe, int type)
+{
+ xe->xe_type |= type & OCFS2_XATTR_TYPE_MASK;
+}
+
+static inline int ocfs2_xattr_get_type(struct ocfs2_xattr_entry *xe)
+{
+ return xe->xe_type & OCFS2_XATTR_TYPE_MASK;
+}
+
#ifdef __KERNEL__
static inline int ocfs2_fast_symlink_chars(struct super_block *sb)
{
offsetof(struct ocfs2_dinode, id2.i_data.id_data);
}
+static inline int ocfs2_max_inline_data_with_xattr(struct super_block *sb,
+ struct ocfs2_dinode *di)
+{
+ unsigned int xattrsize = le16_to_cpu(di->i_xattr_inline_size);
+
+ if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_XATTR_FL)
+ return sb->s_blocksize -
+ offsetof(struct ocfs2_dinode, id2.i_data.id_data) -
+ xattrsize;
+ else
+ return sb->s_blocksize -
+ offsetof(struct ocfs2_dinode, id2.i_data.id_data);
+}
+
static inline int ocfs2_extent_recs_per_inode(struct super_block *sb)
{
int size;
return size / sizeof(struct ocfs2_extent_rec);
}
+static inline int ocfs2_extent_recs_per_inode_with_xattr(
+ struct super_block *sb,
+ struct ocfs2_dinode *di)
+{
+ int size;
+ unsigned int xattrsize = le16_to_cpu(di->i_xattr_inline_size);
+
+ if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_XATTR_FL)
+ size = sb->s_blocksize -
+ offsetof(struct ocfs2_dinode, id2.i_list.l_recs) -
+ xattrsize;
+ else
+ size = sb->s_blocksize -
+ offsetof(struct ocfs2_dinode, id2.i_list.l_recs);
+
+ return size / sizeof(struct ocfs2_extent_rec);
+}
+
static inline int ocfs2_chain_recs_per_inode(struct super_block *sb)
{
int size;
return 0;
}
+
+static inline u16 ocfs2_xattr_recs_per_xb(struct super_block *sb)
+{
+ int size;
+
+ size = sb->s_blocksize -
+ offsetof(struct ocfs2_xattr_block,
+ xb_attrs.xb_root.xt_list.l_recs);
+
+ return size / sizeof(struct ocfs2_extent_rec);
+}
#else
static inline int ocfs2_fast_symlink_chars(int blocksize)
{
return 0;
}
+
+static inline int ocfs2_xattr_recs_per_xb(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);
+}
#endif /* __KERNEL__ */