[RHEL7,COMMIT] ploop: fix trim_extent_mappings() locking

Submitted by Konstantin Khorenko on Dec. 6, 2017, 2:57 p.m.

Details

Message ID 201712061457.vB6EvAtI029027@finist_ce7.work
State New
Series "ploop: fix trim_extent_mappings() locking"
Headers show

Commit Message

Konstantin Khorenko Dec. 6, 2017, 2:57 p.m.
The commit is pushed to "branch-rh7-3.10.0-693.11.1.vz7.39.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-693.11.1.vz7.39.1
------>
commit 841e91712b8697913ccb8a2b50c2bf27cf5c27a2
Author: Vasily Averin <vvs@virtuozzo.com>
Date:   Wed Dec 6 17:57:10 2017 +0300

    ploop: fix trim_extent_mappings() locking
    
    trim_extent_mappings() must obey locking scheme that all other
    callers of lookup_extent_mapping() and extent_lookup() follows: firstly
    hold plo->lock.
    
    Changed in v2:
     - change locking in remove_extent_mapping() from write_lock_irq
       to write_lock because its only caller disables irq now. Thanks
       Vasily Averin for finding.
    
    Changes in v3 (from vvs@):
    - use read_lock_irqsave() in lookup_extent_mapping()
    - added WARN_ON(!irqs_disabled()) in remove_extent_mapping()
    
    https://jira.sw.ru/browse/PSBM-78538
    https://jira.sw.ru/browse/PSBM-45999
    
    Signed-off-by: Maxim Patlasov <mpatlasov@virtuozzo.com>
    Signed-off-by: Vasily Averin <vvs@virtuozzo.com>
---
 drivers/block/ploop/io_direct.c     |  3 ++-
 drivers/block/ploop/io_direct_map.c | 18 +++++++++++++-----
 drivers/block/ploop/io_direct_map.h |  3 ++-
 3 files changed, 17 insertions(+), 7 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/block/ploop/io_direct.c b/drivers/block/ploop/io_direct.c
index d6b1118bf2a3..9fd2d8f67df9 100644
--- a/drivers/block/ploop/io_direct.c
+++ b/drivers/block/ploop/io_direct.c
@@ -1756,7 +1756,8 @@  static int dio_truncate(struct ploop_io * io, struct file * file,
 
 	mutex_lock(&io->files.inode->i_mutex);
 	if (io->files.em_tree)
-		trim_extent_mappings(io->files.em_tree, newattrs.ia_size>>9);
+		trim_extent_mappings(io->plo, io->files.em_tree,
+				     newattrs.ia_size>>9);
 	io->files.inode->i_flags &= ~S_SWAPFILE;
 	err = notify_change(F_DENTRY(file), &newattrs, NULL);
 	io->files.inode->i_flags |= S_SWAPFILE;
diff --git a/drivers/block/ploop/io_direct_map.c b/drivers/block/ploop/io_direct_map.c
index db1da7db3d00..bfc9325b72c6 100644
--- a/drivers/block/ploop/io_direct_map.c
+++ b/drivers/block/ploop/io_direct_map.c
@@ -542,8 +542,9 @@  lookup_extent_mapping(struct extent_map_tree *tree, sector_t start, sector_t len
 {
 	struct extent_map *em;
 	struct rb_node *rb_node;
+	unsigned long flags;
 
-	read_lock_irq(&tree->lock);
+	read_lock_irqsave(&tree->lock, flags);
 	rb_node = tree_search(&tree->map, start);
 	if (!rb_node) {
 		em = NULL;
@@ -557,25 +558,29 @@  lookup_extent_mapping(struct extent_map_tree *tree, sector_t start, sector_t len
 	atomic_inc(&em->refs);
 
 out:
-	read_unlock_irq(&tree->lock);
+	read_unlock_irqrestore(&tree->lock, flags);
 	return em;
 }
 
 /*
  * removes an extent_map struct from the tree.  No reference counts are
  * dropped, and no checks are done to  see if the range is in use
+ *
+ * caller called spin_lock_irq(plo->lock), so we needn't _irq locking
  */
 static int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em)
 {
 	int ret;
 
-	write_lock_irq(&tree->lock);
+	WARN_ON(!irqs_disabled());
+
+	write_lock(&tree->lock);
 	ret = tree_delete(&tree->map, em->start);
 	if (!ret) {
 		list_del_init(&em->lru_link);
 		tree->map_size--;
 	}
-	write_unlock_irq(&tree->lock);
+	write_unlock(&tree->lock);
 	return ret;
 }
 
@@ -834,10 +839,12 @@  static int drop_extent_map(struct extent_map_tree *tree)
 	return 0;
 }
 
-void trim_extent_mappings(struct extent_map_tree *tree, sector_t start)
+void trim_extent_mappings(struct ploop_device *plo,
+			  struct extent_map_tree *tree, sector_t start)
 {
 	struct extent_map *em;
 
+	spin_lock_irq(&plo->lock);
 	while ((em = lookup_extent_mapping(tree, start, ((sector_t)(-1ULL)) - start))) {
 		remove_extent_mapping(tree, em);
 		WARN_ON(atomic_read(&em->refs) != 2);
@@ -847,6 +854,7 @@  void trim_extent_mappings(struct extent_map_tree *tree, sector_t start)
 		/* once for the tree */
 		ploop_extent_put(em);
 	}
+	spin_unlock_irq(&plo->lock);
 }
 
 
diff --git a/drivers/block/ploop/io_direct_map.h b/drivers/block/ploop/io_direct_map.h
index c93b5ac396a1..3db809aa6188 100644
--- a/drivers/block/ploop/io_direct_map.h
+++ b/drivers/block/ploop/io_direct_map.h
@@ -55,7 +55,8 @@  struct extent_map *map_extent_get_block(struct ploop_io *io,
 					struct address_space *mapping,
 					sector_t start, sector_t len, int create,
 					gfp_t gfp_mask, get_block_t get_block);
-void trim_extent_mappings(struct extent_map_tree *tree, sector_t start);
+void trim_extent_mappings(struct ploop_device *plo,
+			  struct extent_map_tree *tree, sector_t start);
 
 int ploop_dio_close(struct ploop_io * io, int rdonly);
 struct extent_map_tree * ploop_dio_open(struct ploop_io * io, int rdonly);