vmw_gmrid_man_get_node reports MOB limit expansion and allocation
failures through vmw_host_printf while holding gman->lock. The helper
formats its messages with GFP_KERNEL allocations, which may sleep.
KDE startup and desktop mode changes can reach this path, producing
"BUG: sleeping function called from invalid context" from kvasprintf()
while the manager spinlock is held. That's likely a separate bug
because KDE shouldn't be using that much memory but to debug
that properly stop filling kernel logs with warnings.
Defer both host messages until after dropping the spinlock. Capture the
failed allocation's page limit and roll back its accounting while locked,
then report the error and free the resource after unlocking. Use
drm_warn for the guest messages so they identify the device.
Fixes: cfdc3458db8a ("drm/vmwgfx: Be a lot more flexible with MOB limits")
Cc: [email protected]
Assisted-by: LLM
Signed-off-by: Zack Rusin <[email protected]>
---
drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c | 55 ++++++++++++-------
1 file changed, 34 insertions(+), 21 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
index d607452dff6a..cc580ce57797 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
@@ -54,8 +54,11 @@ static int vmw_gmrid_man_get_node(struct
ttm_resource_manager *man,
const struct ttm_place *place,
struct ttm_resource **res)
{
+ struct vmw_private *vmw = vmw_priv_from_ttm(bo->bdev);
struct vmwgfx_gmrid_man *gman = to_gmrid_manager(man);
- int id;
+ u32 max_gmr_pages = 0;
+ bool mob_overflow = false;
+ int id, ret = 0;
*res = kmalloc_obj(**res);
if (!*res)
@@ -85,43 +88,53 @@ static int vmw_gmrid_man_get_node(struct
ttm_resource_manager *man,
const unsigned long max_graphics_pages =
totalram_pages() / 2;
uint32_t new_max_pages = 0;
- DRM_WARN("vmwgfx: mob memory overflow. Consider
increasing guest RAM and graphicsMemory.\n");
- vmw_host_printf("vmwgfx, warning: mob memory overflow.
Consider increasing guest RAM and graphicsMemory.\n");
+ mob_overflow = true;
+ drm_warn(&vmw->drm,
+ "vmwgfx: mob memory overflow. Consider
increasing guest RAM and graphicsMemory.\n");
if (gman->max_gmr_pages > (max_graphics_pages / 2)) {
- DRM_WARN("vmwgfx: guest requires more than half
of RAM for graphics.\n");
+ drm_warn(&vmw->drm,
+ "vmwgfx: guest requires more than half
of RAM for graphics.\n");
new_max_pages = max_graphics_pages;
} else
new_max_pages = gman->max_gmr_pages * 2;
if (new_max_pages > gman->max_gmr_pages &&
new_max_pages >= gman->used_gmr_pages) {
- DRM_WARN("vmwgfx: increasing guest mob limits
to %u KiB.\n",
- ((new_max_pages) << (PAGE_SHIFT -
10)));
+ drm_warn(&vmw->drm,
+ "vmwgfx: increasing guest mob limits
to %u KiB.\n",
+ new_max_pages << (PAGE_SHIFT - 10));
gman->max_gmr_pages = new_max_pages;
} else {
- char buf[256];
- snprintf(buf, sizeof(buf),
- "vmwgfx, error: guest graphics is out
of memory (mob limit at: %u KiB).\n",
- ((gman->max_gmr_pages) << (PAGE_SHIFT
- 10)));
- vmw_host_printf(buf);
- DRM_WARN("%s", buf);
- goto nospace;
+ max_gmr_pages = gman->max_gmr_pages;
+ gman->used_gmr_pages -= PFN_UP((*res)->size);
+ ret = -ENOSPC;
+ goto out_unlock;
}
}
}
(*res)->start = id;
+out_unlock:
spin_unlock(&gman->lock);
- return 0;
-nospace:
- gman->used_gmr_pages -= PFN_UP((*res)->size);
- spin_unlock(&gman->lock);
- ida_free(&gman->gmr_ida, id);
- ttm_resource_fini(man, *res);
- kfree(*res);
- return -ENOSPC;
+ /* Host logging allocates with GFP_KERNEL and must run unlocked. */
+ if (mob_overflow)
+ vmw_host_printf("%s",
+ "vmwgfx, warning: mob memory overflow. Consider
increasing guest RAM and graphicsMemory.\n");
+ if (ret) {
+ char buf[256];
+
+ snprintf(buf, sizeof(buf),
+ "vmwgfx, error: guest graphics is out of memory (mob
limit at: %u KiB).\n",
+ max_gmr_pages << (PAGE_SHIFT - 10));
+ vmw_host_printf("%s", buf);
+ drm_warn(&vmw->drm, "%s", buf);
+ ida_free(&gman->gmr_ida, id);
+ ttm_resource_fini(man, *res);
+ kfree(*res);
+ }
+ return ret;
}
static void vmw_gmrid_man_put_node(struct ttm_resource_manager *man,
--
2.53.0