Commit 63c04ee7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'upstream-4.7-rc5' of git://git.infradead.org/linux-ubifs

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
parents 0bf0ea43 4ac1c17b
...@@ -575,6 +575,7 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, ...@@ -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; int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0;
struct ubi_volume *vol = ubi->volumes[idx]; struct ubi_volume *vol = ubi->volumes[idx];
struct ubi_vid_hdr *vid_hdr; struct ubi_vid_hdr *vid_hdr;
uint32_t crc;
vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr) if (!vid_hdr)
...@@ -599,14 +600,8 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, ...@@ -599,14 +600,8 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
goto out_put; goto out_put;
} }
vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); ubi_assert(vid_hdr->vol_type == UBI_VID_DYNAMIC);
err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
if (err) {
up_read(&ubi->fm_eba_sem);
goto write_error;
}
data_size = offset + len;
mutex_lock(&ubi->buf_mutex); mutex_lock(&ubi->buf_mutex);
memset(ubi->peb_buf + offset, 0xFF, len); memset(ubi->peb_buf + offset, 0xFF, len);
...@@ -621,6 +616,19 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, ...@@ -621,6 +616,19 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
memcpy(ubi->peb_buf + offset, buf, len); 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); err = ubi_io_write_data(ubi, ubi->peb_buf, new_pnum, 0, data_size);
if (err) { if (err) {
mutex_unlock(&ubi->buf_mutex); mutex_unlock(&ubi->buf_mutex);
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
#include "ubifs.h" #include "ubifs.h"
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/migrate.h>
static int read_block(struct inode *inode, void *addr, unsigned int block, static int read_block(struct inode *inode, void *addr, unsigned int block,
struct ubifs_data_node *dn) struct ubifs_data_node *dn)
...@@ -1452,6 +1453,26 @@ static int ubifs_set_page_dirty(struct page *page) ...@@ -1452,6 +1453,26 @@ static int ubifs_set_page_dirty(struct page *page)
return ret; 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) 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 = { ...@@ -1591,6 +1612,9 @@ const struct address_space_operations ubifs_file_address_operations = {
.write_end = ubifs_write_end, .write_end = ubifs_write_end,
.invalidatepage = ubifs_invalidatepage, .invalidatepage = ubifs_invalidatepage,
.set_page_dirty = ubifs_set_page_dirty, .set_page_dirty = ubifs_set_page_dirty,
#ifdef CONFIG_MIGRATION
.migratepage = ubifs_migrate_page,
#endif
.releasepage = ubifs_releasepage, .releasepage = ubifs_releasepage,
}; };
......
...@@ -431,6 +431,7 @@ int migrate_page_move_mapping(struct address_space *mapping, ...@@ -431,6 +431,7 @@ int migrate_page_move_mapping(struct address_space *mapping,
return MIGRATEPAGE_SUCCESS; return MIGRATEPAGE_SUCCESS;
} }
EXPORT_SYMBOL(migrate_page_move_mapping);
/* /*
* The expected number of remaining references is the same as that * 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) ...@@ -586,6 +587,7 @@ void migrate_page_copy(struct page *newpage, struct page *page)
mem_cgroup_migrate(page, newpage); mem_cgroup_migrate(page, newpage);
} }
EXPORT_SYMBOL(migrate_page_copy);
/************************************************************ /************************************************************
* Migration functions * Migration functions
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment