diff options
author | Karel Zak | 2018-06-11 12:21:56 +0200 |
---|---|---|
committer | Karel Zak | 2018-06-11 12:36:32 +0200 |
commit | 921f63433ee62894908f7f8c0a622057478e6fa1 (patch) | |
tree | 28e12cb313d197340a3e1bb63143d6a9c190eeb7 /misc-utils/wipefs.c | |
parent | zramctl: (man) explain that --find is necessary (diff) | |
download | kernel-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.c | 60 |
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; } |