Merge branch 'locking-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / nvdimm / btt.c
index b123b0d..4671776 100644 (file)
@@ -541,9 +541,9 @@ static int arena_clear_freelist_error(struct arena_info *arena, u32 lane)
 
 static int btt_freelist_init(struct arena_info *arena)
 {
-       int old, new, ret;
-       u32 i, map_entry;
-       struct log_entry log_new, log_old;
+       int new, ret;
+       struct log_entry log_new;
+       u32 i, map_entry, log_oldmap, log_newmap;
 
        arena->freelist = kcalloc(arena->nfree, sizeof(struct free_entry),
                                        GFP_KERNEL);
@@ -551,24 +551,26 @@ static int btt_freelist_init(struct arena_info *arena)
                return -ENOMEM;
 
        for (i = 0; i < arena->nfree; i++) {
-               old = btt_log_read(arena, i, &log_old, LOG_OLD_ENT);
-               if (old < 0)
-                       return old;
-
                new = btt_log_read(arena, i, &log_new, LOG_NEW_ENT);
                if (new < 0)
                        return new;
 
+               /* old and new map entries with any flags stripped out */
+               log_oldmap = ent_lba(le32_to_cpu(log_new.old_map));
+               log_newmap = ent_lba(le32_to_cpu(log_new.new_map));
+
                /* sub points to the next one to be overwritten */
                arena->freelist[i].sub = 1 - new;
                arena->freelist[i].seq = nd_inc_seq(le32_to_cpu(log_new.seq));
-               arena->freelist[i].block = le32_to_cpu(log_new.old_map);
+               arena->freelist[i].block = log_oldmap;
 
                /*
                 * FIXME: if error clearing fails during init, we want to make
                 * the BTT read-only
                 */
-               if (ent_e_flag(log_new.old_map)) {
+               if (ent_e_flag(log_new.old_map) &&
+                               !ent_normal(log_new.old_map)) {
+                       arena->freelist[i].has_err = 1;
                        ret = arena_clear_freelist_error(arena, i);
                        if (ret)
                                dev_err_ratelimited(to_dev(arena),
@@ -576,7 +578,7 @@ static int btt_freelist_init(struct arena_info *arena)
                }
 
                /* This implies a newly created or untouched flog entry */
-               if (log_new.old_map == log_new.new_map)
+               if (log_oldmap == log_newmap)
                        continue;
 
                /* Check if map recovery is needed */
@@ -584,8 +586,15 @@ static int btt_freelist_init(struct arena_info *arena)
                                NULL, NULL, 0);
                if (ret)
                        return ret;
-               if ((le32_to_cpu(log_new.new_map) != map_entry) &&
-                               (le32_to_cpu(log_new.old_map) == map_entry)) {
+
+               /*
+                * The map_entry from btt_read_map is stripped of any flag bits,
+                * so use the stripped out versions from the log as well for
+                * testing whether recovery is needed. For restoration, use the
+                * 'raw' version of the log entries as that captured what we
+                * were going to write originally.
+                */
+               if ((log_newmap != map_entry) && (log_oldmap == map_entry)) {
                        /*
                         * Last transaction wrote the flog, but wasn't able
                         * to complete the map write. So fix up the map.