Diff for /xfs-cmds/xfsprogs/db/metadump.c between versions 1.1 and 1.2

version 1.1, 2007/06/05 04:03:18 version 1.2, 2007/09/07 06:11:50
Line 42  static void metadump_help(void); Line 42  static void metadump_help(void);
   
 static const cmdinfo_t  metadump_cmd =  static const cmdinfo_t  metadump_cmd =
         { "metadump", NULL, metadump_f, 0, -1, 0,          { "metadump", NULL, metadump_f, 0, -1, 0,
                 "[-e] [-g] [-w] [-o] filename",                  "[-e] [-g] [-m max_extent] [-w] [-o] filename",
                 "dump metadata to a file", metadump_help };                  "dump metadata to a file", metadump_help };
   
 static FILE             *outf;          /* metadump file */  static FILE             *outf;          /* metadump file */
Line 58  static xfs_ino_t cur_ino; Line 58  static xfs_ino_t cur_ino;
   
 static int              show_progress = 0;  static int              show_progress = 0;
 static int              stop_on_read_error = 0;  static int              stop_on_read_error = 0;
   static int              max_extent_size = 20;
 static int              dont_obfuscate = 0;  static int              dont_obfuscate = 0;
 static int              show_warnings = 0;  static int              show_warnings = 0;
 static int              progress_since_warning = 0;  static int              progress_since_warning = 0;
Line 76  metadump_help(void) Line 77  metadump_help(void)
 " The 'metadump' command dumps the known metadata to a compact file suitable\n"  " The 'metadump' command dumps the known metadata to a compact file suitable\n"
 " for compressing and sending to an XFS maintainer for corruption analysis \n"  " for compressing and sending to an XFS maintainer for corruption analysis \n"
 " or xfs_repair failures.\n\n"  " or xfs_repair failures.\n\n"
 " There are 3 options:\n"  " Options:\n"
 "   -e -- Ignore read errors and keep going\n"  "   -e -- Ignore read errors and keep going\n"
 "   -g -- Display dump progress\n"  "   -g -- Display dump progress\n"
   "   -m -- Specify max extent size in blocks to copy (default = 20 blocks)\n"
 "   -o -- Don't obfuscate names and extended attributes\n"  "   -o -- Don't obfuscate names and extended attributes\n"
 "   -w -- Show warnings of bad metadata information\n"  "   -w -- Show warnings of bad metadata information\n"
 "\n");  "\n");
