diff options
author | Karel Zak <kzak@redhat.com> | 2024-04-16 13:36:32 +0200 |
---|---|---|
committer | Karel Zak <kzak@redhat.com> | 2024-04-17 09:38:52 +0200 |
commit | a4c0dce86bcdb3a785667ea1f96ed4127fa0d545 (patch) | |
tree | 0f34afc1695fbbb5bcd54cf60893643c495ebc9f | |
parent | 7817415a5538354dfa24532f3420bfd3e74df795 (diff) | |
download | util-linux-a4c0dce86bcdb3a785667ea1f96ed4127fa0d545.tar.gz |
fdisk: add 'T' command to discard sectors
We currently have blkdiscard(8), but it can be difficult to use for
unpartitioned areas or for partitions when working with a whole-disk
device.
This commit adds BLKDISCARD support to fdisk, so that the user does
not have to specify any range, but instead follows the partition
table.
Addresses: https://github.com/util-linux/util-linux/issues/2804
Signed-off-by: Karel Zak <kzak@redhat.com>
-rw-r--r-- | disk-utils/fdisk-menu.c | 5 | ||||
-rw-r--r-- | disk-utils/fdisk.c | 142 | ||||
-rw-r--r-- | disk-utils/fdisk.h | 2 |
3 files changed, 147 insertions, 2 deletions
diff --git a/disk-utils/fdisk-menu.c b/disk-utils/fdisk-menu.c index 4c6a918934..717554b0e3 100644 --- a/disk-utils/fdisk-menu.c +++ b/disk-utils/fdisk-menu.c @@ -112,6 +112,7 @@ static const struct menu menu_generic = { MENU_BENT_E('v', N_("verify the partition table"), FDISK_DISKLABEL_BSD), MENU_ENT ('i', N_("print information about a partition")), MENU_ENT ('e', N_("resize a partition")), + MENU_ENT ('T', N_("discard (trim) sectors")), MENU_XENT('d', N_("print the raw data of the first sector from the device")), MENU_XENT('D', N_("print the raw data of the disklabel from the device")), @@ -714,6 +715,10 @@ static int generic_menu_cb(struct fdisk_context **cxt0, fdisk_unref_context(cxt); } break; + case 'T': + /* discard (trim) */ + discard_sectors(cxt); + break; } return rc; diff --git a/disk-utils/fdisk.c b/disk-utils/fdisk.c index c75a7a63c8..f75ed2445a 100644 --- a/disk-utils/fdisk.c +++ b/disk-utils/fdisk.c @@ -55,6 +55,15 @@ # include <linux/blkpg.h> #endif +#ifdef __linux__ +# ifdef HAVE_LINUX_FS_H +# include <linux/fs.h> +# endif +# ifndef BLKDISCARD +# define BLKDISCARD _IO(0x12,119) +# endif +#endif + int pwipemode = WIPEMODE_AUTO; int device_is_used; int is_interactive; @@ -201,8 +210,12 @@ static int ask_menu(struct fdisk_context *cxt, struct fdisk_ask *ask, size_t i = 0; /* print menu items */ - while (fdisk_ask_menu_get_item(ask, i++, &key, &name, &desc) == 0) - fprintf(stdout, " %c %s (%s)\n", key, name, desc); + while (fdisk_ask_menu_get_item(ask, i++, &key, &name, &desc) == 0) { + if (desc) + fprintf(stdout, " %c %s (%s)\n", key, name, desc); + else + fprintf(stdout, " %c %s\n", key, name); + } /* ask for key */ snprintf(prompt, sizeof(prompt), _("Select (default %c): "), dft); @@ -771,6 +784,131 @@ void change_partition_type(struct fdisk_context *cxt) fdisk_unref_parttype(t); } +#ifdef BLKDISCARD + +static int do_discard(struct fdisk_context *cxt, struct fdisk_partition *pa) +{ + char buf[512]; + unsigned long ss; + uint64_t range[2]; + int yes = 0; + + ss = fdisk_get_sector_size(cxt); + + range[0] = (uint64_t) fdisk_partition_get_start(pa); + range[1] = (uint64_t) fdisk_partition_get_size(pa); + + snprintf(buf, sizeof(buf), _("All data in the region (%"PRIu64 + "-%"PRIu64") will be lost! Continue?"), + range[0], range[0] + range[1] - 1); + + range[0] *= (uint64_t) ss; + range[1] *= (uint64_t) ss; + + fdisk_ask_yesno(cxt, buf, &yes); + if (!yes) + return 1; + + errno = 0; + if (ioctl(fdisk_get_devfd(cxt), BLKDISCARD, &range)) { + fdisk_warn(cxt, _("BLKDISCARD ioctl failed")); + return -errno; + } + return 0; +} + +static void discard_partition(struct fdisk_context *cxt) +{ + struct fdisk_partition *pa = NULL; + size_t n = 0; + + fdisk_info(cxt, _("\nThe partition sectors will be immediately discarded.\n" + "You can exit this dialog by pressing CTRL+C.\n")); + + if (fdisk_ask_partnum(cxt, &n, FALSE)) + goto done; + if (fdisk_get_partition(cxt, n, &pa)) { + fdisk_warnx(cxt, _("Partition %zu does not exist yet!"), n + 1); + goto done; + } + + if (!fdisk_partition_has_size(pa) || !fdisk_partition_has_start(pa)) { + fdisk_warnx(cxt, _("Partition %zu has unspeficied range"), n + 1); + goto done; + } + + if (do_discard(cxt, pa) == 0) + fdisk_info(cxt, _("Discarded sectors on partition %zu."), n + 1); +done: + fdisk_unref_partition(pa); +} + +static void discard_freespace(struct fdisk_context *cxt) +{ + struct fdisk_partition *pa = NULL; + struct fdisk_table *tb = NULL; + size_t best = 0; + uintmax_t n = 0; + int ct; + + ct = list_freespace_get_table(cxt, &tb, &best); + if (ct <= 0) { + fdisk_info(cxt, _("No free space.")); + goto done; + } + fdisk_info(cxt, _("\nThe unused sectors will be immediately discarded.\n" + "You can exit this dialog by pressing CTRL+C.\n")); + + if (fdisk_ask_number(cxt, 1, best + 1, (uintmax_t) ct, + _("Free space number"), &n) != 0) + goto done; + + pa = fdisk_table_get_partition(tb, n - 1); + if (!pa) + goto done; + + if (!fdisk_partition_has_size(pa) || !fdisk_partition_has_start(pa)) { + fdisk_warnx(cxt, _("Free space %"PRIu64 "has unspeficied range"), n); + goto done; + } + + if (do_discard(cxt, pa) == 0) + fdisk_info(cxt, _("Discarded sectors on free space.")); +done: + fdisk_unref_table(tb); +} + +void discard_sectors(struct fdisk_context *cxt) +{ + int c; + + if (fdisk_is_readonly(cxt)) { + fdisk_warnx(cxt, _("Discarding sectors is not possible in read-only mode.")); + return; + } + + if (fdisk_ask_menu(cxt, _("Type of area to be discarded"), + &c, 'p', _("partition sectors"), 'p', + _("free space sectros"), 'f', NULL) != 0) + return; + + switch (c) { + case 'p': + discard_partition(cxt); + break; + case 'f': + discard_freespace(cxt); + break; + } +} + +#else /* !BLKDISCARD */ +void discard_sectors(struct fdisk_context *cxt) +{ + fdisk_warnx(cxt, _("Discard unsupported on your system.")); +} +#endif /* BLKDISCARD */ + int print_partition_info(struct fdisk_context *cxt) { struct fdisk_partition *pa = NULL; diff --git a/disk-utils/fdisk.h b/disk-utils/fdisk.h index d4578e0724..72d36531f8 100644 --- a/disk-utils/fdisk.h +++ b/disk-utils/fdisk.h @@ -65,4 +65,6 @@ extern void follow_wipe_mode(struct fdisk_context *cxt); extern void resize_partition(struct fdisk_context *cxt); +extern void discard_sectors(struct fdisk_context *cxt); + #endif /* UTIL_LINUX_FDISK_H */ |