summaryrefslogtreecommitdiffstats
path: root/misc-utils/wipefs.c
diff options
context:
space:
mode:
authorKarel Zak2018-06-11 12:21:56 +0200
committerKarel Zak2018-06-11 12:36:32 +0200
commit921f63433ee62894908f7f8c0a622057478e6fa1 (patch)
tree28e12cb313d197340a3e1bb63143d6a9c190eeb7 /misc-utils/wipefs.c
parentzramctl: (man) explain that --find is necessary (diff)
downloadkernel-qcow2-util-linux-921f63433ee62894908f7f8c0a622057478e6fa1.tar.gz
kernel-qcow2-util-linux-921f63433ee62894908f7f8c0a622057478e6fa1.tar.xz
kernel-qcow2-util-linux-921f63433ee62894908f7f8c0a622057478e6fa1.zip
wipefs: postpone BLKRRPART until all is done
It's possible we erase from the whole device before we erase from the partition on the same disk: # wipefs -a /dev/sdc /dev/sdc1 the current code calls re-read PT ioctl immediately after erase (so, before sdc1 is processed). The result is that sdc1 node is no more accessible: # wipefs -a /dev/sdc /dev/sdc1 /dev/sdc: 2 bytes were erased at offset 0x000001fe (dos): 55 aa /dev/sdc: calling ioctl to re-read partition table: Success wipefs: error: /dev/sdc1: probing initialization failed: No such file or directory It seems the most simple solution is to postpone the re-read ioctl and do it as the last thing. # wipefs -a /dev/sdc /dev/sdc1 /dev/sdc: 2 bytes were erased at offset 0x000001fe (dos): 55 aa /dev/sdc1: 2 bytes were erased at offset 0x00000438 (ext4): 53 ef /dev/sdc: calling ioctl to re-read partition table: Success The patch also adds a small delay before the re-read ioctl call. It's not elegant, but without the usleep(25000) the first attempt returns EBUSY. Addresses: https://github.com/karelzak/util-linux/issues/598 Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'misc-utils/wipefs.c')
-rw-r--r--misc-utils/wipefs.c60
1 files changed, 54 insertions, 6 deletions
diff --git a/misc-utils/wipefs.c b/misc-utils/wipefs.c
index 76149d9fc..49c5c8ca1 100644
--- a/misc-utils/wipefs.c
+++ b/misc-utils/wipefs.c
@@ -62,12 +62,17 @@ struct wipe_desc {
};
struct wipe_control {
- const char *devname;
+ char *devname;
const char *type_pattern; /* -t <pattern> */
struct libscols_table *outtab;
struct wipe_desc *offsets; /* -o <offset> -o <offset> ... */
+ size_t ndevs; /* number of devices to probe */
+
+ char **reread; /* devices to BLKRRPART */
+ size_t nrereads; /* size of reread */
+
unsigned int noact : 1,
all : 1,
quiet : 1,
@@ -504,12 +509,25 @@ err:
static void rereadpt(int fd, const char *devname)
{
struct stat st;
+ int try = 0;
if (fstat(fd, &st) || !S_ISBLK(st.st_mode))
return;
- errno = 0;
- ioctl(fd, BLKRRPART);
+ do {
+ /*
+ * Unfortunately, it's pretty common that the first re-read
+ * without delay is uncuccesful. The reason is probably kernel
+ * and/or udevd. Let's wait a moment and try more attempts.
+ */
+ xusleep(25000);
+
+ errno = 0;
+ ioctl(fd, BLKRRPART);
+ if (errno != EBUSY)
+ break;
+ } while (try++ < 4);
+
printf(_("%s: calling ioctl to re-read partition table: %m\n"), devname);
}
#endif
@@ -590,8 +608,21 @@ static int do_wipe(struct wipe_control *ctl)
fsync(blkid_probe_get_fd(pr));
#ifdef BLKRRPART
- if (reread && (mode & O_EXCL))
- rereadpt(blkid_probe_get_fd(pr), ctl->devname);
+ if (reread && (mode & O_EXCL)) {
+ if (ctl->ndevs > 1) {
+ /*
+ * We're going to probe more device, let's postpone
+ * re-read PT ioctl until all is erased to avoid
+ * situation we erase PT on /dev/sda before /dev/sdaN
+ * devices are processed.
+ */
+ if (!ctl->reread)
+ ctl->reread = xcalloc(ctl->ndevs, sizeof(char *));
+
+ ctl->reread[ctl->nrereads++] = ctl->devname;
+ } else
+ rereadpt(blkid_probe_get_fd(pr), ctl->devname);
+ }
#endif
close(blkid_probe_get_fd(pr));
@@ -771,11 +802,28 @@ main(int argc, char **argv)
/*
* Erase
*/
+ size_t i;
+ ctl.ndevs = argc - optind;
+
while (optind < argc) {
ctl.devname = argv[optind++];
do_wipe(&ctl);
+ ctl.ndevs--;
}
- }
+ /* Re-read partition tables on whole-disk devices. This is
+ * postponed until all is done to avoid conflicts.
+ */
+ for (i = 0; i < ctl.nrereads; i++) {
+ char *devname = ctl.reread[i];
+ int fd = open(devname, O_RDONLY);
+
+ if (fd >= 0) {
+ rereadpt(fd, devname);
+ close(fd);
+ }
+ }
+ free(ctl.reread);
+ }
return EXIT_SUCCESS;
}