Skip to content

Commit 9fc747f

Browse files
author
Matthew Wilcox
committed
dax: Convert dax writeback to XArray
Use XArray iteration instead of a pagevec. Signed-off-by: Matthew Wilcox <[email protected]>
1 parent 07f2d89 commit 9fc747f

File tree

1 file changed

+62
-68
lines changed

1 file changed

+62
-68
lines changed

fs/dax.c

Lines changed: 62 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -997,11 +997,9 @@ static void dax_entry_mkclean(struct address_space *mapping, pgoff_t index,
997997
i_mmap_unlock_read(mapping);
998998
}
999999

1000-
static int dax_writeback_one(struct dax_device *dax_dev,
1001-
struct address_space *mapping, pgoff_t index, void *entry)
1000+
static int dax_writeback_one(struct xa_state *xas, struct dax_device *dax_dev,
1001+
struct address_space *mapping, void *entry)
10021002
{
1003-
struct radix_tree_root *pages = &mapping->i_pages;
1004-
void *entry2, **slot;
10051003
unsigned long pfn;
10061004
long ret = 0;
10071005
size_t size;
@@ -1013,38 +1011,44 @@ static int dax_writeback_one(struct dax_device *dax_dev,
10131011
if (WARN_ON(!xa_is_value(entry)))
10141012
return -EIO;
10151013

1016-
xa_lock_irq(pages);
1017-
entry2 = get_unlocked_mapping_entry(mapping, index, &slot);
1018-
/* Entry got punched out / reallocated? */
1019-
if (!entry2 || WARN_ON_ONCE(!xa_is_value(entry2)))
1020-
goto put_unlocked;
1021-
/*
1022-
* Entry got reallocated elsewhere? No need to writeback. We have to
1023-
* compare pfns as we must not bail out due to difference in lockbit
1024-
* or entry type.
1025-
*/
1026-
if (dax_to_pfn(entry2) != dax_to_pfn(entry))
1027-
goto put_unlocked;
1028-
if (WARN_ON_ONCE(dax_is_empty_entry(entry) ||
1029-
dax_is_zero_entry(entry))) {
1030-
ret = -EIO;
1031-
goto put_unlocked;
1014+
if (unlikely(dax_is_locked(entry))) {
1015+
void *old_entry = entry;
1016+
1017+
entry = get_unlocked_entry(xas);
1018+
1019+
/* Entry got punched out / reallocated? */
1020+
if (!entry || WARN_ON_ONCE(!xa_is_value(entry)))
1021+
goto put_unlocked;
1022+
/*
1023+
* Entry got reallocated elsewhere? No need to writeback.
1024+
* We have to compare pfns as we must not bail out due to
1025+
* difference in lockbit or entry type.
1026+
*/
1027+
if (dax_to_pfn(old_entry) != dax_to_pfn(entry))
1028+
goto put_unlocked;
1029+
if (WARN_ON_ONCE(dax_is_empty_entry(entry) ||
1030+
dax_is_zero_entry(entry))) {
1031+
ret = -EIO;
1032+
goto put_unlocked;
1033+
}
1034+
1035+
/* Another fsync thread may have already done this entry */
1036+
if (!xas_get_mark(xas, PAGECACHE_TAG_TOWRITE))
1037+
goto put_unlocked;
10321038
}
10331039

1034-
/* Another fsync thread may have already written back this entry */
1035-
if (!radix_tree_tag_get(pages, index, PAGECACHE_TAG_TOWRITE))
1036-
goto put_unlocked;
10371040
/* Lock the entry to serialize with page faults */
1038-
entry = lock_slot(mapping, slot);
1041+
dax_lock_entry(xas, entry);
1042+
10391043
/*
10401044
* We can clear the tag now but we have to be careful so that concurrent
10411045
* dax_writeback_one() calls for the same index cannot finish before we
10421046
* actually flush the caches. This is achieved as the calls will look
10431047
* at the entry only under the i_pages lock and once they do that
10441048
* they will see the entry locked and wait for it to unlock.
10451049
*/
1046-
radix_tree_tag_clear(pages, index, PAGECACHE_TAG_TOWRITE);
1047-
xa_unlock_irq(pages);
1050+
xas_clear_mark(xas, PAGECACHE_TAG_TOWRITE);
1051+
xas_unlock_irq(xas);
10481052

10491053
/*
10501054
* Even if dax_writeback_mapping_range() was given a wbc->range_start
@@ -1056,24 +1060,26 @@ static int dax_writeback_one(struct dax_device *dax_dev,
10561060
pfn = dax_to_pfn(entry);
10571061
size = PAGE_SIZE << dax_entry_order(entry);
10581062

1059-
dax_entry_mkclean(mapping, index, pfn);
1063+
dax_entry_mkclean(mapping, xas->xa_index, pfn);
10601064
dax_flush(dax_dev, page_address(pfn_to_page(pfn)), size);
10611065
/*
10621066
* After we have flushed the cache, we can clear the dirty tag. There
10631067
* cannot be new dirty data in the pfn after the flush has completed as
10641068
* the pfn mappings are writeprotected and fault waits for mapping
10651069
* entry lock.
10661070
*/
1067-
xa_lock_irq(pages);
1068-
radix_tree_tag_clear(pages, index, PAGECACHE_TAG_DIRTY);
1069-
xa_unlock_irq(pages);
1070-
trace_dax_writeback_one(mapping->host, index, size >> PAGE_SHIFT);
1071-
put_locked_mapping_entry(mapping, index);
1071+
xas_reset(xas);
1072+
xas_lock_irq(xas);
1073+
xas_store(xas, entry);
1074+
xas_clear_mark(xas, PAGECACHE_TAG_DIRTY);
1075+
dax_wake_entry(xas, entry, false);
1076+
1077+
trace_dax_writeback_one(mapping->host, xas->xa_index,
1078+
size >> PAGE_SHIFT);
10721079
return ret;
10731080

10741081
put_unlocked:
1075-
put_unlocked_mapping_entry(mapping, index, entry2);
1076-
xa_unlock_irq(pages);
1082+
put_unlocked_entry(xas, entry);
10771083
return ret;
10781084
}
10791085

@@ -1085,13 +1091,13 @@ static int dax_writeback_one(struct dax_device *dax_dev,
10851091
int dax_writeback_mapping_range(struct address_space *mapping,
10861092
struct block_device *bdev, struct writeback_control *wbc)
10871093
{
1094+
XA_STATE(xas, &mapping->i_pages, wbc->range_start >> PAGE_SHIFT);
10881095
struct inode *inode = mapping->host;
1089-
pgoff_t start_index, end_index;
1090-
pgoff_t indices[PAGEVEC_SIZE];
1096+
pgoff_t end_index = wbc->range_end >> PAGE_SHIFT;
10911097
struct dax_device *dax_dev;
1092-
struct pagevec pvec;
1093-
bool done = false;
1094-
int i, ret = 0;
1098+
void *entry;
1099+
int ret = 0;
1100+
unsigned int scanned = 0;
10951101

10961102
if (WARN_ON_ONCE(inode->i_blkbits != PAGE_SHIFT))
10971103
return -EIO;
@@ -1103,41 +1109,29 @@ int dax_writeback_mapping_range(struct address_space *mapping,
11031109
if (!dax_dev)
11041110
return -EIO;
11051111

1106-
start_index = wbc->range_start >> PAGE_SHIFT;
1107-
end_index = wbc->range_end >> PAGE_SHIFT;
1108-
1109-
trace_dax_writeback_range(inode, start_index, end_index);
1110-
1111-
tag_pages_for_writeback(mapping, start_index, end_index);
1112+
trace_dax_writeback_range(inode, xas.xa_index, end_index);
11121113

1113-
pagevec_init(&pvec);
1114-
while (!done) {
1115-
pvec.nr = find_get_entries_tag(mapping, start_index,
1116-
PAGECACHE_TAG_TOWRITE, PAGEVEC_SIZE,
1117-
pvec.pages, indices);
1114+
tag_pages_for_writeback(mapping, xas.xa_index, end_index);
11181115

1119-
if (pvec.nr == 0)
1116+
xas_lock_irq(&xas);
1117+
xas_for_each_marked(&xas, entry, end_index, PAGECACHE_TAG_TOWRITE) {
1118+
ret = dax_writeback_one(&xas, dax_dev, mapping, entry);
1119+
if (ret < 0) {
1120+
mapping_set_error(mapping, ret);
11201121
break;
1121-
1122-
for (i = 0; i < pvec.nr; i++) {
1123-
if (indices[i] > end_index) {
1124-
done = true;
1125-
break;
1126-
}
1127-
1128-
ret = dax_writeback_one(dax_dev, mapping, indices[i],
1129-
pvec.pages[i]);
1130-
if (ret < 0) {
1131-
mapping_set_error(mapping, ret);
1132-
goto out;
1133-
}
11341122
}
1135-
start_index = indices[pvec.nr - 1] + 1;
1123+
if (++scanned % XA_CHECK_SCHED)
1124+
continue;
1125+
1126+
xas_pause(&xas);
1127+
xas_unlock_irq(&xas);
1128+
cond_resched();
1129+
xas_lock_irq(&xas);
11361130
}
1137-
out:
1131+
xas_unlock_irq(&xas);
11381132
put_dax(dax_dev);
1139-
trace_dax_writeback_range_done(inode, start_index, end_index);
1140-
return (ret < 0 ? ret : 0);
1133+
trace_dax_writeback_range_done(inode, xas.xa_index, end_index);
1134+
return ret;
11411135
}
11421136
EXPORT_SYMBOL_GPL(dax_writeback_mapping_range);
11431137

0 commit comments

Comments
 (0)