Logo Search packages:      
Sourcecode: ocfs2-tools version File versions  Download package

find_dup_extents.c

/* -*- mode: c; c-basic-offset: 8; -*-
 * vim: noexpandtab sw=8 ts=8 sts=0:
 *
 * find_dup_extents.c
 *
 * Simple tool to iterate the inodes and find duplicate extents.
 *
 * Copyright (C) 2004 Oracle.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License, version 2,  as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 021110-1307, USA.
 *
 * Authors: Joel Becker
 *
 *  This code is a port of e2fsprogs/lib/ext2fs/dir_iterate.c
 *  Copyright (C) 1993, 1994, 1994, 1995, 1996, 1997 Theodore Ts'o.
 */

#define _XOPEN_SOURCE 600 /* Triggers magic in features.h */
#define _LARGEFILE64_SOURCE

#include <stdlib.h>
#include <string.h>
#include <inttypes.h>

#include "ocfs2.h"

static void print_usage(void)
{
      fprintf(stderr,
            "Usage: find_dup_extents <filename>\n");
}

struct walk_extents {
      char *argv0;
      ocfs2_filesys *fs;
      uint64_t blkno;
      int has_dups;
      ocfs2_bitmap *extent_map;
      ocfs2_bitmap *dup_map;
};

static int extent_set_func(ocfs2_filesys *fs,
                     struct ocfs2_extent_rec *rec,
                     int tree_depth,
                     uint32_t ccount,
                     uint64_t ref_blkno,
                     int ref_recno,
                     void *priv_data)
{
      errcode_t ret;
      struct walk_extents *we = priv_data;
      uint32_t cluster, i;
      int oldval;
      int b_to_c_bits =
            OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits -
            OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits;

      cluster = (uint32_t)(rec->e_blkno >> b_to_c_bits);
      for (i = 0; i < rec->e_clusters; i++) {
            ret = ocfs2_bitmap_set(we->extent_map,
                               cluster + i,
                               &oldval);
            if (ret) {
                  com_err(we->argv0, ret,
                        "while setting bit for cluster %u",
                        cluster + i);
                  return OCFS2_EXTENT_ABORT;
            }
            if (oldval) {
                  we->has_dups = 1;
                  ret = ocfs2_bitmap_set(we->dup_map,
                                     cluster + i,
                                     NULL);
                  if (ret) {
                        com_err(we->argv0, ret,
                              "while setting bit for cluster %u",
                              cluster + i);
                        return OCFS2_EXTENT_ABORT;
                  }
            }
      }

      return 0;
}

static int extent_test_func(ocfs2_filesys *fs,
                      struct ocfs2_extent_rec *rec,
                      int tree_depth,
                      uint32_t ccount,
                      uint64_t ref_blkno,
                      int ref_recno,
                      void *priv_data)
{
      errcode_t ret;
      struct walk_extents *we = priv_data;
      uint32_t cluster, i;
      int oldval;
      int b_to_c_bits =
            OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits -
            OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits;

      cluster = (uint32_t)(rec->e_blkno >> b_to_c_bits);
      for (i = 0; i < rec->e_clusters; i++) {
            ret = ocfs2_bitmap_test(we->dup_map,
                              cluster + i,
                              &oldval);
            if (ret) {
                  com_err(we->argv0, ret,
                        "while checking bit for cluster %u",
                        cluster + i);
                  return OCFS2_EXTENT_ABORT;
            }
            if (oldval) {
                  fprintf(stdout,
                        "Dup! %20"PRIu64" : %u\n",
                        we->blkno, cluster + i);
            }
      }

      return 0;
}


static errcode_t run_scan(struct walk_extents *we, int test)
{
      errcode_t ret;
      uint64_t blkno;
      char *buf;
      int done;
      struct ocfs2_dinode *di;
      ocfs2_inode_scan *scan;
      int (*extent_func)(ocfs2_filesys *fs,
                     struct ocfs2_extent_rec *rec,
                     int tree_depth,
                     uint32_t ccount,
                     uint64_t ref_blkno,
                     int ref_recno,
                     void *priv_data);

      if (test)
            extent_func = extent_test_func;
      else
            extent_func = extent_set_func;

      ret = ocfs2_malloc_block(we->fs->fs_io, &buf);
      if (ret) {
            com_err(we->argv0, ret,
                  "while allocating inode buffer");
            return ret;
      }

      di = (struct ocfs2_dinode *)buf;

      ret = ocfs2_open_inode_scan(we->fs, &scan);
      if (ret) {
            com_err(we->argv0, ret,
                  "while opening inode scan");
            goto out_free;
      }

      done = 0;
      while (!done) {
            ret = ocfs2_get_next_inode(scan, &blkno, buf);
            if (ret) {
                  com_err(we->argv0, ret,
                        "while getting next inode");
                  goto out_close_scan;
            }
            if (blkno) {
                  if (memcmp(di->i_signature,
                           OCFS2_INODE_SIGNATURE,
                           strlen(OCFS2_INODE_SIGNATURE)))
                        continue;

                  ocfs2_swap_inode_to_cpu(di);

                  if (!(di->i_flags & OCFS2_VALID_FL))
                        continue;

                  if ((di->i_flags & OCFS2_SYSTEM_FL) &&
                      (di->i_flags & (OCFS2_SUPER_BLOCK_FL |
                                  OCFS2_LOCAL_ALLOC_FL |
                                  OCFS2_CHAIN_FL)))
                        continue;

                  if (!di->i_clusters && S_ISLNK(di->i_mode))
                        continue;

                  we->blkno = blkno;
                  ret = ocfs2_extent_iterate(we->fs, blkno,
                                       OCFS2_EXTENT_FLAG_DATA_ONLY,
                                       NULL,
                                       extent_func,
                                       we);
                  if (ret) {
                        com_err(we->argv0, ret,
                              "while walking inode %"PRIu64, blkno);
                        goto out_close_scan;
                  }
            }
            else
                  done = 1;
      }

out_close_scan:
      ocfs2_close_inode_scan(scan);

out_free:
      ocfs2_free(&buf);

      return ret;
}


int main(int argc, char *argv[])
{
      errcode_t ret;
      char *filename;
      ocfs2_filesys *fs;
      struct walk_extents we;

      initialize_ocfs_error_table();

      if (argc < 2) {
            fprintf(stderr, "Missing filename\n");
            print_usage();
            return 1;
      }
      filename = argv[1];

      we.argv0 = argv[0];
      we.has_dups = 0;

      ret = ocfs2_open(filename, OCFS2_FLAG_RO, 0, 0, &fs);
      if (ret) {
            com_err(argv[0], ret,
                  "while opening file \"%s\"", filename);
            goto out;
      }
      we.fs = fs;

        ret = ocfs2_cluster_bitmap_new(fs, "Used extent map",
                                       &we.extent_map);
        if (ret) {
            com_err(argv[0], ret, 
                  "while creating the extent map");
            goto out_close;
      }
        ret = ocfs2_cluster_bitmap_new(fs, "Dup extent map",
                                       &we.dup_map);
        if (ret) {
            com_err(argv[0], ret, 
                  "while creating the dup map");
            goto out_close;
      }

      ret = run_scan(&we, 0);
      if (!ret && we.has_dups)
            ret = run_scan(&we, 1);

      ocfs2_bitmap_free(we.extent_map);
      ocfs2_bitmap_free(we.dup_map);

out_close:
      ret = ocfs2_close(fs);
      if (ret) {
            com_err(argv[0], ret,
                  "while closing file \"%s\"", filename);
      }

out:
      return 0;
}


Generated by  Doxygen 1.6.0   Back to index