* [wic][PATCH v2 0/8] make wic images sparse (#9099)
@ 2016-04-28 10:58 Ed Bartosh
2016-04-28 10:58 ` [wic][PATCH v2 1/8] wic: use truncate utility to create sparse files Ed Bartosh
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: Ed Bartosh @ 2016-04-28 10:58 UTC (permalink / raw)
To: openembedded-core
Hi,
This patchset is a preparation for bmaptool support for wic. Using bmaptool
makes sense only if images are sparsed and this is what's implemented here.
Nice side effect of this work is that making images sparse not only makes
flashing faster. It also makes the process of assembling an image much faster.
Here is how it works:
- wic from master branch spends 36 sec to create an image:
$ time wic create test.wks -e core-image-minimal -o img/
...
real 0m36.878s
user 2m0.496s
sys 0m18.444s
- sparse-aware wic spends 8 seconds to create the same image:
$ time wic create test.wks -e core-image-minimal -o img/
...
real 0m8.672s
user 0m7.292s
sys 0m1.212s
The final image is very sparse, which explains why sparse-aware wic is so fast:
$ ls -lhs img/build/test-201604281219-sda.direct
28M -rw-r--r-- 1 ed users 2.4G Apr 28 12:19 img/build/test-201604281219-sda.direct
bmaptool reports 1.1% of mapped blocks:
$ PATH=tmp/sysroots/x86_64-linux/usr/bin/ bmaptool create img/build/test-201604281219-sda.direct -o img/build/test-201604281219-sda.direct.bmap
$ grep 'mapped blocks' img/build/test-201604281219-sda.direct.bmap
<!-- Count of mapped blocks: 27.2 MiB or 1.1% -->
Flashing is also a lot faster with bmaptool comparing to using dd:
time PATH=./tmp/sysroots/x86_64-linux/usr/bin/ bmaptool copy img/build/test-201604281606-sda.direct /dev/sdb
bmaptool: info: discovered bmap file 'img/build/test-201604281606-sda.direct.bmap'
bmaptool: info: block map format version 2.0
bmaptool: info: 605696 blocks of size 4096 (2.3 GiB), mapped 6986 blocks (27.3 MiB or 1.2%)
bmaptool: info: copying image 'test-201604281606-sda.direct' to block device '/dev/sdb' using bmap file 'test-201604281606-sda.direct.bmap'
bmaptool: info: 100% copied
bmaptool: info: synchronizing '/dev/sdb'
bmaptool: info: copying time: 1.5s, copying speed 17.9 MiB/sec
real 0m1.621s
user 0m0.225s
sys 0m0.089s
time dd if=img/build/test-201604281606-sda.direct of=/dev/sdb bs=4M
591+1 records in
591+1 records out
2480930816 bytes (2.5 GB) copied, 107.483 s, 23.1 MB/s
real 1m47.485s
user 0m0.001s
sys 0m4.324s
The following changes since commit 111f44cacf25799dc296b8e300b571d798067fdc:
selftest: add bmap test (2016-04-27 12:26:59 +0300)
are available in the git repository at:
git://git.yoctoproject.org/poky-contrib ed/wic/sparse-9099
http://git.yoctoproject.org/cgit.cgi/poky-contrib/log/?h=ed/wic/sparse-9099
Ed Bartosh (8):
wic: use truncate utility to create sparse files
wic: get rid of inheritance Disk->DiskImage
wic: get rid of fs_related.makedirs
wic: moved DiskImage to direct.py
wic: add FIEMAP and SEEK_HOLE / SEEK_DATA APIs
wic: add sparse_copy API
wic: use sparse_copy to copy partitions
wic: use sparse_copy to preserve sparseness
scripts/lib/wic/filemap.py | 561 ++++++++++++++++++++++++++++++
scripts/lib/wic/imager/direct.py | 23 +-
scripts/lib/wic/partition.py | 20 +-
scripts/lib/wic/plugins/source/rawcopy.py | 7 +-
scripts/lib/wic/utils/fs_related.py | 84 -----
scripts/lib/wic/utils/partitionedfs.py | 6 +-
6 files changed, 592 insertions(+), 109 deletions(-)
create mode 100644 scripts/lib/wic/filemap.py
delete mode 100644 scripts/lib/wic/utils/fs_related.py
--
Regards,
Ed
^ permalink raw reply [flat|nested] 10+ messages in thread
* [wic][PATCH v2 1/8] wic: use truncate utility to create sparse files
2016-04-28 10:58 [wic][PATCH v2 0/8] make wic images sparse (#9099) Ed Bartosh
@ 2016-04-28 10:58 ` Ed Bartosh
2016-04-28 10:58 ` [wic][PATCH v2 2/8] wic: get rid of inheritance Disk->DiskImage Ed Bartosh
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ed Bartosh @ 2016-04-28 10:58 UTC (permalink / raw)
To: openembedded-core
Used truncate instead of dd to create wic images for the
following reasons:
- dd doesn't preserve sparseness
- truncate syntax is much more clear
- dd requires additional calculations of the image size
in blocks
- the way dd was used in the code is not always correct.
In some cases it was writing one block to the file which makes
it not 100% sparse.
[YOCTO #9099]
Signed-off-by: Ed Bartosh <ed.bartosh@linux.intel.com>
---
scripts/lib/wic/partition.py | 20 +++++---------------
scripts/lib/wic/utils/fs_related.py | 12 +++---------
2 files changed, 8 insertions(+), 24 deletions(-)
diff --git a/scripts/lib/wic/partition.py b/scripts/lib/wic/partition.py
index f40d1bc..2ee64a2 100644
--- a/scripts/lib/wic/partition.py
+++ b/scripts/lib/wic/partition.py
@@ -219,9 +219,7 @@ class Partition(object):
msger.debug("Added %d extra blocks to %s to get to %d total blocks" % \
(extra_blocks, self.mountpoint, rootfs_size))
- dd_cmd = "dd if=/dev/zero of=%s bs=1024 seek=%d count=0 bs=1k" % \
- (rootfs, rootfs_size)
- exec_cmd(dd_cmd)
+ exec_cmd("truncate %s -s %d" % (rootfs, rootfs_size * 1024))
extra_imagecmd = "-i 8192"
@@ -254,9 +252,7 @@ class Partition(object):
msger.debug("Added %d extra blocks to %s to get to %d total blocks" % \
(extra_blocks, self.mountpoint, rootfs_size))
- dd_cmd = "dd if=/dev/zero of=%s bs=1024 seek=%d count=0 bs=1k" % \
- (rootfs, rootfs_size)
- exec_cmd(dd_cmd)
+ exec_cmd("truncate %s -s %d" % (rootfs, rootfs_size * 1024))
label_str = ""
if self.label:
@@ -319,9 +315,7 @@ class Partition(object):
"""
Prepare an empty ext2/3/4 partition.
"""
- dd_cmd = "dd if=/dev/zero of=%s bs=1k seek=%d count=0" % \
- (rootfs, self.size)
- exec_cmd(dd_cmd)
+ exec_cmd("truncate %s -s %d" % (rootfs, self.size * 1024))
extra_imagecmd = "-i 8192"
@@ -338,9 +332,7 @@ class Partition(object):
"""
Prepare an empty btrfs partition.
"""
- dd_cmd = "dd if=/dev/zero of=%s bs=1k seek=%d count=0" % \
- (rootfs, self.size)
- exec_cmd(dd_cmd)
+ exec_cmd("truncate %s -s %d" % (rootfs, self.size * 1024))
label_str = ""
if self.label:
@@ -401,9 +393,7 @@ class Partition(object):
"""
path = "%s/fs.%s" % (cr_workdir, self.fstype)
- dd_cmd = "dd if=/dev/zero of=%s bs=1k seek=%d count=0" % \
- (path, self.size)
- exec_cmd(dd_cmd)
+ exec_cmd("truncate %s -s %d" % (path, self.size * 1024))
import uuid
label_str = ""
diff --git a/scripts/lib/wic/utils/fs_related.py b/scripts/lib/wic/utils/fs_related.py
index 2e74461..2658dcf 100644
--- a/scripts/lib/wic/utils/fs_related.py
+++ b/scripts/lib/wic/utils/fs_related.py
@@ -71,14 +71,8 @@ class DiskImage(Disk):
def create(self):
if self.device is not None:
return
-
- blocks = self.size / 1024
- if self.size - blocks * 1024:
- blocks += 1
-
- # create disk image
- dd_cmd = "dd if=/dev/zero of=%s bs=1024 seek=%d count=1" % \
- (self.image_file, blocks)
- exec_cmd(dd_cmd)
+ # create sparse disk image
+ cmd = "truncate %s -s %s" % (self.image_file, self.size)
+ exec_cmd(cmd)
self.device = self.image_file
--
2.1.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [wic][PATCH v2 2/8] wic: get rid of inheritance Disk->DiskImage
2016-04-28 10:58 [wic][PATCH v2 0/8] make wic images sparse (#9099) Ed Bartosh
2016-04-28 10:58 ` [wic][PATCH v2 1/8] wic: use truncate utility to create sparse files Ed Bartosh
@ 2016-04-28 10:58 ` Ed Bartosh
2016-04-28 10:58 ` [wic][PATCH v2 3/8] wic: get rid of fs_related.makedirs Ed Bartosh
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ed Bartosh @ 2016-04-28 10:58 UTC (permalink / raw)
To: openembedded-core
There is no need in this inheritance as DiskImage class
is used only in one module and no other classes are inherited.
Signed-off-by: Ed Bartosh <ed.bartosh@linux.intel.com>
---
scripts/lib/wic/utils/fs_related.py | 43 ++++++++-----------------------------
1 file changed, 9 insertions(+), 34 deletions(-)
diff --git a/scripts/lib/wic/utils/fs_related.py b/scripts/lib/wic/utils/fs_related.py
index 2658dcf..22aa294 100644
--- a/scripts/lib/wic/utils/fs_related.py
+++ b/scripts/lib/wic/utils/fs_related.py
@@ -32,47 +32,22 @@ def makedirs(dirname):
if err.errno != errno.EEXIST:
raise
-class Disk:
- """
- Generic base object for a disk.
- """
- def __init__(self, size, device=None):
- self._device = device
- self._size = size
-
- def create(self):
- pass
-
- def cleanup(self):
- pass
-
- def get_device(self):
- return self._device
- def set_device(self, path):
- self._device = path
- device = property(get_device, set_device)
-
- def get_size(self):
- return self._size
- size = property(get_size)
-
-
-class DiskImage(Disk):
+class DiskImage():
"""
A Disk backed by a file.
"""
- def __init__(self, image_file, size):
- Disk.__init__(self, size)
- self.image_file = image_file
+ def __init__(self, device, size):
+ self.size = size
+ self.device = device
+ self.created = False
def exists(self):
- return os.path.exists(self.image_file)
+ return os.path.exists(self.device)
def create(self):
- if self.device is not None:
+ if self.created:
return
# create sparse disk image
- cmd = "truncate %s -s %s" % (self.image_file, self.size)
+ cmd = "truncate %s -s %s" % (self.device, self.size)
exec_cmd(cmd)
-
- self.device = self.image_file
+ self.created = True
--
2.1.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [wic][PATCH v2 3/8] wic: get rid of fs_related.makedirs
2016-04-28 10:58 [wic][PATCH v2 0/8] make wic images sparse (#9099) Ed Bartosh
2016-04-28 10:58 ` [wic][PATCH v2 1/8] wic: use truncate utility to create sparse files Ed Bartosh
2016-04-28 10:58 ` [wic][PATCH v2 2/8] wic: get rid of inheritance Disk->DiskImage Ed Bartosh
@ 2016-04-28 10:58 ` Ed Bartosh
2016-04-28 10:58 ` [wic][PATCH v2 4/8] wic: moved DiskImage to direct.py Ed Bartosh
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ed Bartosh @ 2016-04-28 10:58 UTC (permalink / raw)
To: openembedded-core
Removed fs_related.makedirs as is not used anywhere. The name is
easy to confuse with os.makedirs.
Signed-off-by: Ed Bartosh <ed.bartosh@linux.intel.com>
---
scripts/lib/wic/utils/fs_related.py | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/scripts/lib/wic/utils/fs_related.py b/scripts/lib/wic/utils/fs_related.py
index 22aa294..fc3c174 100644
--- a/scripts/lib/wic/utils/fs_related.py
+++ b/scripts/lib/wic/utils/fs_related.py
@@ -16,22 +16,8 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59
# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-from __future__ import with_statement
-import os
-import errno
-
from wic.utils.oe.misc import exec_cmd
-def makedirs(dirname):
- """A version of os.makedirs() that doesn't throw an
- exception if the leaf directory already exists.
- """
- try:
- os.makedirs(dirname)
- except OSError, err:
- if err.errno != errno.EEXIST:
- raise
-
class DiskImage():
"""
A Disk backed by a file.
--
2.1.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [wic][PATCH v2 4/8] wic: moved DiskImage to direct.py
2016-04-28 10:58 [wic][PATCH v2 0/8] make wic images sparse (#9099) Ed Bartosh
` (2 preceding siblings ...)
2016-04-28 10:58 ` [wic][PATCH v2 3/8] wic: get rid of fs_related.makedirs Ed Bartosh
@ 2016-04-28 10:58 ` Ed Bartosh
2016-04-28 10:58 ` [wic][PATCH v2 5/8] wic: add FIEMAP and SEEK_HOLE / SEEK_DATA APIs Ed Bartosh
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ed Bartosh @ 2016-04-28 10:58 UTC (permalink / raw)
To: openembedded-core
Moved DiskImage class from utils/fs_related.py to
imager/direct.py as it's only used there.
Removed fs_related module as it doesn't contain anything
except of DiskImage.
Signed-off-by: Ed Bartosh <ed.bartosh@linux.intel.com>
---
scripts/lib/wic/imager/direct.py | 23 ++++++++++++++++++++--
scripts/lib/wic/utils/fs_related.py | 39 -------------------------------------
2 files changed, 21 insertions(+), 41 deletions(-)
delete mode 100644 scripts/lib/wic/utils/fs_related.py
diff --git a/scripts/lib/wic/imager/direct.py b/scripts/lib/wic/imager/direct.py
index a1b4249..699f9a5 100644
--- a/scripts/lib/wic/imager/direct.py
+++ b/scripts/lib/wic/imager/direct.py
@@ -28,7 +28,6 @@ import os
import shutil
from wic import msger
-from wic.utils import fs_related
from wic.utils.oe.misc import get_bitbake_var
from wic.utils.partitionedfs import Image
from wic.utils.errors import CreatorError, ImageError
@@ -40,6 +39,26 @@ disk_methods = {
"do_install_disk":None,
}
+class DiskImage():
+ """
+ A Disk backed by a file.
+ """
+ def __init__(self, device, size):
+ self.size = size
+ self.device = device
+ self.created = False
+
+ def exists(self):
+ return os.path.exists(self.device)
+
+ def create(self):
+ if self.created:
+ return
+ # create sparse disk image
+ cmd = "truncate %s -s %s" % (self.device, self.size)
+ exec_cmd(cmd)
+ self.created = True
+
class DirectImageCreator(BaseImageCreator):
"""
Installs a system into a file containing a partitioned disk image.
@@ -279,7 +298,7 @@ class DirectImageCreator(BaseImageCreator):
full_path = self._full_path(self.__imgdir, disk_name, "direct")
msger.debug("Adding disk %s as %s with size %s bytes" \
% (disk_name, full_path, disk['min_size']))
- disk_obj = fs_related.DiskImage(full_path, disk['min_size'])
+ disk_obj = DiskImage(full_path, disk['min_size'])
self.__disks[disk_name] = disk_obj
self.__image.add_disk(disk_name, disk_obj)
diff --git a/scripts/lib/wic/utils/fs_related.py b/scripts/lib/wic/utils/fs_related.py
deleted file mode 100644
index fc3c174..0000000
--- a/scripts/lib/wic/utils/fs_related.py
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/env python -tt
-#
-# Copyright (c) 2007, Red Hat, Inc.
-# Copyright (c) 2009, 2010, 2011 Intel, Inc.
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the Free
-# Software Foundation; version 2 of the License
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-# for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc., 59
-# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-from wic.utils.oe.misc import exec_cmd
-
-class DiskImage():
- """
- A Disk backed by a file.
- """
- def __init__(self, device, size):
- self.size = size
- self.device = device
- self.created = False
-
- def exists(self):
- return os.path.exists(self.device)
-
- def create(self):
- if self.created:
- return
- # create sparse disk image
- cmd = "truncate %s -s %s" % (self.device, self.size)
- exec_cmd(cmd)
- self.created = True
--
2.1.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [wic][PATCH v2 5/8] wic: add FIEMAP and SEEK_HOLE / SEEK_DATA APIs
2016-04-28 10:58 [wic][PATCH v2 0/8] make wic images sparse (#9099) Ed Bartosh
` (3 preceding siblings ...)
2016-04-28 10:58 ` [wic][PATCH v2 4/8] wic: moved DiskImage to direct.py Ed Bartosh
@ 2016-04-28 10:58 ` Ed Bartosh
2016-04-28 10:58 ` [wic][PATCH v2 6/8] wic: add sparse_copy API Ed Bartosh
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ed Bartosh @ 2016-04-28 10:58 UTC (permalink / raw)
To: openembedded-core
In order to make wic images sparse set of APIs has been copied
from bmap-tools project.
filemap.py module is taken from bmap-tools project:
https://github.com/01org/bmap-tools/blob/master/bmaptools/Filemap.py
It implements two ways of get information about file block: FIEMAP
ioctl and the 'SEEK_HOLE / SEEK_DATA' features of the file seek
syscall.
Note that this module will be removed as soon as bmaptool utility
supports copying sparse source file into destination file (this is
already agreed with the maintainer of bmap-tools project).
[YOCTO #9099]
Signed-off-by: Ed Bartosh <ed.bartosh@linux.intel.com>
---
scripts/lib/wic/filemap.py | 531 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 531 insertions(+)
create mode 100644 scripts/lib/wic/filemap.py
diff --git a/scripts/lib/wic/filemap.py b/scripts/lib/wic/filemap.py
new file mode 100644
index 0000000..1d04328
--- /dev/null
+++ b/scripts/lib/wic/filemap.py
@@ -0,0 +1,531 @@
+# Copyright (c) 2012 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2,
+# as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+
+"""
+This module implements python implements a way to get file block. Two methods
+are supported - the FIEMAP ioctl and the 'SEEK_HOLE / SEEK_DATA' features of
+the file seek syscall. The former is implemented by the 'FilemapFiemap' class,
+the latter is implemented by the 'FilemapSeek' class. Both classes provide the
+same API. The 'filemap' function automatically selects which class can be used
+and returns an instance of the class.
+"""
+
+# Disable the following pylint recommendations:
+# * Too many instance attributes (R0902)
+# pylint: disable=R0902
+
+import os
+import struct
+import array
+import fcntl
+import tempfile
+import logging
+
+def get_block_size(file_obj):
+ """
+ Returns block size for file object 'file_obj'. Errors are indicated by the
+ 'IOError' exception.
+ """
+
+ from fcntl import ioctl
+ import struct
+
+ # Get the block size of the host file-system for the image file by calling
+ # the FIGETBSZ ioctl (number 2).
+ binary_data = ioctl(file_obj, 2, struct.pack('I', 0))
+ return struct.unpack('I', binary_data)[0]
+
+class ErrorNotSupp(Exception):
+ """
+ An exception of this type is raised when the 'FIEMAP' or 'SEEK_HOLE' feature
+ is not supported either by the kernel or the file-system.
+ """
+ pass
+
+class Error(Exception):
+ """A class for all the other exceptions raised by this module."""
+ pass
+
+
+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 'log' parameter is the logger object
+ to use for printing messages.
+ """
+
+ 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"):
+ self._f_image = image
+ self._image_path = image.name
+ else:
+ self._image_path = image
+ self._open_image_file()
+
+ try:
+ self.image_size = os.fstat(self._f_image.fileno()).st_size
+ except IOError as err:
+ raise Error("cannot get information about file '%s': %s"
+ % (self._f_image.name, err))
+
+ try:
+ self.block_size = get_block_size(self._f_image)
+ except IOError as err:
+ raise Error("cannot get block size for '%s': %s"
+ % (self._image_path, err))
+
+ self.blocks_cnt = self.image_size + self.block_size - 1
+ self.blocks_cnt /= self.block_size
+
+ try:
+ self._f_image.flush()
+ except IOError as err:
+ raise Error("cannot flush image file '%s': %s"
+ % (self._image_path, err))
+
+ try:
+ os.fsync(self._f_image.fileno()),
+ except OSError as err:
+ 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:
+ self._f_image.close()
+
+ def _open_image_file(self):
+ """Open the image file."""
+ try:
+ self._f_image = open(self._image_path, 'rb')
+ except IOError as err:
+ raise Error("cannot open image file '%s': %s"
+ % (self._image_path, err))
+
+ self._f_image_needs_close = True
+
+ def block_is_mapped(self, block): # pylint: disable=W0613,R0201
+ """
+ This method has has to be implemented by child classes. It returns
+ 'True' if block number 'block' of the image file is mapped and 'False'
+ otherwise.
+ """
+
+ raise Error("the method is not implemented")
+
+ def block_is_unmapped(self, block): # pylint: disable=W0613,R0201
+ """
+ This method has has to be implemented by child classes. It returns
+ 'True' if block number 'block' of the image file is not mapped (hole)
+ and 'False' otherwise.
+ """
+
+ raise Error("the method is not implemented")
+
+ def get_mapped_ranges(self, start, count): # pylint: disable=W0613,R0201
+ """
+ This method has has to be implemented by child classes. This is a
+ generator which yields ranges of mapped blocks in the file. The ranges
+ are tuples of 2 elements: [first, last], where 'first' is the first
+ mapped block and 'last' is the last mapped block.
+
+ The ranges are yielded for the area of the file of size 'count' blocks,
+ starting from block 'start'.
+ """
+
+ raise Error("the method is not implemented")
+
+ def get_unmapped_ranges(self, start, count): # pylint: disable=W0613,R0201
+ """
+ This method has has to be implemented by child classes. Just like
+ 'get_mapped_ranges()', but yields unmapped block ranges instead
+ (holes).
+ """
+
+ raise Error("the method is not implemented")
+
+
+# The 'SEEK_HOLE' and 'SEEK_DATA' options of the file seek system call
+_SEEK_DATA = 3
+_SEEK_HOLE = 4
+
+def _lseek(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'
+ argument is supposed to be either '_SEEK_DATA' or '_SEEK_HOLE'. When
+ there is no more data or hole starting from 'offset', this function
+ returns '-1'. Otherwise the data or hole position is returned."""
+
+ try:
+ return os.lseek(file_obj.fileno(), offset, whence)
+ except OSError as err:
+ # The 'lseek' system call returns the ENXIO if there is no data or
+ # hole starting from the specified offset.
+ if err.errno == os.errno.ENXIO:
+ return -1
+ elif err.errno == os.errno.EINVAL:
+ raise ErrorNotSupp("the kernel or file-system does not support "
+ "\"SEEK_HOLE\" and \"SEEK_DATA\"")
+ else:
+ raise
+
+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, log=None):
+ """Refer the '_FilemapBase' class for the documentation."""
+
+ # Call the base class constructor first
+ _FilemapBase.__init__(self, image, log)
+ self._log.debug("FilemapSeek: initializing")
+
+ 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 = _lseek(tmp_obj, 0, _SEEK_HOLE)
+ 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")
+
+ tmp_obj.close()
+
+ def block_is_mapped(self, block):
+ """Refer the '_FilemapBase' class for the documentation."""
+ offs = _lseek(self._f_image, block * self.block_size, _SEEK_DATA)
+ if offs == -1:
+ result = False
+ else:
+ result = (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."""
+ return not self.block_is_mapped(block)
+
+ def _get_ranges(self, start, count, whence1, whence2):
+ """
+ This function implements 'get_mapped_ranges()' and
+ 'get_unmapped_ranges()' depending on what is passed in the 'whence1'
+ and 'whence2' arguments.
+ """
+
+ assert whence1 != whence2
+ end = start * self.block_size
+ limit = end + count * self.block_size
+
+ while True:
+ start = _lseek(self._f_image, end, whence1)
+ if start == -1 or start >= limit or start == self.image_size:
+ break
+
+ end = _lseek(self._f_image, start, whence2)
+ if end == -1 or end == self.image_size:
+ end = self.blocks_cnt * self.block_size
+ if end > limit:
+ end = limit
+
+ 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)
+
+
+# Below goes the FIEMAP ioctl implementation, which is not very readable
+# because it deals with the rather complex FIEMAP ioctl. To understand the
+# code, you need to know the FIEMAP interface, which is documented in the
+# "Documentation/filesystems/fiemap.txt" file in the Linux kernel sources.
+
+# Format string for 'struct fiemap'
+_FIEMAP_FORMAT = "=QQLLLL"
+# sizeof(struct fiemap)
+_FIEMAP_SIZE = struct.calcsize(_FIEMAP_FORMAT)
+# Format string for 'struct fiemap_extent'
+_FIEMAP_EXTENT_FORMAT = "=QQQQQLLLL"
+# sizeof(struct fiemap_extent)
+_FIEMAP_EXTENT_SIZE = struct.calcsize(_FIEMAP_EXTENT_FORMAT)
+# The FIEMAP ioctl number
+_FIEMAP_IOCTL = 0xC020660B
+# This FIEMAP ioctl flag which instructs the kernel to sync the file before
+# reading the block map
+_FIEMAP_FLAG_SYNC = 0x00000001
+# Size of the buffer for 'struct fiemap_extent' elements which will be used
+# when invoking the FIEMAP ioctl. The larger is the buffer, the less times the
+# FIEMAP ioctl will be invoked.
+_FIEMAP_BUFFER_SIZE = 256 * 1024
+
+class FilemapFiemap(_FilemapBase):
+ """
+ This class provides API to the FIEMAP ioctl. Namely, it allows to iterate
+ over all mapped blocks and over all holes.
+
+ This class synchronizes the image file every time it invokes the FIEMAP
+ ioctl in order to work-around early FIEMAP implementation kernel bugs.
+ """
+
+ 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, log)
+ self._log.debug("FilemapFiemap: initializing")
+
+ self._buf_size = _FIEMAP_BUFFER_SIZE
+
+ # Calculate how many 'struct fiemap_extent' elements fit the buffer
+ self._buf_size -= _FIEMAP_SIZE
+ self._fiemap_extent_cnt = self._buf_size / _FIEMAP_EXTENT_SIZE
+ assert self._fiemap_extent_cnt > 0
+ self._buf_size = self._fiemap_extent_cnt * _FIEMAP_EXTENT_SIZE
+ self._buf_size += _FIEMAP_SIZE
+
+ # Allocate a mutable buffer for the FIEMAP ioctl
+ self._buf = array.array('B', [0] * self._buf_size)
+
+ # Check if the FIEMAP ioctl is supported
+ self.block_is_mapped(0)
+
+ def _invoke_fiemap(self, block, count):
+ """
+ Invoke the FIEMAP ioctl for 'count' blocks of the file starting from
+ block number 'block'.
+
+ The full result of the operation is stored in 'self._buf' on exit.
+ Returns the unpacked 'struct fiemap' data structure in form of a python
+ list (just like 'struct.upack()').
+ """
+
+ if self.blocks_cnt != 0 and (block < 0 or block >= self.blocks_cnt):
+ raise Error("bad block number %d, should be within [0, %d]"
+ % (block, self.blocks_cnt))
+
+ # Initialize the 'struct fiemap' part of the buffer. We use the
+ # '_FIEMAP_FLAG_SYNC' flag in order to make sure the file is
+ # synchronized. The reason for this is that early FIEMAP
+ # implementations had many bugs related to cached dirty data, and
+ # synchronizing the file is a necessary work-around.
+ struct.pack_into(_FIEMAP_FORMAT, self._buf, 0, block * self.block_size,
+ count * self.block_size, _FIEMAP_FLAG_SYNC, 0,
+ self._fiemap_extent_cnt, 0)
+
+ try:
+ fcntl.ioctl(self._f_image, _FIEMAP_IOCTL, self._buf, 1)
+ except IOError as err:
+ # Note, the FIEMAP ioctl is supported by the Linux kernel starting
+ # from version 2.6.28 (year 2008).
+ if err.errno == os.errno.EOPNOTSUPP:
+ 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:
+ 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))
+
+ return struct.unpack(_FIEMAP_FORMAT, self._buf[:_FIEMAP_SIZE])
+
+ def block_is_mapped(self, block):
+ """Refer the '_FilemapBase' class for the documentation."""
+ struct_fiemap = self._invoke_fiemap(block, 1)
+
+ # 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.
+ 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."""
+ return not self.block_is_mapped(block)
+
+ def _unpack_fiemap_extent(self, index):
+ """
+ Unpack a 'struct fiemap_extent' structure object number 'index' from
+ the internal 'self._buf' buffer.
+ """
+
+ offset = _FIEMAP_SIZE + _FIEMAP_EXTENT_SIZE * index
+ return struct.unpack(_FIEMAP_EXTENT_FORMAT,
+ self._buf[offset : offset + _FIEMAP_EXTENT_SIZE])
+
+ def _do_get_mapped_ranges(self, start, count):
+ """
+ Implements most the functionality for the 'get_mapped_ranges()'
+ generator: invokes the FIEMAP ioctl, walks through the mapped extents
+ and yields mapped block ranges. However, the ranges may be consecutive
+ (e.g., (1, 100), (100, 200)) and 'get_mapped_ranges()' simply merges
+ them.
+ """
+
+ block = start
+ while block < start + count:
+ struct_fiemap = self._invoke_fiemap(block, count)
+
+ mapped_extents = struct_fiemap[3]
+ if mapped_extents == 0:
+ # No more mapped blocks
+ return
+
+ extent = 0
+ while extent < mapped_extents:
+ fiemap_extent = self._unpack_fiemap_extent(extent)
+
+ # Start of the extent
+ extent_start = fiemap_extent[0]
+ # Starting block number of the extent
+ extent_block = extent_start / self.block_size
+ # Length of the extent
+ extent_len = fiemap_extent[2]
+ # Count of blocks in the extent
+ extent_count = extent_len / self.block_size
+
+ # Extent length and offset have to be block-aligned
+ assert extent_start % self.block_size == 0
+ assert extent_len % self.block_size == 0
+
+ if extent_block > start + count - 1:
+ return
+
+ first = max(extent_block, block)
+ last = min(extent_block + extent_count, start + count) - 1
+ yield (first, last)
+
+ extent += 1
+
+ block = extent_block + extent_count
+
+ 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, 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
+ FIEMAP ioctl is supported, an instance of the 'FilemapFiemap' class is
+ returned. Otherwise, if 'SEEK_HOLE' is supported an instance of the
+ 'FilemapSeek' class is returned. If none of these are supported, the
+ function generates an 'Error' type exception.
+ """
+
+ try:
+ return FilemapFiemap(image, log)
+ except ErrorNotSupp:
+ return FilemapSeek(image, log)
--
2.1.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [wic][PATCH v2 6/8] wic: add sparse_copy API
2016-04-28 10:58 [wic][PATCH v2 0/8] make wic images sparse (#9099) Ed Bartosh
` (4 preceding siblings ...)
2016-04-28 10:58 ` [wic][PATCH v2 5/8] wic: add FIEMAP and SEEK_HOLE / SEEK_DATA APIs Ed Bartosh
@ 2016-04-28 10:58 ` Ed Bartosh
2016-04-28 10:58 ` [wic][PATCH v2 7/8] wic: use sparse_copy to copy partitions Ed Bartosh
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ed Bartosh @ 2016-04-28 10:58 UTC (permalink / raw)
To: openembedded-core
In order to make wic images sparse sparse_copy function has been
copied from meta-ostro:
https://github.com/kad/meta-ostro/blob/master/meta-ostro/lib/image-dsk.py
This function uses filemap APIs to copy source sparse file into
destination file preserving sparseness.
The function has been modified to satisfy wic requirements:
parameter 'skip' has been added.
[YOCTO #9099]
Signed-off-by: Ed Bartosh <ed.bartosh@linux.intel.com>
---
scripts/lib/wic/filemap.py | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/scripts/lib/wic/filemap.py b/scripts/lib/wic/filemap.py
index 1d04328..f8b2ba7 100644
--- a/scripts/lib/wic/filemap.py
+++ b/scripts/lib/wic/filemap.py
@@ -529,3 +529,33 @@ def filemap(image, log=None):
return FilemapFiemap(image, log)
except ErrorNotSupp:
return FilemapSeek(image, log)
+
+def sparse_copy(src_fname, dst_fname, offset=0, skip=0):
+ """Efficiently copy sparse file to or into another file."""
+ fmap = filemap(src_fname)
+ try:
+ dst_file = open(dst_fname, 'r+b')
+ except IOError:
+ dst_file = open(dst_fname, 'wb')
+
+ for first, last in fmap.get_mapped_ranges(0, fmap.blocks_cnt):
+ start = first * fmap.block_size
+ end = (last + 1) * fmap.block_size
+
+ if start < skip < end:
+ start = skip
+
+ fmap._f_image.seek(start, os.SEEK_SET)
+ dst_file.seek(offset + start, os.SEEK_SET)
+
+ chunk_size = 1024 * 1024
+ to_read = end - start
+ read = 0
+
+ while read < to_read:
+ if read + chunk_size > to_read:
+ chunk_size = to_read - read
+ chunk = fmap._f_image.read(chunk_size)
+ dst_file.write(chunk)
+ read += chunk_size
+ dst_file.close()
--
2.1.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [wic][PATCH v2 7/8] wic: use sparse_copy to copy partitions
2016-04-28 10:58 [wic][PATCH v2 0/8] make wic images sparse (#9099) Ed Bartosh
` (5 preceding siblings ...)
2016-04-28 10:58 ` [wic][PATCH v2 6/8] wic: add sparse_copy API Ed Bartosh
@ 2016-04-28 10:58 ` Ed Bartosh
2016-04-28 10:58 ` [wic][PATCH v2 8/8] wic: use sparse_copy to preserve sparseness Ed Bartosh
2016-05-02 13:56 ` [wic][PATCH v2 0/8] make wic images sparse (#9099) Philip Balister
8 siblings, 0 replies; 10+ messages in thread
From: Ed Bartosh @ 2016-04-28 10:58 UTC (permalink / raw)
To: openembedded-core
Copied partition images into final partitioned image using
sparse_copy API. This method preserves sparseness of the
final image. It also makes wic much faster, as unmapped
blocks of the partition images are not copied.
[YOCTO #9099]
Signed-off-by: Ed Bartosh <ed.bartosh@linux.intel.com>
---
scripts/lib/wic/utils/partitionedfs.py | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/scripts/lib/wic/utils/partitionedfs.py b/scripts/lib/wic/utils/partitionedfs.py
index ad596d2..1b3870f 100644
--- a/scripts/lib/wic/utils/partitionedfs.py
+++ b/scripts/lib/wic/utils/partitionedfs.py
@@ -22,6 +22,7 @@ import os
from wic import msger
from wic.utils.errors import ImageError
from wic.utils.oe.misc import exec_cmd, exec_native_cmd
+from wic.filemap import sparse_copy
# Overhead of the MBR partitioning scheme (just one sector)
MBR_OVERHEAD = 1
@@ -338,10 +339,7 @@ class Image(object):
source = part['source_file']
if source:
# install source_file contents into a partition
- cmd = "dd if=%s of=%s bs=%d seek=%d count=%d conv=notrunc" % \
- (source, image_file, self.sector_size,
- part['start'], part['size'])
- exec_cmd(cmd)
+ sparse_copy(source, image_file, part['start'] * self.sector_size)
msger.debug("Installed %s in partition %d, sectors %d-%d, "
"size %d sectors" % \
--
2.1.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [wic][PATCH v2 8/8] wic: use sparse_copy to preserve sparseness
2016-04-28 10:58 [wic][PATCH v2 0/8] make wic images sparse (#9099) Ed Bartosh
` (6 preceding siblings ...)
2016-04-28 10:58 ` [wic][PATCH v2 7/8] wic: use sparse_copy to copy partitions Ed Bartosh
@ 2016-04-28 10:58 ` Ed Bartosh
2016-05-02 13:56 ` [wic][PATCH v2 0/8] make wic images sparse (#9099) Philip Balister
8 siblings, 0 replies; 10+ messages in thread
From: Ed Bartosh @ 2016-04-28 10:58 UTC (permalink / raw)
To: openembedded-core
Used sparse_copy API in favor of dd/cp in rawcopy plugin to
preserve sparseness of the copied raw content.
[YOCTO #9099]
Signed-off-by: Ed Bartosh <ed.bartosh@linux.intel.com>
---
scripts/lib/wic/plugins/source/rawcopy.py | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/scripts/lib/wic/plugins/source/rawcopy.py b/scripts/lib/wic/plugins/source/rawcopy.py
index 0472f53..ba014b0 100644
--- a/scripts/lib/wic/plugins/source/rawcopy.py
+++ b/scripts/lib/wic/plugins/source/rawcopy.py
@@ -20,6 +20,7 @@ import os
from wic import msger
from wic.pluginbase import SourcePlugin
from wic.utils.oe.misc import exec_cmd, get_bitbake_var
+from wic.filemap import sparse_copy
class RawCopyPlugin(SourcePlugin):
"""
@@ -70,11 +71,9 @@ class RawCopyPlugin(SourcePlugin):
dst = os.path.join(cr_workdir, source_params['file'])
if 'skip' in source_params:
- dd_cmd = "dd if=%s of=%s ibs=%s skip=1 conv=notrunc" % \
- (src, dst, source_params['skip'])
+ sparse_copy(src, dst, skip=source_params['skip'])
else:
- dd_cmd = "cp %s %s" % (src, dst)
- exec_cmd(dd_cmd)
+ sparse_copy(src, dst)
# get the size in the right units for kickstart (kB)
du_cmd = "du -Lbks %s" % dst
--
2.1.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [wic][PATCH v2 0/8] make wic images sparse (#9099)
2016-04-28 10:58 [wic][PATCH v2 0/8] make wic images sparse (#9099) Ed Bartosh
` (7 preceding siblings ...)
2016-04-28 10:58 ` [wic][PATCH v2 8/8] wic: use sparse_copy to preserve sparseness Ed Bartosh
@ 2016-05-02 13:56 ` Philip Balister
8 siblings, 0 replies; 10+ messages in thread
From: Philip Balister @ 2016-05-02 13:56 UTC (permalink / raw)
To: Ed Bartosh, openembedded-core
On 04/28/2016 06:58 AM, Ed Bartosh wrote:
> Hi,
>
> This patchset is a preparation for bmaptool support for wic. Using bmaptool
> makes sense only if images are sparsed and this is what's implemented here.
Minor nit, I find bmaptool makes sense even when images are not sparse.
It does check if existing partitions are mounted and seems a little
faster than dd.
Philip
>
> Nice side effect of this work is that making images sparse not only makes
> flashing faster. It also makes the process of assembling an image much faster.
>
> Here is how it works:
> - wic from master branch spends 36 sec to create an image:
> $ time wic create test.wks -e core-image-minimal -o img/
> ...
> real 0m36.878s
> user 2m0.496s
> sys 0m18.444s
>
> - sparse-aware wic spends 8 seconds to create the same image:
> $ time wic create test.wks -e core-image-minimal -o img/
> ...
> real 0m8.672s
> user 0m7.292s
> sys 0m1.212s
>
> The final image is very sparse, which explains why sparse-aware wic is so fast:
> $ ls -lhs img/build/test-201604281219-sda.direct
> 28M -rw-r--r-- 1 ed users 2.4G Apr 28 12:19 img/build/test-201604281219-sda.direct
>
> bmaptool reports 1.1% of mapped blocks:
> $ PATH=tmp/sysroots/x86_64-linux/usr/bin/ bmaptool create img/build/test-201604281219-sda.direct -o img/build/test-201604281219-sda.direct.bmap
> $ grep 'mapped blocks' img/build/test-201604281219-sda.direct.bmap
> <!-- Count of mapped blocks: 27.2 MiB or 1.1% -->
>
> Flashing is also a lot faster with bmaptool comparing to using dd:
>
> time PATH=./tmp/sysroots/x86_64-linux/usr/bin/ bmaptool copy img/build/test-201604281606-sda.direct /dev/sdb
> bmaptool: info: discovered bmap file 'img/build/test-201604281606-sda.direct.bmap'
> bmaptool: info: block map format version 2.0
> bmaptool: info: 605696 blocks of size 4096 (2.3 GiB), mapped 6986 blocks (27.3 MiB or 1.2%)
> bmaptool: info: copying image 'test-201604281606-sda.direct' to block device '/dev/sdb' using bmap file 'test-201604281606-sda.direct.bmap'
> bmaptool: info: 100% copied
> bmaptool: info: synchronizing '/dev/sdb'
> bmaptool: info: copying time: 1.5s, copying speed 17.9 MiB/sec
>
> real 0m1.621s
> user 0m0.225s
> sys 0m0.089s
>
> time dd if=img/build/test-201604281606-sda.direct of=/dev/sdb bs=4M
> 591+1 records in
> 591+1 records out
> 2480930816 bytes (2.5 GB) copied, 107.483 s, 23.1 MB/s
>
> real 1m47.485s
> user 0m0.001s
> sys 0m4.324s
>
> The following changes since commit 111f44cacf25799dc296b8e300b571d798067fdc:
>
> selftest: add bmap test (2016-04-27 12:26:59 +0300)
>
> are available in the git repository at:
>
> git://git.yoctoproject.org/poky-contrib ed/wic/sparse-9099
> http://git.yoctoproject.org/cgit.cgi/poky-contrib/log/?h=ed/wic/sparse-9099
>
> Ed Bartosh (8):
> wic: use truncate utility to create sparse files
> wic: get rid of inheritance Disk->DiskImage
> wic: get rid of fs_related.makedirs
> wic: moved DiskImage to direct.py
> wic: add FIEMAP and SEEK_HOLE / SEEK_DATA APIs
> wic: add sparse_copy API
> wic: use sparse_copy to copy partitions
> wic: use sparse_copy to preserve sparseness
>
> scripts/lib/wic/filemap.py | 561 ++++++++++++++++++++++++++++++
> scripts/lib/wic/imager/direct.py | 23 +-
> scripts/lib/wic/partition.py | 20 +-
> scripts/lib/wic/plugins/source/rawcopy.py | 7 +-
> scripts/lib/wic/utils/fs_related.py | 84 -----
> scripts/lib/wic/utils/partitionedfs.py | 6 +-
> 6 files changed, 592 insertions(+), 109 deletions(-)
> create mode 100644 scripts/lib/wic/filemap.py
> delete mode 100644 scripts/lib/wic/utils/fs_related.py
>
> --
> Regards,
> Ed
>
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2016-05-02 13:56 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-04-28 10:58 [wic][PATCH v2 0/8] make wic images sparse (#9099) Ed Bartosh
2016-04-28 10:58 ` [wic][PATCH v2 1/8] wic: use truncate utility to create sparse files Ed Bartosh
2016-04-28 10:58 ` [wic][PATCH v2 2/8] wic: get rid of inheritance Disk->DiskImage Ed Bartosh
2016-04-28 10:58 ` [wic][PATCH v2 3/8] wic: get rid of fs_related.makedirs Ed Bartosh
2016-04-28 10:58 ` [wic][PATCH v2 4/8] wic: moved DiskImage to direct.py Ed Bartosh
2016-04-28 10:58 ` [wic][PATCH v2 5/8] wic: add FIEMAP and SEEK_HOLE / SEEK_DATA APIs Ed Bartosh
2016-04-28 10:58 ` [wic][PATCH v2 6/8] wic: add sparse_copy API Ed Bartosh
2016-04-28 10:58 ` [wic][PATCH v2 7/8] wic: use sparse_copy to copy partitions Ed Bartosh
2016-04-28 10:58 ` [wic][PATCH v2 8/8] wic: use sparse_copy to preserve sparseness Ed Bartosh
2016-05-02 13:56 ` [wic][PATCH v2 0/8] make wic images sparse (#9099) Philip Balister
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.