summaryrefslogtreecommitdiff
path: root/ironic/common
diff options
context:
space:
mode:
authorDmitry Tantsur <dtantsur@protonmail.com>2023-03-31 15:39:50 +0200
committerDmitry Tantsur <dtantsur@protonmail.com>2023-03-31 15:49:15 +0200
commit59c6ad96ce35c9deecfedb5698c5806f3883a8af (patch)
tree80b9eff0322e3a6ac7002e8cfb03c74ea2590bc5 /ironic/common
parentabbd859b766c339f5de33ff08704a7b9ad045bef (diff)
downloadironic-59c6ad96ce35c9deecfedb5698c5806f3883a8af.tar.gz
Always fall back from hard linking to copying files
The current check is insufficient: it passes for Kubernetes shared volumes, although hard-linking between them is not possible. This patch changes the approach to trying a hard link and falling back to copyfile instead. The patch relies on optimizations in Python 3.8 and thus should not be backported beyond the Zed series to avoid performance regression. Change-Id: I929944685b3ac61b2f63d2549198a2d8a1c8fe35
Diffstat (limited to 'ironic/common')
-rw-r--r--ironic/common/image_service.py35
1 files changed, 14 insertions, 21 deletions
diff --git a/ironic/common/image_service.py b/ironic/common/image_service.py
index 5280ee6bc..4b95b5152 100644
--- a/ironic/common/image_service.py
+++ b/ironic/common/image_service.py
@@ -34,10 +34,6 @@ from ironic.common import utils
from ironic.conf import CONF
IMAGE_CHUNK_SIZE = 1024 * 1024 # 1mb
-# NOTE(kaifeng) Image will be truncated to 2GiB by sendfile,
-# we use a large chunk size here for a better performance
-# while keep the chunk size less than the size limit.
-SENDFILE_CHUNK_SIZE = 1024 * 1024 * 1024 # 1Gb
LOG = log.getLogger(__name__)
@@ -264,26 +260,23 @@ class FileImageService(BaseImageService):
"""
source_image_path = self.validate_href(image_href)
dest_image_path = image_file.name
- local_device = os.stat(dest_image_path).st_dev
try:
- # We should have read and write access to source file to create
- # hard link to it.
- if (local_device == os.stat(source_image_path).st_dev
- and os.access(source_image_path, os.R_OK | os.W_OK)):
- image_file.close()
- os.remove(dest_image_path)
+ image_file.close()
+ os.remove(dest_image_path)
+
+ try:
os.link(source_image_path, dest_image_path)
+ except OSError as exc:
+ LOG.debug('Could not create a link from %(src)s to %(dest)s, '
+ 'will copy the content instead. Error: %(exc)s.',
+ {'src': source_image_path, 'dest': dest_image_path,
+ 'exc': exc})
else:
- filesize = os.path.getsize(source_image_path)
- offset = 0
- with open(source_image_path, 'rb') as input_img:
- while offset < filesize:
- count = min(SENDFILE_CHUNK_SIZE, filesize - offset)
- nbytes_out = os.sendfile(image_file.fileno(),
- input_img.fileno(),
- offset,
- count)
- offset += nbytes_out
+ return
+
+ # NOTE(dtantsur): starting with Python 3.8, copyfile() uses
+ # efficient copying (i.e. sendfile) under the hood.
+ shutil.copyfile(source_image_path, dest_image_path)
except Exception as e:
raise exception.ImageDownloadFailed(image_href=image_href,
reason=str(e))