On Thu, Mar 21, 2013 at 4:39 PM, Richard W.M. Jones <rjo...@redhat.com> wrote: > On Thu, Mar 21, 2013 at 04:26:23PM +0100, Stefan Hajnoczi wrote: >> On Thu, Mar 21, 2013 at 01:38:58PM +0000, Richard W.M. Jones wrote: >> > From: "Richard W.M. Jones" <rjo...@redhat.com> >> > >> > qemu-system-x86_64 -drive file=ssh://hostname/some/image >> > >> > QEMU will ssh into 'hostname' and open '/some/image' which is made >> > available as a standard block device. >> > >> > You can specify a username (ssh://user@host/...) and/or a port number >> > (ssh://host:port/...). >> >> I can see this being handy for qemu-img since it gives you the ability >> to work with remote image files. >> >> > Current limitations: >> > >> > - Authentication must be done without passwords or passphrases, using >> > ssh-agent. Other authentication methods are not supported. (*) >> > >> > - Does not check host key. (*) >> > >> > - New remote files cannot be created. (*) >> >> Would be important to fix these limitations. Authentication methods to >> make this more usable. Host key check for security. File creation for >> qemu-img. > > I agree. > >> > - Uses coroutine read/write, instead of true AIO. (libssh2 supports >> > non-blocking access, so this could be fixed with some effort). >> >> This patch does not really use coroutines - the SSH I/O is blocking! >> >> Coroutines must submit the SSH I/O and then yield so the QEMU event loop >> can get on with other work. When SSH I/O finishes the request's >> coroutine is re-entered and the request gets completed. > > Hmm OK. Is there any documentation at all on how coroutines are > supposed to work? Or AIO for that matter? For example, do coroutines > really replace all the read/write syscalls deep inside a library > (libssh2) so that these calls context switch, or am I missing the > point of how this works entirely?
Before we go into coroutines, take a look at AIO since it may fit libssh2's non-blocking mode of operation better. Doing AIO means implementing .bdrv_aio_readv()/.bdrv_aio_writev(). These functions cannot block so you need to use non-blocking libssh2 interfaces and let QEMU's event loop notify us of readability/writability (see qemu_aio_set_fd_handler()). Look at block/iscsi.c:iscsi_aio_readv() for an example of how to interface with an asynchronous library. Back to coroutines. Coroutines are just a primitive, like threads, that your code can use. They aren't a framework for how to do block I/O. If you want an example, take a look at block/sheepdog.c: static coroutine_fn void do_co_req(void *opaque) { int ret; Coroutine *co; [...] co = qemu_coroutine_self(); qemu_aio_set_fd_handler(sockfd, NULL, restart_co_req, have_co_req, co); ret = send_co_req(sockfd, hdr, data, wlen); Using qemu_aio_set_fd_handler() we tell the event loop to call restart_co_req() when the file descriptor becomes writable. Then we call send_co_req() which yields if send(2) returns EAGAIN. This is an example of setting up an event handler, invoking a non-blocking syscall, and yielding on EAGAIN. Here is what restart_co_req() looks like: static void restart_co_req(void *opaque) { Coroutine *co = opaque; qemu_coroutine_enter(co, NULL); } If you want to make the code clean and reusable it's best to put the event handler, non-blocking I/O, and yield/re-enter into a function that can be reused. That way each callers don't duplicate this low-level code. Hope this gives you an idea of how to use coroutines for block drivers. >> > This is implemented using libssh2 on the client side. The server just >> > requires a regular ssh daemon with sftp-server support. Most ssh >> > daemons on Unix/Linux systems will work out of the box. >> >> How much of a win over sshfs is this? >> >> sshfs can be mounted by unprivileged users and QEMU accesses it like a >> regular file. So the sshfs approach already works today. > > Sure, but compared to having to install and set up sshfs and FUSE, > using this is a lot simpler. It's also potentially faster since it > cuts out FUSE and context switching to the sshfs process. > > BTW I looked into the implementation of sshfs before starting this, > and what it does is to run an 'ssh' client subprocess, then implements > the sftp protocol by hand on top. So using libssh2 cuts out *two* > external processes (plus FUSE). I see. Benchmarks would be interesting once AIO or coroutines is implemented. Stefan