Merge tag 'upstream-4.7-rc5' of git://git.infradead.org/linux-ubifs
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 24 Jun 2016 05:48:48 +0000 (22:48 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 24 Jun 2016 05:48:48 +0000 (22:48 -0700)
Pull UBI/UBIFS fixes from Richard Weinberger:
 "This contains fixes for two critical bugs in UBI and UBIFS:

   - fix the possibility of losing data upon a power cut when UBI tries
     to recover from a write error

   - fix page migration on UBIFS.  It turned out that the default page
     migration function is not suitable for UBIFS"

* tag 'upstream-4.7-rc5' of git://git.infradead.org/linux-ubifs:
  UBIFS: Implement ->migratepage()
  mm: Export migrate_page_move_mapping and migrate_page_copy
  ubi: Make recover_peb power cut aware
  gpio: make library immune to error pointers
  gpio: make sure gpiod_to_irq() returns negative on NULL desc
  gpio: 104-idi-48: Fix missing spin_lock_init for ack_lock

drivers/mtd/ubi/eba.c
fs/ubifs/file.c
mm/migrate.c

index 5780dd1..ebf5172 100644 (file)
@@ -575,6 +575,7 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
        int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0;
        struct ubi_volume *vol = ubi->volumes[idx];
        struct ubi_vid_hdr *vid_hdr;
+       uint32_t crc;
 
        vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
        if (!vid_hdr)
@@ -599,14 +600,8 @@ retry:
                goto out_put;
        }
 
-       vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
-       err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
-       if (err) {
-               up_read(&ubi->fm_eba_sem);
-               goto write_error;
-       }
+       ubi_assert(vid_hdr->vol_type == UBI_VID_DYNAMIC);
 
-       data_size = offset + len;
        mutex_lock(&ubi->buf_mutex);
        memset(ubi->peb_buf + offset, 0xFF, len);
 
@@ -621,6 +616,19 @@ retry:
 
        memcpy(ubi->peb_buf + offset, buf, len);
 
+       data_size = offset + len;
+       crc = crc32(UBI_CRC32_INIT, ubi->peb_buf, data_size);
+       vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
+       vid_hdr->copy_flag = 1;
+       vid_hdr->data_size = cpu_to_be32(data_size);
+       vid_hdr->data_crc = cpu_to_be32(crc);
+       err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
+       if (err) {
+               mutex_unlock(&ubi->buf_mutex);
+               up_read(&ubi->fm_eba_sem);
+               goto write_error;
+       }
+
        err = ubi_io_write_data(ubi, ubi->peb_buf, new_pnum, 0, data_size);
        if (err) {
                mutex_unlock(&ubi->buf_mutex);
index 0831697..7bbf420 100644 (file)
@@ -52,6 +52,7 @@
 #include "ubifs.h"
 #include <linux/mount.h>
 #include <linux/slab.h>
+#include <linux/migrate.h>
 
 static int read_block(struct inode *inode, void *addr, unsigned int block,
                      struct ubifs_data_node *dn)
@@ -1452,6 +1453,26 @@ static int ubifs_set_page_dirty(struct page *page)
        return ret;
 }
 
+#ifdef CONFIG_MIGRATION
+static int ubifs_migrate_page(struct address_space *mapping,
+               struct page *newpage, struct page *page, enum migrate_mode mode)
+{
+       int rc;
+
+       rc = migrate_page_move_mapping(mapping, newpage, page, NULL, mode, 0);
+       if (rc != MIGRATEPAGE_SUCCESS)
+               return rc;
+
+       if (PagePrivate(page)) {
+               ClearPagePrivate(page);
+               SetPagePrivate(newpage);
+       }
+
+       migrate_page_copy(newpage, page);
+       return MIGRATEPAGE_SUCCESS;
+}
+#endif
+
 static int ubifs_releasepage(struct page *page, gfp_t unused_gfp_flags)
 {
        /*
@@ -1591,6 +1612,9 @@ const struct address_space_operations ubifs_file_address_operations = {
        .write_end      = ubifs_write_end,
        .invalidatepage = ubifs_invalidatepage,
        .set_page_dirty = ubifs_set_page_dirty,
+#ifdef CONFIG_MIGRATION
+       .migratepage    = ubifs_migrate_page,
+#endif
        .releasepage    = ubifs_releasepage,
 };
 
index 9baf41c..bd3fdc2 100644 (file)
@@ -431,6 +431,7 @@ int migrate_page_move_mapping(struct address_space *mapping,
 
        return MIGRATEPAGE_SUCCESS;
 }
+EXPORT_SYMBOL(migrate_page_move_mapping);
 
 /*
  * The expected number of remaining references is the same as that
@@ -586,6 +587,7 @@ void migrate_page_copy(struct page *newpage, struct page *page)
 
        mem_cgroup_migrate(page, newpage);
 }
+EXPORT_SYMBOL(migrate_page_copy);
 
 /************************************************************
  *                    Migration functions