dax: Allow DAX code to replace exceptional entries
authorJan Kara <jack@suse.cz>
Thu, 12 May 2016 16:29:17 +0000 (18:29 +0200)
committerRoss Zwisler <ross.zwisler@linux.intel.com>
Thu, 19 May 2016 21:18:30 +0000 (15:18 -0600)
Currently we forbid page_cache_tree_insert() to replace exceptional radix
tree entries for DAX inodes. However to make DAX faults race free we will
lock radix tree entries and when hole is created, we need to replace
such locked radix tree entry with a hole page. So modify
page_cache_tree_insert() to allow that.

Reviewed-by: Ross Zwisler <ross.zwisler@linux.intel.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Ross Zwisler <ross.zwisler@linux.intel.com>
include/linux/dax.h
mm/filemap.c

index 70600b63083f9859746af1916b3d90e22bff4b26..aa148937bb3fb21bfe2f89dd9140f0ffd6fda74c 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/fs.h>
 #include <linux/mm.h>
+#include <linux/radix-tree.h>
 #include <asm/pgtable.h>
 
 /* We use lowest available exceptional entry bit for locking */
index f2479af09da91ae8767b009c294bef2e3e75fc2e..dfe55c2cfb34a94660f43f5294cfdf0ce3bf6f5c 100644 (file)
@@ -597,14 +597,21 @@ static int page_cache_tree_insert(struct address_space *mapping,
                if (!radix_tree_exceptional_entry(p))
                        return -EEXIST;
 
-               if (WARN_ON(dax_mapping(mapping)))
-                       return -EINVAL;
-
-               if (shadowp)
-                       *shadowp = p;
                mapping->nrexceptional--;
-               if (node)
-                       workingset_node_shadows_dec(node);
+               if (!dax_mapping(mapping)) {
+                       if (shadowp)
+                               *shadowp = p;
+                       if (node)
+                               workingset_node_shadows_dec(node);
+               } else {
+                       /* DAX can replace empty locked entry with a hole */
+                       WARN_ON_ONCE(p !=
+                               (void *)(RADIX_TREE_EXCEPTIONAL_ENTRY |
+                                        RADIX_DAX_ENTRY_LOCK));
+                       /* DAX accounts exceptional entries as normal pages */
+                       if (node)
+                               workingset_node_pages_dec(node);
+               }
        }
        radix_tree_replace_slot(slot, page);
        mapping->nrpages++;