[libvirt] virStream: this function is not supported by the connection driver

John Ferlan jferlan at redhat.com
Wed Feb 3 22:18:59 UTC 2016

On 02/01/2016 08:27 AM, Wido den Hollander wrote:
>> Op 1 februari 2016 om 14:11 schreef Michal Privoznik <mprivozn at redhat.com>:
>> On 31.01.2016 12:03, Wido den Hollander wrote:
>>> On 01/31/2016 08:37 AM, Michal Privoznik wrote:
>>>> On 30.01.2016 19:59, Wido den Hollander wrote:
>>>>> Hi,
>>>>> I'm trying to implement the volUpload and volDownload functions for the
>>>>> RBD storage driver but I keep getting this:
>>>>> 2016-01-30 18:56:11.675+0000: 6447: debug :
>>>>> virStorageBackendRBDVolDownload:1395 : Read 4096 bytes at offset 0 from
>>>>> RBD image libvirt/wido1
>>>>> 2016-01-30 18:56:11.675+0000: 6447: debug : virStreamSend:168 :
>>>>> stream=0x7fe780000930, data=0x7fe780062df0, nbytes=4096
>>>>> 2016-01-30 18:56:11.675+0000: 6447: error : virStreamSend:186 : this
>>>>> function is not supported by the connection driver: virStreamSend
>>>>> I reference to the stream with virStreamRef(stream); and then I use
>>>>> virStreamSend() to write data to the stream, but that fails.
>>>>> I've looked through the source and couldn't find anything what might be
>>>>> the issue.
>>>>> Libvirt is running locally on my system and I'm using qemu:///system to
>>>>> connect locally with virsh.
>>>>> Do I need to initialize the stream in any way before I can write data to
>>>>> it?
>>>> Interesting, seems like all virStream drivers have implemented Send()
>>>> and Recv() (what's the point in having them if they haven't, right?).
>>>> How are you creating the stream? You know that you need to create the
>>>> stream on both client and server side, right?
>>> It's in the storage backend driver, so I assume the stream has already
>>> been created.
>>> This is the code:
>>> https://github.com/wido/libvirt/commit/bbb6403ebd952d7c3f2fba8c60f77087e06a2a22
>> Oh, slightly unrelated: you should move @buf allocation out of while() -
>> you need to allocate it only once, not each time per iteration.
> Thanks, I'll take a look at that as well.
>>> static int
>>> virStorageBackendRBDVolDownload(virConnectPtr conn,
>>>                                 virStoragePoolObjPtr pool,
>>>                                 virStorageVolDefPtr vol,
>>>                                 virStreamPtr stream,
>>>                                 unsigned long long offset,
>>>                                 unsigned long long length,
>>>                                 unsigned int flags)
>>> ..
>>> ..
>>> virStreamRef(stream);
>>> ..
>>> ..
>>> while (1) {
>>>   rbd_read()
>>>   virStreamSend(X, stream)
>>> }

I suggest looking at virStorageBackendVolDownloadLocal which is what
other storage backends (fs, disk, iscsi, logical, mpath, scsi, and zfs)
use in order to set things up.

In fact trying to follow what happens from virsh-volume.c processing
(cmdVolDownload) through to the virStorageBackendVolDownloadLocal.
Although, after my quick read, I don't think you're going to like what
you find.

The way I've read it, the code uses virFDStreamOpenBlockDevice to
associate the stream with the vol->target.path.  Eventually, the calls
reach virFDStreamOpenFileInternal and virFDStreamOpenInternal (although
it seems to be a special case for virFDStreamOpen).

Then once the stream is associated, the virStreamRecvAll uses
virshStreamSink in order to 'safewrite' what it 'read()'s from the
virFDStreamRead code.

Of course your read is done via 'rbd_read' and I'll make the assumption
for the Upload function you'd need some sort of rbd_write.

IOW: The "default" stream code assumes usage of an FDStream for local
file processing. The rbd code doesn't fit that model, thus you need one
for an rbd connection. If you use cscope, search on 'streamSend' or
'streamRecv' - you see the default and one for esx (commit id
'125007d37') added more recently.

Note that the docs for virStorageVolDownload states:

 * Download the content of the volume as a stream. If @length
 * is zero, then the remaining contents of the volume after
 * @offset will be downloaded.
 * This call sets up an asynchronous stream; subsequent use of
 * stream APIs is necessary to transfer the actual data,
 * determine how much data is successfully transferred, and
 * detect any errors. The results will be unpredictable if
 * another active stream is writing to the storage volume.


>>> And that gives me the error I posted above.
>>> I checked the docs: https://libvirt.org/html/libvirt-libvirt-stream.html
>>> Couldn't find anything additional about what I needed to do. I assume
>>> the storage driver creates the stream for me.
>> Actually, it's daemon dispatch function that creates it in
>> remoteDispatchStorageVolDownload(). Now the question is, what connection
>> URI you're using and whether it is a remote one (so that the daemon is
>> involved). If not, you need to create the stream on your own. On the
>> other hand - I don't know how are you testing this - virsh does create
>> the stream for you.
> Simple, it's my local system running libvirtd:
> $ env LIBVIRT_DEBUG=1 ./run ./daemon/libvirtd -f libvirtd.conf -v > libvirt.log
> 2>&1
> Afterwards I run:
> $ ./tools/virsh pool-start rbdpool
> $ ./tools/virsh vol-download libvirt/myvolume /tmp/myvolume
> In that case the stream should have been created by virsh, right?
>> What you can do is to set breakpoint at virStreamSend and see what does
>> @st look like. st->driver should point to actual driver implementation
>> and you should see it filled with callbacks.
> Good point, I'll look at that as well.
>> I have no RBD set up to help you more.  Sorry.
> Np. This doesn't seem RBD related, but mainly virStream.
> Wido
>> Michal
> --
> libvir-list mailing list
> libvir-list at redhat.com
> https://www.redhat.com/mailman/listinfo/libvir-list

More information about the libvir-list mailing list