Whamcloud - gitweb
LU-934 e2fsck: copy EA from external inode, fix size check 86/1886/3
authorAlexander.Boyko <alexander_boyko@xyratex.com>
Fri, 16 Dec 2011 22:11:48 +0000 (02:11 +0400)
committerAlexander.Boyko <alexander_boyko@xyratex.com>
Mon, 9 Jan 2012 10:11:21 +0000 (14:11 +0400)
This patch fixes the following issues:
- pass1.c check_ea_in_inode() compares e_value_size to fit in free
  space of inode, but for xattr in external inode this is wrong.
- e2fsck_lfsck_find_ea() have no code to copy EA from external inode.

Signed-off-by: Alexander Boyko <alexander_boyko@xyratex.com>
Xyratex-bug-id: MRP-291
Change-Id: I7bc556f0e2c9f300c8bc060b7e18167c93426644

patches/e2fsprogs-large-ea.patch
patches/e2fsprogs-lfsck.patch

index ef212f1..ca6093c 100644 (file)
@@ -141,7 +141,7 @@ Index: e2fsprogs/e2fsck/pass1.c
  static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
  {
        struct ext2_super_block *sb = ctx->fs->super;
-@@ -307,18 +420,25 @@ static void check_ea_in_inode(e2fsck_t c
+@@ -307,23 +420,31 @@ static void check_ea_in_inode(e2fsck_t c
                /* attribute len eats this space */
                remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
  
@@ -174,7 +174,14 @@ Index: e2fsprogs/e2fsck/pass1.c
                }
  
                /* Value size cannot be larger than EA space in inode */
-@@ -338,7 +458,10 @@ static void check_ea_in_inode(e2fsck_t c
+               if (entry->e_value_offs > storage_size ||
+-                  entry->e_value_offs + entry->e_value_size > storage_size) {
++                  (entry->e_value_inum == 0 &&
++                  entry->e_value_offs + entry->e_value_size > storage_size)) {
+                       problem = PR_1_INODE_EA_BAD_VALUE;
+                       goto fix;
+               }
+@@ -338,7 +459,10 @@ static void check_ea_in_inode(e2fsck_t c
                        goto fix;
                }
  
@@ -186,7 +193,7 @@ Index: e2fsprogs/e2fsck/pass1.c
  
                entry = EXT2_EXT_ATTR_NEXT(entry);
        }
-@@ -627,7 +750,7 @@ int e2fsck_pass1_delete_attr(e2fsck_t ct
+@@ -627,7 +751,7 @@ int e2fsck_pass1_delete_attr(e2fsck_t ct
                if (EXT2_EXT_IS_LAST_ENTRY(entry)) {
                        if (in_inode) {
                                entry = entry_blk;
@@ -195,7 +202,7 @@ Index: e2fsprogs/e2fsck/pass1.c
                                entry_size = ext2fs_attr_get_next_attr(entry,
                                                        index, name, len, 1);
                                in_inode = 0;
-@@ -1654,6 +1777,7 @@ static int check_ext_attr(e2fsck_t ctx, 
+@@ -1654,6 +1778,7 @@ static int check_ext_attr(e2fsck_t ctx, 
        struct ext2_ext_attr_entry *entry;
        int             count;
        region_t        region = 0;
@@ -203,7 +210,7 @@ Index: e2fsprogs/e2fsck/pass1.c
  
        blk = ext2fs_file_acl_block(inode);
        if (blk == 0)
-@@ -1775,19 +1899,27 @@ static int check_ext_attr(e2fsck_t ctx, 
+@@ -1775,19 +1900,27 @@ static int check_ext_attr(e2fsck_t ctx, 
                                goto clear_extattr;
                        break;
                }
@@ -244,7 +251,7 @@ Index: e2fsprogs/e2fsck/pass1.c
                                goto clear_extattr;
                }
  
-@@ -2996,18 +3128,6 @@ static errcode_t e2fsck_get_alloc_block(
+@@ -2996,18 +3129,6 @@ static errcode_t e2fsck_get_alloc_block(
        return (0);
  }
  
@@ -415,7 +422,7 @@ Index: e2fsprogs/lib/ext2fs/ext2fs.h
 ===================================================================
 --- e2fsprogs.orig/lib/ext2fs/ext2fs.h
 +++ e2fsprogs/lib/ext2fs/ext2fs.h
-@@ -571,6 +571,7 @@ typedef struct ext2_icount *ext2_icount_
+@@ -570,6 +570,7 @@ typedef struct ext2_icount *ext2_icount_
                                         EXT3_FEATURE_INCOMPAT_EXTENTS|\
                                         EXT4_FEATURE_INCOMPAT_FLEX_BG|\
                                         EXT4_FEATURE_INCOMPAT_MMP|\
@@ -423,7 +430,7 @@ Index: e2fsprogs/lib/ext2fs/ext2fs.h
                                         EXT4_FEATURE_INCOMPAT_64BIT)
  #else
  #define EXT2_LIB_FEATURE_INCOMPAT_SUPP        (EXT2_FEATURE_INCOMPAT_FILETYPE|\
-@@ -580,6 +581,7 @@ typedef struct ext2_icount *ext2_icount_
+@@ -579,6 +580,7 @@ typedef struct ext2_icount *ext2_icount_
                                         EXT3_FEATURE_INCOMPAT_EXTENTS|\
                                         EXT4_FEATURE_INCOMPAT_FLEX_BG|\
                                         EXT4_FEATURE_INCOMPAT_MMP|\
@@ -590,3 +597,48 @@ Index: e2fsprogs/misc/tune2fs.c
        if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
                /*
                 * If adding a journal flag, let the create journal
+Index: e2fsprogs/debugfs/debugfs.c
+===================================================================
+--- e2fsprogs.orig/debugfs/debugfs.c
++++ e2fsprogs/debugfs/debugfs.c
+@@ -502,6 +502,7 @@ static void internal_dump_inode_extra(FI
+       struct ext2_ext_attr_entry *entry;
+       __u32 *magic;
+       char *start, *end;
++      int inode_xattr;
+       unsigned int storage_size;
+       fprintf(out, "Size of extra inode fields: %u\n", inode->i_extra_isize);
+@@ -524,17 +525,28 @@ static void internal_dump_inode_extra(FI
+               while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
+                       struct ext2_ext_attr_entry *next =
+                               EXT2_EXT_ATTR_NEXT(entry);
+-                      if (entry->e_value_size > storage_size ||
+-                                      (char *) next >= end) {
++                      inode_xattr =
++                              EXT2_HAS_INCOMPAT_FEATURE(current_fs->super,
++                                      EXT4_FEATURE_INCOMPAT_EA_INODE) &&
++                                      entry->e_value_offs == 0 &&
++                                      entry->e_value_inum != 0;
++                      if ((entry->e_value_size > storage_size &&
++                           !inode_xattr) || (char *)next >= end) {
+                               fprintf(out, "invalid EA entry in inode\n");
+                               return;
+                       }
+                       fprintf(out, "  ");
++
+                       dump_xattr_string(out, EXT2_EXT_ATTR_NAME(entry),
+                                         entry->e_name_len);
+                       fprintf(out, " = \"");
+-                      dump_xattr_string(out, start + entry->e_value_offs,
+-                                              entry->e_value_size);
++                      if (inode_xattr)
++                              fprintf(out, "inode <%u>",
++                                      entry->e_value_inum);
++                      else
++                              dump_xattr_string(out,
++                                                start + entry->e_value_offs,
++                                                entry->e_value_size);
+                       fprintf(out, "\" (%u)\n", entry->e_value_size);
+                       entry = next;
+               }
index afd478e..cfabc41 100644 (file)
@@ -92,7 +92,7 @@ Index: e2fsprogs/configure.in
  dnl handle --enable-compression
  dnl
  AC_ARG_ENABLE([compression],
-@@ -763,6 +811,7 @@ AC_CHECK_HEADERS(net/if.h,,,
+@@ -763,6 +819,7 @@ AC_CHECK_HEADERS(net/if.h,,,
  #include <sys/socket.h>
  #endif
  ]])
@@ -100,7 +100,7 @@ Index: e2fsprogs/configure.in
  AC_FUNC_VPRINTF
  dnl Check to see if dirent has member d_reclen. On cygwin those d_reclen
  dnl is not decleared.
-@@ -880,6 +929,31 @@ SOCKET_LIB=''
+@@ -880,6 +937,31 @@ SOCKET_LIB=''
  AC_CHECK_LIB(socket, socket, [SOCKET_LIB=-lsocket])
  AC_SUBST(SOCKET_LIB)
  dnl
@@ -419,7 +419,7 @@ Index: e2fsprogs/e2fsck/pass1.c
        int problem = 0;
  
        inode = (struct ext2_inode_large *) pctx->inode;
-@@ -458,6 +461,9 @@ static void check_ea_in_inode(e2fsck_t c
+@@ -459,6 +462,9 @@ static void check_ea_in_inode(e2fsck_t c
                        goto fix;
                }
  
@@ -429,7 +429,7 @@ Index: e2fsprogs/e2fsck/pass1.c
                /* If EA value is stored in external inode then it does not
                 * consume space here */
                if (entry->e_value_inum == 0)
-@@ -465,6 +471,10 @@ static void check_ea_in_inode(e2fsck_t c
+@@ -466,8 +472,16 @@ static void check_ea_in_inode(e2fsck_t c
  
                entry = EXT2_EXT_ATTR_NEXT(entry);
        }
@@ -438,11 +438,18 @@ Index: e2fsprogs/e2fsck/pass1.c
 +              e2fsck_lfsck_save_ea(ctx, pctx->ino, inode->i_generation,
 +                                   lmm, lma);
  fix:
-       /*
+-      /*
++      if (lmm)
++              ext2fs_free_mem(&lmm);
++      if (lma)
++              ext2fs_free_mem(&lma);
++ /*
         * it seems like a corruption. it's very unlikely we could repair
-@@ -1005,6 +1015,12 @@ void e2fsck_pass1(e2fsck_t ctx)
+        * EA(s) in automatic fashion -bzzz
+        */
+@@ -1006,6 +1020,12 @@ void e2fsck_pass1(e2fsck_t ctx)
                ext2fs_mark_block_bitmap2(ctx->block_found_map,
-                                         fs->super->s_mmp_block);
+                                         fs->super->s_mmp_block);
  
 +      if (!(ctx->options & E2F_OPT_READONLY) &&
 +          (ctx->lustre_devtype & LUSTRE_TYPE) == LUSTRE_MDS) {
@@ -452,8 +459,8 @@ Index: e2fsprogs/e2fsck/pass1.c
 +
        while (1) {
                if (ino % EXT2_MMP_INODE_INTERVAL == 0) {
-                       if (e2fsck_mmp_update(fs))
-@@ -1513,6 +1529,9 @@ void e2fsck_pass1(e2fsck_t ctx)
+                       if (e2fsck_mmp_update(fs))
+@@ -1511,6 +1531,9 @@ void e2fsck_pass1(e2fsck_t ctx)
                }
                e2fsck_pass1_dupblocks(ctx, block_buf);
        }
@@ -463,7 +470,7 @@ Index: e2fsprogs/e2fsck/pass1.c
        ext2fs_free_mem(&inodes_to_process);
  endit:
        e2fsck_use_inode_shortcuts(ctx, 0);
-@@ -1780,6 +1799,8 @@ static int check_ext_attr(e2fsck_t ctx, 
+@@ -1778,6 +1801,8 @@ static int check_ext_attr(e2fsck_t ctx, 
        struct ext2_ext_attr_entry *entry;
        int             count;
        region_t        region = 0;
@@ -472,7 +479,7 @@ Index: e2fsprogs/e2fsck/pass1.c
        int ret;
  
        blk = ext2fs_file_acl_block(inode);
-@@ -1936,8 +1957,19 @@ static int check_ext_attr(e2fsck_t ctx, 
+@@ -1934,13 +1959,28 @@ static int check_ext_attr(e2fsck_t ctx, 
                        entry->e_hash = hash;
                }
  
@@ -492,6 +499,27 @@ Index: e2fsprogs/e2fsck/pass1.c
        if (region_allocate(region, (char *)entry - (char *)header, 4)) {
                if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
                        goto clear_extattr;
+       }
+       region_free(region);
++      if (lmm)
++              ext2fs_free_mem(&lmm);
++      if (lma)
++              ext2fs_free_mem(&lma);
+       count = header->h_refcount - 1;
+       if (count)
+@@ -1950,6 +1990,11 @@ static int check_ext_attr(e2fsck_t ctx, 
+       return 1;
+ clear_extattr:
++      if (lmm)
++                ext2fs_free_mem(&lmm);
++      if (lma)
++              ext2fs_free_mem(&lma);
++
+       if (region)
+               region_free(region);
+       ext2fs_file_acl_block_set(inode, 0);
 Index: e2fsprogs/e2fsck/unix.c
 ===================================================================
 --- e2fsprogs.orig/e2fsck/unix.c
@@ -693,7 +721,7 @@ Index: e2fsprogs/misc/mke2fs.c
 ===================================================================
 --- e2fsprogs.orig/misc/mke2fs.c
 +++ e2fsprogs/misc/mke2fs.c
-@@ -1398,7 +1398,7 @@ profile_error:
+@@ -1401,7 +1401,7 @@ profile_error:
                        }
                        break;
                case 'v':
@@ -734,17 +762,15 @@ Index: e2fsprogs/e2fsprogs.spec.in
  Provides: e2fsprogs-libs = %{version} ldiskfsprogs = %{version}
  Obsoletes: e4fsprogs e2fsprogs-libs < %{version}
  %endif
-@@ -72,7 +76,8 @@ SMP systems.
+@@ -72,6 +76,7 @@ SMP systems.
  
  %build
  %configure --enable-elf-shlibs --enable-nls --disable-defrag \
--      %{?extra_config_flags:%extra_config_flags}
 +      @WITH_LUSTRE@ @ENABLE_LFSCK@ \
-+      %{?extra_config_flags:%extra_config_flags}
+       %{?extra_config_flags:%extra_config_flags}
  make
  make check
-@@ -142,6 +146,7 @@ exit 0
+@@ -142,6 +147,7 @@ exit 0
  %{_root_sbindir}/resize2fs
  %{_root_sbindir}/tune2fs
  %{_sbindir}/filefrag
@@ -752,7 +778,7 @@ Index: e2fsprogs/e2fsprogs.spec.in
  %{_sbindir}/mklost+found
  %{_sbindir}/e2freefrag
  
-@@ -170,6 +175,7 @@ exit 0
+@@ -169,6 +175,7 @@ exit 0
  %{_mandir}/man8/debugfs.8*
  %{_mandir}/man8/dumpe2fs.8*
  %{_mandir}/man8/e2fsck.8*
@@ -3713,7 +3739,7 @@ Index: e2fsprogs/e2fsck/pass6.c
 ===================================================================
 --- /dev/null
 +++ e2fsprogs/e2fsck/pass6.c
-@@ -0,0 +1,1511 @@
+@@ -0,0 +1,1551 @@
 +/* -*- mode: c; c-basic-offset: 8; -*-
 + * vim:shiftwidth=8:tabstop=8:
 + *
@@ -4146,6 +4172,11 @@ Index: e2fsprogs/e2fsck/pass6.c
 +                       struct lov_user_md **lmm,
 +                       struct lustre_mdt_attrs **lma)
 +{
++      char *ea = NULL;
++      int retval;
++      unsigned int got;
++      ext2_file_t file;
++
 +      /* This ensures that we don't open the file here if traversing an OST */
 +      if ((ctx->lustre_devtype & LUSTRE_TYPE) != LUSTRE_MDS)
 +              return 0;
@@ -4157,24 +4188,59 @@ Index: e2fsprogs/e2fsck/pass6.c
 +          entry->e_name_index == EXT3_XATTR_INDEX_LUSTRE)
 +              return 0;
 +
++      ea = e2fsck_allocate_memory(ctx, entry->e_value_size,
++                                         "EA");
++
++      if (entry->e_value_inum != 0) {
++              /* EA in external inode */
++              retval = ext2fs_file_open(ctx->fs, entry->e_value_inum,
++                                        0, &file);
++              if (!retval) {
++                      retval = ext2fs_file_read(file, ea,
++                                                entry->e_value_size, &got);
++                      ext2fs_file_close(file);
++                      if (retval != 0) {
++                              ext2fs_free_mem(&ea);
++                              return 0;
++                      }
++              } else {
++                      ext2fs_free_mem(&ea);
++                      return 0;
++              }
++      } else {
++              memcpy(ea, value, entry->e_value_size);
++      }
++
 +      if (strncmp(entry->e_name, XATTR_LUSTRE_MDS_LOV_EA,
 +                  entry->e_name_len) == 0) {
-+              *lmm = value;
++              if (*lmm) {
++                      ext2fs_free_mem(&ea);
++                      return -EINVAL;
++              }
++              *lmm = ea;
 +              letocpu_lov_user_md(*lmm);
 +
 +              if (lfsck_check_lov_ea(ctx, *lmm)) {
 +                      *lmm = NULL;
 +                      ctx->flags |= E2F_FLAG_ABORT;
++                      ext2fs_free_mem(&ea);
 +                      return -EINVAL;
 +              }
 +      } else if (strncmp(entry->e_name, XATTR_LUSTRE_MDT_LMA_EA,
 +                         entry->e_name_len) == 0) {
-+              *lma = value;
++              if (*lma) {
++                      ext2fs_free_mem(&ea);
++                      return -EINVAL;
++              }
++              *lma = ea;
 +              if (lfsck_check_lma_ea(ctx, *lma)) {
 +                      *lma = NULL;
 +                      ctx->flags |= E2F_FLAG_ABORT;
++                      ext2fs_free_mem(&ea);
 +                      return -EINVAL;
 +              }
++      } else {
++              ext2fs_free_mem(&ea);
 +      }
 +
 +      return 0;