// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2003 Silicon Graphics, Inc. * All Rights Reserved. */ #include "global.h" /* * Block I/O parameterization. A basic block (BB) is the lowest size of * filesystem allocation, and must equal 512. Length units given to bio * routines are in BB's. */ /* Assume that if we have BTOBB, then we have the rest */ #ifndef BTOBB #define BBSHIFT 9 #define BBSIZE (1<> BBSHIFT) #define BTOBBT(bytes) ((__u64)(bytes) >> BBSHIFT) #define BBTOB(bbs) ((bbs) << BBSHIFT) #define OFFTOBBT(bytes) ((__u64)(bytes) >> BBSHIFT) #define SEEKLIMIT32 0x7fffffff #define BBSEEKLIMIT32 BTOBBT(SEEKLIMIT32) #define SEEKLIMIT 0x7fffffffffffffffLL #define BBSEEKLIMIT OFFTOBBT(SEEKLIMIT) #endif #ifndef OFFTOBB #define OFFTOBB(bytes) (((__u64)(bytes) + BBSIZE - 1) >> BBSHIFT) #define BBTOOFF(bbs) ((__u64)(bbs) << BBSHIFT) #endif #define FSBTOBB(f) (OFFTOBBT(FSBTOOFF(f))) #define BBTOFSB(b) (OFFTOFSB(BBTOOFF(b))) #define OFFTOFSB(o) ((o) / blocksize) #define FSBTOOFF(f) ((f) * blocksize) void usage(void) { printf("usage: alloc [-b blocksize] [-d dir] [-f file] [-n] [-r] [-t]\n" "flags:\n" " -n - non-interractive mode\n" " -r - real time file\n" " -t - truncate on open\n" "\n" "commands:\n" " r [offset] [length] - reserve\n" " u [offset] [length] - unreserve\n" " a [offset] [length] - alloc *** identical to free\n" " f [offset] [length] - free *** identical to alloc\n" " m/p [offset] [length] - print map\n" " s - sync file\n" " t [offset] - truncate\n" " q - quit\n" " h/? - this help\n"); } int fd = -1; int blocksize; char *filename; /* params are in bytes */ void map(off64_t off, off64_t len) { struct getbmap bm[2]; bzero(bm, sizeof(bm)); bm[0].bmv_count = 2; bm[0].bmv_offset = OFFTOBB(off); if (len==(off64_t)-1) { /* unsigned... */ bm[0].bmv_length = -1; printf(" MAP off=%lld, len=%lld [%lld-]\n", (long long)off, (long long)len, (long long)BBTOFSB(bm[0].bmv_offset)); } else { bm[0].bmv_length = OFFTOBB(len); printf(" MAP off=%lld, len=%lld [%lld,%lld]\n", (long long)off, (long long)len, (long long)BBTOFSB(bm[0].bmv_offset), (long long)BBTOFSB(bm[0].bmv_length)); } printf(" [ofs,count]: start..end\n"); for (;;) { #ifdef XFS_IOC_GETBMAP if (xfsctl(filename, fd, XFS_IOC_GETBMAP, bm) < 0) { #else #ifdef F_GETBMAP if (fcntl(fd, F_GETBMAP, bm) < 0) { #else bozo! #endif #endif perror("getbmap"); break; } if (bm[0].bmv_entries == 0) break; printf(" [%lld,%lld]: ", (long long)BBTOFSB(bm[1].bmv_offset), (long long)BBTOFSB(bm[1].bmv_length)); if (bm[1].bmv_block == -1) printf("hole"); else printf("%lld..%lld", (long long)BBTOFSB(bm[1].bmv_block), (long long)BBTOFSB(bm[1].bmv_block + bm[1].bmv_length - 1)); printf("\n"); } } #ifdef HAVE_FALLOCATE # define USE_LINUX_PREALLOCATE enum linux_opno { FREESP = 0, ALLOCSP, UNRESVSP, RESVSP, }; /* emulate the irix preallocation functions with linux vfs calls */ static int linux_preallocate( int fd, enum linux_opno opno, const struct flock64 *f) { struct stat sbuf; int ret; assert(f->l_whence == SEEK_SET); switch (opno) { case FREESP: return ftruncate(fd, f->l_start); case ALLOCSP: ret = fstat(fd, &sbuf); if (ret) return ret; return fallocate(fd, 0, sbuf.st_size, f->l_start - sbuf.st_size); case UNRESVSP: return fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, f->l_start, f->l_len); case RESVSP: return fallocate(fd, FALLOC_FL_KEEP_SIZE, f->l_start, f->l_len); } /* should never get here */ errno = EINVAL; return -1; } #endif int main(int argc, char **argv) { int c; char *dirname = NULL; int done = 0; int status = 0; struct flock64 f; off64_t len; char line[1024]; off64_t off; int oflags; static char *opnames[] = { "freesp", "allocsp", "unresvsp", "resvsp" }; int opno; #if defined(HAVE_FALLOCATE) /* see static function above */ #elif defined(XFS_IOC_FREESP64) #define USE_XFSCTL /* Assume that if we have FREESP64 then we have the rest */ static int optab[] = { XFS_IOC_FREESP64, XFS_IOC_ALLOCSP64, XFS_IOC_UNRESVSP64, XFS_IOC_RESVSP64 }; #elif defined(F_FREESP64) #define USE_FCNTL static int optab[] = { F_FREESP64, F_ALLOCSP64, F_UNRESVSP64, F_RESVSP64 }; #else # error Dont know how to preallocate space! #endif int rflag = 0; struct statvfs64 svfs; int tflag = 0; int nflag = 0; int unlinkit = 0; int64_t v; while ((c = getopt(argc, argv, "b:d:f:rtn")) != -1) { switch (c) { case 'b': blocksize = atoi(optarg); break; case 'd': if (filename) { printf("can't specify both -d and -f\n"); exit(1); } dirname = optarg; break; case 'f': if (dirname) { printf("can't specify both -d and -f\n"); exit(1); } filename = optarg; break; case 'r': rflag = 1; break; case 't': tflag = 1; break; case 'n': nflag++; break; default: printf("unknown option\n"); usage(); exit(1); } } if (!dirname && !filename) dirname = "."; if (!filename) { static char tmpfile[] = "allocXXXXXX"; mkstemp(tmpfile); filename = malloc(strlen(tmpfile) + strlen(dirname) + 2); sprintf(filename, "%s/%s", dirname, tmpfile); unlinkit = 1; } oflags = O_RDWR | O_CREAT | (tflag ? O_TRUNC : 0); fd = open(filename, oflags, 0666); if (!nflag) { printf("alloc:\n"); printf(" filename %s\n", filename); } if (fd < 0) { perror(filename); exit(1); } if (!blocksize) { if (fstatvfs64(fd, &svfs) < 0) { perror(filename); status = 1; goto done; } blocksize = (int)svfs.f_bsize; } if (blocksize<0) { fprintf(stderr,"illegal blocksize %d\n", blocksize); status = 1; goto done; } printf(" blocksize %d\n", blocksize); if (rflag) { struct fsxattr a; #ifdef XFS_IOC_FSGETXATTR if (xfsctl(filename, fd, XFS_IOC_FSGETXATTR, &a) < 0) { perror("XFS_IOC_FSGETXATTR"); status = 1; goto done; } #else #ifdef F_FSGETXATTR if (fcntl(fd, F_FSGETXATTR, &a) < 0) { perror("F_FSGETXATTR"); status = 1; goto done; } #else bozo! #endif #endif a.fsx_xflags |= XFS_XFLAG_REALTIME; #ifdef XFS_IOC_FSSETXATTR if (xfsctl(filename, fd, XFS_IOC_FSSETXATTR, &a) < 0) { perror("XFS_IOC_FSSETXATTR"); status = 1; goto done; } #else #ifdef F_FSSETXATTR if (fcntl(fd, F_FSSETXATTR, &a) < 0) { perror("F_FSSETXATTR"); status = 1; goto done; } #else bozo! #endif #endif } while (!done) { char *p; if (!nflag) printf("alloc> "); fflush(stdout); if (!fgets(line, 1024, stdin)) break; p=line+strlen(line); if (p!=line&&p[-1]=='\n') p[-1]=0; opno = 0; switch (line[0]) { case 'r': opno++; case 'u': opno++; case 'a': opno++; case 'f': v = strtoll(&line[2], &p, 0); if (*p == 'b') { off = FSBTOOFF(v); p++; } else off = v; f.l_whence = SEEK_SET; f.l_start = off; if (*p == '\0') v = -1; else v = strtoll(p, &p, 0); if (*p == 'b') { len = FSBTOOFF(v); p++; } else len = v; printf(" CMD %s, off=%lld, len=%lld\n", opnames[opno], (long long)off, (long long)len); f.l_len = len; #if defined(USE_LINUX_PREALLOCATE) c = linux_preallocate(fd, opno, &f); #elif defined(USE_XFSCTL) c = xfsctl(filename, fd, optab[opno], &f); #elif defined(USE_FCNTL) c = fcntl(fd, optab[opno], &f); #else # error Dont know how to preallocate space! #endif if (c < 0) { perror(opnames[opno]); break; } map(off,len); break; case 'p': case 'm': p = &line[1]; v = strtoll(p, &p, 0); if (*p == 'b') { off = FSBTOOFF(v); p++; } else off = v; if (*p == '\0') len = -1; else { v = strtoll(p, &p, 0); if (*p == 'b') len = FSBTOOFF(v); else len = v; } map(off,len); break; case 't': p = &line[1]; v = strtoll(p, &p, 0); if (*p == 'b') off = FSBTOOFF(v); else off = v; printf(" TRUNCATE off=%lld\n", (long long)off); if (ftruncate64(fd, off) < 0) { perror("ftruncate"); break; } break; case 's': printf(" SYNC\n"); fsync(fd); break; case 'q': printf(" QUIT\n"); done = 1; break; case '?': case 'h': usage(); break; default: printf("unknown command '%s'\n", line); break; } } if (!nflag) printf("\n"); done: if (fd != -1) close(fd); if (unlinkit) unlink(filename); exit(status); /* NOTREACHED */ }