]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
sfdisk: add --discard-free
authorKarel Zak <kzak@redhat.com>
Mon, 16 Sep 2024 12:50:43 +0000 (14:50 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 17 Sep 2024 11:19:09 +0000 (13:19 +0200)
Why do we need this? It can be difficult for end-users to discard
unpartitioned areas using blkdiscard, as it requires using fdisk to
obtain a list of free areas and then using blkdiscard with the correct
--offset and --length options. It is less risky for end-users to use
(s)fdisk, as they have a better understanding of the disk layout.

Addresses: https://github.com/util-linux/util-linux/issues/2804
Signed-off-by: Karel Zak <kzak@redhat.com>
bash-completion/sfdisk
disk-utils/sfdisk.8.adoc
disk-utils/sfdisk.c
sys-utils/blkdiscard.8.adoc

index b075ccc911602faab687da18a65288d7ce183d5a..4dc57c4eaf1f36ea470e53c3499b69f70b27c8fa 100644 (file)
@@ -58,6 +58,7 @@ _sfdisk_module()
                                --show-geometry
                                --list
                                --list-free
+                               --discard-free
                                --disk-id
                                --reorder
                                --show-size
index b2e5279d268d7f6fcd73a40778ea6f7c3856c8d7..26ccad5a3b2241d13af94ad91cc7d27c2a90a042 100644 (file)
@@ -116,6 +116,13 @@ Change the GPT partition UUID. If _uuid_ is not specified, then print the curren
 *--disk-id* _device_ [__id__]::
 Change the disk identifier. If _id_ is not specified, then print the current identifier. The identifier is UUID for GPT or unsigned integer for MBR.
 
+*--discard-free* _device_ ::
+Discard any unused (unpartitioned) sectors on the device. Use the *--list-free* option to get a list of the free regions. See also *blkdiscard*(8).
++
+WARNING: All data in the discarded regions on the device will be lost! Do not use this option if you are unsure.
++
+Note that the 'T' command in *fdisk* provides a dialog to specify which unused area should be discarded. However, *sfdisk* always discards all unpartitioned regions (except for the areas where it is not possible to create partitions, such as the beginning of the device).
+
 *-r*, *--reorder* _device_::
 Renumber the partitions, ordering them by their start offset.
 
index 71b0191d212ff54d3759a6af416d84fe3a80d4fb..cf402007b512027a04d8c1629de52b0cb535f3bb 100644 (file)
@@ -87,6 +87,7 @@ enum {
        ACT_PARTUUID,
        ACT_PARTLABEL,
        ACT_PARTATTRS,
+       ACT_DISCARD_FREE,
        ACT_DISKID,
        ACT_DELETE,
        ACT_BACKUP_SECTORS,
@@ -1369,6 +1370,69 @@ static int command_partattrs(struct sfdisk *sf, int argc, char **argv)
        return write_changes(sf);
 }
 
+/*
+ * sfdisk --discard-free <device>
+ */
+static int command_discard_free(struct sfdisk *sf, int argc, char **argv)
+{
+       struct fdisk_table *tb = NULL;
+       struct fdisk_iter *itr = NULL;
+       struct fdisk_partition *pa = NULL;
+       const char *devname = NULL;
+       uint64_t ss;
+       int rc;
+
+       if (!argc)
+               errx(EXIT_FAILURE, _("no disk device specified"));
+       devname = argv[0];
+       if (argc > 1)
+               errx(EXIT_FAILURE, _("unexpected arguments"));
+
+       itr = fdisk_new_iter(FDISK_ITER_FORWARD);
+       if (!itr)
+               err(EXIT_FAILURE, _("failed to allocate iterator"));
+
+       assign_device(sf, devname, 0);
+
+       ss = fdisk_get_sector_size(sf->cxt);
+
+       rc = fdisk_get_freespaces(sf->cxt, &tb);
+       if (rc) {
+                fdisk_warn(sf->cxt, _("failed to gather unpartitioned space"));
+                goto done;
+       }
+
+       while (fdisk_table_next_partition(tb, itr, &pa) == 0) {
+               uint64_t range[2];
+
+               if (!fdisk_partition_has_size(pa) ||
+                   !fdisk_partition_has_start(pa))
+                       continue;
+
+               range[0] = (uint64_t) fdisk_partition_get_start(pa);
+               range[1] = (uint64_t) fdisk_partition_get_size(pa);
+
+               fdisk_info(sf->cxt, _("Discarding region %"PRIu64
+                                            "-%"PRIu64""),
+                               range[0], range[0] + range[1] - 1);
+
+               range[0] *= ss;
+               range[1] *= ss;
+
+               errno = 0;
+               if (ioctl(fdisk_get_devfd(sf->cxt), BLKDISCARD, &range)) {
+                       rc = -errno;
+                       fdisk_warn(sf->cxt, _("BLKDISCARD ioctl failed"));
+                       break;
+               }
+       }
+
+done:
+       fdisk_free_iter(itr);
+       fdisk_unref_table(tb);
+       return rc;
+}
+
 /*
  * sfdisk --disk-id <device> [<str>]
  */
@@ -2070,6 +2134,7 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_(" --part-attrs <dev> <part> [<str>] print or change partition attributes\n"), out);
 
        fputs(USAGE_SEPARATOR, out);
