diff options
Diffstat (limited to 'fs/dax.c')
-rw-r--r-- | fs/dax.c | 60 |
1 files changed, 35 insertions, 25 deletions
@@ -98,12 +98,6 @@ static void *dax_make_entry(pfn_t pfn, unsigned long flags) | |||
98 | return xa_mk_value(flags | (pfn_t_to_pfn(pfn) << DAX_SHIFT)); | 98 | return xa_mk_value(flags | (pfn_t_to_pfn(pfn) << DAX_SHIFT)); |
99 | } | 99 | } |
100 | 100 | ||
101 | static void *dax_make_page_entry(struct page *page) | ||
102 | { | ||
103 | pfn_t pfn = page_to_pfn_t(page); | ||
104 | return dax_make_entry(pfn, PageHead(page) ? DAX_PMD : 0); | ||
105 | } | ||
106 | |||
107 | static bool dax_is_locked(void *entry) | 101 | static bool dax_is_locked(void *entry) |
108 | { | 102 | { |
109 | return xa_to_value(entry) & DAX_LOCKED; | 103 | return xa_to_value(entry) & DAX_LOCKED; |
@@ -116,12 +110,12 @@ static unsigned int dax_entry_order(void *entry) | |||
116 | return 0; | 110 | return 0; |
117 | } | 111 | } |
118 | 112 | ||
119 | static int dax_is_pmd_entry(void *entry) | 113 | static unsigned long dax_is_pmd_entry(void *entry) |
120 | { | 114 | { |
121 | return xa_to_value(entry) & DAX_PMD; | 115 | return xa_to_value(entry) & DAX_PMD; |
122 | } | 116 | } |
123 | 117 | ||
124 | static int dax_is_pte_entry(void *entry) | 118 | static bool dax_is_pte_entry(void *entry) |
125 | { | 119 | { |
126 | return !(xa_to_value(entry) & DAX_PMD); | 120 | return !(xa_to_value(entry) & DAX_PMD); |
127 | } | 121 | } |
@@ -222,9 +216,8 @@ static void *get_unlocked_entry(struct xa_state *xas) | |||
222 | ewait.wait.func = wake_exceptional_entry_func; | 216 | ewait.wait.func = wake_exceptional_entry_func; |
223 | 217 | ||
224 | for (;;) { | 218 | for (;;) { |
225 | entry = xas_load(xas); | 219 | entry = xas_find_conflict(xas); |
226 | if (!entry || xa_is_internal(entry) || | 220 | if (!entry || WARN_ON_ONCE(!xa_is_value(entry)) || |
227 | WARN_ON_ONCE(!xa_is_value(entry)) || | ||
228 | !dax_is_locked(entry)) | 221 | !dax_is_locked(entry)) |
229 | return entry; | 222 | return entry; |
230 | 223 | ||
@@ -255,6 +248,7 @@ static void dax_unlock_entry(struct xa_state *xas, void *entry) | |||
255 | { | 248 | { |
256 | void *old; | 249 | void *old; |
257 | 250 | ||
251 | BUG_ON(dax_is_locked(entry)); | ||
258 | xas_reset(xas); | 252 | xas_reset(xas); |
259 | xas_lock_irq(xas); | 253 | xas_lock_irq(xas); |
260 | old = xas_store(xas, entry); | 254 | old = xas_store(xas, entry); |
@@ -352,16 +346,27 @@ static struct page *dax_busy_page(void *entry) | |||
352 | return NULL; | 346 | return NULL; |
353 | } | 347 | } |
354 | 348 | ||
349 | /* | ||
350 | * dax_lock_mapping_entry - Lock the DAX entry corresponding to a page | ||
351 | * @page: The page whose entry we want to lock | ||
352 | * | ||
353 | * Context: Process context. | ||
354 | * Return: %true if the entry was locked or does not need to be locked. | ||
355 | */ | ||
355 | bool dax_lock_mapping_entry(struct page *page) | 356 | bool dax_lock_mapping_entry(struct page *page) |
356 | { | 357 | { |
357 | XA_STATE(xas, NULL, 0); | 358 | XA_STATE(xas, NULL, 0); |
358 | void *entry; | 359 | void *entry; |
360 | bool locked; | ||
359 | 361 | ||
362 | /* Ensure page->mapping isn't freed while we look at it */ | ||
363 | rcu_read_lock(); | ||
360 | for (;;) { | 364 | for (;;) { |
361 | struct address_space *mapping = READ_ONCE(page->mapping); | 365 | struct address_space *mapping = READ_ONCE(page->mapping); |
362 | 366 | ||
367 | locked = false; | ||
363 | if (!dax_mapping(mapping)) | 368 | if (!dax_mapping(mapping)) |
364 | return false; | 369 | break; |
365 | 370 | ||
366 | /* | 371 | /* |
367 | * In the device-dax case there's no need to lock, a | 372 | * In the device-dax case there's no need to lock, a |
@@ -370,8 +375,9 @@ bool dax_lock_mapping_entry(struct page *page) | |||
370 | * otherwise we would not have a valid pfn_to_page() | 375 | * otherwise we would not have a valid pfn_to_page() |
371 | * translation. | 376 | * translation. |
372 | */ | 377 | */ |
378 | locked = true; | ||
373 | if (S_ISCHR(mapping->host->i_mode)) | 379 | if (S_ISCHR(mapping->host->i_mode)) |
374 | return true; | 380 | break; |
375 | 381 | ||
376 | xas.xa = &mapping->i_pages; | 382 | xas.xa = &mapping->i_pages; |
377 | xas_lock_irq(&xas); | 383 | xas_lock_irq(&xas); |
@@ -382,28 +388,35 @@ bool dax_lock_mapping_entry(struct page *page) | |||
382 | xas_set(&xas, page->index); | 388 | xas_set(&xas, page->index); |
383 | entry = xas_load(&xas); | 389 | entry = xas_load(&xas); |
384 | if (dax_is_locked(entry)) { | 390 | if (dax_is_locked(entry)) { |
391 | rcu_read_unlock(); | ||
385 | entry = get_unlocked_entry(&xas); | 392 | entry = get_unlocked_entry(&xas); |
386 | /* Did the page move while we slept? */ | 393 | xas_unlock_irq(&xas); |
387 | if (dax_to_pfn(entry) != page_to_pfn(page)) { | 394 | put_unlocked_entry(&xas, entry); |
388 | xas_unlock_irq(&xas); | 395 | rcu_read_lock(); |
389 | continue; | 396 | continue; |
390 | } | ||
391 | } | 397 | } |
392 | dax_lock_entry(&xas, entry); | 398 | dax_lock_entry(&xas, entry); |
393 | xas_unlock_irq(&xas); | 399 | xas_unlock_irq(&xas); |
394 | return true; | 400 | break; |
395 | } | 401 | } |
402 | rcu_read_unlock(); | ||
403 | return locked; | ||
396 | } | 404 | } |
397 | 405 | ||
398 | void dax_unlock_mapping_entry(struct page *page) | 406 | void dax_unlock_mapping_entry(struct page *page) |
399 | { | 407 | { |
400 | struct address_space *mapping = page->mapping; | 408 | struct address_space *mapping = page->mapping; |
401 | XA_STATE(xas, &mapping->i_pages, page->index); | 409 | XA_STATE(xas, &mapping->i_pages, page->index); |
410 | void *entry; | ||
402 | 411 | ||
403 | if (S_ISCHR(mapping->host->i_mode)) | 412 | if (S_ISCHR(mapping->host->i_mode)) |
404 | return; | 413 | return; |
405 | 414 | ||
406 | dax_unlock_entry(&xas, dax_make_page_entry(page)); | 415 | rcu_read_lock(); |
416 | entry = xas_load(&xas); | ||
417 | rcu_read_unlock(); | ||
418 | entry = dax_make_entry(page_to_pfn_t(page), dax_is_pmd_entry(entry)); | ||
419 | dax_unlock_entry(&xas, entry); | ||
407 | } | 420 | } |
408 | 421 | ||
409 | /* | 422 | /* |
@@ -445,11 +458,9 @@ static void *grab_mapping_entry(struct xa_state *xas, | |||
445 | retry: | 458 | retry: |
446 | xas_lock_irq(xas); | 459 | xas_lock_irq(xas); |
447 | entry = get_unlocked_entry(xas); | 460 | entry = get_unlocked_entry(xas); |
448 | if (xa_is_internal(entry)) | ||
449 | goto fallback; | ||
450 | 461 | ||
451 | if (entry) { | 462 | if (entry) { |
452 | if (WARN_ON_ONCE(!xa_is_value(entry))) { | 463 | if (!xa_is_value(entry)) { |
453 | xas_set_err(xas, EIO); | 464 | xas_set_err(xas, EIO); |
454 | goto out_unlock; | 465 | goto out_unlock; |
455 | } | 466 | } |
@@ -1628,8 +1639,7 @@ dax_insert_pfn_mkwrite(struct vm_fault *vmf, pfn_t pfn, unsigned int order) | |||
1628 | /* Did we race with someone splitting entry or so? */ | 1639 | /* Did we race with someone splitting entry or so? */ |
1629 | if (!entry || | 1640 | if (!entry || |
1630 | (order == 0 && !dax_is_pte_entry(entry)) || | 1641 | (order == 0 && !dax_is_pte_entry(entry)) || |
1631 | (order == PMD_ORDER && (xa_is_internal(entry) || | 1642 | (order == PMD_ORDER && !dax_is_pmd_entry(entry))) { |
1632 | !dax_is_pmd_entry(entry)))) { | ||
1633 | put_unlocked_entry(&xas, entry); | 1643 | put_unlocked_entry(&xas, entry); |
1634 | xas_unlock_irq(&xas); | 1644 | xas_unlock_irq(&xas); |
1635 | trace_dax_insert_pfn_mkwrite_no_entry(mapping->host, vmf, | 1645 | trace_dax_insert_pfn_mkwrite_no_entry(mapping->host, vmf, |