Line 206  scan_btree( Line 208  scan_btree(
   
 static int  static int
 valid_bno(  valid_bno(
         xfs_agblock_t           bno,  
         xfs_agnumber_t          agno,          xfs_agnumber_t          agno,
         xfs_agblock_t           agbno,          xfs_agblock_t           agbno)
         typnm_t                 btype)  
 {  {
         if (bno > 0 && bno <= mp->m_sb.sb_agblocks)          if (agno < (mp->m_sb.sb_agcount - 1) && agbno > 0 &&
                           agbno <= mp->m_sb.sb_agblocks)
                   return 1;
           if (agno == (mp->m_sb.sb_agcount - 1) && agbno > 0 &&
                           agbno <= (mp->m_sb.sb_dblocks -
                            (mp->m_sb.sb_agcount - 1) * mp->m_sb.sb_agblocks))
                 return 1;                  return 1;
   
         if (show_warnings)  
                 print_warning("invalid block number (%u) in %s block %u/%u",  
                                 bno, typtab[btype].name, agno, agbno);  
         return 0;          return 0;
 }  }
   
   
 static int  static int
 scanfunc_freesp(  scanfunc_freesp(
         xfs_btree_hdr_t         *bthdr,          xfs_btree_hdr_t         *bthdr,
Line 231  scanfunc_freesp( Line 234  scanfunc_freesp(
 {  {
         xfs_alloc_ptr_t         *pp;          xfs_alloc_ptr_t         *pp;
         int                     i;          int                     i;
         int                     nrecs;          int                     numrecs;
   
         if (level == 0)          if (level == 0)
                 return 1;                  return 1;
   
         nrecs = be16_to_cpu(bthdr->bb_numrecs);          numrecs = be16_to_cpu(bthdr->bb_numrecs);
         if (nrecs > mp->m_alloc_mxr[1]) {          if (numrecs > mp->m_alloc_mxr[1]) {
                 if (show_warnings)                  if (show_warnings)
                         print_warning("invalid nrecs (%u) in %s block %u/%u",                          print_warning("invalid numrecs (%u) in %s block %u/%u",
                                         nrecs, typtab[btype].name, agno, agbno);                                  numrecs, typtab[btype].name, agno, agbno);
                 return 1;                  return 1;
         }          }
   
         pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, bthdr, 1,          pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, bthdr, 1,
                         mp->m_alloc_mxr[1]);                          mp->m_alloc_mxr[1]);
         for (i = 0; i < nrecs; i++) {          for (i = 0; i < numrecs; i++) {
                 if (!valid_bno(be32_to_cpu(pp[i]), agno, agbno, btype))                  if (!valid_bno(agno, be32_to_cpu(pp[i]))) {
                           if (show_warnings)
                                   print_warning("invalid block number (%u/%u) "
                                           "in %s block %u/%u",
                                           agno, be32_to_cpu(pp[i]),
                                           typtab[btype].name, agno, agbno);
                         continue;                          continue;
                   }
                 if (!scan_btree(agno, be32_to_cpu(pp[i]), level, btype, arg,                  if (!scan_btree(agno, be32_to_cpu(pp[i]), level, btype, arg,
                                 scanfunc_freesp))                                  scanfunc_freesp))
                         return 0;                          return 0;
Line 492  obfuscate_sf_dir( Line 501  obfuscate_sf_dir(
         if (ino_dir_size > XFS_DFORK_DSIZE(dip, mp)) {          if (ino_dir_size > XFS_DFORK_DSIZE(dip, mp)) {
                 ino_dir_size = XFS_DFORK_DSIZE(dip, mp);                  ino_dir_size = XFS_DFORK_DSIZE(dip, mp);
                 if (show_warnings)                  if (show_warnings)
                         print_warning("invalid size for dir inode %llu",                          print_warning("invalid size in dir inode %llu",
                                         (long long)cur_ino);                                          (long long)cur_ino);
         }          }
   
Line 539  static void Line 548  static void
 obfuscate_sf_symlink(  obfuscate_sf_symlink(
         xfs_dinode_t            *dip)          xfs_dinode_t            *dip)
 {  {
         int                     i;          int                     len;
   
           len = dip->di_core.di_size;
           if (len > XFS_DFORK_DSIZE(dip, mp)) {
                   if (show_warnings)
                           print_warning("invalid size (%d) in symlink inode %llu",
                                           len, (long long)cur_ino);
                   len = XFS_DFORK_DSIZE(dip, mp);
           }
   
         for (i = 0; i < dip->di_core.di_size; i++)          while (len > 0)
                 dip->di_u.di_symlink[i] = random() % 127 + 1;                  dip->di_u.di_symlink[--len] = random() % 127 + 1;
 }  }
   
 static void  static void
Line 858  process_bmbt_reclist( Line 875  process_bmbt_reclist(
         typnm_t                 btype)          typnm_t                 btype)
 {  {
         int                     i;          int                     i;
         xfs_dfiloff_t           o;          xfs_dfiloff_t           o, op;
         xfs_dfsbno_t            s;          xfs_dfsbno_t            s;
         xfs_dfilblks_t          c;          xfs_dfilblks_t          c, cp;
         int                     f;          int                     f;
         xfs_dfiloff_t           last;          xfs_dfiloff_t           last;
           xfs_agnumber_t          agno;
           xfs_agblock_t           agbno;
   
         if (btype == TYP_DATA)          if (btype == TYP_DATA)
                 return 1;                  return 1;
Line 873  process_bmbt_reclist( Line 892  process_bmbt_reclist(
         for (i = 0; i < numrecs; i++, rp++) {          for (i = 0; i < numrecs; i++, rp++) {
                 convert_extent(rp, &o, &s, &c, &f);                  convert_extent(rp, &o, &s, &c, &f);
   
                   /*
                    * ignore extents that are clearly bogus, and if a bogus
                    * one is found, stop processing remaining extents
                    */
                   if (i > 0 && op + cp > o) {
                           if (show_warnings)
                                   print_warning("bmap extent %d in %s ino %llu "
                                           "starts at %llu, previous extent "
                                           "ended at %llu", i,
                                           typtab[btype].name, (long long)cur_ino,
                                           o, op + cp - 1);
                           break;
                   }
   
                   if (c > max_extent_size) {
                           /*
                            * since we are only processing non-data extents,
                            * large numbers of blocks in a metadata extent is
                            * extremely rare and more than likely to be corrupt.
                            */
                           if (show_warnings)
                                   print_warning("suspicious count %u in bmap "
                                           "extent %d in %s ino %llu", c, i,
                                           typtab[btype].name, (long long)cur_ino);
                           break;
                   }
   
                   op = o;
                   cp = c;
   
                   agno = XFS_FSB_TO_AGNO(mp, s);
                   agbno = XFS_FSB_TO_AGBNO(mp, s);
   
                   if (!valid_bno(agno, agbno)) {
                           if (show_warnings)
                                   print_warning("invalid block number %u/%u "
                                           "(%llu) in bmap extent %d in %s ino "
                                           "%llu", agno, agbno, s, i,
                                           typtab[btype].name, (long long)cur_ino);
                           break;
                   }
   
                   if (!valid_bno(agno, agbno + c - 1)) {
                           if (show_warnings)
                                   print_warning("bmap extent %i in %s inode %llu "
                                           "overflows AG (end is %u/%u)", i,
                                           typtab[btype].name, (long long)cur_ino,
                                           agno, agbno + c - 1);
                           break;
                   }
   
                 push_cur();                  push_cur();
                 set_cur(&typtab[btype], XFS_FSB_TO_DADDR(mp, s), c * blkbb,                  set_cur(&typtab[btype], XFS_FSB_TO_DADDR(mp, s), c * blkbb,
                                 DB_RING_IGN, NULL);                                  DB_RING_IGN, NULL);
                 if (iocur_top->data == NULL) {                  if (iocur_top->data == NULL) {
                         print_warning("cannot read %s block %u/%u",                          print_warning("cannot read %s block %u/%u (%llu)",
                                         typtab[btype].name,                                          typtab[btype].name, agno, agbno, s);
                                         XFS_FSB_TO_AGNO(mp, s),  
                                         XFS_FSB_TO_AGBNO(mp, s));  
                         if (stop_on_read_error)                          if (stop_on_read_error)
                                 return 0;                                  return 0;
                 } else {                  } else {
Line 1054  process_exinode( Line 1122  process_exinode(
         typnm_t                 itype)          typnm_t                 itype)
 {  {
         int                     whichfork;          int                     whichfork;
           xfs_extnum_t            nex;
   
         whichfork = (itype == TYP_ATTR) ? XFS_ATTR_FORK : XFS_DATA_FORK;          whichfork = (itype == TYP_ATTR) ? XFS_ATTR_FORK : XFS_DATA_FORK;
   
         return process_bmbt_reclist(          nex = XFS_DFORK_NEXTENTS_HOST(dip, whichfork);
                         (xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip, whichfork),          if (nex < 0 || nex > XFS_DFORK_SIZE_HOST(dip, mp, whichfork) /
                         XFS_DFORK_NEXTENTS_HOST(dip, whichfork), itype);                                  sizeof(xfs_bmbt_rec_t)) {
                   if (show_warnings)
                           print_warning("bad number of extents %d in inode %lld",
                                   nex, (long long)cur_ino);
                   return 1;
           }
   
           return process_bmbt_reclist((xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip,
                                           whichfork), nex, itype);
 }  }
   
 static int  static int
Line 1108  process_inode( Line 1185  process_inode(
         success = 1;          success = 1;
         cur_ino = XFS_AGINO_TO_INO(mp, agno, agino);          cur_ino = XFS_AGINO_TO_INO(mp, agno, agino);
   
   
         /* copy appropriate data fork metadata */          /* copy appropriate data fork metadata */
         switch (dip->di_core.di_mode & S_IFMT) {          switch (dip->di_core.di_mode & S_IFMT) {
                 case S_IFDIR:                  case S_IFDIR:
Line 1118  process_inode( Line 1194  process_inode(
                 case S_IFLNK:                  case S_IFLNK:
                         success = process_inode_data(dip, TYP_SYMLINK);                          success = process_inode_data(dip, TYP_SYMLINK);
                         break;                          break;
                 default:                  case S_IFREG:
                         success = process_inode_data(dip, TYP_DATA);                          success = process_inode_data(dip, TYP_DATA);
                           break;
                   default: ;
         }          }
         clear_nametable();          clear_nametable();
   
         /* copy extended attributes if they exist */          /* copy extended attributes if they exist and forkoff is valid */
         if (success && dip->di_core.di_forkoff) {          if (success && XFS_CFORK_DSIZE(&dip->di_core, mp) < XFS_LITINO(mp)) {
                 attr_data.remote_val_count = 0;                  attr_data.remote_val_count = 0;
                 switch (dip->di_core.di_aformat) {                  switch (dip->di_core.di_aformat) {
                         case XFS_DINODE_FMT_LOCAL:                          case XFS_DINODE_FMT_LOCAL:
Line 1165  copy_inode_chunk( Line 1243  copy_inode_chunk(
         agbno = XFS_AGINO_TO_AGBNO(mp, agino);          agbno = XFS_AGINO_TO_AGBNO(mp, agino);
         off = XFS_INO_TO_OFFSET(mp, agino);          off = XFS_INO_TO_OFFSET(mp, agino);
   
           if (agino == 0 || agino == NULLAGINO || !valid_bno(agno, agbno) ||
                           !valid_bno(agno, XFS_AGINO_TO_AGBNO(mp,
                                           agino + XFS_INODES_PER_CHUNK - 1))) {
                   if (show_warnings)
                           print_warning("bad inode number %llu (%u/%u)",
                                   XFS_AGINO_TO_INO(mp, agno, agino), agno, agino);
                   return 1;
           }
   
         push_cur();          push_cur();
         set_cur(&typtab[TYP_INODE], XFS_AGB_TO_DADDR(mp, agno, agbno),          set_cur(&typtab[TYP_INODE], XFS_AGB_TO_DADDR(mp, agno, agbno),
                         XFS_FSB_TO_BB(mp, XFS_IALLOC_BLOCKS(mp)),                          XFS_FSB_TO_BB(mp, XFS_IALLOC_BLOCKS(mp)),
Line 1175  copy_inode_chunk( Line 1262  copy_inode_chunk(
         }          }
   
         /*          /*
            * check for basic assumptions about inode chunks, and if any
            * assumptions fail, don't process the inode chunk.
            */
   
           if ((mp->m_sb.sb_inopblock <= XFS_INODES_PER_CHUNK && off != 0) ||
                           (mp->m_sb.sb_inopblock > XFS_INODES_PER_CHUNK &&
                                           off % XFS_INODES_PER_CHUNK != 0) ||
                           (XFS_SB_VERSION_HASALIGN(&mp->m_sb) &&
                                           agbno % mp->m_sb.sb_inoalignmt != 0)) {
                   if (show_warnings)
                           print_warning("badly aligned inode (start = %llu)",
                                           XFS_AGINO_TO_INO(mp, agno, agino));
                   goto skip_processing;
           }
   
           /*
          * scan through inodes and copy any btree extent lists, directory           * scan through inodes and copy any btree extent lists, directory
          * contents and extended attributes.           * contents and extended attributes.
          */           */
   
         for (i = 0; i < XFS_INODES_PER_CHUNK; i++) {          for (i = 0; i < XFS_INODES_PER_CHUNK; i++) {
                 xfs_dinode_t            *dip;                  xfs_dinode_t            *dip;
   
Line 1191  copy_inode_chunk( Line 1293  copy_inode_chunk(
                 if (!process_inode(agno, agino + i, dip))                  if (!process_inode(agno, agino + i, dip))
                         return 0;                          return 0;
         }          }
   skip_processing:
         if (!write_buf(iocur_top))          if (!write_buf(iocur_top))
                 return 0;                  return 0;
   
Line 1219  scanfunc_ino( Line 1321  scanfunc_ino(
         xfs_inobt_rec_t         *rp;          xfs_inobt_rec_t         *rp;
         xfs_inobt_ptr_t         *pp;          xfs_inobt_ptr_t         *pp;
         int                     i;          int                     i;
           int                     numrecs;
   
           numrecs = be16_to_cpu(bthdr->bb_numrecs);
   
         if (level == 0) {          if (level == 0) {
                   if (numrecs > mp->m_inobt_mxr[0]) {
                           if (show_warnings)
                                   print_warning("invalid numrecs %d in %s "
                                           "block %u/%u", numrecs,
                                           typtab[btype].name, agno, agbno);
                           numrecs = mp->m_inobt_mxr[0];
                   }
                 rp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_inobt,                  rp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_inobt,
                                 bthdr, 1, mp->m_inobt_mxr[0]);                                  bthdr, 1, mp->m_inobt_mxr[0]);
                 for (i = 0; i < be16_to_cpu(bthdr->bb_numrecs); i++, rp++) {                  for (i = 0; i < numrecs; i++, rp++) {
                         if (!copy_inode_chunk(agno, rp))                          if (!copy_inode_chunk(agno, rp))
                                 return 0;                                  return 0;
                 }                  }
         } else {                  return 1;
                 pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_inobt,          }
                                 bthdr, 1, mp->m_inobt_mxr[1]);  
                 for (i = 0; i < be16_to_cpu(bthdr->bb_numrecs); i++) {          if (numrecs > mp->m_inobt_mxr[1]) {
                         if (!valid_bno(be32_to_cpu(pp[i]), agno, agbno, btype))                  if (show_warnings)
                                 continue;                          print_warning("invalid numrecs %d in %s block %u/%u",
                         if (!scan_btree(agno, be32_to_cpu(pp[i]), level,                                  numrecs, typtab[btype].name, agno, agbno);
                                         btype, arg, scanfunc_ino))                  numrecs = mp->m_inobt_mxr[1];
                                 return 0;          }
   
           pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_inobt,
                           bthdr, 1, mp->m_inobt_mxr[1]);
           for (i = 0; i < numrecs; i++) {
                   if (!valid_bno(agno, be32_to_cpu(pp[i]))) {
                           if (show_warnings)
                                   print_warning("invalid block number (%u/%u) "
                                           "in %s block %u/%u",
                                           agno, be32_to_cpu(pp[i]),
                                           typtab[btype].name, agno, agbno);
                           continue;
                 }                  }
                   if (!scan_btree(agno, be32_to_cpu(pp[i]), level,
                                   btype, arg, scanfunc_ino))
                           return 0;
         }          }
         return 1;          return 1;
 }  }
Line 1441  metadump_f( Line 1567  metadump_f(
         xfs_agnumber_t  agno;          xfs_agnumber_t  agno;
         int             c;          int             c;
         int             start_iocur_sp;          int             start_iocur_sp;
           char            *p;
   
         exitcode = 1;          exitcode = 1;
         show_progress = 0;          show_progress = 0;
Line 1453  metadump_f( Line 1580  metadump_f(
                 return 0;                  return 0;
         }          }
   
         while ((c = getopt(argc, argv, "egow")) != EOF) {          while ((c = getopt(argc, argv, "egm:ow")) != EOF) {
                 switch (c) {                  switch (c) {
                         case 'e':                          case 'e':
                                 stop_on_read_error = 1;                                  stop_on_read_error = 1;
Line 1461  metadump_f( Line 1588  metadump_f(
                         case 'g':                          case 'g':
                                 show_progress = 1;                                  show_progress = 1;
                                 break;                                  break;
                           case 'm':
                                   max_extent_size = (int)strtol(optarg, &p, 0);
                                   if (*p != '\0' || max_extent_size <= 0) {
                                           print_warning("bad max extent size %s",
                                                           optarg);
                                           return 0;
                                   }
                                   break;
                         case 'o':                          case 'o':
                                 dont_obfuscate = 1;                                  dont_obfuscate = 1;
                                 break;                                  break;

Removed from v.1.1  
changed lines
  Added in v.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>