Hello Boris,
welcome to the mailing list and thank you for the elaborate description of your scenario and approach.
As a side note, the discussion reminds me of a very similar problem we addressed some years ago:
http://genode.org/documentation/release-notes/12.02#Device_drivers
Unfortunately, we removed the described d3m component later on because it turned out to be not as flexible as we hoped for. However, on the positive side, scenarios like your's are not completely alien to Genode. ;-)
This is exactly what we're trying to do now. We want to create a custom component called "media" that monitors usb devices by reading the report. It provides a service to other components through which they can request a filesystem session in order to read-write from/to the usb-stick. For this, it spawns the part_blk and rump_fs components as children if the usb is plugged in, and kills them once the usb is plugged out. It roughly looks like this:
rump_fs part_blk
| |
CLI media USB_drv
| | |
init
This looks very good to me.
But this raises a few questions. First, the filesystem interface needs to be presented to the client somehow. To avoid adding another layer of indirection into media, essentially duplicating rump_fs's entire API, we would like the client (in this case CLI) to be directly connected to rump_fs. The client can then ask media if the USB is connected before calling a function from rump_fs.
You are right that wrapping the 'File_system' interface would be cumbersome. In your case, it is better to let CLI use the rump_fs-provided session directly. This can be achieved by letting the media component pass the session capability as obtained from rump_fs to its parent (init). So CLI would use the rump_fs session directly.
However, this means that rump_fs provides a service, announces it to its parent (media), and media has to decide what to do with that announce. It can implement rump_fs as a slave, but that way the entire API needs to be copied into media so media can present it as its own service to the client.
You are already on the right track. Running rump_fs as a slave is good. You just missed a tiny piece of the puzzle: The 'Slave::Connection' does not only provide the session interface of the slave's service but also the corresponding 'Session_capability' (it inherits 'CONNECTION::Client', so the 'Slave::Connection' _is_ a session capability). Instead of calling the 'File_system' methods, the media component would pass this 'Session_capability' to init as response to the 'File_system' session request that originated from init.
Services can only be provided to direct parents, and to other components in the parent's subtree. Therefore, copying the API from the child to the parent seems unavoidable.
There is no such limitation. But you are right that the use case has been so rare that it is near to impossible to find examples in Genode's source tree. The above mentioned d3m was such an example. Other examples are the GDB monitor (however, here we temporarily removed the feature to run Genode services within GDB monitor).
Another problem that pops up is that media has to spawn all these subcomponents as children. In order to route block session requests from rump-fs to part-blk, media needs to implement some routing policy and effectively serves the same role for these two components as init serves for the system. So we could:
- Copy all necessary code for routing from init to media (which is
almost all code if we want to be generic).
- Let media spawn another init child component (let's call it sub-init
for now) which in turn spawns rump-fs and part-blk and does the routing.
To us, the second option seems much more clean as it involves no code-copying. However, services announced by rump-fs can not be used by other components that are not children of the new init, and are kind of useless. Their announcements can not be passed on to the parents, leaving us with the same problem as we had with rump_fs but with the additional problem that even if there would be a custom way to forward service announces and requests to the parent/child respectively, sub-init has no such policy, and this functionality has to be included in sub-init's code as well, adding a lot of complexity.
I agree with everything you said. Until Genode 16.11 is was not reasonable for init to forward session requests to its children because of the synchronous nature of the parent interface. Now that we revised this interface to work asynchronously [1], we can move forward and add this feature to init. Indeed, I plan to add it along with the dynamic reconfiguability of init in the near-term future (as outlined in my original road-map posting [2]). With the new version of init, scenarios like your's will become pretty straight-forward to realize.
[1] http://genode.org/documentation/release-notes/16.11#Asynchronous_parent-chil... [2] https://sourceforge.net/p/genode/mailman/genode-main/thread/585A6FE2.1060800...
And how should we solve cases such as the above scenario?
In the not-too-distant future, your case should be well covered by init, alleviating the need to implement a custom runtime component. In the meantime, I recommend you to follow the slave approach described above (forwarding the session capability of the 'Slave::Connection' to init).
I would be very interested to hear how this turns out. Should my above description remain too vague or leave your questions unanswered, please don't hesitate to get back to me.
Cheers Norman