Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'dax-fixes-5.13-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm

Pull dax fixes from Dan Williams:
"A fix for a hang condition due to missed wakeups in the filesystem-dax
core when exercised by virtiofs.

This bug has been there from the beginning, but the condition has
not triggered on other filesystems since they hold a lock over
invalidation events"

* tag 'dax-fixes-5.13-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm:
dax: Wake up all waiters after invalidating dax entry
dax: Add a wakeup mode parameter to put_unlocked_entry()
dax: Add an enum for specifying dax wakup mode

+23 -12
+23 -12
fs/dax.c
··· 144 144 struct exceptional_entry_key key; 145 145 }; 146 146 147 + /** 148 + * enum dax_wake_mode: waitqueue wakeup behaviour 149 + * @WAKE_ALL: wake all waiters in the waitqueue 150 + * @WAKE_NEXT: wake only the first waiter in the waitqueue 151 + */ 152 + enum dax_wake_mode { 153 + WAKE_ALL, 154 + WAKE_NEXT, 155 + }; 156 + 147 157 static wait_queue_head_t *dax_entry_waitqueue(struct xa_state *xas, 148 158 void *entry, struct exceptional_entry_key *key) 149 159 { ··· 192 182 * The important information it's conveying is whether the entry at 193 183 * this index used to be a PMD entry. 194 184 */ 195 - static void dax_wake_entry(struct xa_state *xas, void *entry, bool wake_all) 185 + static void dax_wake_entry(struct xa_state *xas, void *entry, 186 + enum dax_wake_mode mode) 196 187 { 197 188 struct exceptional_entry_key key; 198 189 wait_queue_head_t *wq; ··· 207 196 * must be in the waitqueue and the following check will see them. 208 197 */ 209 198 if (waitqueue_active(wq)) 210 - __wake_up(wq, TASK_NORMAL, wake_all ? 0 : 1, &key); 199 + __wake_up(wq, TASK_NORMAL, mode == WAKE_ALL ? 0 : 1, &key); 211 200 } 212 201 213 202 /* ··· 275 264 finish_wait(wq, &ewait.wait); 276 265 } 277 266 278 - static void put_unlocked_entry(struct xa_state *xas, void *entry) 267 + static void put_unlocked_entry(struct xa_state *xas, void *entry, 268 + enum dax_wake_mode mode) 279 269 { 280 - /* If we were the only waiter woken, wake the next one */ 281 270 if (entry && !dax_is_conflict(entry)) 282 - dax_wake_entry(xas, entry, false); 271 + dax_wake_entry(xas, entry, mode); 283 272 } 284 273 285 274 /* ··· 297 286 old = xas_store(xas, entry); 298 287 xas_unlock_irq(xas); 299 288 BUG_ON(!dax_is_locked(old)); 300 - dax_wake_entry(xas, entry, false); 289 + dax_wake_entry(xas, entry, WAKE_NEXT); 301 290 } 302 291 303 292 /* ··· 535 524 536 525 dax_disassociate_entry(entry, mapping, false); 537 526 xas_store(xas, NULL); /* undo the PMD join */ 538 - dax_wake_entry(xas, entry, true); 527 + dax_wake_entry(xas, entry, WAKE_ALL); 539 528 mapping->nrpages -= PG_PMD_NR; 540 529 entry = NULL; 541 530 xas_set(xas, index); ··· 633 622 entry = get_unlocked_entry(&xas, 0); 634 623 if (entry) 635 624 page = dax_busy_page(entry); 636 - put_unlocked_entry(&xas, entry); 625 + put_unlocked_entry(&xas, entry, WAKE_NEXT); 637 626 if (page) 638 627 break; 639 628 if (++scanned % XA_CHECK_SCHED) ··· 675 664 mapping->nrpages -= 1UL << dax_entry_order(entry); 676 665 ret = 1; 677 666 out: 678 - put_unlocked_entry(&xas, entry); 667 + put_unlocked_entry(&xas, entry, WAKE_ALL); 679 668 xas_unlock_irq(&xas); 680 669 return ret; 681 670 } ··· 948 937 xas_lock_irq(xas); 949 938 xas_store(xas, entry); 950 939 xas_clear_mark(xas, PAGECACHE_TAG_DIRTY); 951 - dax_wake_entry(xas, entry, false); 940 + dax_wake_entry(xas, entry, WAKE_NEXT); 952 941 953 942 trace_dax_writeback_one(mapping->host, index, count); 954 943 return ret; 955 944 956 945 put_unlocked: 957 - put_unlocked_entry(xas, entry); 946 + put_unlocked_entry(xas, entry, WAKE_NEXT); 958 947 return ret; 959 948 } 960 949 ··· 1695 1684 /* Did we race with someone splitting entry or so? */ 1696 1685 if (!entry || dax_is_conflict(entry) || 1697 1686 (order == 0 && !dax_is_pte_entry(entry))) { 1698 - put_unlocked_entry(&xas, entry); 1687 + put_unlocked_entry(&xas, entry, WAKE_NEXT); 1699 1688 xas_unlock_irq(&xas); 1700 1689 trace_dax_insert_pfn_mkwrite_no_entry(mapping->host, vmf, 1701 1690 VM_FAULT_NOPAGE);