+// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like. Any license provided herein, whether implied or
- * otherwise, applies only to this software file. Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA 94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
*/
-#include <xfs/libxfs.h>
+#include "platform_defs.h"
#include "command.h"
+#include "input.h"
#include "init.h"
#include "io.h"
" Holes are marked by replacing the startblock..endblock with 'hole'.\n"
" All the file offsets and disk blocks are in units of 512-byte blocks.\n"
" -a -- prints the attribute fork map instead of the data fork.\n"
+" -c -- prints the copy-on-write fork map instead of the data fork.\n"
+" This works only if the kernel was compiled in debug mode.\n"
" -d -- suppresses a DMAPI read event, offline portions shown as holes.\n"
+" -e -- print delayed allocation extents.\n"
" -l -- also displays the length of each extent in 512-byte blocks.\n"
+" -n -- query n extents.\n"
+" -p -- obtain all unwritten extents as well (w/ -v show which are unwritten.)\n"
+" -v -- Verbose information, specify ag info. Show flags legend on 2nd -v\n"
" Note: the bmap for non-regular files can be obtained provided the file\n"
" was opened appropriately (in particular, must be opened read-only).\n"
"\n"));
}
-static int
-numlen(
- off64_t val)
-{
- off64_t tmp;
- int len;
-
- for (len = 0, tmp = val; tmp > 0; tmp = tmp/10)
- len++;
- return (len == 0 ? 1 : len);
-}
-
int
bmap_f(
int argc,
int loop = 0;
int flg = 0;
int aflag = 0;
+ int cflag = 0;
int lflag = 0;
int nflag = 0;
+ int pflag = 0;
int vflag = 0;
+ int is_rt = 0;
int bmv_iflags = 0; /* flags for XFS_IOC_GETBMAPX */
int i = 0;
int c;
+ int egcnt;
- while ((c = getopt(argc, argv, "adln:pv")) != EOF) {
+ while ((c = getopt(argc, argv, "acdeln:pv")) != EOF) {
switch (c) {
case 'a': /* Attribute fork. */
bmv_iflags |= BMV_IF_ATTRFORK;
aflag = 1;
break;
+ case 'c': /* CoW fork. */
+ bmv_iflags |= BMV_IF_COWFORK | BMV_IF_DELALLOC;
+ cflag = 1;
+ break;
+ case 'e':
+ bmv_iflags |= BMV_IF_DELALLOC;
+ break;
case 'l': /* list number of blocks with each extent */
lflag = 1;
break;
break;
case 'p':
/* report unwritten preallocated blocks */
+ pflag = 1;
bmv_iflags |= BMV_IF_PREALLOC;
break;
case 'v': /* Verbose output */
return command_usage(&bmap_cmd);
}
}
- if (aflag)
+ if (aflag || cflag)
bmv_iflags &= ~(BMV_IF_PREALLOC|BMV_IF_NO_DMAPI_READ);
if (vflag) {
exitcode = 1;
return 0;
}
- c = xfsctl(file->name, file->fd, XFS_IOC_FSGETXATTR, &fsx);
+ c = xfsctl(file->name, file->fd, FS_IOC_FSGETXATTR, &fsx);
if (c < 0) {
fprintf(stderr,
_("%s: cannot read attrs on \"%s\": %s\n"),
return 0;
}
- if (fsx.fsx_xflags == XFS_XFLAG_REALTIME) {
+ if (fsx.fsx_xflags == FS_XFLAG_REALTIME) {
/*
* ag info not applicable to rt, continue
* without ag output.
*/
- vflag = 0;
+ is_rt = 1;
}
}
- map_size = nflag ? nflag+1 : 32; /* initial guess - 256 */
+ map_size = nflag ? nflag+2 : 32; /* initial guess - 32 */
map = malloc(map_size*sizeof(*map));
if (map == NULL) {
fprintf(stderr, _("%s: malloc of %d bytes failed.\n"),
/* Try the xfsctl(XFS_IOC_GETBMAPX) for the number of extents specified
- * by nflag, or the initial guess number of extents (256).
+ * by nflag, or the initial guess number of extents (32).
*
* If there are more extents than we guessed, use xfsctl
- * (XFS_IOC_FSGETXATTR[A]) to get the extent count, realloc some more
+ * (FS_IOC_FSGETXATTR[A]) to get the extent count, realloc some more
* space based on this count, and try again.
*
* If the initial FGETBMAPX attempt returns EINVAL, this may mean
* EINVAL, check the length with fstat() and return "no extents"
* if the length == 0.
*
- * Why not do the xfsctl(XFS_IOC_FSGETXATTR[A]) first? Two reasons:
+ * Why not do the xfsctl(FS_IOC_FSGETXATTR[A]) first? Two reasons:
* (1) The extent count may be wrong for a file with delayed
* allocation blocks. The XFS_IOC_GETBMAPX forces the real
* allocation and fixes up the extent count.
* (2) For XFS_IOC_GETBMAP[X] on a DMAPI file that has been moved
* offline by a DMAPI application (e.g., DMF) the
- * XFS_IOC_FSGETXATTR only reflects the extents actually online.
+ * FS_IOC_FSGETXATTR only reflects the extents actually online.
* Doing XFS_IOC_GETBMAPX call first forces that data blocks online
* and then everything proceeds normally (see PV #545725).
*
do { /* loop a miximum of two times */
- bzero(map, sizeof(*map)); /* zero header */
+ memset(map, 0, sizeof(*map)); /* zero header */
map->bmv_length = -1;
map->bmv_count = map_size;
break;
if (map->bmv_entries < map->bmv_count-1)
break;
- /* Get number of extents from xfsctl XFS_IOC_FSGETXATTR[A]
+ /* Get number of extents from xfsctl FS_IOC_FSGETXATTR[A]
* syscall.
*/
i = xfsctl(file->name, file->fd, aflag ?
- XFS_IOC_FSGETXATTRA : XFS_IOC_FSGETXATTR, &fsx);
+ XFS_IOC_FSGETXATTRA : FS_IOC_FSGETXATTR, &fsx);
if (i < 0) {
- fprintf(stderr, "%s: xfsctl(XFS_IOC_FSGETXATTR%s) "
+ fprintf(stderr, "%s: xfsctl(FS_IOC_FSGETXATTR%s) "
"[\"%s\"]: %s\n", progname, aflag ? "A" : "",
file->name, strerror(errno));
free(map);
exitcode = 1;
return 0;
}
- if (fsx.fsx_nextents >= map_size-1) {
- map_size = 2*(fsx.fsx_nextents+1);
+ if (2 * fsx.fsx_nextents > map_size) {
+ map_size = 2 * fsx.fsx_nextents + 1;
map = realloc(map, map_size*sizeof(*map));
if (map == NULL) {
fprintf(stderr,
return 0;
}
}
+ egcnt = nflag ? min(nflag, map->bmv_entries) : map->bmv_entries;
printf("%s:\n", file->name);
if (!vflag) {
- for (i = 0; i < map->bmv_entries; i++) {
+ for (i = 0; i < egcnt; i++) {
printf("\t%d: [%lld..%lld]: ", i,
(long long) map[i + 1].bmv_offset,
(long long)(map[i + 1].bmv_offset +
map[i + 1].bmv_length - 1LL));
if (map[i + 1].bmv_block == -1)
printf(_("hole"));
+ else if (map[i + 1].bmv_block == -2)
+ printf(_("delalloc"));
else {
printf("%lld..%lld",
(long long) map[i + 1].bmv_block,
#define MINRANGE_WIDTH 16
#define MINAG_WIDTH 2
#define MINTOT_WIDTH 5
-#define max(a,b) (a > b ? a : b)
-#define NFLG 5 /* count of flags */
-#define FLG_NULL 000000 /* Null flag */
-#define FLG_PRE 010000 /* Unwritten extent */
-#define FLG_BSU 001000 /* Not on begin of stripe unit */
-#define FLG_ESU 000100 /* Not on end of stripe unit */
-#define FLG_BSW 000010 /* Not on begin of stripe width */
-#define FLG_ESW 000001 /* Not on end of stripe width */
+#define NFLG 6 /* count of flags */
+#define FLG_NULL 0000000 /* Null flag */
+#define FLG_SHARED 0100000 /* shared extent */
+#define FLG_PRE 0010000 /* Unwritten extent */
+#define FLG_BSU 0001000 /* Not on begin of stripe unit */
+#define FLG_ESU 0000100 /* Not on end of stripe unit */
+#define FLG_BSW 0000010 /* Not on begin of stripe width */
+#define FLG_ESW 0000001 /* Not on end of stripe width */
int agno;
off64_t agoff, bbperag;
int foff_w, boff_w, aoff_w, tot_w, agno_w;
foff_w = boff_w = aoff_w = MINRANGE_WIDTH;
tot_w = MINTOT_WIDTH;
- bbperag = (off64_t)fsgeo.agblocks *
- (off64_t)fsgeo.blocksize / BBSIZE;
- sunit = (fsgeo.sunit * fsgeo.blocksize) / BBSIZE;
- swidth = (fsgeo.swidth * fsgeo.blocksize) / BBSIZE;
- flg = sunit;
+ if (is_rt)
+ sunit = swidth = bbperag = 0;
+ else {
+ bbperag = (off64_t)fsgeo.agblocks *
+ (off64_t)fsgeo.blocksize / BBSIZE;
+ sunit = (fsgeo.sunit * fsgeo.blocksize) / BBSIZE;
+ swidth = (fsgeo.swidth * fsgeo.blocksize) / BBSIZE;
+ }
+ flg = sunit | pflag;
/*
* Go through the extents and figure out the width
* needed for all columns.
*/
- for (i = 0; i < map->bmv_entries; i++) {
+ for (i = 0; i < egcnt; i++) {
snprintf(rbuf, sizeof(rbuf), "[%lld..%lld]:",
(long long) map[i + 1].bmv_offset,
(long long)(map[i + 1].bmv_offset +
if (map[i + 1].bmv_block == -1) {
foff_w = max(foff_w, strlen(rbuf));
tot_w = max(tot_w,
- numlen(map[i+1].bmv_length));
+ numlen(map[i+1].bmv_length, 10));
} else {
snprintf(bbuf, sizeof(bbuf), "%lld..%lld",
(long long) map[i + 1].bmv_block,
(long long)(map[i + 1].bmv_block +
map[i + 1].bmv_length - 1LL));
- agno = map[i + 1].bmv_block / bbperag;
- agoff = map[i + 1].bmv_block - (agno * bbperag);
- snprintf(abuf, sizeof(abuf), "(%lld..%lld)",
- (long long)agoff, (long long)
- (agoff + map[i + 1].bmv_length - 1LL));
- foff_w = max(foff_w, strlen(rbuf));
boff_w = max(boff_w, strlen(bbuf));
- aoff_w = max(aoff_w, strlen(abuf));
+ if (!is_rt) {
+ agno = map[i + 1].bmv_block / bbperag;
+ agoff = map[i + 1].bmv_block -
+ (agno * bbperag);
+ snprintf(abuf, sizeof(abuf),
+ "(%lld..%lld)",
+ (long long)agoff,
+ (long long)(agoff +
+ map[i + 1].bmv_length - 1LL));
+ aoff_w = max(aoff_w, strlen(abuf));
+ } else
+ aoff_w = 0;
+ foff_w = max(foff_w, strlen(rbuf));
tot_w = max(tot_w,
- numlen(map[i+1].bmv_length));
+ numlen(map[i+1].bmv_length, 10));
}
}
- agno_w = max(MINAG_WIDTH, numlen(fsgeo.agcount));
+ agno_w = is_rt ? 0 : max(MINAG_WIDTH, numlen(fsgeo.agcount, 10));
printf("%4s: %-*s %-*s %*s %-*s %*s%s\n",
_("EXT"),
foff_w, _("FILE-OFFSET"),
- boff_w, _("BLOCK-RANGE"),
- agno_w, _("AG"),
- aoff_w, _("AG-OFFSET"),
+ boff_w, is_rt ? _("RT-BLOCK-RANGE") : _("BLOCK-RANGE"),
+ agno_w, is_rt ? "" : _("AG"),
+ aoff_w, is_rt ? "" : _("AG-OFFSET"),
tot_w, _("TOTAL"),
flg ? _(" FLAGS") : "");
- for (i = 0; i < map->bmv_entries; i++) {
+ for (i = 0; i < egcnt; i++) {
flg = FLG_NULL;
if (map[i + 1].bmv_oflags & BMV_OF_PREALLOC) {
flg |= FLG_PRE;
}
+ if (map[i + 1].bmv_oflags & BMV_OF_SHARED)
+ flg |= FLG_SHARED;
+ if (map[i + 1].bmv_oflags & BMV_OF_DELALLOC)
+ map[i + 1].bmv_block = -2;
/*
* If striping enabled, determine if extent starts/ends
* on a stripe unit boundary.
agno_w, "",
aoff_w, "",
tot_w, (long long)map[i+1].bmv_length);
+ } else if (map[i + 1].bmv_block == -2) {
+ printf("%4d: %-*s %-*s %*s %-*s %*lld\n",
+ i,
+ foff_w, rbuf,
+ boff_w, _("delalloc"),
+ agno_w, "",
+ aoff_w, "",
+ tot_w, (long long)map[i+1].bmv_length);
} else {
snprintf(bbuf, sizeof(bbuf), "%lld..%lld",
(long long) map[i + 1].bmv_block,
(long long)(map[i + 1].bmv_block +
map[i + 1].bmv_length - 1LL));
- agno = map[i + 1].bmv_block / bbperag;
- agoff = map[i + 1].bmv_block - (agno * bbperag);
- snprintf(abuf, sizeof(abuf), "(%lld..%lld)",
- (long long)agoff, (long long)
- (agoff + map[i + 1].bmv_length - 1LL));
- printf("%4d: %-*s %-*s %*d %-*s %*lld",
- i,
- foff_w, rbuf,
- boff_w, bbuf,
- agno_w, agno,
- aoff_w, abuf,
- tot_w, (long long)map[i+1].bmv_length);
- if (flg == FLG_NULL) {
+ printf("%4d: %-*s %-*s", i, foff_w, rbuf,
+ boff_w, bbuf);
+ if (!is_rt) {
+ agno = map[i + 1].bmv_block / bbperag;
+ agoff = map[i + 1].bmv_block -
+ (agno * bbperag);
+ snprintf(abuf, sizeof(abuf),
+ "(%lld..%lld)",
+ (long long)agoff,
+ (long long)(agoff +
+ map[i + 1].bmv_length - 1LL));
+ printf(" %*d %-*s", agno_w, agno,
+ aoff_w, abuf);
+ } else
+ printf(" ");
+ printf(" %*lld", tot_w,
+ (long long)map[i+1].bmv_length);
+ if (flg == FLG_NULL && !pflag) {
printf("\n");
} else {
printf(" %-*.*o\n", NFLG, NFLG, flg);
}
}
}
- if (flg && vflag > 1) {
+ if ((flg || pflag) && vflag > 1) {
printf(_(" FLAG Values:\n"));
+ printf(_(" %*.*o Shared extent\n"),
+ NFLG+1, NFLG+1, FLG_SHARED);
printf(_(" %*.*o Unwritten preallocated extent\n"),
NFLG+1, NFLG+1, FLG_PRE);
printf(_(" %*.*o Doesn't begin on stripe unit\n"),
void
bmap_init(void)
{
- bmap_cmd.name = _("bmap");
+ bmap_cmd.name = "bmap";
bmap_cmd.cfunc = bmap_f;
bmap_cmd.argmin = 0;
bmap_cmd.argmax = -1;