From patchwork Fri Apr 8 07:51:03 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kazuya Mio X-Patchwork-Id: 90284 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id E0CF8B6F8E for ; Fri, 8 Apr 2011 18:06:28 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932148Ab1DHIG1 (ORCPT ); Fri, 8 Apr 2011 04:06:27 -0400 Received: from TYO202.gate.nec.co.jp ([202.32.8.206]:56070 "EHLO tyo202.gate.nec.co.jp" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932099Ab1DHIGZ (ORCPT ); Fri, 8 Apr 2011 04:06:25 -0400 Received: from mailgate3.nec.co.jp ([10.7.69.193]) by tyo202.gate.nec.co.jp (8.13.8/8.13.4) with ESMTP id p3886FC0019103; Fri, 8 Apr 2011 17:06:15 +0900 (JST) Received: (from root@localhost) by mailgate3.nec.co.jp (8.11.7/3.7W-MAILGATE-NEC) id p3886Ef08029; Fri, 8 Apr 2011 17:06:14 +0900 (JST) Received: from mail02.kamome.nec.co.jp (mail02.kamome.nec.co.jp [10.25.43.5]) by mailsv4.nec.co.jp (8.13.8/8.13.4) with ESMTP id p3885T2t000914; Fri, 8 Apr 2011 17:06:14 +0900 (JST) Received: from saigo.jp.nec.com ([10.26.220.6] [10.26.220.6]) by mail03.kamome.nec.co.jp with ESMTP id BT-MMP-328704; Fri, 8 Apr 2011 16:51:10 +0900 Received: from [10.64.168.30] ([10.64.168.30] [10.64.168.30]) by mail.jp.nec.com with ESMTP; Fri, 8 Apr 2011 16:51:10 +0900 Message-ID: <4D9EBE67.3010603@sx.jp.nec.com> Date: Fri, 08 Apr 2011 16:51:03 +0900 From: Kazuya Mio User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; ja; rv:1.9.2.15) Gecko/20110303 Thunderbird/3.1.9 MIME-Version: 1.0 To: ext4 , Theodore Tso Subject: [PATCH 01/11] libe2p: Add new function get_fragment_score() Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org This patch adds get_fragment_score() to libe2p. get_fragment_score() returns the fragmentation score. It shows the percentage of extents whose size is smaller than the input argument "threshold". However, there are some cases that cannot be merged into a next extent. The following extents are excepted from the calculation of fragmentation score: - The extent whose initialize status is different from the next extent - There is a hole between the extent and its next extent - The extent is a tail Signed-off-by: Kazuya Mio --- lib/e2p/Makefile.in | 6 + lib/e2p/e2p.h | 2 lib/e2p/fragment_score.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 2 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/lib/e2p/Makefile.in b/lib/e2p/Makefile.in index 9775a98..c62a81d 100644 --- a/lib/e2p/Makefile.in +++ b/lib/e2p/Makefile.in @@ -19,7 +19,7 @@ all:: e2p.pc OBJS= feature.o fgetflags.o fsetflags.o fgetversion.o fsetversion.o \ getflags.o getversion.o hashstr.o iod.o ls.o mntopts.o \ parse_num.o pe.o pf.o ps.o setflags.o setversion.o uuid.o \ - ostype.o percent.o + ostype.o percent.o fragment_score.o SRCS= $(srcdir)/feature.c $(srcdir)/fgetflags.c \ $(srcdir)/fsetflags.c $(srcdir)/fgetversion.c \ @@ -28,7 +28,7 @@ SRCS= $(srcdir)/feature.c $(srcdir)/fgetflags.c \ $(srcdir)/ls.c $(srcdir)/mntopts.c $(srcdir)/parse_num.c \ $(srcdir)/pe.c $(srcdir)/pf.c $(srcdir)/ps.c \ $(srcdir)/setflags.c $(srcdir)/setversion.c $(srcdir)/uuid.c \ - $(srcdir)/ostype.c $(srcdir)/percent.c + $(srcdir)/ostype.c $(srcdir)/percent.c $(srcdir)/fragment_score.c HFILES= e2p.h LIBRARY= libe2p @@ -162,3 +162,5 @@ ostype.o: $(srcdir)/ostype.c $(srcdir)/e2p.h \ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h percent.o: $(srcdir)/percent.c $(srcdir)/e2p.h \ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h +fragment_score.o: $(srcdir)/fragment_score.c $(srcdir)/e2p.h \ + $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h diff --git a/lib/e2p/e2p.h b/lib/e2p/e2p.h index 4a68dd9..52a8e51 100644 --- a/lib/e2p/e2p.h +++ b/lib/e2p/e2p.h @@ -72,3 +72,5 @@ char *e2p_os2string(int os_type); int e2p_string2os(char *str); unsigned int e2p_percent(int percent, unsigned int base); + +int get_fragment_score(int fd, size_t threshold); diff --git a/lib/e2p/fragment_score.c b/lib/e2p/fragment_score.c new file mode 100644 index 0000000..3ad21b9 --- /dev/null +++ b/lib/e2p/fragment_score.c @@ -0,0 +1,142 @@ +/* + * fragment_score.c --- Get file fragmentation score on ext4 filesystem. + * + * Copyright (C) 2011 Kazuya Mio + * NEC Software Tohoku, Ltd. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#define _LARGEFILE64_SOURCE + +#if HAVE_ERRNO_H +#include +#endif +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "e2p.h" + +#define EXT3_IOC_GETFLAGS _IOR('f', 1, long) + +#ifdef HAVE_FSTAT64 +#define FSTAT fstat64 +#define STRUCT_STAT struct stat64 +#else +#define FSTAT fstat +#define STRUCT_STAT struct stat +#endif + +static int is_target_extent(struct fiemap_extent *cur_fm_ext, + struct fiemap_extent *next_fm_ext) +{ + /* Check a hole between the extent */ + if ((cur_fm_ext->fe_logical + cur_fm_ext->fe_length) + < next_fm_ext->fe_logical) + return 0; + /* Check a defference of unwritten flag */ + if ((cur_fm_ext->fe_flags & FIEMAP_EXTENT_UNWRITTEN) + != (next_fm_ext->fe_flags & FIEMAP_EXTENT_UNWRITTEN)) + return 0; + + /* target extent */ + return 1; +} + +int get_fragment_score(int fd, size_t threshold) +{ + unsigned int flags = 0; + STRUCT_STAT fileinfo; + struct statfs fsinfo; + char buf[4096] = ""; + struct fiemap *fiemap = (struct fiemap *)buf; + struct fiemap_extent *fm_ext = &fiemap->fm_extents[0]; + struct fiemap_extent prev_fm_ext; + int count = (sizeof(buf) - sizeof(*fiemap)) / + sizeof(struct fiemap_extent); + int tot_extents = 0; + int frag_extents = 0; + unsigned int i; + int first = 1, last = 0; + + if (FSTAT(fd, &fileinfo) < 0 || + fstatfs(fd, &fsinfo) < 0) + return -1; + if (ioctl(fd, EXT3_IOC_GETFLAGS, &flags) < 0) + flags = 0; + + /* + * Return an error if the target file is not the following cases. + * - regular file + * - extent format file on ext4 filesystem + */ + if (!S_ISREG(fileinfo.st_mode) || + fsinfo.f_type != EXT2_SUPER_MAGIC || + !(flags & EXT4_EXTENTS_FL)) { + errno = EOPNOTSUPP; + return -1; + } + + memset(fiemap, 0, sizeof(struct fiemap)); + fiemap->fm_start = 0; + fiemap->fm_length = ~0ULL; + fiemap->fm_extent_count = count; + + do { + fiemap->fm_flags = 0; + if (ioctl(fd, FS_IOC_FIEMAP, (unsigned long) fiemap) < 0) + return -1; + + /* If 0 extents are returned, then more ioctls are not needed */ + if (fiemap->fm_mapped_extents == 0) + break; + + if (first != 0) + first = 0; + else { + /* Check the last extent gotten by previous FIEMAP */ + if (is_target_extent(&prev_fm_ext, &fm_ext[0])) { + tot_extents++; + if (prev_fm_ext.fe_length < threshold) + frag_extents++; + } + } + + for (i = 0; i < fiemap->fm_mapped_extents; i++) { + if (fm_ext[i].fe_flags & FIEMAP_EXTENT_LAST) { + last = 1; + continue; + } + + if (fiemap->fm_mapped_extents - 1 == i) { + memcpy(&prev_fm_ext, &fm_ext[i], + sizeof(struct fiemap_extent)); + continue; + } + + /* Check target extent */ + if (!is_target_extent(&fm_ext[i], &fm_ext[i+1])) + continue; + + tot_extents++; + + if (fm_ext[i].fe_length < threshold) + frag_extents++; + } + + fiemap->fm_start = (fm_ext[i-1].fe_logical + + fm_ext[i-1].fe_length); + } while (last == 0); + + return tot_extents == 0 ? 0 : (100 * frag_extents) / tot_extents; +}