mkswap: check for holes and unwanted extentd in file
Let's make mkswap(8) more user-friend and report possible swapon issues already when user initialize a swap file. The extents check produces warnings, no exit with error. # dd if=/dev/zero of=img count=100 bs=1MiB # chmod 0600 img # fallocate --dig-hole --offset 64520192 --length 1MiB img # fallocate --dig-hole --offset 84520960 --length 1MiB img # ./mkswap img mkswap: extents check failed: - hole detected at offset 64520192 (size 1048576 bytes) - hole detected at offset 84520960 (size 1048576 bytes) file img can be rejected by kernel on swap activation. Setting up swapspace version 1, size = 100 MiB (104853504 bytes) no label, UUID=92091112-26b5-47aa-a02a-592e52528319 It checks for holes in the file, and for unknown, inline, shared and deallocated extents. Addresses: https://github.com/karelzak/util-linux/issues/1120 Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
933f095feb
commit
195025c29e
|
@ -281,6 +281,7 @@ AC_CHECK_HEADERS([ \
|
||||||
linux/btrfs.h \
|
linux/btrfs.h \
|
||||||
linux/cdrom.h \
|
linux/cdrom.h \
|
||||||
linux/falloc.h \
|
linux/falloc.h \
|
||||||
|
linux/fiemap.h \
|
||||||
linux/watchdog.h \
|
linux/watchdog.h \
|
||||||
linux/fd.h \
|
linux/fd.h \
|
||||||
linux/raw.h \
|
linux/raw.h \
|
||||||
|
|
|
@ -16,12 +16,17 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#ifdef HAVE_LIBSELINUX
|
#ifdef HAVE_LIBSELINUX
|
||||||
#include <selinux/selinux.h>
|
# include <selinux/selinux.h>
|
||||||
#include <selinux/context.h>
|
# include <selinux/context.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_LINUX_FIEMAP_H
|
||||||
|
# include <linux/fs.h>
|
||||||
|
# include <linux/fiemap.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "linux_version.h"
|
#include "linux_version.h"
|
||||||
|
@ -209,6 +214,89 @@ static void check_blocks(struct mkswap_control *ctl)
|
||||||
free(buffer);
|
free(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_LINUX_FIEMAP_H
|
||||||
|
static void check_extents_print_hdr(int *n)
|
||||||
|
{
|
||||||
|
if (*n == 0) {
|
||||||
|
fputc('\n', stderr);
|
||||||
|
warnx(_("extents check failed:"));
|
||||||
|
}
|
||||||
|
++*n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_extents(struct mkswap_control *ctl)
|
||||||
|
{
|
||||||
|
char buf[BUFSIZ] = { 0 };
|
||||||
|
struct fiemap *fiemap = (struct fiemap *) buf;
|
||||||
|
int last = 0, nerrs = 0;
|
||||||
|
uint64_t last_logical = 0;
|
||||||
|
|
||||||
|
memset(fiemap, 0, sizeof(struct fiemap));
|
||||||
|
|
||||||
|
do {
|
||||||
|
int rc;
|
||||||
|
size_t n, i;
|
||||||
|
|
||||||
|
fiemap->fm_length = ~0ULL;
|
||||||
|
fiemap->fm_flags = 0;
|
||||||
|
fiemap->fm_extent_count =
|
||||||
|
(sizeof(buf) - sizeof(*fiemap)) / sizeof(struct fiemap_extent);
|
||||||
|
|
||||||
|
rc = ioctl(ctl->fd, FS_IOC_FIEMAP, (unsigned long) fiemap);
|
||||||
|
if (rc < 0) {
|
||||||
|
warn(_("FIEMAP failed -- ignore extents check"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = fiemap->fm_mapped_extents;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
struct fiemap_extent *e = &fiemap->fm_extents[i];
|
||||||
|
|
||||||
|
if (e->fe_logical > last_logical) {
|
||||||
|
check_extents_print_hdr(&nerrs);
|
||||||
|
fprintf(stderr, (" - hole detected at offset %ju (size %ju bytes)\n"),
|
||||||
|
(uintmax_t) last_logical,
|
||||||
|
(uintmax_t) e->fe_logical - last_logical);
|
||||||
|
}
|
||||||
|
|
||||||
|
last_logical = (e->fe_logical + e->fe_length);
|
||||||
|
|
||||||
|
if (e->fe_flags & FIEMAP_EXTENT_LAST)
|
||||||
|
last = 1;
|
||||||
|
if (e->fe_flags & FIEMAP_EXTENT_UNKNOWN) {
|
||||||
|
check_extents_print_hdr(&nerrs);
|
||||||
|
fprintf(stderr, _(" - unknown file extent type at offset %ju\n"),
|
||||||
|
(uintmax_t) last_logical);
|
||||||
|
}
|
||||||
|
if (e->fe_flags & FIEMAP_EXTENT_DATA_INLINE){
|
||||||
|
check_extents_print_hdr(&nerrs);
|
||||||
|
fprintf(stderr, _(" - data inline extent at offset %ju\n"),
|
||||||
|
(uintmax_t) last_logical);
|
||||||
|
}
|
||||||
|
if (e->fe_flags & FIEMAP_EXTENT_SHARED){
|
||||||
|
check_extents_print_hdr(&nerrs);
|
||||||
|
fprintf(stderr, _(" - shared extent at offset %ju\n"),
|
||||||
|
(uintmax_t) last_logical);
|
||||||
|
}
|
||||||
|
if (e->fe_flags & FIEMAP_EXTENT_DELALLOC){
|
||||||
|
check_extents_print_hdr(&nerrs);
|
||||||
|
fprintf(stderr, _(" - deallocated extent at offset %ju\n"),
|
||||||
|
(uintmax_t) last_logical);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
fiemap->fm_start = fiemap->fm_extents[n - 1].fe_logical
|
||||||
|
+ fiemap->fm_extents[n - 1].fe_length;
|
||||||
|
} while (last == 0);
|
||||||
|
|
||||||
|
if (nerrs)
|
||||||
|
fprintf(stderr, _("file %s can be rejected by kernel on swap activation.\n\n"),
|
||||||
|
ctl->devname);
|
||||||
|
}
|
||||||
|
#endif /* HAVE_LINUX_FIEMAP_H */
|
||||||
|
|
||||||
/* return size in pages */
|
/* return size in pages */
|
||||||
static unsigned long long get_size(const struct mkswap_control *ctl)
|
static unsigned long long get_size(const struct mkswap_control *ctl)
|
||||||
{
|
{
|
||||||
|
@ -497,6 +585,10 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
if (ctl.check)
|
if (ctl.check)
|
||||||
check_blocks(&ctl);
|
check_blocks(&ctl);
|
||||||
|
#ifdef HAVE_LINUX_FIEMAP_H
|
||||||
|
if (S_ISREG(ctl.devstat.st_mode))
|
||||||
|
check_extents(&ctl);
|
||||||
|
#endif
|
||||||
|
|
||||||
wipe_device(&ctl);
|
wipe_device(&ctl);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue