 xen: speed up grant-table reclaim · gregkh/linux@c04e989 · GitHub Skip to content Navigation Menu Toggle navigation Sign in Appearance settings Platform AI CODE CREATION GitHub Copilot Write better code with AI GitHub Spark Build and deploy intelligent apps GitHub Models Manage and compare prompts MCP Registry New Integrate external tools DEVELOPER WORKFLOWS Actions Automate any workflow Codespaces Instant dev environments Issues Plan and track work Code Review Manage code changes APPLICATION SECURITY GitHub Advanced Security Find and fix vulnerabilities Code security Secure your code as you build Secret protection  EXPLORE Why GitHub Documentation Blog Changelog Marketplace View all features Solutions BY COMPANY SIZE Enterprises Small and medium teams Startups Nonprofits BY USE CASE App Modernization DevSecOps DevOps CI/CD View all use cases BY INDUSTRY Healthcare Financial services Manufacturing Government View all industries View all solutions Resources EXPLORE BY TOPIC AI Software Development DevOps Security View all topics EXPLORE BY TYPE Customer stories Events &amp; webinars Ebooks &amp; reports Business insights GitHub Skills SUPPORT &amp; SERVICES Documentation Customer support Community forum Trust center Partners View all resources Open Source COMMUNITY GitHub Sponsors Fund open source developers PROGRAMS Security Lab Maintainer Community Accelerator GitHub Stars Archive Program REPOSITORIES Topics Trending Collections Enterprise ENTERPRISE SOLUTIONS Enterprise platform AI-powered developer platform AVAILABLE ADD-ONS GitHub Advanced Security Enterprise-grade security features Copilot for Business Enterprise-grade AI features Premium Support Enterprise-grade 24/7 support Pricing Search or jump to... Search code, repositories, users, issues, pull requests... --> Search Clear Search syntax tips Provide feedback --> We read every piece of feedback, and take your input very seriously.  Cancel Submit feedback Saved searches Use saved searches to filter your results more quickly --> Name Query To see all available qualifiers, see our documentation . Cancel Create saved search Sign in Sign up Appearance settings Resetting focus You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session. Dismiss alert {{ message }} gregkh / linux Public Notifications You must be signed in to change notification settings Fork 676 Star 636 Code Actions Security and quality 0 Insights Additional navigation options Code Actions Security and quality Insights Commit c04e989 Browse files Browse files DemiMarie authored and jgross1 committed xen: speed up grant-table reclaim When a grant entry is still in use by the remote domain, Linux must put it on a deferred list. Normally, this list is very short, because the PV network and block protocols expect the backend to unmap the grant first. However, Qubes OS's GUI protocol is subject to the constraints of the X Window System, and as such winds up with the frontend unmapping the window first. As a result, the list can grow very large, resulting in a massive memory leak and eventual VM freeze. To partially solve this problem, make the number of entries that the VM will attempt to free at each iteration tunable. The default is still 10, but it can be overridden via a module parameter. This is Cc: stable because (when combined with appropriate userspace changes) it fixes a severe performance and stability problem for Qubes OS users. Cc: stable@vger.kernel.org Signed-off-by: Demi Marie Obenour &lt;demi@invisiblethingslab.com&gt; Reviewed-by: Juergen Gross &lt;jgross@suse.com&gt; Link: https://lore.kernel.org/r/20230726165354.1252-1-demi@invisiblethingslab.com Signed-off-by: Juergen Gross &lt;jgross@suse.com&gt; 1 parent 58f6259 commit c04e989 Copy full SHA for c04e989 2 file s changed + 40 - 11 Lines changed: 40 additions &amp; 11 deletions File tree Expand file tree Collapse file tree Open diff view settings Filter options Documentation/ABI/testing sysfs-module drivers/xen grant-table.c Expand file tree Collapse file tree Open diff view settings Collapse file ‎ Documentation/ABI/testing/sysfs-module ‎ Copy file name to clipboard Expand all lines: Documentation/ABI/testing/sysfs-module + 11 Lines changed: 11 additions &amp; 0 deletions Original file line number Diff line number Diff line change @@ -60,3 +60,14 @@ Description: Module taint flags: 60 60 C staging driver module 61 61 E unsigned module 62 62 == ===================== 63 + 64 + What: /sys/module/grant_table/parameters/free_per_iteration 65 + Date: July 2023 66 + KernelVersion: 6.5 but backported to all supported stable branches 67 + Contact: Xen developer discussion &lt;xen-devel@lists.xenproject.org&gt; 68 + Description: Read and write number of grant entries to attempt to free per iteration. 69 + 70 + Note: Future versions of Xen and Linux may provide a better 71 + interface for controlling the rate of deferred grant reclaim 72 + or may not need it at all. 73 + Users: Qubes OS (https://www.qubes-os.org) Collapse file ‎ drivers/xen/grant-table.c ‎ Copy file name to clipboard Expand all lines: drivers/xen/grant-table.c + 29 - 11 Lines changed: 29 additions &amp; 11 deletions Original file line number Diff line number Diff line change @@ -498,14 +498,21 @@ static LIST_HEAD(deferred_list); 498 498 static void gnttab_handle_deferred ( struct timer_list * ); 499 499 static DEFINE_TIMER ( deferred_timer , gnttab_handle_deferred ) ; 500 500 501 + static atomic64_t deferred_count ; 502 + static atomic64_t leaked_count ; 503 + static unsigned int free_per_iteration = 10 ; 504 + module_param ( free_per_iteration , uint , 0600 ); 505 + 501 506 static void gnttab_handle_deferred ( struct timer_list * unused ) 502 507 { 503 - unsigned int nr = 10 ; 508 + unsigned int nr = READ_ONCE ( free_per_iteration ); 509 + const bool ignore_limit = nr == 0 ; 504 510 struct deferred_entry * first = NULL ; 505 511 unsigned long flags ; 512 + size_t freed = 0 ; 506 513 507 514 spin_lock_irqsave ( &amp; gnttab_list_lock , flags ); 508 - while ( nr -- ) { 515 + while ( ( ignore_limit || nr -- ) &amp;&amp; ! list_empty ( &amp; deferred_list ) ) { 509 516 struct deferred_entry * entry 510 517 = list_first_entry ( &amp; deferred_list , 511 518 struct deferred_entry , list ); @@ -515,10 +522,14 @@ static void gnttab_handle_deferred(struct timer_list *unused) 515 522 list_del ( &amp; entry -&gt; list ); 516 523 spin_unlock_irqrestore ( &amp; gnttab_list_lock , flags ); 517 524 if ( _gnttab_end_foreign_access_ref ( entry -&gt; ref )) { 525 + uint64_t ret = atomic64_dec_return ( &amp; deferred_count ); 526 + 518 527 put_free_entry ( entry -&gt; ref ); 519 - pr_debug ( &quot;freeing g.e. %#x (pfn %#lx)\n&quot; , 520 - entry -&gt; ref , page_to_pfn ( entry -&gt; page )); 528 + pr_debug ( &quot;freeing g.e. %#x (pfn %#lx), %llu remaining\n&quot; , 529 + entry -&gt; ref , page_to_pfn ( entry -&gt; page ), 530 + ( unsigned long long ) ret ); 521 531 put_page ( entry -&gt; page ); 532 + freed ++ ; 522 533 kfree ( entry ); 523 534 entry = NULL ; 524 535 } else { @@ -530,21 +541,22 @@ static void gnttab_handle_deferred(struct timer_list *unused) 530 541 spin_lock_irqsave ( &amp; gnttab_list_lock , flags ); 531 542 if ( entry ) 532 543 list_add_tail ( &amp; entry -&gt; list , &amp; deferred_list ); 533 - else if ( list_empty ( &amp; deferred_list )) 534 - break ; 535 544 } 536 - if (! list_empty ( &amp; deferred_list ) &amp;&amp; ! timer_pending ( &amp; deferred_timer )) { 545 + if ( list_empty ( &amp; deferred_list )) 546 + WARN_ON ( atomic64_read ( &amp; deferred_count )); 547 + else if (! timer_pending ( &amp; deferred_timer )) { 537 548 deferred_timer . expires = jiffies + HZ ; 538 549 add_timer ( &amp; deferred_timer ); 539 550 } 540 551 spin_unlock_irqrestore ( &amp; gnttab_list_lock , flags ); 552 + pr_debug ( &quot;Freed %zu references&quot; , freed ); 541 553 } 542 554 543 555 static void gnttab_add_deferred ( grant_ref_t ref , struct page * page ) 544 556 { 545 557 struct deferred_entry * entry ; 546 558 gfp_t gfp = ( in_atomic () || irqs_disabled ()) ? GFP_ATOMIC : GFP_KERNEL ; 547 - const char * what = KERN_WARNING "leaking" ; 559 + uint64_t leaked , deferred ; 548 560 549 561 entry = kmalloc ( sizeof ( * entry ), gfp ); 550 562 if (! page ) { @@ -567,10 +579,16 @@ static void gnttab_add_deferred(grant_ref_t ref, struct page *page) 567 579 add_timer ( &amp; deferred_timer ); 568 580 } 569 581 spin_unlock_irqrestore ( &amp; gnttab_list_lock , flags ); 570 - what = KERN_DEBUG &quot;deferring&quot; ; 582 + deferred = atomic64_inc_return ( &amp; deferred_count ); 583 + leaked = atomic64_read ( &amp; leaked_count ); 584 + pr_debug ( &quot;deferring g.e. %#x (pfn %#lx) (total deferred %llu, total leaked %llu)\n&quot; , 585 + ref , page ? page_to_pfn ( page ) : -1 , deferred , leaked ); 586 + } else { 587 + deferred = atomic64_read ( &amp; deferred_count ); 588 + leaked = atomic64_inc_return ( &amp; leaked_count ); 589 + pr_warn ( &quot;leaking g.e. %#x (pfn %#lx) (total deferred %llu, total leaked %llu)\n&quot; , 590 + ref , page ? page_to_pfn ( page ) : -1 , deferred , leaked ); 571 591 } 572 - printk ( &quot;%s g.e. %#x (pfn %#lx)\n&quot; , 573 - what , ref , page ? page_to_pfn ( page ) : -1 ); 574 592 } 575 593 576 594 int gnttab_try_end_foreign_access ( grant_ref_t ref ) 0 commit comments Comments 0 ( 0 ) Footer &copy; 2026 GitHub,&nbsp;Inc. Footer navigation Terms Privacy Security Status Community Docs Contact Manage cookies Do not share my personal information You can’t perform that action at this time. 