2323from nova .openstack .common import excutils
2424from nova .openstack .common import fileutils
2525from nova .openstack .common import lockutils
26+ from nova .openstack .common import log as logging
2627from nova import utils
2728from nova .virt .disk import api as disk
2829from nova .virt import images
5253CONF = cfg .CONF
5354CONF .register_opts (__imagebackend_opts )
5455CONF .import_opt ('base_dir_name' , 'nova.virt.libvirt.imagecache' )
56+ CONF .import_opt ('preallocate_images' , 'nova.virt.driver' )
57+
58+ LOG = logging .getLogger (__name__ )
5559
5660
5761class Image (object ):
@@ -67,6 +71,7 @@ def __init__(self, source_type, driver_format, is_block_dev=False):
6771 self .source_type = source_type
6872 self .driver_format = driver_format
6973 self .is_block_dev = is_block_dev
74+ self .preallocate = False
7075
7176 # NOTE(mikal): We need a lock directory which is shared along with
7277 # instance files, to cover the scenario where multiple compute nodes
@@ -133,6 +138,25 @@ def call_if_not_exists(target, *args, **kwargs):
133138 self .create_image (call_if_not_exists , base , size ,
134139 * args , ** kwargs )
135140
141+ if size and self .preallocate and self ._can_fallocate ():
142+ utils .execute ('fallocate' , '-n' , '-l' , size , self .path )
143+
144+ def _can_fallocate (self ):
145+ """Check once per class, whether fallocate(1) is available,
146+ and that the instances directory supports fallocate(2).
147+ """
148+ can_fallocate = getattr (self .__class__ , 'can_fallocate' , None )
149+ if can_fallocate is None :
150+ _out , err = utils .trycmd ('fallocate' , '-n' , '-l' , '1' ,
151+ self .path + '.fallocate_test' )
152+ utils .delete_if_exists (self .path + '.fallocate_test' )
153+ can_fallocate = not err
154+ self .__class__ .can_fallocate = can_fallocate
155+ if not can_fallocate :
156+ LOG .error ('Unable to preallocate_images=%s at path: %s' %
157+ (CONF .preallocate_images , self .path ))
158+ return can_fallocate
159+
136160 def snapshot_create (self ):
137161 raise NotImplementedError
138162
@@ -152,6 +176,7 @@ def __init__(self, instance=None, disk_name=None, path=None,
152176 os .path .join (libvirt_utils .get_instance_path (instance ),
153177 disk_name ))
154178 self .snapshot_name = snapshot_name
179+ self .preallocate = CONF .preallocate_images != 'none'
155180
156181 def create_image (self , prepare_template , base , size , * args , ** kwargs ):
157182 @lockutils .synchronized (base , 'nova-' , external = True ,
@@ -190,11 +215,15 @@ def __init__(self, instance=None, disk_name=None, path=None,
190215 os .path .join (libvirt_utils .get_instance_path (instance ),
191216 disk_name ))
192217 self .snapshot_name = snapshot_name
218+ self .preallocate = CONF .preallocate_images != 'none'
193219
194220 def create_image (self , prepare_template , base , size , * args , ** kwargs ):
195221 @lockutils .synchronized (base , 'nova-' , external = True ,
196222 lock_path = self .lock_path )
197223 def copy_qcow2_image (base , target , size ):
224+ # TODO(pbrady): Consider copying the cow image here
225+ # with preallocation=metadata set for performance reasons.
226+ # This would be keyed on a 'preallocate_images' setting.
198227 libvirt_utils .create_cow_image (base , target )
199228 if size :
200229 disk .extend (target , size )
@@ -241,13 +270,19 @@ def __init__(self, instance=None, disk_name=None, path=None,
241270 self .escape (disk_name ))
242271 self .path = os .path .join ('/dev' , self .vg , self .lv )
243272
273+ # TODO(pbrady): possibly deprecate libvirt_sparse_logical_volumes
274+ # for the more general preallocate_images
244275 self .sparse = CONF .libvirt_sparse_logical_volumes
276+ self .preallocate = not self .sparse
245277
246278 if snapshot_name :
247279 self .snapshot_name = snapshot_name
248280 self .snapshot_path = os .path .join ('/dev' , self .vg ,
249281 self .snapshot_name )
250282
283+ def _can_fallocate (self ):
284+ return False
285+
251286 def create_image (self , prepare_template , base , size , * args , ** kwargs ):
252287 @lockutils .synchronized (base , 'nova-' , external = True ,
253288 lock_path = self .lock_path )
0 commit comments