[bmap-tools] [PATCH 13/14] Filemap: add debugging facility

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


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

Add the 'log' parameter to the Filemap* classes to allow passing the logger
object where the debugging prints will go. This is similar to what we have in
the BmapCopy module. Also add the same parameter to 'BmapCreate' and make sure
that 'bmaptool' passes its logger to 'BmapCreate', which then passes it to
'Filemap*' objects, where we use it for debugging.

This makes sure that '--debug' triggers debugging messages from 'Filemap*'
ojects.

Change-Id: Idc9686edc4809856720481f79e37887d29a8b0df
Signed-off-by: Artem Bityutskiy <artem.bityutskiy at intel.com>
---
 bmaptool                |  2 +-
 bmaptools/BmapCreate.py | 10 +++++--
 bmaptools/Filemap.py    | 79 ++++++++++++++++++++++++++++++++++++++-----------
 3 files changed, 70 insertions(+), 21 deletions(-)

diff --git a/bmaptool b/bmaptool
index 0c6a349..5214a83 100755
--- a/bmaptool
+++ b/bmaptool
@@ -555,7 +555,7 @@ def create_command(args, log):
             raise SystemExit(1)
 
     try:
-        creator = BmapCreate.BmapCreate(args.image, output, "sha256")
+        creator = BmapCreate.BmapCreate(args.image, output, "sha256", log)
         creator.generate(not args.no_checksum)
     except BmapCreate.Error as err:
         log.error(str(err))
diff --git a/bmaptools/BmapCreate.py b/bmaptools/BmapCreate.py
index 6e9e2f9..b70fd73 100644
--- a/bmaptools/BmapCreate.py
+++ b/bmaptools/BmapCreate.py
@@ -43,6 +43,7 @@ This module uses the FIBMAP ioctl to detect holes.
 # pylint: disable=R0902,R0903
 
 import hashlib
+import logging
 from bmaptools.BmapHelpers import human_size
 from bmaptools import Filemap
 
@@ -117,7 +118,7 @@ class BmapCreate(object):
     the FIEMAP ioctl to generate the bmap.
     """
 
-    def __init__(self, image, bmap, chksum_type="sha256"):
+    def __init__(self, image, bmap, chksum_type="sha256", log=None):
         """
         Initialize a class instance:
         * image  - full path or a file-like object of the image to create bmap
