diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-06-24 01:48:48 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-06-24 01:48:48 -0400 |
| commit | 63c04ee7d3b7c8d8e2726cb7c5f8a5f6fcc1e3b2 (patch) | |
| tree | 8ead21ef2c7e84bcd30511d50925416018abd93e | |
| parent | 0bf0ea431f84bcf34facc5b1f792d000f5957565 (diff) | |
| parent | 4ac1c17b2044a1b4b2fbed74451947e905fc2992 (diff) | |
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
| -rw-r--r-- | drivers/mtd/ubi/eba.c | 22 | ||||
| -rw-r--r-- | fs/ubifs/file.c | 24 | ||||
| -rw-r--r-- | mm/migrate.c | 2 |
3 files changed, 41 insertions, 7 deletions
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 5780dd1ba79d..ebf517271d29 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c | |||
| @@ -575,6 +575,7 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, | |||
| 575 | int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0; | 575 | int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0; |
| 576 | struct ubi_volume *vol = ubi->volumes[idx]; | 576 | struct ubi_volume *vol = ubi->volumes[idx]; |
| 577 | struct ubi_vid_hdr *vid_hdr; | 577 | struct ubi_vid_hdr *vid_hdr; |
| 578 | uint32_t crc; | ||
| 578 | 579 | ||
| 579 | vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); | 580 | vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); |
| 580 | if (!vid_hdr) | 581 | if (!vid_hdr) |
| @@ -599,14 +600,8 @@ retry: | |||
| 599 | goto out_put; | 600 | goto out_put; |
| 600 | } | 601 | } |
| 601 | 602 | ||
| 602 | vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); | 603 | ubi_assert(vid_hdr->vol_type == UBI_VID_DYNAMIC); |
| 603 | err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr); | ||
| 604 | if (err) { | ||
| 605 | up_read(&ubi->fm_eba_sem); | ||
| 606 | goto write_error; | ||
| 607 | } | ||
| 608 | 604 | ||
| 609 | data_size = offset + len; | ||
| 610 | mutex_lock(&ubi->buf_mutex); | 605 | mutex_lock(&ubi->buf_mutex); |
| 611 | memset(ubi->peb_buf + offset, 0xFF, len); | 606 | memset(ubi->peb_buf + offset, 0xFF, len); |
| 612 | 607 | ||
| @@ -621,6 +616,19 @@ retry: | |||
| 621 | 616 | ||
| 622 | memcpy(ubi->peb_buf + offset, buf, len); | 617 | memcpy(ubi->peb_buf + offset, buf, len); |
| 623 | 618 | ||
| 619 | data_size = offset + len; | ||
| 620 | crc = crc32(UBI_CRC32_INIT, ubi->peb_buf, data_size); | ||
| 621 | vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); | ||
| 622 | vid_hdr->copy_flag = 1; | ||
| 623 | vid_hdr->data_size = cpu_to_be32(data_size); | ||
| 624 | vid_hdr->data_crc = cpu_to_be32(crc); | ||
| 625 | err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr); | ||
| 626 | if (err) { | ||
| 627 | mutex_unlock(&ubi->buf_mutex); | ||
| 628 | up_read(&ubi->fm_eba_sem); | ||
| 629 | goto write_error; | ||
| 630 | } | ||
| 631 | |||
| 624 | err = ubi_io_write_data(ubi, ubi->peb_buf, new_pnum, 0, data_size); | 632 | err = ubi_io_write_data(ubi, ubi->peb_buf, new_pnum, 0, data_size); |
| 625 | if (err) { | 633 | if (err) { |
| 626 | mutex_unlock(&ubi->buf_mutex); | 634 | mutex_unlock(&ubi->buf_mutex); |
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 08316972ff93..7bbf420d1289 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c | |||
| @@ -52,6 +52,7 @@ | |||
| 52 | #include "ubifs.h" | 52 | #include "ubifs.h" |
| 53 | #include <linux/mount.h> | 53 | #include <linux/mount.h> |
| 54 | #include <linux/slab.h> | 54 | #include <linux/slab.h> |
| 55 | #include <linux/migrate.h> | ||
| 55 | 56 | ||
| 56 | static int read_block(struct inode *inode, void *addr, unsigned int block, | 57 | static int read_block(struct inode *inode, void *addr, unsigned int block, |
| 57 | struct ubifs_data_node *dn) | 58 | struct ubifs_data_node *dn) |
| @@ -1452,6 +1453,26 @@ static int ubifs_set_page_dirty(struct page *page) | |||
| 1452 | return ret; | 1453 | return ret; |
| 1453 | } | 1454 | } |
| 1454 | 1455 | ||
| 1456 | #ifdef CONFIG_MIGRATION | ||
| 1457 | static int ubifs_migrate_page(struct address_space *mapping, | ||
| 1458 | struct page *newpage, struct page *page, enum migrate_mode mode) | ||
| 1459 | { | ||
| 1460 | int rc; | ||
| 1461 | |||
| 1462 | rc = migrate_page_move_mapping(mapping, newpage, page, NULL, mode, 0); | ||
| 1463 | if (rc != MIGRATEPAGE_SUCCESS) | ||
| 1464 | return rc; | ||
| 1465 | |||
| 1466 | if (PagePrivate(page)) { | ||
| 1467 | ClearPagePrivate(page); | ||
| 1468 | SetPagePrivate(newpage); | ||
| 1469 | } | ||
| 1470 | |||
| 1471 | migrate_page_copy(newpage, page); | ||
| 1472 | return MIGRATEPAGE_SUCCESS; | ||
| 1473 | } | ||
| 1474 | #endif | ||
| 1475 | |||
| 1455 | static int ubifs_releasepage(struct page *page, gfp_t unused_gfp_flags) | 1476 | static int ubifs_releasepage(struct page *page, gfp_t unused_gfp_flags) |
| 1456 | { | 1477 | { |
| 1457 | /* | 1478 | /* |
| @@ -1591,6 +1612,9 @@ const struct address_space_operations ubifs_file_address_operations = { | |||
| 1591 | .write_end = ubifs_write_end, | 1612 | .write_end = ubifs_write_end, |
| 1592 | .invalidatepage = ubifs_invalidatepage, | 1613 | .invalidatepage = ubifs_invalidatepage, |
| 1593 | .set_page_dirty = ubifs_set_page_dirty, | 1614 | .set_page_dirty = ubifs_set_page_dirty, |
| 1615 | #ifdef CONFIG_MIGRATION | ||
| 1616 | .migratepage = ubifs_migrate_page, | ||
| 1617 | #endif | ||
| 1594 | .releasepage = ubifs_releasepage, | 1618 | .releasepage = ubifs_releasepage, |
| 1595 | }; | 1619 | }; |
| 1596 | 1620 | ||
diff --git a/mm/migrate.c b/mm/migrate.c index 9baf41c877ff..bd3fdc202e8b 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
| @@ -431,6 +431,7 @@ int migrate_page_move_mapping(struct address_space *mapping, | |||
| 431 | 431 | ||
| 432 | return MIGRATEPAGE_SUCCESS; | 432 | return MIGRATEPAGE_SUCCESS; |
| 433 | } | 433 | } |
| 434 | EXPORT_SYMBOL(migrate_page_move_mapping); | ||
| 434 | 435 | ||
| 435 | /* | 436 | /* |
| 436 | * The expected number of remaining references is the same as that | 437 | * 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 | 587 | ||
| 587 | mem_cgroup_migrate(page, newpage); | 588 | mem_cgroup_migrate(page, newpage); |
| 588 | } | 589 | } |
| 590 | EXPORT_SYMBOL(migrate_page_copy); | ||
| 589 | 591 | ||
| 590 | /************************************************************ | 592 | /************************************************************ |
| 591 | * Migration functions | 593 | * Migration functions |
