check: Remount file system if MOUNT_OPTIONS changed
[xfstests-dev.git] / src / alloc.c
1 /*
2  * Copyright (c) 2000-2003 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18  
19 #include "global.h"
20
21 /*
22  * Block I/O parameterization.  A basic block (BB) is the lowest size of
23  * filesystem allocation, and must equal 512.  Length units given to bio
24  * routines are in BB's.
25  */
26
27 /* Assume that if we have BTOBB, then we have the rest */
28 #ifndef BTOBB
29 #define BBSHIFT         9
30 #define BBSIZE          (1<<BBSHIFT)
31 #define BBMASK          (BBSIZE-1)
32 #define BTOBB(bytes)    (((__u64)(bytes) + BBSIZE - 1) >> BBSHIFT)
33 #define BTOBBT(bytes)   ((__u64)(bytes) >> BBSHIFT)
34 #define BBTOB(bbs)      ((bbs) << BBSHIFT)
35 #define OFFTOBBT(bytes) ((__u64)(bytes) >> BBSHIFT)
36
37 #define SEEKLIMIT32     0x7fffffff
38 #define BBSEEKLIMIT32   BTOBBT(SEEKLIMIT32)
39 #define SEEKLIMIT       0x7fffffffffffffffLL
40 #define BBSEEKLIMIT     OFFTOBBT(SEEKLIMIT)
41 #endif
42
43 #ifndef OFFTOBB
44 #define OFFTOBB(bytes)  (((__u64)(bytes) + BBSIZE - 1) >> BBSHIFT)
45 #define BBTOOFF(bbs)    ((__u64)(bbs) << BBSHIFT)
46 #endif
47
48 #define FSBTOBB(f)      (OFFTOBBT(FSBTOOFF(f)))
49 #define BBTOFSB(b)      (OFFTOFSB(BBTOOFF(b)))
50 #define OFFTOFSB(o)     ((o) / blocksize)
51 #define FSBTOOFF(f)     ((f) * blocksize)
52
53 void usage(void)
54 {
55     printf("usage: alloc [-b blocksize] [-d dir] [-f file] [-n] [-r] [-t]\n"
56            "flags:\n"
57            "    -n - non-interractive mode\n"
58            "    -r - real time file\n"
59            "    -t - truncate on open\n"
60            "\n"  
61            "commands:\n"  
62            "    r   [offset] [length] - reserve\n"
63            "    u   [offset] [length] - unreserve\n"
64            "    a   [offset] [length] - alloc      *** identical to free\n"
65            "    f   [offset] [length] - free       *** identical to alloc\n" 
66            "    m/p [offset] [length] - print map\n"
67            "    s                     - sync file\n"
68            "    t   [offset]          - truncate\n"
69            "    q                     - quit\n"
70            "    h/?                   - this help\n");
71            
72 }
73
74 int             fd = -1;
75 int             blocksize;
76 char            *filename;
77
78 /* params are in bytes */
79 void map(off64_t off, off64_t len)
80 {
81     struct getbmap      bm[2];
82     
83     bzero(bm, sizeof(bm));
84
85     bm[0].bmv_count = 2;
86     bm[0].bmv_offset = OFFTOBB(off);
87     if (len==(off64_t)-1) { /* unsigned... */
88         bm[0].bmv_length = -1;
89         printf("    MAP off=%lld, len=%lld [%lld-]\n", 
90                 (long long)off, (long long)len,
91                 (long long)BBTOFSB(bm[0].bmv_offset));
92     } else {
93         bm[0].bmv_length = OFFTOBB(len);
94         printf("    MAP off=%lld, len=%lld [%lld,%lld]\n", 
95                 (long long)off, (long long)len,
96                 (long long)BBTOFSB(bm[0].bmv_offset),
97                 (long long)BBTOFSB(bm[0].bmv_length));
98     }
99     
100     printf("        [ofs,count]: start..end\n");
101     for (;;) {
102 #ifdef XFS_IOC_GETBMAP
103             if (xfsctl(filename, fd, XFS_IOC_GETBMAP, bm) < 0) {
104 #else
105 #ifdef F_GETBMAP
106             if (fcntl(fd, F_GETBMAP, bm) < 0) {
107 #else
108 bozo!
109 #endif
110 #endif
111                     perror("getbmap");
112                     break;
113             }
114
115             if (bm[0].bmv_entries == 0)
116                     break;
117
118             printf("        [%lld,%lld]: ",
119                     (long long)BBTOFSB(bm[1].bmv_offset),
120                     (long long)BBTOFSB(bm[1].bmv_length));
121
122             if (bm[1].bmv_block == -1)
123                     printf("hole");
124             else
125                     printf("%lld..%lld",
126                             (long long)BBTOFSB(bm[1].bmv_block),
127                             (long long)BBTOFSB(bm[1].bmv_block +
128                                     bm[1].bmv_length - 1));
129             printf("\n");
130     }
131 }
132
133 int
134 main(int argc, char **argv)
135 {
136         int             c;
137         char            *dirname = NULL;
138         int             done = 0;
139         int             status = 0;
140         struct flock64  f;
141         off64_t         len;
142         char            line[1024];
143         off64_t         off;
144         int             oflags;
145         static char     *opnames[] = { "freesp",
146                                        "allocsp",
147                                        "unresvsp",
148                                        "resvsp" };
149         int             opno;
150
151         /* Assume that if we have FREESP64 then we have the rest */
152 #ifdef XFS_IOC_FREESP64
153 #define USE_XFSCTL
154         static int      optab[] = { XFS_IOC_FREESP64,
155                                     XFS_IOC_ALLOCSP64,
156                                     XFS_IOC_UNRESVSP64,
157                                     XFS_IOC_RESVSP64 };
158 #else
159 #ifdef F_FREESP64
160 #define USE_FCNTL
161         static int      optab[] = { F_FREESP64,
162                                     F_ALLOCSP64,
163                                     F_UNRESVSP64,
164                                     F_RESVSP64 };
165 #else
166 bozo!
167 #endif
168 #endif
169         int             rflag = 0;
170         struct statvfs64        svfs;
171         int             tflag = 0;
172         int             nflag = 0;
173         int             unlinkit = 0;
174         __int64_t       v;
175
176         while ((c = getopt(argc, argv, "b:d:f:rtn")) != -1) {
177                 switch (c) {
178                 case 'b':
179                         blocksize = atoi(optarg);
180                         break;
181                 case 'd':
182                         if (filename) {
183                                 printf("can't specify both -d and -f\n");
184                                 exit(1);
185                         }
186                         dirname = optarg;
187                         break;
188                 case 'f':
189                         if (dirname) {
190                                 printf("can't specify both -d and -f\n");
191                                 exit(1);
192                         }
193                         filename = optarg;
194                         break;
195                 case 'r':
196                         rflag = 1;
197                         break;
198                 case 't':
199                         tflag = 1;
200                         break;
201                 case 'n':
202                         nflag++;
203                         break;
204                 default:
205                         printf("unknown option\n");
206                         usage();
207                         exit(1);
208                 }
209         }
210         if (!dirname && !filename)
211                 dirname = ".";
212         if (!filename) {
213                 static char     tmpfile[] = "allocXXXXXX";
214
215                 mkstemp(tmpfile);
216                 filename = malloc(strlen(tmpfile) + strlen(dirname) + 2);
217                 sprintf(filename, "%s/%s", dirname, tmpfile);
218                 unlinkit = 1;
219         }
220         oflags = O_RDWR | O_CREAT | (tflag ? O_TRUNC : 0);
221         fd = open(filename, oflags, 0666);
222         if (!nflag) {
223             printf("alloc:\n");
224             printf("    filename %s\n", filename);
225         }
226         if (fd < 0) {
227                 perror(filename);
228                 exit(1);
229         }
230         if (!blocksize) {
231                 if (fstatvfs64(fd, &svfs) < 0) {
232                         perror(filename);
233                         status = 1;
234                         goto done;
235                 }
236                 blocksize = (int)svfs.f_bsize;
237         }
238         if (blocksize<0) {
239                 fprintf(stderr,"illegal blocksize %d\n", blocksize);
240                 status = 1;
241                 goto done;
242         }
243         printf("    blocksize %d\n", blocksize);
244         if (rflag) {
245                 struct fsxattr a;
246
247 #ifdef XFS_IOC_FSGETXATTR
248                 if (xfsctl(filename, fd, XFS_IOC_FSGETXATTR, &a) < 0) {
249                         perror("XFS_IOC_FSGETXATTR");
250                         status = 1;
251                         goto done;
252                 }
253 #else
254 #ifdef F_FSGETXATTR
255                 if (fcntl(fd, F_FSGETXATTR, &a) < 0) {
256                         perror("F_FSGETXATTR");
257                         status = 1;
258                         goto done;
259                 }
260 #else
261 bozo!
262 #endif
263 #endif
264
265                 a.fsx_xflags |= XFS_XFLAG_REALTIME;
266
267 #ifdef XFS_IOC_FSSETXATTR
268                 if (xfsctl(filename, fd, XFS_IOC_FSSETXATTR, &a) < 0) {
269                         perror("XFS_IOC_FSSETXATTR");
270                         status = 1;
271                         goto done;
272                 }
273 #else
274 #ifdef F_FSSETXATTR
275                 if (fcntl(fd, F_FSSETXATTR, &a) < 0) {
276                         perror("F_FSSETXATTR");
277                         status = 1;
278                         goto done;
279                 }
280 #else
281 bozo!
282 #endif
283 #endif
284         }
285         while (!done) {
286                 char *p;
287                 
288                 if (!nflag) printf("alloc> ");
289                 fflush(stdout);
290                 if (!fgets(line, 1024, stdin)) break;
291                 
292                 p=line+strlen(line);
293                 if (p!=line&&p[-1]=='\n') p[-1]=0;
294                 
295                 opno = 0;
296                 switch (line[0]) {
297                 case 'r':
298                         opno++;
299                 case 'u':
300                         opno++;
301                 case 'a':
302                         opno++;
303                 case 'f':
304                         v = strtoll(&line[2], &p, 0);
305                         if (*p == 'b') {
306                                 off = FSBTOOFF(v);
307                                 p++;
308                         } else
309                                 off = v;
310                         f.l_whence = SEEK_SET;
311                         f.l_start = off;
312                         if (*p == '\0')
313                                 v = -1;
314                         else
315                                 v = strtoll(p, &p, 0);
316                         if (*p == 'b') {
317                                 len = FSBTOOFF(v);
318                                 p++;
319                         } else
320                                 len = v;
321                         
322                         printf("    CMD %s, off=%lld, len=%lld\n", 
323                                 opnames[opno], (long long)off, (long long)len);
324                         
325                         f.l_len = len;
326 #ifdef USE_XFSCTL
327                         c = xfsctl(filename, fd, optab[opno], &f);
328 #else
329 #ifdef USE_FCNTL
330                         c = fcntl(fd, optab[opno], &f);
331 #else
332 bozo!
333 #endif
334 #endif
335                         if (c < 0) {
336                                 perror(opnames[opno]);
337                                 break;
338                         }
339                         
340                         map(off,len);                        
341                         break;
342                 case 'p':
343                 case 'm':
344                         p = &line[1];
345                         v = strtoll(p, &p, 0);
346                         if (*p == 'b') {
347                                 off = FSBTOOFF(v);
348                                 p++;
349                         } else
350                                 off = v;
351                         if (*p == '\0')
352                                 len = -1;
353                         else {
354                                 v = strtoll(p, &p, 0);
355                                 if (*p == 'b')
356                                         len = FSBTOOFF(v);
357                                 else
358                                         len = v;
359                         }
360                         map(off,len);
361                         break;
362                 case 't':
363                         p = &line[1];
364                         v = strtoll(p, &p, 0);
365                         if (*p == 'b')
366                                 off = FSBTOOFF(v);
367                         else
368                                 off = v;
369                         printf("    TRUNCATE off=%lld\n", (long long)off);
370                         if (ftruncate64(fd, off) < 0) {
371                                 perror("ftruncate");
372                                 break;
373                         }
374                         break;
375                 case 's':
376                         printf("    SYNC\n");
377                         fsync(fd);
378                         break;
379                 case 'q':
380                         printf("    QUIT\n");
381                         done = 1;
382                         break;
383                 case '?':
384                 case 'h':
385                         usage();
386                         break;
387                 default:
388                         printf("unknown command '%s'\n", line);
389                         break;
390                 }
391         }
392         if (!nflag) printf("\n");
393 done:
394         if (fd != -1)
395                 close(fd);
396         if (unlinkit)
397                 unlink(filename);
398         exit(status);
399         /* NOTREACHED */
400 }