On Wed, Feb 19, 2020 at 03:22:49PM +0100, Daniel Vetter wrote:
On Wed, Feb 19, 2020 at 2:33 PM Greg Kroah-Hartman gregkh@linuxfoundation.org wrote:
On Wed, Feb 19, 2020 at 03:28:47PM +0200, Laurent Pinchart wrote:
Hi Daniel,
Thank you for the patch.
On Wed, Feb 19, 2020 at 11:20:33AM +0100, Daniel Vetter wrote:
We have lots of these. And the cleanup code tends to be of dubious quality. The biggest wrong pattern is that developers use devm_, which ties the release action to the underlying struct device, whereas all the userspace visible stuff attached to a drm_device can long outlive that one (e.g. after a hotunplug while userspace has open files and mmap'ed buffers). Give people what they want, but with more correctness.
Mostly copied from devres.c, with types adjusted to fit drm_device and a few simplifications - I didn't (yet) copy over everything. Since the types don't match code sharing looked like a hopeless endeavour.
For now it's only super simplified, no groups, you can't remove actions (but kfree exists, we'll need that soon). Plus all specific to drm_device ofc, including the logging. Which I didn't bother to make compile-time optional, since none of the other drm logging is compile time optional either.
One tricky bit here is the chicken&egg between allocating your drm_device structure and initiliazing it with drm_dev_init. For perfect onion unwinding we'd need to have the action to kfree the allocation registered before drm_dev_init registers any of its own release handlers. But drm_dev_init doesn't know where exactly the drm_device is emebedded into the overall structure, and by the time it returns it'll all be too late. And forcing drivers to be able clean up everything except the one kzalloc is silly.
Work around this by having a very special final_kfree pointer. This also avoids troubles with the list head possibly disappearing from underneath us when we release all resources attached to the drm_device.
This is all a very good idea ! Many subsystems are plagged by drivers using devm_k*alloc to allocate data accessible by userspace. Since the introduction of devm_*, we've likely reduced the number of memory leaks, but I'm pretty sure we've increased the risk of crashes as I've seen some drivers that used .release() callbacks correctly being naively converted to incorrect devm_* usage :-(
This leads me to a question: if other subsystems have the same problem, could we turn this implementation into something more generic ? It doesn't have to be done right away and shouldn't block merging this series, but I think it would be very useful.
It shouldn't be that hard to tie this into a drv_m() type of a thing (driver_memory?)
And yes, I think it's much better than devm_* for the obvious reasons of this being needed here.
There's two reasons I went with copypasta instead of trying to share code:
- Type checking, I definitely don't want people to mix up devm_ with
drmm_. But even if we do a drv_m that subsystems could embed we do have quite a few different types of component drivers (and with drm_panel and drm_bridge even standardized), and I don't want people to be able to pass the wrong kind of struct to e.g. a managed drmm_connector_init - it really needs to be the drm_device, not a panel or bridge or something else.
Fair enough, that makes sense.
- We could still share the code as a kind of implementation/backend
library. But it's not much, and with embedding I could use the drm device logging stuff which is kinda nice. But if there's more demand for this I can definitely see the point in sharing this, as Laurent pointed out with the tiny optimization with not allocating a NULL void
- that I've done (and screwed up) it's not entirely trivial code.
I think moving over time to having this be a backend library is good. But no rush/issues here with this going in now, it solves a real need and we can refactor it later on to try to make it more "bus/class" generic as needed.
thanks,
greg k-h