Merge tag 'upstream-5.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs
Pull UBI, UBIFS and JFFS2 updates from Richard Weinberger: "UBI: - Be less stupid when placing a fastmap anchor - Try harder to get an empty PEB in case of contention - Make ubiblock to warn if image is not a multiple of 512 UBIFS: - Various fixes in error paths JFFS2: - Various fixes in error paths" * tag 'upstream-5.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs: jffs2: Fix memory leak in jffs2_scan_eraseblock() error path jffs2: Remove jffs2_gc_fetch_page and jffs2_gc_release_page jffs2: Fix possible null-pointer dereferences in jffs2_add_frag_to_fragtree() ubi: block: Warn if volume size is not multiple of 512 ubifs: Fix memory leak bug in alloc_ubifs_info() error path ubifs: Fix memory leak in __ubifs_node_verify_hmac error path ubifs: Fix memory leak in read_znode() error path ubi: ubi_wl_get_peb: Increase the number of attempts while getting PEB ubi: Don't do anchor move within fastmap area ubifs: Remove redundant assignment to pointer fname
This commit is contained in:
@@ -345,15 +345,36 @@ static const struct blk_mq_ops ubiblock_mq_ops = {
|
|||||||
.init_request = ubiblock_init_request,
|
.init_request = ubiblock_init_request,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int calc_disk_capacity(struct ubi_volume_info *vi, u64 *disk_capacity)
|
||||||
|
{
|
||||||
|
u64 size = vi->used_bytes >> 9;
|
||||||
|
|
||||||
|
if (vi->used_bytes % 512) {
|
||||||
|
pr_warn("UBI: block: volume size is not a multiple of 512, "
|
||||||
|
"last %llu bytes are ignored!\n",
|
||||||
|
vi->used_bytes - (size << 9));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sector_t)size != size)
|
||||||
|
return -EFBIG;
|
||||||
|
|
||||||
|
*disk_capacity = size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int ubiblock_create(struct ubi_volume_info *vi)
|
int ubiblock_create(struct ubi_volume_info *vi)
|
||||||
{
|
{
|
||||||
struct ubiblock *dev;
|
struct ubiblock *dev;
|
||||||
struct gendisk *gd;
|
struct gendisk *gd;
|
||||||
u64 disk_capacity = vi->used_bytes >> 9;
|
u64 disk_capacity;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if ((sector_t)disk_capacity != disk_capacity)
|
ret = calc_disk_capacity(vi, &disk_capacity);
|
||||||
return -EFBIG;
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check that the volume isn't already handled */
|
/* Check that the volume isn't already handled */
|
||||||
mutex_lock(&devices_mutex);
|
mutex_lock(&devices_mutex);
|
||||||
if (find_dev_nolock(vi->ubi_num, vi->vol_id)) {
|
if (find_dev_nolock(vi->ubi_num, vi->vol_id)) {
|
||||||
@@ -507,7 +528,8 @@ out_unlock:
|
|||||||
static int ubiblock_resize(struct ubi_volume_info *vi)
|
static int ubiblock_resize(struct ubi_volume_info *vi)
|
||||||
{
|
{
|
||||||
struct ubiblock *dev;
|
struct ubiblock *dev;
|
||||||
u64 disk_capacity = vi->used_bytes >> 9;
|
u64 disk_capacity;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Need to lock the device list until we stop using the device,
|
* Need to lock the device list until we stop using the device,
|
||||||
@@ -520,11 +542,16 @@ static int ubiblock_resize(struct ubi_volume_info *vi)
|
|||||||
mutex_unlock(&devices_mutex);
|
mutex_unlock(&devices_mutex);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
if ((sector_t)disk_capacity != disk_capacity) {
|
|
||||||
|
ret = calc_disk_capacity(vi, &disk_capacity);
|
||||||
|
if (ret) {
|
||||||
mutex_unlock(&devices_mutex);
|
mutex_unlock(&devices_mutex);
|
||||||
dev_warn(disk_to_dev(dev->gd), "the volume is too big (%d LEBs), cannot resize",
|
if (ret == -EFBIG) {
|
||||||
vi->size);
|
dev_warn(disk_to_dev(dev->gd),
|
||||||
return -EFBIG;
|
"the volume is too big (%d LEBs), cannot resize",
|
||||||
|
vi->size);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&dev->dev_mutex);
|
mutex_lock(&dev->dev_mutex);
|
||||||
|
@@ -196,7 +196,7 @@ static int produce_free_peb(struct ubi_device *ubi)
|
|||||||
*/
|
*/
|
||||||
int ubi_wl_get_peb(struct ubi_device *ubi)
|
int ubi_wl_get_peb(struct ubi_device *ubi)
|
||||||
{
|
{
|
||||||
int ret, retried = 0;
|
int ret, attempts = 0;
|
||||||
struct ubi_fm_pool *pool = &ubi->fm_pool;
|
struct ubi_fm_pool *pool = &ubi->fm_pool;
|
||||||
struct ubi_fm_pool *wl_pool = &ubi->fm_wl_pool;
|
struct ubi_fm_pool *wl_pool = &ubi->fm_wl_pool;
|
||||||
|
|
||||||
@@ -221,12 +221,12 @@ again:
|
|||||||
|
|
||||||
if (pool->used == pool->size) {
|
if (pool->used == pool->size) {
|
||||||
spin_unlock(&ubi->wl_lock);
|
spin_unlock(&ubi->wl_lock);
|
||||||
if (retried) {
|
attempts++;
|
||||||
|
if (attempts == 10) {
|
||||||
ubi_err(ubi, "Unable to get a free PEB from user WL pool");
|
ubi_err(ubi, "Unable to get a free PEB from user WL pool");
|
||||||
ret = -ENOSPC;
|
ret = -ENOSPC;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
retried = 1;
|
|
||||||
up_read(&ubi->fm_eba_sem);
|
up_read(&ubi->fm_eba_sem);
|
||||||
ret = produce_free_peb(ubi);
|
ret = produce_free_peb(ubi);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@@ -710,6 +710,12 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
|
|||||||
if (!e2)
|
if (!e2)
|
||||||
goto out_cancel;
|
goto out_cancel;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Anchor move within the anchor area is useless.
|
||||||
|
*/
|
||||||
|
if (e2->pnum < UBI_FM_MAX_START)
|
||||||
|
goto out_cancel;
|
||||||
|
|
||||||
self_check_in_wl_tree(ubi, e1, &ubi->used);
|
self_check_in_wl_tree(ubi, e1, &ubi->used);
|
||||||
rb_erase(&e1->u.rb, &ubi->used);
|
rb_erase(&e1->u.rb, &ubi->used);
|
||||||
dbg_wl("anchor-move PEB %d to PEB %d", e1->pnum, e2->pnum);
|
dbg_wl("anchor-move PEB %d to PEB %d", e1->pnum, e2->pnum);
|
||||||
|
@@ -682,33 +682,6 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
|
|||||||
return JFFS2_INODE_INFO(inode);
|
return JFFS2_INODE_INFO(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
|
|
||||||
struct jffs2_inode_info *f,
|
|
||||||
unsigned long offset,
|
|
||||||
unsigned long *priv)
|
|
||||||
{
|
|
||||||
struct inode *inode = OFNI_EDONI_2SFFJ(f);
|
|
||||||
struct page *pg;
|
|
||||||
|
|
||||||
pg = read_cache_page(inode->i_mapping, offset >> PAGE_SHIFT,
|
|
||||||
jffs2_do_readpage_unlock, inode);
|
|
||||||
if (IS_ERR(pg))
|
|
||||||
return (void *)pg;
|
|
||||||
|
|
||||||
*priv = (unsigned long)pg;
|
|
||||||
return kmap(pg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void jffs2_gc_release_page(struct jffs2_sb_info *c,
|
|
||||||
unsigned char *ptr,
|
|
||||||
unsigned long *priv)
|
|
||||||
{
|
|
||||||
struct page *pg = (void *)*priv;
|
|
||||||
|
|
||||||
kunmap(pg);
|
|
||||||
put_page(pg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jffs2_flash_setup(struct jffs2_sb_info *c) {
|
static int jffs2_flash_setup(struct jffs2_sb_info *c) {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
@@ -1165,12 +1165,13 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
|
|||||||
struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,
|
struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,
|
||||||
uint32_t start, uint32_t end)
|
uint32_t start, uint32_t end)
|
||||||
{
|
{
|
||||||
|
struct inode *inode = OFNI_EDONI_2SFFJ(f);
|
||||||
struct jffs2_full_dnode *new_fn;
|
struct jffs2_full_dnode *new_fn;
|
||||||
struct jffs2_raw_inode ri;
|
struct jffs2_raw_inode ri;
|
||||||
uint32_t alloclen, offset, orig_end, orig_start;
|
uint32_t alloclen, offset, orig_end, orig_start;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
unsigned char *comprbuf = NULL, *writebuf;
|
unsigned char *comprbuf = NULL, *writebuf;
|
||||||
unsigned long pg;
|
struct page *page;
|
||||||
unsigned char *pg_ptr;
|
unsigned char *pg_ptr;
|
||||||
|
|
||||||
memset(&ri, 0, sizeof(ri));
|
memset(&ri, 0, sizeof(ri));
|
||||||
@@ -1325,15 +1326,18 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
|
|||||||
* end up here trying to GC the *same* page that jffs2_write_begin() is
|
* end up here trying to GC the *same* page that jffs2_write_begin() is
|
||||||
* trying to write out, read_cache_page() will not deadlock. */
|
* trying to write out, read_cache_page() will not deadlock. */
|
||||||
mutex_unlock(&f->sem);
|
mutex_unlock(&f->sem);
|
||||||
pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg);
|
page = read_cache_page(inode->i_mapping, start >> PAGE_SHIFT,
|
||||||
mutex_lock(&f->sem);
|
jffs2_do_readpage_unlock, inode);
|
||||||
|
if (IS_ERR(page)) {
|
||||||
if (IS_ERR(pg_ptr)) {
|
|
||||||
pr_warn("read_cache_page() returned error: %ld\n",
|
pr_warn("read_cache_page() returned error: %ld\n",
|
||||||
PTR_ERR(pg_ptr));
|
PTR_ERR(page));
|
||||||
return PTR_ERR(pg_ptr);
|
mutex_lock(&f->sem);
|
||||||
|
return PTR_ERR(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pg_ptr = kmap(page);
|
||||||
|
mutex_lock(&f->sem);
|
||||||
|
|
||||||
offset = start;
|
offset = start;
|
||||||
while(offset < orig_end) {
|
while(offset < orig_end) {
|
||||||
uint32_t datalen;
|
uint32_t datalen;
|
||||||
@@ -1396,6 +1400,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jffs2_gc_release_page(c, pg_ptr, &pg);
|
kunmap(page);
|
||||||
|
put_page(page);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@@ -226,7 +226,7 @@ static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *r
|
|||||||
lastend = this->ofs + this->size;
|
lastend = this->ofs + this->size;
|
||||||
} else {
|
} else {
|
||||||
dbg_fragtree2("lookup gave no frag\n");
|
dbg_fragtree2("lookup gave no frag\n");
|
||||||
lastend = 0;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See if we ran off the end of the fragtree */
|
/* See if we ran off the end of the fragtree */
|
||||||
|
@@ -183,9 +183,6 @@ unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
|
|||||||
struct jffs2_inode_info *f,
|
struct jffs2_inode_info *f,
|
||||||
unsigned long offset,
|
unsigned long offset,
|
||||||
unsigned long *priv);
|
unsigned long *priv);
|
||||||
void jffs2_gc_release_page(struct jffs2_sb_info *c,
|
|
||||||
unsigned char *pg,
|
|
||||||
unsigned long *priv);
|
|
||||||
void jffs2_flash_cleanup(struct jffs2_sb_info *c);
|
void jffs2_flash_cleanup(struct jffs2_sb_info *c);
|
||||||
|
|
||||||
|
|
||||||
|
@@ -527,8 +527,11 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
|
|||||||
err = jffs2_fill_scan_buf(c, sumptr,
|
err = jffs2_fill_scan_buf(c, sumptr,
|
||||||
jeb->offset + c->sector_size - sumlen,
|
jeb->offset + c->sector_size - sumlen,
|
||||||
sumlen - buf_len);
|
sumlen - buf_len);
|
||||||
if (err)
|
if (err) {
|
||||||
|
if (sumlen > buf_size)
|
||||||
|
kfree(sumptr);
|
||||||
return err;
|
return err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -479,8 +479,10 @@ int __ubifs_node_verify_hmac(const struct ubifs_info *c, const void *node,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
err = ubifs_node_calc_hmac(c, node, len, ofs_hmac, hmac);
|
err = ubifs_node_calc_hmac(c, node, len, ofs_hmac, hmac);
|
||||||
if (err)
|
if (err) {
|
||||||
|
kfree(hmac);
|
||||||
return err;
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
err = crypto_memneq(hmac, node + ofs_hmac, hmac_len);
|
err = crypto_memneq(hmac, node + ofs_hmac, hmac_len);
|
||||||
|
|
||||||
|
@@ -2817,7 +2817,6 @@ void dbg_debugfs_init_fs(struct ubifs_info *c)
|
|||||||
c->vi.ubi_num, c->vi.vol_id);
|
c->vi.ubi_num, c->vi.vol_id);
|
||||||
if (n == UBIFS_DFS_DIR_LEN) {
|
if (n == UBIFS_DFS_DIR_LEN) {
|
||||||
/* The array size is too small */
|
/* The array size is too small */
|
||||||
fname = UBIFS_DFS_DIR_NAME;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2267,8 +2267,10 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = ubifs_fill_super(sb, data, flags & SB_SILENT ? 1 : 0);
|
err = ubifs_fill_super(sb, data, flags & SB_SILENT ? 1 : 0);
|
||||||
if (err)
|
if (err) {
|
||||||
|
kfree(c);
|
||||||
goto out_deact;
|
goto out_deact;
|
||||||
|
}
|
||||||
/* We do not support atime */
|
/* We do not support atime */
|
||||||
sb->s_flags |= SB_ACTIVE;
|
sb->s_flags |= SB_ACTIVE;
|
||||||
if (IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT))
|
if (IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT))
|
||||||
|
@@ -284,6 +284,7 @@ static int read_znode(struct ubifs_info *c, struct ubifs_zbranch *zzbr,
|
|||||||
err = ubifs_node_check_hash(c, idx, zzbr->hash);
|
err = ubifs_node_check_hash(c, idx, zzbr->hash);
|
||||||
if (err) {
|
if (err) {
|
||||||
ubifs_bad_hash(c, idx, zzbr->hash, lnum, offs);
|
ubifs_bad_hash(c, idx, zzbr->hash, lnum, offs);
|
||||||
|
kfree(idx);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user