ocfs2: Add the basic xattr disk layout in ocfs2_fs.h
Tao Ma [Mon, 18 Aug 2008 09:38:46 +0000 (17:38 +0800)]
Ocfs2 uses a very flexible structure for storing extended attributes on
disk. Small amount of attributes are stored directly in the inode block - up
to 256 bytes worth. If that fills up, attributes are also stored in an
external block, linked to from the inode block. That block can in turn
expand to a btree, capable of storing large numbers of attributes.

Individual attribute values are stored inline if they're small enough
(currently about 80 bytes, this can be changed though), and otherwise are
expanded to a btree. The theoretical limit to the size of an individual
attribute is about the same as an inode, though the kernel's upper bound on
the size of an attributes data is far smaller.

Signed-off-by: Tao Ma <tao.ma@oracle.com>
Signed-off-by: Mark Fasheh <mfasheh@suse.com>

fs/ocfs2/ocfs2_fs.h

index 4f61985..1b46505 100644 (file)
@@ -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)                      \
@@ -715,6 +716,123 @@ struct ocfs2_group_desc
 /*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_reserved1;
+       __le32  xh_reserved2;
+       __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
+
+/*
+ * 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)
 {