[bmap-tools] [PATCH 08/14] Filemap: implement ugly heuristics for SEEK_HOLE

Artem Bityutskiy dedekind1 at gmail.com
Tue Jan 21 12:34:29 EST 2014


From: Artem Bityutskiy <artem.bityutskiy at intel.com>

Old kernels do not have real SEEK_HOLE support, but instead, provide a stub
implementation which just returns EOF. And there seem to be no easy way to find
out whether the implementation is real or fake. But we need to know this,
because it is crucial for use since we won't get the block map with fake
SEEK_HOLE implementation.

This patch implements an ugly test which appends a hole to the image file,
tests whether SEEK_HOLE is fake or not, and then truncats the image file back
to the original size.

Change-Id: Ib5744d5247aa0cda02517afe7189059cc5efeb9b
Signed-off-by: Artem Bityutskiy <artem.bityutskiy at intel.com>
---
 bmaptools/Filemap.py | 43 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/bmaptools/Filemap.py b/bmaptools/Filemap.py
index 2daf77e..fcc2f2c 100644
--- a/bmaptools/Filemap.py
+++ b/bmaptools/Filemap.py
@@ -26,6 +26,7 @@ import os
 import struct
 import array
 import fcntl
+import tempfile
 from bmaptools import BmapHelpers
 
 
@@ -153,6 +154,8 @@ _SEEK_HOLE = 4
 class FilemapSeek(_FilemapBase):
     """
     This class uses the 'SEEK_HOLE' and 'SEEK_DATA' to find file block mapping.
+    Unfortunately, the current implementation requires the caller to have write
+    access to the image file.
     """
 
     def __init__(self, image):
@@ -161,6 +164,46 @@ class FilemapSeek(_FilemapBase):
         # Call the base class constructor first
         _FilemapBase.__init__(self, image)
 
+        self._probe_seek_hole()
+
+    def _probe_seek_hole(self):
+        """
+        Check whether the system implements 'SEEK_HOLE' and 'SEEK_DATA'.
+        Unfortunately, there seems to be no clean way for detecting this,
+        because often the system just fakes them by just assuming that all
+        files are fully mapped, so 'SEEK_HOLE' always returns EOF and
+        'SEEK_DATA' always returns the requested offset.
+
+        I could not invent a better way of detecting the fake 'SEEK_HOLE'
+        implementation than just to create a temporary file in the same
+        directory where the image file resides. It would be nice to change this
+        to something better.
+        """
+
+        directory = os.path.dirname(self._image_path)
+
+        try:
+            tmp_obj = tempfile.TemporaryFile("w+", dir=directory)
+        except IOError as err:
+            raise ErrorNotSupp("cannot create a temporary in \"%s\": %s"
+                              % (directory, err))
+
+        try:
+            os.ftruncate(tmp_obj.fileno(), self.block_size)
+        except OSError as err:
+            raise ErrorNotSupp("cannot truncate temporary file in \"%s\": %s"
+                               % (directory, err))
+
+        offs = self._lseek(tmp_obj, 0, _SEEK_HOLE)
+        if offs != 0:
+            # We are dealing with the stub 'SEEK_HOLE' implementation which
+            # always returns EOF.
+            raise ErrorNotSupp("the file-system does not support "
+                               "\"SEEK_HOLE\" and \"SEEK_DATA\" but only "
+                               "provides a stub implementation")
+
+        tmp_obj.close()
+
     def _lseek(self, file_obj, offset, whence):
         """This is a helper function which invokes 'os.lseek' for file object
         'file_obj' and with specified 'offset' and 'whence'. The 'whence'
-- 
1.8.3.1




More information about the Bmap-tools mailing list