From patchwork Mon Nov 14 06:23:54 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kazuya Mio X-Patchwork-Id: 125483 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 C0402B7134 for ; Mon, 14 Nov 2011 17:31:42 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751693Ab1KNGbl (ORCPT ); Mon, 14 Nov 2011 01:31:41 -0500 Received: from TYO201.gate.nec.co.jp ([202.32.8.193]:57227 "EHLO tyo201.gate.nec.co.jp" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750944Ab1KNGbk (ORCPT ); Mon, 14 Nov 2011 01:31:40 -0500 Received: from mailgate3.nec.co.jp ([10.7.69.195]) by tyo201.gate.nec.co.jp (8.13.8/8.13.4) with ESMTP id pAE6VYl2016979; Mon, 14 Nov 2011 15:31:34 +0900 (JST) Received: (from root@localhost) by mailgate3.nec.co.jp (8.11.7/3.7W-MAILGATE-NEC) id pAE6VYA20711; Mon, 14 Nov 2011 15:31:34 +0900 (JST) Received: from mail02.kamome.nec.co.jp (mail02.kamome.nec.co.jp [10.25.43.5]) by mailsv3.nec.co.jp (8.13.8/8.13.4) with ESMTP id pAE6VXYA024379; Mon, 14 Nov 2011 15:31:33 +0900 (JST) Received: from kameyata.jp.nec.com ([10.26.220.29] [10.26.220.29]) by mail01b.kamome.nec.co.jp with ESMTP id BT-MMP-876239; Mon, 14 Nov 2011 15:23:55 +0900 Received: from [10.64.168.30] ([10.64.168.30] [10.64.168.30]) by mail.jp.nec.com with ESMTPA id BT-MMP-43146; Mon, 14 Nov 2011 15:23:55 +0900 Message-ID: <4EC0B3FA.9080607@sx.jp.nec.com> Date: Mon, 14 Nov 2011 15:23:54 +0900 From: Kazuya Mio User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; ja; rv:1.9.2.18) Gecko/20110613 Thunderbird/3.1.11 MIME-Version: 1.0 To: ext4 CC: Theodore Tso , Andreas Dilger Subject: [PATCH v3 01/11] libe2p: Add new function e2p_get_fragscore() Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org This patch adds e2p_get_fragscore() to libe2p. e2p_get_fragscore() returns the fragmentation score. If the number of extents per specified blocks is smaller than 1, the fragmentation score is set to zero that means the file has no fragmentation. On the other hand, if it is bigger than 1, the fragmentation score is set to more than 1 that means the file has bad fragmentation. The higher fragmentation score means the worse fragmentation. Fragmentation score treats extents, whose file offset continues and whose status is the same, as one chunk. If the number of extents in chunk is equal to the ideal number of extents, the chunk is not used for the fragmentation score because there is no fragmentation in the chunk. The ideal number of extents is calculated based on @max_chunk_blks. Signed-off-by: Kazuya Mio --- lib/e2p/Makefile.in | 6 +- lib/e2p/e2p.h | 3 + lib/e2p/fragment_score.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 140 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 e2d0940..b0a1398 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 @@ -182,3 +182,5 @@ ostype.o: $(srcdir)/ostype.c $(top_builddir)/lib/config.h \ percent.o: $(srcdir)/percent.c $(top_builddir)/lib/config.h \ $(top_builddir)/lib/dirpaths.h $(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..5881256 100644 --- a/lib/e2p/e2p.h +++ b/lib/e2p/e2p.h @@ -72,3 +72,6 @@ char *e2p_os2string(int os_type); int e2p_string2os(char *str); unsigned int e2p_percent(int percent, unsigned int base); + +unsigned int e2p_get_fragscore(int fd, unsigned int threshold, + unsigned int max_chunk_blks, int *errp); diff --git a/lib/e2p/fragment_score.c b/lib/e2p/fragment_score.c new file mode 100644 index 0000000..ba2b3ff --- /dev/null +++ b/lib/e2p/fragment_score.c @@ -0,0 +1,133 @@ +/* + * fragment_score.c --- Get file fragmentation score. + * + * 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% + */ + +#include "config.h" +#if HAVE_ERRNO_H +#include +#endif +#include +#include +#include +#include +#include "e2p.h" + +#define FIGETBSZ _IO(0x00, 2) + +#define bad_contiguous_exts(max, cnt, len) \ + ((!max && cnt > 1) || len <= (__u64)max * (cnt - 1)) + +static int is_extent_continued(struct fiemap_extent *prev_fm_ext, + struct fiemap_extent *cur_fm_ext) +{ + /* Check a hole between the extent */ + if ((prev_fm_ext->fe_logical + prev_fm_ext->fe_length) + < cur_fm_ext->fe_logical) + return 0; + + /* Check a defference of unwritten flag */ + if ((prev_fm_ext->fe_flags & FIEMAP_EXTENT_UNWRITTEN) + != (cur_fm_ext->fe_flags & FIEMAP_EXTENT_UNWRITTEN)) + return 0; + + /* Two extents are continued */ + return 1; +} + +/* + * This function returns the fragmentation score that shows how badly fragmented + * the file might be. The score is extents per @threshold, so the higher score + * means the worse fragmentation. + * + * Fragmentation score treats extents, whose file offset continues and + * whose status is the same, as one chunk. If the number of extents + * in chunk is equal to the ideal number of extents, the chunk is not used for + * the fragmentation score because there is no fragment in the chunk. + * The ideal number of extents is calculated based on @max_chunk_blks. + */ +unsigned int e2p_get_fragscore(int fd, unsigned int threshold, + unsigned int max_chunk_blks, int *errp) +{ + char buf[4096] = ""; + struct fiemap *fiemap = (struct fiemap *)buf; + struct fiemap_extent *fm_ext = &fiemap->fm_extents[0]; + struct fiemap_extent prev_fm_ext; + unsigned int count = (sizeof(buf) - sizeof(*fiemap)) / + sizeof(struct fiemap_extent); + unsigned int total_cnt = 0, total_len = 0; + unsigned int ext_cnt = 0, ext_len = 0; + unsigned int i; + int bs, last = 0; + + if (!threshold) { + *errp = EINVAL; + return 0; + } + + /* Get the block size */ + if (ioctl(fd, FIGETBSZ, &bs) < 0) { + *errp = errno; + return 0; + } + + memset(fiemap, 0, sizeof(struct fiemap)); + fiemap->fm_length = ~0ULL; + fiemap->fm_extent_count = count; + + do { + if (ioctl(fd, FS_IOC_FIEMAP, (unsigned long) fiemap) < 0) { + *errp = errno; + return 0; + } + + /* If 0 extents are returned, then more ioctls are not needed */ + if (fiemap->fm_mapped_extents == 0) + break; + + for (i = 0; i < fiemap->fm_mapped_extents; i++) { + if (ext_cnt && !is_extent_continued(&prev_fm_ext, + &fm_ext[i])) { + if (bad_contiguous_exts(max_chunk_blks, + ext_cnt, ext_len)) { + total_cnt += ext_cnt; + total_len += ext_len; + } + ext_cnt = 0; + ext_len = 0; + } + ext_cnt++; + ext_len += fm_ext[i].fe_length / bs; + + memcpy(&prev_fm_ext, &fm_ext[i], + sizeof(struct fiemap_extent)); + + if (fm_ext[i].fe_flags & FIEMAP_EXTENT_LAST) + last = 1; + } + + fiemap->fm_start = (fm_ext[i-1].fe_logical + + fm_ext[i-1].fe_length); + } while (last == 0); + + /* Check the tail contiguous extent */ + if (ext_cnt) { + if (bad_contiguous_exts(max_chunk_blks, ext_cnt, ext_len)) { + total_cnt += ext_cnt; + total_len += ext_len; + } + } + + /* Return 0 if there is no valid contiguous extent */ + if (!total_len) + return 0; + + return (unsigned int)(total_cnt / ((double)total_len / threshold)); +}