Tiger Yang wrote:

> +#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));
> +}
I remember with 512, there is no xattr in inode.
> +
> +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_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--) {
no le16_to_cpu in tools. there are also some below, please remove them.
> +             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);
bucket size isn't block size. So you can't just read and handle the 
first block for a bucket. the same for the write.

> +             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) {
you mean inline_xattr here?
> +             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)) {
you should handle xb_flags swap first.
> +             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);
> +     }
> +}
> +

_______________________________________________
Ocfs2-devel mailing list
[email protected]
http://oss.oracle.com/mailman/listinfo/ocfs2-devel

Reply via email to