Improve setting of "events_cleared" for write-intent bitmaps.
authorNeil Brown <neilb@notabene.brown>
Fri, 27 Jun 2008 22:31:22 +0000 (08:31 +1000)
committerNeil Brown <neilb@notabene.brown>
Fri, 27 Jun 2008 22:31:22 +0000 (08:31 +1000)
When an array is degraded, bits in the write-intent bitmap are not
cleared, so that if the missing device is re-added, it can be synced
by only updated those parts of the device that have changed since
it was removed.

The enable this a 'events_cleared' value is stored. It is the event
counter for the array the last time that any bits were cleared.

Sometimes - if a device disappears from an array while it is 'clean' -
the events_cleared value gets updated incorrectly (there are subtle
ordering issues between updateing events in the main metadata and the
bitmap metadata) resulting in the missing device appearing to require
a full resync when it is re-added.

With this patch, we update events_cleared precisely when we are about
to clear a bit in the bitmap.  We record events_cleared when we clear
the bit internally, and copy that to the superblock which is written
out before the bit on storage.  This makes it more "obviously correct".

We also need to update events_cleared when the event_count is going
backwards (as happens on a dirty->clean transition of a non-degraded
array).

Thanks to Mike Snitzer for identifying this problem and testing early
"fixes".

Cc: "Mike Snitzer" <snitzer@gmail.com>
Signed-off-by: Neil Brown <neilb@suse.de>
drivers/md/bitmap.c
include/linux/raid/bitmap.h

index b26927ce889cead2717db3f4d3896bbd9bacc4e2..dedba16d42f723cb75f87396659e31899d010fc8 100644 (file)
@@ -454,8 +454,11 @@ void bitmap_update_sb(struct bitmap *bitmap)
        spin_unlock_irqrestore(&bitmap->lock, flags);
        sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0);
        sb->events = cpu_to_le64(bitmap->mddev->events);
-       if (!bitmap->mddev->degraded)
-               sb->events_cleared = cpu_to_le64(bitmap->mddev->events);
+       if (bitmap->mddev->events < bitmap->events_cleared) {
+               /* rocking back to read-only */
+               bitmap->events_cleared = bitmap->mddev->events;
+               sb->events_cleared = cpu_to_le64(bitmap->events_cleared);
+       }
        kunmap_atomic(sb, KM_USER0);
        write_page(bitmap, bitmap->sb_page, 1);
 }
@@ -1085,9 +1088,19 @@ void bitmap_daemon_work(struct bitmap *bitmap)
                        } else
                                spin_unlock_irqrestore(&bitmap->lock, flags);
                        lastpage = page;
-/*
-                       printk("bitmap clean at page %lu\n", j);
-*/
+
+                       /* We are possibly going to clear some bits, so make
+                        * sure that events_cleared is up-to-date.
+                        */
+                       if (bitmap->need_sync) {
+                               bitmap_super_t *sb;
+                               bitmap->need_sync = 0;
+                               sb = kmap_atomic(bitmap->sb_page, KM_USER0);
+                               sb->events_cleared =
+                                       cpu_to_le64(bitmap->events_cleared);
+                               kunmap_atomic(sb, KM_USER0);
+                               write_page(bitmap, bitmap->sb_page, 1);
+                       }
                        spin_lock_irqsave(&bitmap->lock, flags);
                        clear_page_attr(bitmap, page, BITMAP_PAGE_CLEAN);
                }
@@ -1257,6 +1270,12 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto
                        return;
                }
 
+               if (success &&
+                   bitmap->events_cleared < bitmap->mddev->events) {
+                       bitmap->events_cleared = bitmap->mddev->events;
+                       bitmap->need_sync = 1;
+               }
+
                if (!success && ! (*bmc & NEEDED_MASK))
                        *bmc |= NEEDED_MASK;
 
index 78bfdea24a8ecd3f2465a031a7956fd8ba43f63a..e98900671ca91d7a4f76ae91ac7393f6613bd5ee 100644 (file)
@@ -221,6 +221,7 @@ struct bitmap {
        unsigned long syncchunk;
 
        __u64   events_cleared;
+       int need_sync;
 
        /* bitmap spinlock */
        spinlock_t lock;