@@ -126,8 +127,13 @@ class BmapCreate(object):
                    bmap to
         * chksum - type of the check sum to use in the bmap file (all checksum
                    types which python's "hashlib" module supports are allowed).
+        * log     - the logger object to use for printing messages.
         """
 
+        self._log = log
+        if self._log is None:
+            self._log = logging.getLogger(__name__)
+
         self.image_size = None
         self.image_size_human = None
         self.block_size = None
@@ -165,7 +171,7 @@ class BmapCreate(object):
             self._bmap_path = bmap
             self._open_bmap_file()
 
-        self.filemap = Filemap.filemap(self._f_image)
+        self.filemap = Filemap.filemap(self._f_image, self._log)
 
         self.image_size = self.filemap.image_size
         self.image_size_human = human_size(self.image_size)
diff --git a/bmaptools/Filemap.py b/bmaptools/Filemap.py
index 2c120bf..94504f9 100644
--- a/bmaptools/Filemap.py
+++ b/bmaptools/Filemap.py
@@ -27,6 +27,7 @@ import struct
 import array
 import fcntl
 import tempfile
+import logging
 from bmaptools import BmapHelpers
 
 
@@ -46,15 +47,20 @@ class _FilemapBase(object):
     """
     This is a base class for a couple of other classes in this module. This
     class simply performs the common parts of the initialization process: opens
-    the image file, gets its size, etc.
+    the image file, gets its size, etc. The 'log' parameter is the logger object
+    to use for printing messages.
     """
 
-    def __init__(self, image):
+    def __init__(self, image, log=None):
         """
         Initialize a class instance. The 'image' argument is full path to the
         file or file object to operate on.
         """
 
+        self._log = log
+        if self._log is None:
+            self._log = logging.getLogger(__name__)
+
         self._f_image_needs_close = False
 
         if hasattr(image, "fileno"):
@@ -91,6 +97,10 @@ class _FilemapBase(object):
             raise Error("cannot synchronize image file '%s': %s "
                         % (self._image_path, err.strerror))
 
+        self._log.debug("opened image \"%s\"" % self._image_path)
+        self._log.debug("block size %d, blocks count %d, image size %d"
+                        % (self.block_size, self.blocks_cnt, self.image_size))
+
     def __del__(self):
         """The class destructor which just closes the image file."""
         if self._f_image_needs_close:
@@ -158,11 +168,12 @@ class FilemapSeek(_FilemapBase):
     access to the image file.
     """
 
-    def __init__(self, image):
+    def __init__(self, image, log=None):
         """Refer the '_FilemapBase' class for the documentation."""
 
         # Call the base class constructor first
-        _FilemapBase.__init__(self, image)
+        _FilemapBase.__init__(self, image, log)
+        self._log.debug("FilemapSeek: initializing")
 
         self._probe_seek_hole()
 
@@ -198,6 +209,7 @@ class FilemapSeek(_FilemapBase):
         if offs != 0:
             # We are dealing with the stub 'SEEK_HOLE' implementation which
             # always returns EOF.
+            self._log.debug("lseek(0, SEEK_HOLE) returned %d" % offs)
             raise ErrorNotSupp("the file-system does not support "
                                "\"SEEK_HOLE\" and \"SEEK_DATA\" but only "
                                "provides a stub implementation")
@@ -228,9 +240,13 @@ class FilemapSeek(_FilemapBase):
         """Refer the '_FilemapBase' class for the documentation."""
         offs = self._lseek(self._f_image, block * self.block_size, _SEEK_DATA)
         if offs == -1:
-            return False
+            result = False
+        else:
+            result = (offs / self.block_size == block)
 
-        return offs / self.block_size == block
+        self._log.debug("FilemapSeek: block_is_mapped(%d) returns %s"
+                        % (block, result))
+        return result
 
     def block_is_unmapped(self, block):
         """Refer the '_FilemapBase' class for the documentation."""
@@ -258,14 +274,22 @@ class FilemapSeek(_FilemapBase):
             if end > limit:
                 end = limit
 
-            yield (start / self.block_size, end / self.block_size - 1)
+            start_blk = start / self.block_size
+            end_blk = end / self.block_size - 1
+            self._log.debug("FilemapSeek: yielding range (%d, %d)"
+                            % (start_blk, end_blk))
+            yield (start_blk, end_blk)
 
     def get_mapped_ranges(self, start, count):
         """Refer the '_FilemapBase' class for the documentation."""
+        self._log.debug("FilemapSeek: get_mapped_ranges(%d,  %d(%d))"
+                        % (start, count, start + count - 1))
         return self._get_ranges(start, count, _SEEK_DATA, _SEEK_HOLE)
 
     def get_unmapped_ranges(self, start, count):
         """Refer the '_FilemapBase' class for the documentation."""
+        self._log.debug("FilemapSeek: get_unmapped_ranges(%d,  %d(%d))"
+                        % (start, count, start + count - 1))
         return self._get_ranges(start, count, _SEEK_HOLE, _SEEK_DATA)
 
 
@@ -301,14 +325,15 @@ class FilemapFiemap(_FilemapBase):
     ioctl in order to work-around early FIEMAP implementation kernel bugs.
     """
 
-    def __init__(self, image):
+    def __init__(self, image, log=None):
         """
         Initialize a class instance. The 'image' argument is full the file
         object to operate on.
         """
 
         # Call the base class constructor first
-        _FilemapBase.__init__(self, image)
+        _FilemapBase.__init__(self, image, log)
+        self._log.debug("FilemapFiemap: initializing")
 
         self._buf_size = _FIEMAP_BUFFER_SIZE
 
@@ -354,11 +379,15 @@ class FilemapFiemap(_FilemapBase):
             # Note, the FIEMAP ioctl is supported by the Linux kernel starting
             # from version 2.6.28 (year 2008).
             if err.errno == os.errno.EOPNOTSUPP:
-                raise ErrorNotSupp("the FIEMAP ioctl is not supported by "
-                                   "the file-system")
+                errstr = "FilemapFiemap: the FIEMAP ioctl is not supported " \
+                         "by the file-system"
+                self._log.debug(errstr)
+                raise ErrorNotSupp(errstr)
             if err.errno == os.errno.ENOTTY:
-                raise ErrorNotSupp("the FIEMAP ioctl is not supported by "
-                                   "the kernel")
+                errstr = "FilemapFiemap: the FIEMAP ioctl is not supported " \
+                         "by the kernel"
+                self._log.debug(errstr)
+                raise ErrorNotSupp(errstr)
             raise Error("the FIEMAP ioctl failed for '%s': %s"
                         % (self._image_path, err))
 
@@ -371,7 +400,10 @@ class FilemapFiemap(_FilemapBase):
         # The 3rd element of 'struct_fiemap' is the 'fm_mapped_extents' field.
         # If it contains zero, the block is not mapped, otherwise it is
         # mapped.
-        return bool(struct_fiemap[3])
+        result = bool(struct_fiemap[3])
+        self._log.debug("FilemapFiemap: block_is_mapped(%d) returns %s"
+                        % (block, result))
+        return result
 
     def block_is_unmapped(self, block):
         """Refer the '_FilemapBase' class for the documentation."""
@@ -435,33 +467,44 @@ class FilemapFiemap(_FilemapBase):
 
     def get_mapped_ranges(self, start, count):
         """Refer the '_FilemapBase' class for the documentation."""
+        self._log.debug("FilemapFiemap: get_mapped_ranges(%d,  %d(%d))"
+                        % (start, count, start + count - 1))
         iterator = self._do_get_mapped_ranges(start, count)
-
         first_prev, last_prev = iterator.next()
 
         for first, last in iterator:
             if last_prev == first - 1:
                 last_prev = last
             else:
+                self._log.debug("FilemapFiemap: yielding range (%d, %d)"
+                                % (first_prev, last_prev))
                 yield (first_prev, last_prev)
                 first_prev, last_prev = first, last
 
+        self._log.debug("FilemapFiemap: yielding range (%d, %d)"
+                        % (first_prev, last_prev))
         yield (first_prev, last_prev)
 
     def get_unmapped_ranges(self, start, count):
         """Refer the '_FilemapBase' class for the documentation."""
+        self._log.debug("FilemapFiemap: get_unmapped_ranges(%d,  %d(%d))"
+                        % (start, count, start + count - 1))
         hole_first = start
         for first, last in self._do_get_mapped_ranges(start, count):
             if first > hole_first:
+                self._log.debug("FilemapFiemap: yielding range (%d, %d)"
+                                % (hole_first, first - 1))
                 yield (hole_first, first - 1)
 
             hole_first = last + 1
 
         if hole_first < start + count:
+            self._log.debug("FilemapFiemap: yielding range (%d, %d)"
+                            % (hole_first, start + count - 1))
             yield (hole_first, start + count - 1)
 
 
-def filemap(image):
+def filemap(image, log=None):
     """
     Create and return an instance of a Filemap class - 'FilemapFiemap' or
     'FilemapSeek', depending on what the system we run on supports. If the
@@ -472,6 +515,6 @@ def filemap(image):
     """
 
     try:
-        return FilemapFiemap(image)
+        return FilemapFiemap(image, log)
     except ErrorNotSupp:
-        return FilemapSeek(image)
+        return FilemapSeek(image, log)
-- 
1.8.3.1




More information about the Bmap-tools mailing list