The current dax_lock_page() locks dax entry by obtaining mapping and index in page. To support 1-to-N RMAP in NVDIMM, we need a new function to lock a specific dax entry corresponding to this file's mapping,index. And output the page corresponding to the specific dax entry for caller use. Signed-off-by: Shiyang Ruan <ruansy.fnst@xxxxxxxxxxx> Reviewed-by: Christoph Hellwig <hch@xxxxxx> --- fs/dax.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/dax.h | 8 ++++++++ 2 files changed, 52 insertions(+) diff --git a/fs/dax.c b/fs/dax.c index c8d57080c1aa..964512107c23 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -455,6 +455,50 @@ void dax_unlock_page(struct page *page, dax_entry_t cookie) dax_unlock_entry(&xas, (void *)cookie); } +/* + * dax_load_page - Load the page corresponding to a (mapping,offset) + * @mapping: the file's mapping whose entry we want to load + * @index: the offset within this file + * @page: output the dax page corresponding to this dax entry + * + * Return: error if it isn't a dax mapping, otherwise 0. + */ +int dax_load_page(struct address_space *mapping, pgoff_t index, + struct page **page) +{ + XA_STATE(xas, &mapping->i_pages, 0); + void *entry; + + if (!dax_mapping(mapping)) + return -EBUSY; + + rcu_read_lock(); + for (;;) { + entry = NULL; + xas_lock_irq(&xas); + xas_set(&xas, index); + entry = xas_load(&xas); + if (dax_is_locked(entry)) { + rcu_read_unlock(); + wait_entry_unlocked(&xas, entry); + rcu_read_lock(); + continue; + } + if (entry && + !dax_is_zero_entry(entry) && !dax_is_empty_entry(entry)) { + /* + * Output the page if the dax entry exists and isn't + * a zero or empty entry. + */ + *page = pfn_to_page(dax_to_pfn(entry)); + } + xas_unlock_irq(&xas); + break; + } + rcu_read_unlock(); + return 0; +} + /* * Find page cache entry at given index. If it is a DAX entry, return it * with the entry locked. If the page cache doesn't contain an entry at diff --git a/include/linux/dax.h b/include/linux/dax.h index 96cfc63b12fd..530ff9733dd9 100644 --- a/include/linux/dax.h +++ b/include/linux/dax.h @@ -155,6 +155,8 @@ struct page *dax_layout_busy_page(struct address_space *mapping); struct page *dax_layout_busy_page_range(struct address_space *mapping, loff_t start, loff_t end); dax_entry_t dax_lock_page(struct page *page); void dax_unlock_page(struct page *page, dax_entry_t cookie); +int dax_load_page(struct address_space *mapping, + unsigned long index, struct page **page); #else static inline struct page *dax_layout_busy_page(struct address_space *mapping) { @@ -182,6 +184,12 @@ static inline dax_entry_t dax_lock_page(struct page *page) static inline void dax_unlock_page(struct page *page, dax_entry_t cookie) { } + +static inline int dax_load_page(struct address_space *mapping, + unsigned long index, struct page **page) +{ + return 0; +} #endif int dax_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero, -- 2.34.1