[Ocfs2-tools-devel] [PATCH 11/19] Ocfs2-tools: Add utility funcs of doing fiemap statistics.

Tristan Ye tristan.ye at oracle.com
Tue Apr 13 19:50:11 PDT 2010


Common functions to do fiemaps which will be used for task('--space-usage')
and task('--file-statistics').

Signed-off-by: Tristan Ye <tristan.ye at oracle.com>
---
 o2info/operations.c |  205 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 205 insertions(+), 0 deletions(-)

diff --git a/o2info/operations.c b/o2info/operations.c
index cd134e5..68e8cdd 100644
--- a/o2info/operations.c
+++ b/o2info/operations.c
@@ -319,3 +319,208 @@ out:
 DEFINE_O2INFO_OP(fs_features,
 		 fs_features_run,
 		 NULL);
+
+/*
+ * File statistics from fiemap.
+ */
+struct o2info_fiemap_stats {
+	uint32_t blocksize;
+	uint32_t clustersize;
+	uint32_t num_extents;
+	uint32_t num_extents_xattr;
+	uint32_t clusters;
+	float frag;
+	float score;
+	uint32_t shared;
+	uint32_t holes;
+	uint32_t unwrittens;
+	uint32_t xattr;
+};
+
+static int ul_log2(unsigned long arg)
+{
+	unsigned int i = 0;
+
+	arg >>= 1;
+	while (arg) {
+		i++;
+		arg >>= 1;
+	}
+
+	return i;
+}
+
+static int figure_extents(int fd, uint32_t *num, int flags)
+{
+	int ret;
+	static struct fiemap fiemap;
+
+	fiemap.fm_start = 0ULL;
+	fiemap.fm_length = FIEMAP_MAX_OFFSET;
+
+	if (flags & FIEMAP_FLAG_XATTR)
+		fiemap.fm_flags = FIEMAP_FLAG_XATTR;
+
+	fiemap.fm_extent_count = 0;
+	ret = ioctl(fd, FS_IOC_FIEMAP, &fiemap);
+	if (ret < 0) {
+		ret = errno;
+		tcom_err(ret, "fiemap get count error");
+		return -1;
+	}
+
+	*num = fiemap.fm_mapped_extents;
+
+	return 0;
+}
+
+static uint32_t clusters_in_bytes(uint32_t clustersize, uint32_t bytes)
+{
+	uint64_t ret = bytes + clustersize - 1;
+
+	if (ret < bytes)
+		ret = UINT64_MAX;
+
+	ret = ret >> ul_log2(clustersize);
+	if (ret > UINT32_MAX)
+		ret = UINT32_MAX;
+
+	return (uint32_t)ret;
+}
+
+static int do_fiemap(int fd, int flags, struct o2info_fiemap_stats *ofs,
+		     struct o2info_operation *op)
+{
+
+	char buf[4096];
+
+	int ret = 0, last = 0;
+	int cluster_shift = 0, blk_shift = 0;
+	int count = (sizeof(buf) - sizeof(struct fiemap)) /
+		     sizeof(struct fiemap_extent);
+
+	struct fiemap *fiemap = (struct fiemap *)buf;
+	struct fiemap_extent *fm_ext = &fiemap->fm_extents[0];
+	uint32_t num_extents = 0, extents_got = 0, i;
+
+	uint32_t prev_start = 0, prev_len = 0;
+	uint32_t start = 0, len = 0, phy_pos = 0;
+
+	if (ofs->clustersize)
+		cluster_shift = ul_log2(ofs->clustersize);
+
+	if (ofs->blocksize)
+		blk_shift = ul_log2(ofs->blocksize);
+
+	memset(fiemap, 0, sizeof(*fiemap));
+
+	ret = figure_extents(fd, &num_extents, 0);
+	if (ret)
+		return -1;
+
+	do {
+		fiemap->fm_length = ~0ULL;
+		if (flags & FIEMAP_FLAG_XATTR)
+			fiemap->fm_flags = FIEMAP_FLAG_XATTR;
+		else
+			fiemap->fm_flags = flags;
+		fiemap->fm_extent_count = count;
+
+		ret = ioctl(fd, FS_IOC_FIEMAP, (unsigned long)fiemap);
+		if (ret < 0) {
+			ret = errno;
+			if (errno == EBADR) {
+				o2i_error(op, "fiemap failed with unsupported"
+					  " flags %x\n", fiemap->fm_flags);
+			} else
+				o2i_error(op, "fiemap error: %s\n",
+					  strerror(ret));
+			return -1;
+		}
+
+		if (!fiemap->fm_mapped_extents)
+			break;
+
+		for (i = 0; i < fiemap->fm_mapped_extents; i++) {
+
+			start = fm_ext[i].fe_logical >> cluster_shift;
+			len = fm_ext[i].fe_length >> cluster_shift;
+			phy_pos = fm_ext[i].fe_physical >> blk_shift;
+
+			if (fiemap->fm_flags & FIEMAP_FLAG_XATTR) {
+				ofs->xattr += len;
+			} else {
+				if (fm_ext[i].fe_flags &
+				    FIEMAP_EXTENT_UNWRITTEN)
+					ofs->unwrittens += len;
+
+				if (fm_ext[i].fe_flags & FIEMAP_EXTENT_SHARED)
+					ofs->shared += len;
+
+				if ((prev_start + prev_len) < start)
+					ofs->holes += start - prev_start -
+						      prev_len;
+			}
+
+			if (fm_ext[i].fe_flags & FIEMAP_EXTENT_LAST)
+				last = 1;
+
+			prev_start = start;
+			prev_len = len;
+
+			extents_got++;
+			ofs->clusters += len;
+		}
+
+		fiemap->fm_start = (fm_ext[i-1].fe_logical +
+				    fm_ext[i-1].fe_length);
+	} while (!last);
+
+	if (extents_got != num_extents) {
+		o2i_error(op, "Got wrong extents number, expected:%lu, "
+			  "got:%lu\n", num_extents, extents_got);
+		return -1;
+	}
+
+	if (flags & FIEMAP_FLAG_XATTR)
+		ofs->num_extents_xattr = num_extents;
+	else
+		ofs->num_extents = num_extents;
+
+	return ret;
+}
+
+static int get_fiemap_stats(struct o2info_operation *op,
+			    struct o2info_method *om,
+			    struct o2info_fiemap_stats *ofs)
+{
+	int ret = 0, flags = 0;
+	static struct o2info_volinfo vf;
+
+	memset(ofs, 0, sizeof(*ofs));
+
+	if (om->om_method == O2INFO_USE_IOCTL)
+		ret = get_volinfo_ioctl(op, om->om_fd, &vf);
+	else
+		ret = get_volinfo_libocfs2(op, om->om_fs, &vf);
+	if (ret)
+		return -1;
+
+	ofs->blocksize = vf.blocksize;
+	ofs->clustersize = vf.clustersize;
+
+	ret = do_fiemap(om->om_fd, flags, ofs, op);
+	if (ret)
+		return ret;
+
+	if (ofs->clusters > 1 && ofs->num_extents) {
+		float e = ofs->num_extents, c = ofs->clusters;
+		int clusters_per_mb = clusters_in_bytes(ofs->clustersize,
+							OCFS2_MAX_CLUSTERSIZE);
+		ofs->frag = 100 * (e / c);
+		ofs->score = ofs->frag * clusters_per_mb;
+	}
+
+	return ret;
+}
+
-- 
1.5.5




More information about the Ocfs2-tools-devel mailing list