This pull requests contains fixes for two critical bugs in UBI and UBIFS:
1. Fixes the possibility of losing data upon a power cut when UBI tries to recover from a write error. 2. Fixes page migration on UBIFS. It turned out that the default page migration function is not suitable for UBIFS. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABAgAGBQJXa5tEAAoJEEtJtSqsAOnW090P/RcQjIfVf2g3r8VRp38OQPbb MTd4sD/rnyt5Eq0QYUPWG5xcYK2BWI1PwpdB81JvW5hxnXPgG8DpVIxjzt/7Xgnp QheYe9tMfgYjDntz1rzGVa/uHSAldP9V4czgczrBW/0lwnRsZ6mLY1RA9Oz0hRdG cp53I8CSD0DPyqU0XkgzLkzVUstmySwQ5i46C0kQEnlRcytReOLgcjSrXXn+/Zih yZxhtDQSCKmQAfVmERggPXVHo8jFtVfej52ja7RFcMA2uXvXqljOBNCyLUYPdYka XdQEKsXRLl69ktFUXwZwPAYAW23I8+PMpsoljHDVc0hF25p8omp3D+7HE18SsMSv 6RNnUwz+PDbiFApyoTu0SBgHN/OO9o6rjNNoRIInoKpk0NvWmrMQOo6BIFsX4yq1 0dOVJiKXVoFuo75Yw9mOKdrV/Z5P1TvgdTBj6g03aUM9vcX1Gz6+1xKkvcXGgh02 8qFDZdZ5L87TlpMkvtWO87Ir0ssrfjxpvxR8pPsxxqvxbfUuVmss4ILuh9AVSVk+ d1zrz30+JZzTbIrky/7R31i6Bx2+reYdTKiPIkST9sF5WblUPSeyUoKq1OlNRYxj n+0Q8S5Tm/6AHXUOQFxurbXU+D7G7TaL/CsBeepvV/AqJb07+vBxUuGFH1rDbmLB r5dTfOXn3iNEmmNyrhgN =EDeX -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
63c04ee7d3
|
@ -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,
|
||||||
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,
|
||||||
|
|
||||||
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 @@
|
||||||
#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)
|
||||||
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 = {
|
||||||
.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,
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
mem_cgroup_migrate(page, newpage);
|
mem_cgroup_migrate(page, newpage);
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(migrate_page_copy);
|
||||||
|
|
||||||
/************************************************************
|
/************************************************************
|
||||||
* Migration functions
|
* Migration functions
|
||||||
|
|
Loading…
Reference in New Issue