]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/prealloc.c
5805897a4a0a26156b0c3fddf73fe981f93d377d
[thirdparty/xfsprogs-dev.git] / io / prealloc.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2003-2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
5 */
6
7 #if defined(HAVE_FALLOCATE)
8 #include <linux/falloc.h>
9 #endif
10 #include "command.h"
11 #include "input.h"
12 #include "init.h"
13 #include "io.h"
14
15 #ifndef FALLOC_FL_PUNCH_HOLE
16 #define FALLOC_FL_PUNCH_HOLE 0x02
17 #endif
18
19 #ifndef FALLOC_FL_COLLAPSE_RANGE
20 #define FALLOC_FL_COLLAPSE_RANGE 0x08
21 #endif
22
23 #ifndef FALLOC_FL_ZERO_RANGE
24 #define FALLOC_FL_ZERO_RANGE 0x10
25 #endif
26
27 #ifndef FALLOC_FL_INSERT_RANGE
28 #define FALLOC_FL_INSERT_RANGE 0x20
29 #endif
30
31 #ifndef FALLOC_FL_UNSHARE_RANGE
32 #define FALLOC_FL_UNSHARE_RANGE 0x40
33 #endif
34
35 static cmdinfo_t allocsp_cmd;
36 static cmdinfo_t freesp_cmd;
37 static cmdinfo_t resvsp_cmd;
38 static cmdinfo_t unresvsp_cmd;
39 static cmdinfo_t zero_cmd;
40 #if defined(HAVE_FALLOCATE)
41 static cmdinfo_t falloc_cmd;
42 static cmdinfo_t fpunch_cmd;
43 static cmdinfo_t fcollapse_cmd;
44 static cmdinfo_t finsert_cmd;
45 static cmdinfo_t fzero_cmd;
46 static cmdinfo_t funshare_cmd;
47 #endif
48
49 static int
50 offset_length(
51 char *offset,
52 char *length,
53 xfs_flock64_t *segment)
54 {
55 size_t blocksize, sectsize;
56
57 init_cvtnum(&blocksize, &sectsize);
58 memset(segment, 0, sizeof(*segment));
59 segment->l_whence = SEEK_SET;
60 segment->l_start = cvtnum(blocksize, sectsize, offset);
61 if (segment->l_start < 0) {
62 printf(_("non-numeric offset argument -- %s\n"), offset);
63 return 0;
64 }
65 segment->l_len = cvtnum(blocksize, sectsize, length);
66 if (segment->l_len < 0) {
67 printf(_("non-numeric length argument -- %s\n"), length);
68 return 0;
69 }
70 return 1;
71 }
72
73 /*
74 * These ioctls were withdrawn in Linux 5.17, but we'll keep them around for
75 * a few releases.
76 */
77 #ifndef XFS_IOC_ALLOCSP64
78 # define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64)
79 #endif
80 #ifndef XFS_IOC_FREESP64
81 # define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64)
82 #endif
83
84 static int
85 allocsp_f(
86 int argc,
87 char **argv)
88 {
89 xfs_flock64_t segment;
90
91 if (!offset_length(argv[1], argv[2], &segment)) {
92 exitcode = 1;
93 return 0;
94 }
95
96 if (xfsctl(file->name, file->fd, XFS_IOC_ALLOCSP64, &segment) < 0) {
97 perror("XFS_IOC_ALLOCSP64");
98 exitcode = 1;
99 return 0;
100 }
101 return 0;
102 }
103
104 static int
105 freesp_f(
106 int argc,
107 char **argv)
108 {
109 xfs_flock64_t segment;
110
111 if (!offset_length(argv[1], argv[2], &segment)) {
112 exitcode = 1;
113 return 0;
114 }
115
116 if (xfsctl(file->name, file->fd, XFS_IOC_FREESP64, &segment) < 0) {
117 perror("XFS_IOC_FREESP64");
118 exitcode = 1;
119 return 0;
120 }
121 return 0;
122 }
123
124 static int
125 resvsp_f(
126 int argc,
127 char **argv)
128 {
129 xfs_flock64_t segment;
130
131 if (!offset_length(argv[1], argv[2], &segment)) {
132 exitcode = 1;
133 return 0;
134 }
135
136 if (xfsctl(file->name, file->fd, XFS_IOC_RESVSP64, &segment) < 0) {
137 perror("XFS_IOC_RESVSP64");
138 exitcode = 1;
139 return 0;
140 }
141 return 0;
142 }
143
144 static int
145 unresvsp_f(
146 int argc,
147 char **argv)
148 {
149 xfs_flock64_t segment;
150
151 if (!offset_length(argv[1], argv[2], &segment)) {
152 exitcode = 1;
153 return 0;
154 }
155
156 if (xfsctl(file->name, file->fd, XFS_IOC_UNRESVSP64, &segment) < 0) {
157 perror("XFS_IOC_UNRESVSP64");
158 exitcode = 1;
159 return 0;
160 }
161 return 0;
162 }
163
164 static int
165 zero_f(
166 int argc,
167 char **argv)
168 {
169 xfs_flock64_t segment;
170
171 if (!offset_length(argv[1], argv[2], &segment)) {
172 exitcode = 1;
173 return 0;
174 }
175
176 if (xfsctl(file->name, file->fd, XFS_IOC_ZERO_RANGE, &segment) < 0) {
177 perror("XFS_IOC_ZERO_RANGE");
178 exitcode = 1;
179 return 0;
180 }
181 return 0;
182 }
183
184
185 #if defined (HAVE_FALLOCATE)
186 static void
187 falloc_help(void)
188 {
189 printf(_(
190 "\n"
191 " modifies space associated with part of a file via fallocate"
192 "\n"
193 " Example:\n"
194 " 'falloc 0 1m' - fills all holes within the first megabyte\n"
195 "\n"
196 " falloc uses the fallocate system call to alter space allocations in the\n"
197 " open file. The following operations are supported:\n"
198 " All the file offsets are in units of bytes.\n"
199 " -c -- collapses the given range.\n"
200 " -i -- inserts a hole into the given range of the file.\n"
201 " -k -- do not change file size.\n"
202 " -p -- unmap the given range from the file.\n"
203 " -u -- unshare shared extents in the given range.\n"
204 "\n"));
205 }
206
207 static int
208 fallocate_f(
209 int argc,
210 char **argv)
211 {
212 xfs_flock64_t segment;
213 int mode = 0;
214 int c;
215
216 while ((c = getopt(argc, argv, "cikpu")) != EOF) {
217 switch (c) {
218 case 'c':
219 mode = FALLOC_FL_COLLAPSE_RANGE;
220 break;
221 case 'i':
222 mode = FALLOC_FL_INSERT_RANGE;
223 break;
224 case 'k':
225 mode = FALLOC_FL_KEEP_SIZE;
226 break;
227 case 'p':
228 mode = FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE;
229 break;
230 case 'u':
231 mode = FALLOC_FL_UNSHARE_RANGE;
232 break;
233 default:
234 exitcode = 1;
235 command_usage(&falloc_cmd);
236 }
237 }
238 if (optind != argc - 2) {
239 exitcode = 1;
240 return command_usage(&falloc_cmd);
241 }
242
243 if (!offset_length(argv[optind], argv[optind+1], &segment)) {
244 exitcode = 1;
245 return 0;
246 }
247
248 if (fallocate(file->fd, mode,
249 segment.l_start, segment.l_len)) {
250 perror("fallocate");
251 exitcode = 1;
252 return 0;
253 }
254 return 0;
255 }
256
257 static int
258 fpunch_f(
259 int argc,
260 char **argv)
261 {
262 xfs_flock64_t segment;
263 int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE;
264
265 if (!offset_length(argv[1], argv[2], &segment)) {
266 exitcode = 1;
267 return 0;
268 }
269
270 if (fallocate(file->fd, mode,
271 segment.l_start, segment.l_len)) {
272 perror("fallocate");
273 exitcode = 1;
274 return 0;
275 }
276 return 0;
277 }
278
279 static int
280 fcollapse_f(
281 int argc,
282 char **argv)
283 {
284 xfs_flock64_t segment;
285 int mode = FALLOC_FL_COLLAPSE_RANGE;
286
287 if (!offset_length(argv[1], argv[2], &segment)) {
288 exitcode = 1;
289 return 0;
290 }
291
292 if (fallocate(file->fd, mode,
293 segment.l_start, segment.l_len)) {
294 perror("fallocate");
295 exitcode = 1;
296 return 0;
297 }
298 return 0;
299 }
300
301 static int
302 finsert_f(
303 int argc,
304 char **argv)
305 {
306 xfs_flock64_t segment;
307 int mode = FALLOC_FL_INSERT_RANGE;
308
309 if (!offset_length(argv[1], argv[2], &segment)) {
310 exitcode = 1;
311 return 0;
312 }
313
314 if (fallocate(file->fd, mode,
315 segment.l_start, segment.l_len)) {
316 perror("fallocate");
317 exitcode = 1;
318 return 0;
319 }
320 return 0;
321 }
322
323 static int
324 fzero_f(
325 int argc,
326 char **argv)
327 {
328 xfs_flock64_t segment;
329 int mode = FALLOC_FL_ZERO_RANGE;
330 int c;
331
332 while ((c = getopt(argc, argv, "k")) != EOF) {
333 switch (c) {
334 case 'k':
335 mode |= FALLOC_FL_KEEP_SIZE;
336 break;
337 default:
338 command_usage(&fzero_cmd);
339 }
340 }
341 if (optind != argc - 2)
342 return command_usage(&fzero_cmd);
343
344 if (!offset_length(argv[optind], argv[optind + 1], &segment))
345 return 0;
346
347 if (fallocate(file->fd, mode, segment.l_start, segment.l_len)) {
348 perror("fallocate");
349 return 0;
350 }
351 return 0;
352 }
353
354 static int
355 funshare_f(
356 int argc,
357 char **argv)
358 {
359 xfs_flock64_t segment;
360 int c;
361 int mode = FALLOC_FL_UNSHARE_RANGE;
362
363 while ((c = getopt(argc, argv, "")) != EOF) {
364 switch (c) {
365 default:
366 command_usage(&funshare_cmd);
367 }
368 }
369 if (optind != argc - 2)
370 return command_usage(&funshare_cmd);
371
372 if (!offset_length(argv[optind], argv[optind + 1], &segment)) {
373 exitcode = 1;
374 return 0;
375 }
376
377 if (fallocate(file->fd, mode, segment.l_start, segment.l_len)) {
378 perror("fallocate");
379 exitcode = 1;
380 return 0;
381 }
382 return 0;
383 }
384 #endif /* HAVE_FALLOCATE */
385
386 void
387 prealloc_init(void)
388 {
389 allocsp_cmd.name = "allocsp";
390 allocsp_cmd.cfunc = allocsp_f;
391 allocsp_cmd.argmin = 2;
392 allocsp_cmd.argmax = 2;
393 allocsp_cmd.flags = CMD_NOMAP_OK;
394 allocsp_cmd.args = _("off len");
395 allocsp_cmd.oneline = _("allocates zeroed space for part of a file");
396
397 freesp_cmd.name = "freesp";
398 freesp_cmd.cfunc = freesp_f;
399 freesp_cmd.argmin = 2;
400 freesp_cmd.argmax = 2;
401 freesp_cmd.flags = CMD_NOMAP_OK;
402 freesp_cmd.args = _("off len");
403 freesp_cmd.oneline = _("frees space associated with part of a file");
404
405 resvsp_cmd.name = "resvsp";
406 resvsp_cmd.cfunc = resvsp_f;
407 resvsp_cmd.argmin = 2;
408 resvsp_cmd.argmax = 2;
409 resvsp_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
410 resvsp_cmd.args = _("off len");
411 resvsp_cmd.oneline =
412 _("reserves space associated with part of a file");
413
414 unresvsp_cmd.name = "unresvsp";
415 unresvsp_cmd.cfunc = unresvsp_f;
416 unresvsp_cmd.argmin = 2;
417 unresvsp_cmd.argmax = 2;
418 unresvsp_cmd.args = _("off len");
419 unresvsp_cmd.flags = CMD_NOMAP_OK;
420 unresvsp_cmd.oneline =
421 _("frees reserved space associated with part of a file");
422
423 zero_cmd.name = "zero";
424 zero_cmd.cfunc = zero_f;
425 zero_cmd.argmin = 2;
426 zero_cmd.argmax = 2;
427 zero_cmd.flags = CMD_NOMAP_OK;
428 zero_cmd.args = _("off len");
429 zero_cmd.oneline =
430 _("Converts the given range of a file to allocated zeros");
431
432 add_command(&allocsp_cmd);
433 add_command(&freesp_cmd);
434 add_command(&resvsp_cmd);
435 add_command(&unresvsp_cmd);
436 add_command(&zero_cmd);
437
438 #if defined (HAVE_FALLOCATE)
439 falloc_cmd.name = "falloc";
440 falloc_cmd.cfunc = fallocate_f;
441 falloc_cmd.argmin = 2;
442 falloc_cmd.argmax = -1;
443 falloc_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
444 falloc_cmd.args = _("[-c] [-k] [-p] [-u] off len");
445 falloc_cmd.oneline =
446 _("allocates space associated with part of a file via fallocate");
447 falloc_cmd.help = falloc_help;
448 add_command(&falloc_cmd);
449
450 fpunch_cmd.name = "fpunch";
451 fpunch_cmd.cfunc = fpunch_f;
452 fpunch_cmd.argmin = 2;
453 fpunch_cmd.argmax = 2;
454 fpunch_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
455 fpunch_cmd.args = _("off len");
456 fpunch_cmd.oneline =
457 _("de-allocates space associated with part of a file via fallocate");
458 add_command(&fpunch_cmd);
459
460 fcollapse_cmd.name = "fcollapse";
461 fcollapse_cmd.cfunc = fcollapse_f;
462 fcollapse_cmd.argmin = 2;
463 fcollapse_cmd.argmax = 2;
464 fcollapse_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
465 fcollapse_cmd.args = _("off len");
466 fcollapse_cmd.oneline =
467 _("de-allocates space and eliminates the hole by shifting extents");
468 add_command(&fcollapse_cmd);
469
470 finsert_cmd.name = "finsert";
471 finsert_cmd.cfunc = finsert_f;
472 finsert_cmd.argmin = 2;
473 finsert_cmd.argmax = 2;
474 finsert_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
475 finsert_cmd.args = _("off len");
476 finsert_cmd.oneline =
477 _("creates new space for writing within file by shifting extents");
478 add_command(&finsert_cmd);
479
480 fzero_cmd.name = "fzero";
481 fzero_cmd.cfunc = fzero_f;
482 fzero_cmd.argmin = 2;
483 fzero_cmd.argmax = 3;
484 fzero_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
485 fzero_cmd.args = _("[-k] off len");
486 fzero_cmd.oneline =
487 _("zeroes space and eliminates holes by preallocating");
488 add_command(&fzero_cmd);
489
490 funshare_cmd.name = "funshare";
491 funshare_cmd.cfunc = funshare_f;
492 funshare_cmd.argmin = 2;
493 funshare_cmd.argmax = 2;
494 funshare_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
495 funshare_cmd.args = _("off len");
496 funshare_cmd.oneline =
497 _("unshares shared blocks within the range");
498 add_command(&funshare_cmd);
499 #endif /* HAVE_FALLOCATE */
500 }