|
|
faf1e5 |
From e78ae6d16009263a8dfcd91ea8ce8fc08a077529 Mon Sep 17 00:00:00 2001
|
|
|
faf1e5 |
From: Eduardo Otubo <otubo@redhat.com>
|
|
|
faf1e5 |
Date: Tue, 28 Apr 2020 08:22:03 +0200
|
|
|
faf1e5 |
Subject: [PATCH 1/3] Do not use fallocate in swap file creation on xfs. (#70)
|
|
|
faf1e5 |
|
|
|
faf1e5 |
RH-Author: Eduardo Otubo <otubo@redhat.com>
|
|
|
faf1e5 |
Message-id: <20200422130428.7663-2-otubo@redhat.com>
|
|
|
faf1e5 |
Patchwork-id: 96031
|
|
|
faf1e5 |
O-Subject: [RHEL-7.7.z/RHEL-7.8.z cloud-init PATCH 1/3] Do not use fallocate in swap file creation on xfs. (#70)
|
|
|
faf1e5 |
Bugzilla: 1801094
|
|
|
faf1e5 |
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
|
|
faf1e5 |
RH-Acked-by: Cathy Avery <cavery@redhat.com>
|
|
|
faf1e5 |
|
|
|
faf1e5 |
commit 6603706eec1c39d9d591c8ffa0ef7171b74d84d6
|
|
|
faf1e5 |
Author: Eduardo Otubo <otubo@redhat.com>
|
|
|
faf1e5 |
Date: Thu Jan 23 17:41:48 2020 +0100
|
|
|
faf1e5 |
|
|
|
faf1e5 |
Do not use fallocate in swap file creation on xfs. (#70)
|
|
|
faf1e5 |
|
|
|
faf1e5 |
When creating a swap file on an xfs filesystem, fallocate cannot be used.
|
|
|
faf1e5 |
Doing so results in failure of swapon and a message like:
|
|
|
faf1e5 |
swapon: swapfile has holes
|
|
|
faf1e5 |
|
|
|
faf1e5 |
The solution here is to maintain a list (currently containing only XFS)
|
|
|
faf1e5 |
of filesystems where fallocate cannot be used. The, on those fileystems
|
|
|
faf1e5 |
use the slower but functional 'dd' method.
|
|
|
faf1e5 |
|
|
|
faf1e5 |
Signed-off-by: Eduardo Otubo <otubo@redhat.com>
|
|
|
faf1e5 |
Co-authored-by: Adam Dobrawy <naczelnik@jawnosc.tk>
|
|
|
faf1e5 |
Co-authored-by: Scott Moser <smoser@brickies.net>
|
|
|
faf1e5 |
Co-authored-by: Daniel Watkins <daniel@daniel-watkins.co.uk>
|
|
|
faf1e5 |
|
|
|
faf1e5 |
LP: #1781781
|
|
|
faf1e5 |
|
|
|
faf1e5 |
Signed-off-bt: Eduardo Otubo <otubo@redhat.com>
|
|
|
faf1e5 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
faf1e5 |
---
|
|
|
faf1e5 |
cloudinit/config/cc_mounts.py | 67 ++++++++++++++++------
|
|
|
faf1e5 |
.../unittests/test_handler/test_handler_mounts.py | 12 ++++
|
|
|
faf1e5 |
2 files changed, 62 insertions(+), 17 deletions(-)
|
|
|
faf1e5 |
|
|
|
faf1e5 |
diff --git a/cloudinit/config/cc_mounts.py b/cloudinit/config/cc_mounts.py
|
|
|
faf1e5 |
index 123ffb8..6884ddf 100644
|
|
|
faf1e5 |
--- a/cloudinit/config/cc_mounts.py
|
|
|
faf1e5 |
+++ b/cloudinit/config/cc_mounts.py
|
|
|
faf1e5 |
@@ -223,13 +223,58 @@ def suggested_swapsize(memsize=None, maxsize=None, fsys=None):
|
|
|
faf1e5 |
return size
|
|
|
faf1e5 |
|
|
|
faf1e5 |
|
|
|
faf1e5 |
+def create_swapfile(fname, size):
|
|
|
faf1e5 |
+ """Size is in MiB."""
|
|
|
faf1e5 |
+
|
|
|
faf1e5 |
+ errmsg = "Failed to create swapfile '%s' of size %dMB via %s: %s"
|
|
|
faf1e5 |
+
|
|
|
faf1e5 |
+ def create_swap(fname, size, method):
|
|
|
faf1e5 |
+ LOG.debug("Creating swapfile in '%s' on fstype '%s' using '%s'",
|
|
|
faf1e5 |
+ fname, fstype, method)
|
|
|
faf1e5 |
+
|
|
|
faf1e5 |
+ if method == "fallocate":
|
|
|
faf1e5 |
+ cmd = ['fallocate', '-l', '%dM' % size, fname]
|
|
|
faf1e5 |
+ elif method == "dd":
|
|
|
faf1e5 |
+ cmd = ['dd', 'if=/dev/zero', 'of=%s' % fname, 'bs=1M',
|
|
|
faf1e5 |
+ 'count=%d' % size]
|
|
|
faf1e5 |
+
|
|
|
faf1e5 |
+ try:
|
|
|
faf1e5 |
+ util.subp(cmd, capture=True)
|
|
|
faf1e5 |
+ except util.ProcessExecutionError as e:
|
|
|
faf1e5 |
+ LOG.warning(errmsg, fname, size, method, e)
|
|
|
faf1e5 |
+ util.del_file(fname)
|
|
|
faf1e5 |
+
|
|
|
faf1e5 |
+ swap_dir = os.path.dirname(fname)
|
|
|
faf1e5 |
+ util.ensure_dir(swap_dir)
|
|
|
faf1e5 |
+
|
|
|
faf1e5 |
+ fstype = util.get_mount_info(swap_dir)[1]
|
|
|
faf1e5 |
+
|
|
|
faf1e5 |
+ if fstype in ("xfs", "btrfs"):
|
|
|
faf1e5 |
+ create_swap(fname, size, "dd")
|
|
|
faf1e5 |
+ else:
|
|
|
faf1e5 |
+ try:
|
|
|
faf1e5 |
+ create_swap(fname, size, "fallocate")
|
|
|
faf1e5 |
+ except util.ProcessExecutionError as e:
|
|
|
faf1e5 |
+ LOG.warning(errmsg, fname, size, "dd", e)
|
|
|
faf1e5 |
+ LOG.warning("Will attempt with dd.")
|
|
|
faf1e5 |
+ create_swap(fname, size, "dd")
|
|
|
faf1e5 |
+
|
|
|
faf1e5 |
+ util.chmod(fname, 0o600)
|
|
|
faf1e5 |
+ try:
|
|
|
faf1e5 |
+ util.subp(['mkswap', fname])
|
|
|
faf1e5 |
+ except util.ProcessExecutionError:
|
|
|
faf1e5 |
+ util.del_file(fname)
|
|
|
faf1e5 |
+ raise
|
|
|
faf1e5 |
+
|
|
|
faf1e5 |
+
|
|
|
faf1e5 |
def setup_swapfile(fname, size=None, maxsize=None):
|
|
|
faf1e5 |
"""
|
|
|
faf1e5 |
fname: full path string of filename to setup
|
|
|
faf1e5 |
size: the size to create. set to "auto" for recommended
|
|
|
faf1e5 |
maxsize: the maximum size
|
|
|
faf1e5 |
"""
|
|
|
faf1e5 |
- tdir = os.path.dirname(fname)
|
|
|
faf1e5 |
+ swap_dir = os.path.dirname(fname)
|
|
|
faf1e5 |
+ mibsize = str(int(size / (2 ** 20)))
|
|
|
faf1e5 |
if str(size).lower() == "auto":
|
|
|
faf1e5 |
try:
|
|
|
faf1e5 |
memsize = util.read_meminfo()['total']
|
|
|
faf1e5 |
@@ -237,28 +282,16 @@ def setup_swapfile(fname, size=None, maxsize=None):
|
|
|
faf1e5 |
LOG.debug("Not creating swap: failed to read meminfo")
|
|
|
faf1e5 |
return
|
|
|
faf1e5 |
|
|
|
faf1e5 |
- util.ensure_dir(tdir)
|
|
|
faf1e5 |
- size = suggested_swapsize(fsys=tdir, maxsize=maxsize,
|
|
|
faf1e5 |
+ util.ensure_dir(swap_dir)
|
|
|
faf1e5 |
+ size = suggested_swapsize(fsys=swap_dir, maxsize=maxsize,
|
|
|
faf1e5 |
memsize=memsize)
|
|
|
faf1e5 |
|
|
|
faf1e5 |
if not size:
|
|
|
faf1e5 |
LOG.debug("Not creating swap: suggested size was 0")
|
|
|
faf1e5 |
return
|
|
|
faf1e5 |
|
|
|
faf1e5 |
- mbsize = str(int(size / (2 ** 20)))
|
|
|
faf1e5 |
- msg = "creating swap file '%s' of %sMB" % (fname, mbsize)
|
|
|
faf1e5 |
- try:
|
|
|
faf1e5 |
- util.ensure_dir(tdir)
|
|
|
faf1e5 |
- util.log_time(LOG.debug, msg, func=util.subp,
|
|
|
faf1e5 |
- args=[['sh', '-c',
|
|
|
faf1e5 |
- ('rm -f "$1" && umask 0066 && '
|
|
|
faf1e5 |
- '{ fallocate -l "${2}M" "$1" || '
|
|
|
faf1e5 |
- ' dd if=/dev/zero "of=$1" bs=1M "count=$2"; } && '
|
|
|
faf1e5 |
- 'mkswap "$1" || { r=$?; rm -f "$1"; exit $r; }'),
|
|
|
faf1e5 |
- 'setup_swap', fname, mbsize]])
|
|
|
faf1e5 |
-
|
|
|
faf1e5 |
- except Exception as e:
|
|
|
faf1e5 |
- raise IOError("Failed %s: %s" % (msg, e))
|
|
|
faf1e5 |
+ util.log_time(LOG.debug, msg="Setting up swap file", func=create_swapfile,
|
|
|
faf1e5 |
+ args=[fname, mibsize])
|
|
|
faf1e5 |
|
|
|
faf1e5 |
return fname
|
|
|
faf1e5 |
|
|
|
faf1e5 |
diff --git a/tests/unittests/test_handler/test_handler_mounts.py b/tests/unittests/test_handler/test_handler_mounts.py
|
|
|
faf1e5 |
index 0fb160b..7bcefa0 100644
|
|
|
faf1e5 |
--- a/tests/unittests/test_handler/test_handler_mounts.py
|
|
|
faf1e5 |
+++ b/tests/unittests/test_handler/test_handler_mounts.py
|
|
|
faf1e5 |
@@ -181,6 +181,18 @@ class TestFstabHandling(test_helpers.FilesystemMockingTestCase):
|
|
|
faf1e5 |
|
|
|
faf1e5 |
return dev
|
|
|
faf1e5 |
|
|
|
faf1e5 |
+ def test_swap_integrity(self):
|
|
|
faf1e5 |
+ '''Ensure that the swap file is correctly created and can
|
|
|
faf1e5 |
+ swapon successfully. Fixing the corner case of:
|
|
|
faf1e5 |
+ kernel: swapon: swapfile has holes'''
|
|
|
faf1e5 |
+
|
|
|
faf1e5 |
+ fstab = '/swap.img swap swap defaults 0 0\n'
|
|
|
faf1e5 |
+
|
|
|
faf1e5 |
+ with open(cc_mounts.FSTAB_PATH, 'w') as fd:
|
|
|
faf1e5 |
+ fd.write(fstab)
|
|
|
faf1e5 |
+ cc = {'swap': ['filename: /swap.img', 'size: 512', 'maxsize: 512']}
|
|
|
faf1e5 |
+ cc_mounts.handle(None, cc, self.mock_cloud, self.mock_log, [])
|
|
|
faf1e5 |
+
|
|
|
faf1e5 |
def test_fstab_no_swap_device(self):
|
|
|
faf1e5 |
'''Ensure that cloud-init adds a discovered swap partition
|
|
|
faf1e5 |
to /etc/fstab.'''
|
|
|
faf1e5 |
--
|
|
|
faf1e5 |
1.8.3.1
|
|
|
faf1e5 |
|