From: Eric Sandeen <sandeen@sandeen.net>
To: xfs-oss <xfs@oss.sgi.com>
Subject: [PATCH 0/2 v2] hook xfs to fiemap ioctl
Date: Sat, 25 Oct 2008 08:26:25 -0500 [thread overview]
Message-ID: <49031E81.7040807@sandeen.net> (raw)
Update & resend, including some checkpatch fixes, a bugfix, and
incorporating some of Christoph's and Dave's comments.
Also, here's a very hacky (don't laugh!) test app. I'll clean it
up at some point :)
-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_logical; /* logical offset in bytes for the start of
* the extent from the beginning of the file */
__u64 fe_physical; /* physical offset in bytes for the start
* of the extent from the beginning of the disk */
__u64 fe_length; /* length in bytes for this extent */
__u64 fe_reserved64[2];
__u32 fe_flags; /* FIEMAP_EXTENT_* flags for this extent */
__u32 fe_reserved[3];
};
struct fiemap {
__u64 fm_start; /* logical offset (inclusive) at
* which to start mapping (in) */
__u64 fm_length; /* logical length of mapping which
* userspace wants (in) */
__u32 fm_flags; /* FIEMAP_FLAG_* flags for request (in/out) */
__u32 fm_mapped_extents;/* number of extents that were mapped (out) */
__u32 fm_extent_count; /* size of fm_extents array (in) */
__u32 fm_reserved;
struct fiemap_extent fm_extents[0]; /* array of mapped extents (out) */
};
#define FIEMAP_MAX_OFFSET (~0ULL)
#define FIEMAP_FLAG_SYNC 0x00000001 /* sync file data before map */
#define FIEMAP_FLAG_XATTR 0x00000002 /* map extended attribute tree */
#define FIEMAP_FLAGS_COMPAT (FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR)
#define FIEMAP_EXTENT_LAST 0x00000001 /* Last extent in file. */
#define FIEMAP_EXTENT_UNKNOWN 0x00000002 /* Data location unknown. */
#define FIEMAP_EXTENT_DELALLOC 0x00000004 /* Location still pending.
* Sets EXTENT_UNKNOWN. */
#define FIEMAP_EXTENT_ENCODED 0x00000008 /* Data can not be read
* while fs is unmounted */
#define FIEMAP_EXTENT_DATA_ENCRYPTED 0x00000080 /* Data is encrypted by fs.
* Sets EXTENT_NO_BYPASS. */
#define FIEMAP_EXTENT_NOT_ALIGNED 0x00000100 /* Extent offsets may not be
* block aligned. */
#define FIEMAP_EXTENT_DATA_INLINE 0x00000200 /* Data mixed with metadata.
* Sets EXTENT_NOT_ALIGNED.*/
#define FIEMAP_EXTENT_DATA_TAIL 0x00000400 /* Multiple files in block.
* Sets EXTENT_NOT_ALIGNED.*/
#define FIEMAP_EXTENT_UNWRITTEN 0x00000800 /* Space allocated, but
* no data (i.e. zero). */
#define FIEMAP_EXTENT_MERGED 0x00001000 /* File does not natively
* support extents. Result
* merged for efficiency. */
#define FIGETBSZ _IO(0x00, 2) /* get the block size used for bmap */
#define FS_IOC_FIEMAP _IOWR('f', 11, struct fiemap)
// #define FS_IOC_FIECOUNT _IOWR('f', 12, struct fiecount)
/* 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(" -X : set FIEMAP_FLAG_XATTR to report xattr mapping\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;
for (i = 0; i < fiemap->fm_mapped_extents; i++) {
__u64 logical = fiemap->fm_extents[i].fe_logical;
__u64 phys = fiemap->fm_extents[i].fe_physical;
__u64 length = fiemap->fm_extents[i].fe_length;
int flags = fiemap->fm_extents[i].fe_flags;
__u64 last_logical = 0;
if (i) {
last_logical =
fiemap->fm_extents[i-1].fe_logical +
fiemap->fm_extents[i-1].fe_length - 1;
}
printf("ext: %3u logical: [%8llu..%8llu] phys: %8llu..%8llu flags: 0x%03X tot: %llu\n",
i + start_extent,
logical / blocksize,
(logical + length - 1) / blocksize,
phys / blocksize,
(phys + length - 1) / blocksize,
flags,
(length / blocksize));
if (fiemap->fm_extents[i].fe_flags & FIEMAP_EXTENT_LAST) {
*is_last = 1;
break; /* XXX should we? or should look for exents filled in past last? */
}
}
if (fiemap->fm_mapped_extents < fiemap->fm_extent_count)
*is_last = 1;
}
void show_extents_raw(struct fiemap *fiemap, int start_extent, int *is_last)
{
unsigned int i;
for (i = 0; i < fiemap->fm_mapped_extents; i++) {
printf("Extent %3u: logical: %10lld physical: %10lld length: %10lld flags 0x%03X\n",
i + start_extent,
fiemap->fm_extents[i].fe_logical,
fiemap->fm_extents[i].fe_physical,
fiemap->fm_extents[i].fe_length,
fiemap->fm_extents[i].fe_flags);
if (fiemap->fm_extents[i].fe_flags & FIEMAP_EXTENT_LAST) {
*is_last = 1;
break;
/* XXX should we? or should look for extents wrongly filled in past last? */
}
}
if (fiemap->fm_mapped_extents < fiemap->fm_extent_count)
*is_last = 1;
}
int main(int argc, char**argv)
{
int blocksize = 0; /* filesystem blocksize */
uint count = 32; /* extent count */
int fd; /* file descriptor */
int last = 0; /* last extent found */
int xattr = 0; /* return xattr mapping */
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 */
__u32 flags = 0;
struct fiemap *fiemap;
/* XXX er, can llength be ~0ULL if start > 0? */
while ((opt = getopt(argc, argv, "s:l:c:m:rSCLXv")) != -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;
/* return extents for xattrs */
case 'X':
xattr++;
break;
/* be verbose */
case 'v':
verbose++;
break;
default:
usage();
}
}
fname = argv[optind++];
if (!fname)
usage();
/* Set the flags for the header */
if (sync)
flags |= FIEMAP_FLAG_SYNC;
if (xattr)
flags |= FIEMAP_FLAG_XATTR;
/* 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);
}
/* set up the header */
fiemap = (struct fiemap *)fiebuf;
fiemap->fm_start = lstart;
fiemap->fm_length = llength;
fiemap->fm_flags = flags;
fiemap->fm_extent_count = count;
fiemap->fm_mapped_extents = 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\n",
fiemap->fm_start, fiemap->fm_length,
fiemap->fm_flags, fiemap->fm_extent_count);
rc = ioctl(fd, FS_IOC_FIEMAP, (unsigned long)fiemap);
if (rc < 0) {
perror("FIEMAP ioctl failed");
printf("flags 0x%x\n", fiemap->fm_flags);
close(fd);
exit(1);
}
if (verbose)
printf("Output: start %llu length %llu flags 0x%X count %u mapped %u\n",
fiemap->fm_start, fiemap->fm_length,
fiemap->fm_flags, fiemap->fm_extent_count,
fiemap->fm_mapped_extents);
if (raw)
show_extents_raw(fiemap, start_ext, &last);
else
show_extents_table(fiemap, blocksize, start_ext, &last);
if (!last) {
int last_map = fiemap->fm_mapped_extents - 1;
__u64 foo; /* XXX Ummmm */
foo = fiemap->fm_extents[last_map].fe_logical +
fiemap->fm_extents[last_map].fe_length;
/* Set up the next call arguments */ /* move to top */
fiemap->fm_start = foo;
fiemap->fm_length = lstart + llength - foo;
fiemap->fm_extent_count = count;
}
/* keeps track of extent nrs. we've printed; rather, pass by value! */
start_ext += fiemap->fm_mapped_extents;
/* XXX need to stop if we've reached what we asked for */
maxioctls--;
} while (!last && maxioctls > 0);
close(fd);
return 0;
}
next reply other threads:[~2008-10-25 13:26 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-10-25 13:26 Eric Sandeen [this message]
2008-10-25 13:33 ` [PATCH 1/2 v2] convert xfs_getbmap to take formatter functions Eric Sandeen
2008-10-25 20:25 ` Christoph Hellwig
2008-10-25 20:27 ` Christoph Hellwig
2008-10-25 20:28 ` Eric Sandeen
2008-10-25 13:34 ` [PATCH 2/2 v2] hook up fiemap & associated formatter Eric Sandeen
2008-10-25 20:26 ` Christoph Hellwig
2008-10-26 4:38 ` Eric Sandeen
2008-10-25 20:20 ` [PATCH 0/2 v2] hook xfs to fiemap ioctl Christoph Hellwig
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=49031E81.7040807@sandeen.net \
--to=sandeen@sandeen.net \
--cc=xfs@oss.sgi.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.