diff options
author | David Nieto <dmartineznie@nvidia.com> | 2017-02-13 14:22:59 -0500 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2017-03-20 19:39:55 -0400 |
commit | 74fe1caa2b56aab24c17ad4dd2524128fc237894 (patch) | |
tree | 0793bb92b67d64690658f3f7cd1a8e1ea93206ba /drivers/gpu/nvgpu/gk20a/gk20a.c | |
parent | 469308becaff326da02fcf791e803e812e1cf9f8 (diff) |
gpu: nvgpu: Add refcounting to driver fds
The main driver structure is not refcounted properly,
so when the driver unload, file desciptors associated to the
driver are kept open with dangling references to the main object.
This change adds referencing to the gk20a structure.
bug 200277762
JIRA: EVLR-1023
Change-Id: Id892e9e1677a344789e99bf649088c076f0bf8de
Signed-off-by: David Nieto <dmartineznie@nvidia.com>
Reviewed-on: http://git-master/r/1317420
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/gk20a.c')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a.c | 64 |
1 files changed, 63 insertions, 1 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.c b/drivers/gpu/nvgpu/gk20a/gk20a.c index 30c0f2fb..1d6fb0e9 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/gk20a.c | |||
@@ -1712,7 +1712,7 @@ static int __exit gk20a_remove(struct platform_device *pdev) | |||
1712 | platform->remove(dev); | 1712 | platform->remove(dev); |
1713 | 1713 | ||
1714 | set_gk20a(pdev, NULL); | 1714 | set_gk20a(pdev, NULL); |
1715 | kfree(g); | 1715 | gk20a_put(g); |
1716 | 1716 | ||
1717 | gk20a_dbg_fn("removed"); | 1717 | gk20a_dbg_fn("removed"); |
1718 | 1718 | ||
@@ -2274,6 +2274,68 @@ int gk20a_read_ptimer(struct gk20a *g, u64 *value) | |||
2274 | return -EBUSY; | 2274 | return -EBUSY; |
2275 | } | 2275 | } |
2276 | 2276 | ||
2277 | /* | ||
2278 | * Free the gk20a struct. | ||
2279 | */ | ||
2280 | static void gk20a_free_cb(struct kref *refcount) | ||
2281 | { | ||
2282 | struct gk20a *g = container_of(refcount, | ||
2283 | struct gk20a, refcount); | ||
2284 | |||
2285 | gk20a_dbg(gpu_dbg_shutdown, "Freeing GK20A struct!"); | ||
2286 | kfree(g); | ||
2287 | } | ||
2288 | |||
2289 | /** | ||
2290 | * gk20a_get() - Increment ref count on driver | ||
2291 | * | ||
2292 | * @g The driver to increment | ||
2293 | * This will fail if the driver is in the process of being released. In that | ||
2294 | * case it will return NULL. Otherwise a pointer to the driver passed in will | ||
2295 | * be returned. | ||
2296 | */ | ||
2297 | struct gk20a * __must_check gk20a_get(struct gk20a *g) | ||
2298 | { | ||
2299 | int success; | ||
2300 | |||
2301 | /* | ||
2302 | * Handle the possibility we are still freeing the gk20a struct while | ||
2303 | * gk20a_get() is called. Unlikely but plausible race condition. Ideally | ||
2304 | * the code will never be in such a situation that this race is | ||
2305 | * possible. | ||
2306 | */ | ||
2307 | success = kref_get_unless_zero(&g->refcount); | ||
2308 | |||
2309 | gk20a_dbg(gpu_dbg_shutdown, "GET: refs currently %d %s", | ||
2310 | atomic_read(&g->refcount.refcount), success ? "" : "(FAILED)"); | ||
2311 | |||
2312 | return success ? g : NULL; | ||
2313 | } | ||
2314 | |||
2315 | /** | ||
2316 | * gk20a_put() - Decrement ref count on driver | ||
2317 | * | ||
2318 | * @g - The driver to decrement | ||
2319 | * | ||
2320 | * Decrement the driver ref-count. If neccesary also free the underlying driver | ||
2321 | * memory | ||
2322 | */ | ||
2323 | void gk20a_put(struct gk20a *g) | ||
2324 | { | ||
2325 | /* | ||
2326 | * Note - this is racy, two instances of this could run before the | ||
2327 | * actual kref_put(0 runs, you could see something like: | ||
2328 | * | ||
2329 | * ... PUT: refs currently 2 | ||
2330 | * ... PUT: refs currently 2 | ||
2331 | * ... Freeing GK20A struct! | ||
2332 | */ | ||
2333 | gk20a_dbg(gpu_dbg_shutdown, "PUT: refs currently %d", | ||
2334 | atomic_read(&g->refcount.refcount)); | ||
2335 | |||
2336 | kref_put(&g->refcount, gk20a_free_cb); | ||
2337 | } | ||
2338 | |||
2277 | MODULE_LICENSE("GPL v2"); | 2339 | MODULE_LICENSE("GPL v2"); |
2278 | module_init(gk20a_init); | 2340 | module_init(gk20a_init); |
2279 | module_exit(gk20a_exit); | 2341 | module_exit(gk20a_exit); |