[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <47EA6DA9.4010103@redhat.com>
Date: Wed, 26 Mar 2008 10:37:13 -0500
From: Eric Sandeen <sandeen@...hat.com>
To: ext4 development <linux-ext4@...r.kernel.org>
Subject: [PATCH 0/3] fiemap patches (RFC/testing)
Since Akira would like to use the fiemap ioctl for defrag, I thought I should
put what I have so far out on the list, at least. This could go in the unstable
part of the tree if you like, though I need to do more testing etc before it's
really ready to go.
Also, below is a quick test application I was using with the ioctl.
-Eric
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/vfs.h>
#include <ext2fs/ext2_types.h>
/*************************************************/
/* All this should come from fiemap.h eventually */
struct fiemap_extent {
__u64 fe_offset; /* offset in bytes for the start of the extent */
__u64 fe_length; /* length in bytes for the extent */
__u32 fe_flags; /* returned FIEMAP_EXTENT_* flags for the extent */
__u32 fe_lun; /* logical device number for extent (starting at 0) */
};
struct fiemap {
__u64 fm_start; /* logical starting byte offset (in/out) */
__u64 fm_length; /* logical length of map (in/out) */
__u32 fm_flags; /* FIEMAP_FLAG_* flags for request (in/out) */
__u32 fm_extent_count; /* number of extents in fm_extents (in/out) */
__u64 fm_end_offset; /* logical offset of end of mapping in last ioctl */
struct fiemap_extent fm_extents[0];
};
#define FIEMAP_FLAG_SYNC 0x00000001 /* sync file data before map */
#define FIEMAP_FLAG_HSM_READ 0x00000002 /* get data from HSM before map */
#define FIEMAP_FLAG_NUM_EXTENTS 0x00000004 /* return only number of extents */
#define FIEMAP_FLAG_INCOMPAT 0xff000000 /* error for unknown flags in here */
#define FIEMAP_FLAG_LUN_OFFSET 0x01000000 /* use lun offsets, instead of
* logical file offsets */
#define FIEMAP_EXTENT_HOLE 0x00000001 /* has no data or space allocation */
#define FIEMAP_EXTENT_UNWRITTEN 0x00000002 /* space allocated, but no data */
#define FIEMAP_EXTENT_UNMAPPED 0x00000004 /* has data but no space allocation*/
#define FIEMAP_EXTENT_ERROR 0x00000008 /* mapping error, errno in fe_start*/
#define FIEMAP_EXTENT_NO_DIRECT 0x00000010 /* cannot access data directly */
#define FIEMAP_EXTENT_LAST 0x00000020 /* last extent in the file */
#define FIEMAP_EXTENT_DELALLOC 0x00000040 /* has data but not yet written,
must have EXTENT_UNKNOWN set */
#define FIEMAP_EXTENT_SECONDARY 0x00000080 /* data (also) in secondary storage,
not in primary if EXTENT_UNKNOWN*/
#define FIEMAP_EXTENT_EOF 0x00000100 /* if fm_start+fm_len is beyond EOF*/
#define FIGETBSZ _IO(0x00, 2) /* get the block size used for bmap */
#define EXT4_IOC_FIEMAP _IOWR('f', 10, struct fiemap) /* get file extent info*/
/* End of what should be coming from fiemap.h */
/**********************************************/
void usage(void)
{
printf("Usage: fiemap [-vrSCL] [-s start] [-l length] [-c buf count] [-m max] filename\n");
printf(" -v : verbose mode\n");
printf(" -r : raw output: print raw ioctl structure values\n");
printf(" -S : set FIEMAP_FLAG_SYNC to sync before mapping\n");
printf(" -C : set FIEMAP_FLAG_NUM_EXTENTS to only get extent count, not mapping\n");
printf(" -L : set FIEMAP_FLAG_LUN_OFFSET to report extents in lun order\n");
printf(" -s start : start of mapping in bytes (default 0)\n");
printf(" -l length : length of mapping in bytes (default to end of file)\n");
printf(" -c count : count of extents in ioctl input structure (default 32)\n");
printf(" -m max : max nr of ioctls to call before exit (default 512)\n");
exit(EXIT_FAILURE);
}
#define EXABYTES(x) ((long long)(x) << 60)
#define PETABYTES(x) ((long long)(x) << 50)
#define TERABYTES(x) ((long long)(x) << 40)
#define GIGABYTES(x) ((long long)(x) << 30)
#define MEGABYTES(x) ((long long)(x) << 20)
#define KILOBYTES(x) ((long long)(x) << 10)
long long
cvtnum(char *s)
{
long long i;
char *sp;
int c;
i = strtoll(s, &sp, 0);
if (i == 0 && sp == s)
return -1LL;
if (*sp == '\0')
return i;
if (sp[1] != '\0')
return -1LL;
c = tolower(*sp);
switch (c) {
case 'k':
return KILOBYTES(i);
case 'm':
return MEGABYTES(i);
case 'g':
return GIGABYTES(i);
case 't':
return TERABYTES(i);
case 'p':
return PETABYTES(i);
case 'e':
return EXABYTES(i);
}
return -1LL;
}
void show_extents_table(struct fiemap *fiemap, int blocksize, int start_extent, int *is_last)
{
unsigned int i;
__u64 lstart;
lstart = fiemap->fm_start;
for (i = 0; i < fiemap->fm_extent_count; i++) {
__u64 length = fiemap->fm_extents[i].fe_length;
__u64 phys = fiemap->fm_extents[i].fe_offset;
int flags = fiemap->fm_extents[i].fe_flags;
printf("ext: %3u logical: [%8llu..%8llu] phys: %8llu..%8llu flags: 0x%03X tot: %llu\n",
i + start_extent,
lstart, lstart + length - 1,
(phys / blocksize),
(flags & FIEMAP_EXTENT_HOLE) ? 0 : (phys + length - 1) / blocksize,
flags,
(length / blocksize));
lstart += length;
if (fiemap->fm_extents[i].fe_flags & FIEMAP_EXTENT_LAST) {
*is_last = 1;
return; /* XXX should we? or should look for exents filled in past last? */
}
}
}
void show_extents_raw(struct fiemap *fiemap, int start_extent, int *is_last)
{
unsigned int i;
for (i = 0; i < fiemap->fm_extent_count; i++) {
printf("\tExtent %3u: start: %10lld length: %10lld flags 0x%03X lun %3u\n",
i + start_extent,
fiemap->fm_extents[i].fe_offset,
fiemap->fm_extents[i].fe_length,
fiemap->fm_extents[i].fe_flags,
fiemap->fm_extents[i].fe_lun);
if (fiemap->fm_extents[i].fe_flags & FIEMAP_EXTENT_LAST) {
*is_last = 1;
return; /* XXX should we? or should look for exents filled in past last? */
}
}
}
int main(int argc, char**argv)
{
int blocksize = 0; /* filesystem blocksize */
uint count = 32; /* extent count */
int countonly = 0; /* return only extent count? */
int fd; /* file descriptor */
int last = 0; /* last extent found */
int lunwise = 0; /* return extents lun-wise */
int maxioctls = 512; /* max ioctls to try */
int opt;
int rc;
int raw = 0; /* raw output format */
int sync = 0; /* sync file before mapping */
int verbose = 0; /* verbose output */
char *fname; /* filename to map */
char *fiebuf; /* fiemap buffer / ioctl argument */
__u64 lstart = 0; /* logical input mapping start */
__u64 llength = ~0ULL;/* logical input mapping length */
uint start_ext = 0; /* starting extent nr. for this batch */
struct fiemap *fiemap;
while ((opt = getopt(argc, argv, "s:l:c:m:rSCLv")) != -1) {
switch(opt) {
/* logical mapping offset */
case 's':
lstart = cvtnum(optarg);
break;
/* logical mapping length */
case 'l':
llength = cvtnum(optarg);
break;
/* count of extent buffers to send */
case 'c':
count = atoi(optarg);
break;
/* max nr. of ioctls to try (safety net) */
case 'm':
maxioctls = atoi(optarg);
break;
/* raw format output */
case 'r':
raw++;
break;
/* sync file before mapping */
case 'S':
sync++;
break;
/* count extents only, no details */
case 'C':
countonly++;
break;
/* return extents in lun order */
case 'L':
lunwise++;
break;
/* be verbose */
case 'v':
verbose++;
break;
default:
usage();
}
}
fname = argv[optind++];
if (!fname)
usage();
/* The whole buffer, extent maps and all */
fiebuf = malloc(sizeof (struct fiemap) + (count * sizeof(struct fiemap_extent)));
if (!fiebuf) {
perror("Could not allocate fiemap buffers");
exit(1);
}
/* Just the header */
fiemap = (struct fiemap *)fiebuf;
fiemap->fm_start = lstart;
fiemap->fm_length = llength;
fiemap->fm_flags = 0;
if (sync)
fiemap->fm_flags |= FIEMAP_FLAG_SYNC;
if (countonly)
fiemap->fm_flags |= FIEMAP_FLAG_NUM_EXTENTS;
if (lunwise)
fiemap->fm_flags |= FIEMAP_FLAG_LUN_OFFSET;
fiemap->fm_extent_count = count;
fiemap->fm_end_offset = 0; /* output only */
fd = open(fname, O_RDONLY);
if (fd < 0) {
perror("Can't open file");
exit(1);
}
if (ioctl(fd, FIGETBSZ, &blocksize) < 0) {
perror("Can't get block size");
close(fd);
return;
}
do {
if (verbose)
printf("Input: start %llu length %llu flags 0x%X count %u end_offset %lld\n",
fiemap->fm_start, fiemap->fm_length,
fiemap->fm_flags, fiemap->fm_extent_count,
fiemap->fm_end_offset);
rc = ioctl(fd, EXT4_IOC_FIEMAP, (unsigned long)fiemap);
if (rc < 0) {
perror("FIEMAP ioctl failed");
close(fd);
exit(1);
}
if (verbose)
printf("Output: start %llu length %llu flags 0x%X count %u end_offset %lld\n",
fiemap->fm_start, fiemap->fm_length,
fiemap->fm_flags, fiemap->fm_extent_count,
fiemap->fm_end_offset);
if (raw)
show_extents_raw(fiemap, start_ext, &last);
else
show_extents_table(fiemap, blocksize, start_ext, &last);
start_ext += fiemap->fm_extent_count;
/* Did we finish up the last of the reqest? */
if (fiemap->fm_length >= llength)
break;
/* Set up the next call arguments */
fiemap->fm_start += fiemap->fm_length;
llength -= fiemap->fm_length;
fiemap->fm_length = llength;
fiemap->fm_extent_count = count;
maxioctls--;
} while (!last && maxioctls > 0);
close(fd);
return 0;
}
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists