aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarel Zak <kzak@redhat.com>2024-04-16 13:36:32 +0200
committerKarel Zak <kzak@redhat.com>2024-04-17 09:38:52 +0200
commita4c0dce86bcdb3a785667ea1f96ed4127fa0d545 (patch)
tree0f34afc1695fbbb5bcd54cf60893643c495ebc9f
parent7817415a5538354dfa24532f3420bfd3e74df795 (diff)
downloadutil-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.c5
-rw-r--r--disk-utils/fdisk.c142
-rw-r--r--disk-utils/fdisk.h2
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 */