Skip to content

Commit

Permalink
zfs-vol: implement volume-create 2/2: Volume.create
Browse files Browse the repository at this point in the history
We create sparse volumes, making the SR a thin-provisioning one.

Cache as vsize the actual size created by the zfs command (which in
zfs-2.1 unlike in zfs-0.8 does round up requested size to be acceptable).

Note that if Volume.set were not implemented yet (or indeed cannot
complete and returns an error), we face xapi-project/xen-api#5530: if
the Volume.set call fails (to add the vdi-type=user custom-key
record), then the VDI object is not created (though, as this happens
after Volume.create, the zvol and DB entries were indeed created and
there suppression was not requested by SMAPI after the error).  But
since all the VDI information that count are here, "xe sr-scan" will
bring those VDI to life (after implementation of SR.ls).

Originally-by: Matias Ezequiel Vara Larsen <[email protected]>
Signed-off-by: Yann Dirson <[email protected]>
  • Loading branch information
ydirson committed Apr 4, 2024
1 parent dd03a5b commit d613303
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 1 deletion.
1 change: 1 addition & 0 deletions plugins/volume/org.xen.xapi.storage.zfs-vol/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def query(self, dbg):
"version": "3.0",
"required_api_version": "5.0",
"features": [
"VDI_CREATE",
],
"configuration": {},
"required_cluster_stack": []}
Expand Down
45 changes: 44 additions & 1 deletion plugins/volume/org.xen.xapi.storage.zfs-vol/volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,61 @@
from xapi.storage.libs.libcow.volume_implementation import Implementation as \
DefaultImplementation

import zfsutils

@util.decorate_all_routines(util.log_exceptions_in_function)
class Implementation(DefaultImplementation):
"Volume driver to provide raw volumes from zvol's"

def create(self, dbg, sr, name, description, size, sharable):
meta = util.get_sr_metadata(dbg, 'file://' + sr)
pool_name = meta["zpool"]

with VolumeContext(self.callbacks, sr, 'w') as opq:
image_type = ImageFormat.IMAGE_RAW
image_format = ImageFormat.get_format(image_type)
vdi_uuid = str(uuid.uuid4())

with PollLock(opq, 'gl', self.callbacks, 0.5):
with self.callbacks.db_context(opq) as db:
volume = db.insert_new_volume(size, image_type)
db.insert_vdi(
name, description, vdi_uuid, volume.id, sharable)
path = zfsutils.zvol_path(pool_name, volume.id)
zfsutils.vol_create(dbg, path, size)

vol_name = zfsutils.zvol_path(pool_name, volume.id)
volume.vsize = zfsutils.vol_get_size(dbg, vol_name)
if volume.vsize != size:
log.debug("%s: VDI.create adjusted requested size %s to %s",
dbg, size, volume.vsize)
db.update_volume_vsize(volume.id, volume.vsize)

vdi_uri = self.callbacks.getVolumeUriPrefix(opq) + vdi_uuid

return {
'key': vdi_uuid,
'uuid': vdi_uuid,
'name': name,
'description': description,
'read_write': True,
'virtual_size': volume.vsize,
'physical_utilisation': zfsutils.vol_get_used(dbg, vol_name),
'uri': [image_format.uri_prefix + vdi_uri],
'sharable': False,
'keys': {}
}

def call_volume_command():
"""Parse the arguments and call the required command"""
log.log_call_argv()
fsp = importlib.import_module("zfs-vol")
cmd = xapi.storage.api.v5.volume.Volume_commandline(
Implementation(fsp.Callbacks()))
base = os.path.basename(sys.argv[0])
if base == "Volume.set":
if base == "Volume.create":
cmd.create()
elif base == "Volume.set":
cmd.set()
elif base == "Volume.unset":
cmd.unset()
Expand Down
3 changes: 3 additions & 0 deletions plugins/volume/org.xen.xapi.storage.zfs-vol/zfs-vol.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@

class Callbacks(xapi.storage.libs.libcow.callbacks.Callbacks):
"ZFS-vol callbacks"

def getVolumeUriPrefix(self, opq):
return "zfs-vol/" + opq + "|"
11 changes: 11 additions & 0 deletions plugins/volume/org.xen.xapi.storage.zfs-vol/zfsutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@

MOUNT_ROOT = '/var/run/sr-mount'

def zvol_path(pool_name, vol_id):
return "{}/{}".format(pool_name, vol_id)

###

def pool_mountpoint(dbg, pool_name):
cmd = "zfs get mountpoint -H -o value".split() + [ pool_name ]
return call(dbg, cmd).strip()
Expand Down Expand Up @@ -37,3 +42,9 @@ def pool_get_free_space(dbg, sr_path):
# size is returned in bytes
cmd = "zpool get -Hp -o value free".split() + [ sr_path ]
return int(call(dbg, cmd))

def vol_create(dbg, zvol_path, size_mib):
cmd = ("zfs create -s".split() + [zvol_path]
+ ['-V', str(size_mib)]
)
call(dbg, cmd)

0 comments on commit d613303

Please sign in to comment.