]> git.baikalelectronics.ru Git - kernel.git/commitdiff
dm bufio: introduce forget_buffer_locked
authorMikulas Patocka <mpatocka@redhat.com>
Tue, 2 Jun 2020 13:34:40 +0000 (15:34 +0200)
committerMike Snitzer <snitzer@redhat.com>
Fri, 5 Jun 2020 18:59:41 +0000 (14:59 -0400)
Introduce a function forget_buffer_locked that forgets a range of
buffers. It is more efficient than calling forget_buffer in a loop.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
drivers/md/dm-bufio.c
include/linux/dm-bufio.h

index ff19add97e0b5f2bf9d07f93daa0edfca0a38a68..95f6c544aa013fc0de5db6d6a213eb8b7081216c 100644 (file)
@@ -262,6 +262,29 @@ static struct dm_buffer *__find(struct dm_bufio_client *c, sector_t block)
        return NULL;
 }
 
+static struct dm_buffer *__find_next(struct dm_bufio_client *c, sector_t block)
+{
+       struct rb_node *n = c->buffer_tree.rb_node;
+       struct dm_buffer *b;
+       struct dm_buffer *best = NULL;
+
+       while (n) {
+               b = container_of(n, struct dm_buffer, node);
+
+               if (b->block == block)
+                       return b;
+
+               if (block <= b->block) {
+                       n = n->rb_left;
+                       best = b;
+               } else {
+                       n = n->rb_right;
+               }
+       }
+
+       return best;
+}
+
 static void __insert(struct dm_bufio_client *c, struct dm_buffer *b)
 {
        struct rb_node **new = &c->buffer_tree.rb_node, *parent = NULL;
@@ -1434,6 +1457,14 @@ retry:
 }
 EXPORT_SYMBOL_GPL(dm_bufio_release_move);
 
+static void forget_buffer_locked(struct dm_buffer *b)
+{
+       if (likely(!b->hold_count) && likely(!b->state)) {
+               __unlink_buffer(b);
+               __free_buffer_wake(b);
+       }
+}
+
 /*
  * Free the given buffer.
  *
@@ -1447,15 +1478,36 @@ void dm_bufio_forget(struct dm_bufio_client *c, sector_t block)
        dm_bufio_lock(c);
 
        b = __find(c, block);
-       if (b && likely(!b->hold_count) && likely(!b->state)) {
-               __unlink_buffer(b);
-               __free_buffer_wake(b);
-       }
+       if (b)
+               forget_buffer_locked(b);
 
        dm_bufio_unlock(c);
 }
 EXPORT_SYMBOL_GPL(dm_bufio_forget);
 
+void dm_bufio_forget_buffers(struct dm_bufio_client *c, sector_t block, sector_t n_blocks)
+{
+       struct dm_buffer *b;
+       sector_t end_block = block + n_blocks;
+
+       while (block < end_block) {
+               dm_bufio_lock(c);
+
+               b = __find_next(c, block);
+               if (b) {
+                       block = b->block + 1;
+                       forget_buffer_locked(b);
+               }
+
+               dm_bufio_unlock(c);
+
+               if (!b)
+                       break;
+       }
+
+}
+EXPORT_SYMBOL_GPL(dm_bufio_forget_buffers);
+
 void dm_bufio_set_minimum_buffers(struct dm_bufio_client *c, unsigned n)
 {
        c->minimum_buffers = n;
index 5ec6bfbde9ae131c986ce376b14ae9e518053df9..29d255fdd5d641cf31eefefcc3d47744e87734d3 100644 (file)
@@ -136,6 +136,13 @@ void dm_bufio_release_move(struct dm_buffer *b, sector_t new_block);
  */
 void dm_bufio_forget(struct dm_bufio_client *c, sector_t block);
 
+/*
+ * Free the given range of buffers.
+ * This is just a hint, if the buffer is in use or dirty, this function
+ * does nothing.
+ */
+void dm_bufio_forget_buffers(struct dm_bufio_client *c, sector_t block, sector_t n_blocks);
+
 /*
  * Set the minimum number of buffers before cleanup happens.
  */