+       fputs(_(" --discard-free <dev>              discard (trim) unpartitioned areas\n"), out);
        fputs(_(" --disk-id <dev> [<str>]           print or change disk label ID (UUID)\n"), out);
        fputs(_(" --relocate <oper> <dev>           move partition header\n"), out);
 
@@ -2142,6 +2207,7 @@ int main(int argc, char *argv[])
                OPT_PARTLABEL,
                OPT_PARTTYPE,
                OPT_PARTATTRS,
+               OPT_DISCARDFREE,
                OPT_DISKID,
                OPT_BYTES,
                OPT_COLOR,
@@ -2194,6 +2260,8 @@ int main(int argc, char *argv[])
                { "part-type",  no_argument,    NULL, OPT_PARTTYPE },
                { "part-attrs", no_argument,    NULL, OPT_PARTATTRS },
 
+               { "discard-free", no_argument, NULL, OPT_DISCARDFREE },
+
                { "disk-id",    no_argument,    NULL, OPT_DISKID },
 
                { "show-pt-geometry", no_argument, NULL, 'G' },         /* deprecated */
@@ -2340,6 +2408,9 @@ int main(int argc, char *argv[])
                case OPT_PARTATTRS:
                        sf->act = ACT_PARTATTRS;
                        break;
+               case OPT_DISCARDFREE:
+                       sf->act = ACT_DISCARD_FREE;
+                       break;
                case OPT_DISKID:
                        sf->act = ACT_DISKID;
                        break;
@@ -2462,6 +2533,10 @@ int main(int argc, char *argv[])
                rc = command_partattrs(sf, argc - optind, argv + optind);
                break;
 
+       case ACT_DISCARD_FREE:
+               rc = command_discard_free(sf, argc - optind, argv + optind);
+               break;
+
        case ACT_DISKID:
                rc = command_diskid(sf, argc - optind, argv + optind);
                break;
index cf661acd9c367b359ca07ad8040d9e22480c4395..3be78b49dcca6c98578c96ad1792f9d6281ecc8a 100644 (file)
@@ -24,7 +24,7 @@ The _device_ argument is the pathname of the block device.
 
 *WARNING: All data in the discarded region on the device will be lost!*
 
-Since util-linux v2.41, fdisk has the ability to discard sectors on both partitions and unpartitioned areas using the 'T' command.
+Since util-linux v2.41, *fdisk* has the ability to discard sectors on both partitions and unpartitioned areas using the 'T' command. Additionally, *sfdisk* has the option --discard-free to discard unpartitioned areas.
 
 == OPTIONS