]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - mm/truncate.c
scsi: cxlflash: Remove port configuration assumptions
[mirror_ubuntu-zesty-kernel.git] / mm / truncate.c
index fd97f1dbce290f39e1d0d0367006df954f20e8f1..c2d7deae28bb013f268eedad5db30c731f1bf0db 100644 (file)
 #include <linux/rmap.h>
 #include "internal.h"
 
-static void clear_exceptional_entry(struct address_space *mapping,
-                                   pgoff_t index, void *entry)
+static void clear_shadow_entry(struct address_space *mapping, pgoff_t index,
+                              void *entry)
 {
        struct radix_tree_node *node;
        void **slot;
 
-       /* Handled by shmem itself */
-       if (shmem_mapping(mapping))
-               return;
-
-       if (dax_mapping(mapping)) {
-               dax_delete_mapping_entry(mapping, index);
-               return;
-       }
        spin_lock_irq(&mapping->tree_lock);
        /*
         * Regular page slots are stabilized by the page lock even
@@ -55,6 +47,53 @@ unlock:
        spin_unlock_irq(&mapping->tree_lock);
 }
 
+/*
+ * Unconditionally remove exceptional entry. Usually called from truncate path.
+ */
+static void truncate_exceptional_entry(struct address_space *mapping,
+                                      pgoff_t index, void *entry)
+{
+       /* Handled by shmem itself */
+       if (shmem_mapping(mapping))
+               return;
+
+       if (dax_mapping(mapping)) {
+               dax_delete_mapping_entry(mapping, index);
+               return;
+       }
+       clear_shadow_entry(mapping, index, entry);
+}
+
+/*
+ * Invalidate exceptional entry if easily possible. This handles exceptional
+ * entries for invalidate_inode_pages().
+ */
+static int invalidate_exceptional_entry(struct address_space *mapping,
+                                       pgoff_t index, void *entry)
+{
+       /* Handled by shmem itself, or for DAX we do nothing. */
+       if (shmem_mapping(mapping) || dax_mapping(mapping))
+               return 1;
+       clear_shadow_entry(mapping, index, entry);
+       return 1;
+}
+
+/*
+ * Invalidate exceptional entry if clean. This handles exceptional entries for
+ * invalidate_inode_pages2() so for DAX it evicts only clean entries.
+ */
+static int invalidate_exceptional_entry2(struct address_space *mapping,
+                                        pgoff_t index, void *entry)
+{
+       /* Handled by shmem itself */
+       if (shmem_mapping(mapping))
+               return 1;
+       if (dax_mapping(mapping))
+               return dax_invalidate_mapping_entry_sync(mapping, index);
+       clear_shadow_entry(mapping, index, entry);
+       return 1;
+}
+
 /**
  * do_invalidatepage - invalidate part or all of a page
  * @page: the page which is affected
@@ -262,7 +301,8 @@ void truncate_inode_pages_range(struct address_space *mapping,
                                break;
 
                        if (radix_tree_exceptional_entry(page)) {
-                               clear_exceptional_entry(mapping, index, page);
+                               truncate_exceptional_entry(mapping, index,
+                                                          page);
                                continue;
                        }
 
@@ -351,7 +391,8 @@ void truncate_inode_pages_range(struct address_space *mapping,
                        }
 
                        if (radix_tree_exceptional_entry(page)) {
-                               clear_exceptional_entry(mapping, index, page);
+                               truncate_exceptional_entry(mapping, index,
+                                                          page);
                                continue;
                        }
 
@@ -470,7 +511,8 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
                                break;
 
                        if (radix_tree_exceptional_entry(page)) {
-                               clear_exceptional_entry(mapping, index, page);
+                               invalidate_exceptional_entry(mapping, index,
+                                                            page);
                                continue;
                        }
 
@@ -592,7 +634,9 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
                                break;
 
                        if (radix_tree_exceptional_entry(page)) {
-                               clear_exceptional_entry(mapping, index, page);
+                               if (!invalidate_exceptional_entry2(mapping,
+                                                                  index, page))
+                                       ret = -EBUSY;
                                continue;
                        }
 
@@ -638,6 +682,17 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
                cond_resched();
                index++;
        }
+       /*
+        * For DAX we invalidate page tables after invalidating radix tree.  We
+        * could invalidate page tables while invalidating each entry however
+        * that would be expensive. And doing range unmapping before doesn't
+        * work as we have no cheap way to find whether radix tree entry didn't
+        * get remapped later.
+        */
+       if (dax_mapping(mapping)) {
+               unmap_mapping_range(mapping, (loff_t)start << PAGE_SHIFT,
+                                   (loff_t)(end - start + 1) << PAGE_SHIFT, 0);
+       }
        cleancache_invalidate_inode(mapping);
        return ret;
 }