diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-05-04 03:58:59 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-05-04 03:58:59 +0200 |
commit | 9f2692326b9c6db8d0e866d555606b12a507a363 (patch) | |
tree | 6cc3f63d9419aac5ee98d1ac4d43876509c4b3ab | |
parent | Merge tag 'pm-6.4-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/raf... (diff) | |
parent | ubifs: Fix memleak when insert_old_idx() failed (diff) | |
download | linux-9f2692326b9c6db8d0e866d555606b12a507a363.tar.xz linux-9f2692326b9c6db8d0e866d555606b12a507a363.zip |
Merge tag 'ubifs-for-linus-6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs
Pull UBI and UBIFS updates from Richard Weinberger:
"UBI:
- Fix error value for try_write_vid_and_data()
- Minor cleanups
UBIFS:
- Fixes for various memory leaks
- Minor cleanups"
* tag 'ubifs-for-linus-6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs:
ubifs: Fix memleak when insert_old_idx() failed
Revert "ubifs: dirty_cow_znode: Fix memleak in error handling path"
ubifs: Fix memory leak in do_rename
ubifs: Free memory for tmpfile name
ubi: Fix return value overwrite issue in try_write_vid_and_data()
ubifs: Remove return in compr_exit()
ubi: Simplify bool conversion
-rw-r--r-- | drivers/mtd/ubi/build.c | 2 | ||||
-rw-r--r-- | drivers/mtd/ubi/eba.c | 19 | ||||
-rw-r--r-- | fs/ubifs/compress.c | 1 | ||||
-rw-r--r-- | fs/ubifs/dir.c | 7 | ||||
-rw-r--r-- | fs/ubifs/tnc.c | 142 |
5 files changed, 102 insertions, 69 deletions
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 9cd565daad36..8b91a55ec0d2 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -1266,7 +1266,7 @@ static int __init ubi_init(void) mutex_lock(&ubi_devices_mutex); err = ubi_attach_mtd_dev(mtd, p->ubi_num, p->vid_hdr_offs, p->max_beb_per1024, - p->enable_fm == 0 ? true : false); + p->enable_fm == 0); mutex_unlock(&ubi_devices_mutex); if (err < 0) { pr_err("UBI error: cannot attach mtd%d\n", diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 403b79d6efd5..655ff41863e2 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -946,7 +946,7 @@ static int try_write_vid_and_data(struct ubi_volume *vol, int lnum, int offset, int len) { struct ubi_device *ubi = vol->ubi; - int pnum, opnum, err, vol_id = vol->vol_id; + int pnum, opnum, err, err2, vol_id = vol->vol_id; pnum = ubi_wl_get_peb(ubi); if (pnum < 0) { @@ -981,10 +981,19 @@ static int try_write_vid_and_data(struct ubi_volume *vol, int lnum, out_put: up_read(&ubi->fm_eba_sem); - if (err && pnum >= 0) - err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1); - else if (!err && opnum >= 0) - err = ubi_wl_put_peb(ubi, vol_id, lnum, opnum, 0); + if (err && pnum >= 0) { + err2 = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1); + if (err2) { + ubi_warn(ubi, "failed to return physical eraseblock %d, error %d", + pnum, err2); + } + } else if (!err && opnum >= 0) { + err2 = ubi_wl_put_peb(ubi, vol_id, lnum, opnum, 0); + if (err2) { + ubi_warn(ubi, "failed to return physical eraseblock %d, error %d", + opnum, err2); + } + } return err; } diff --git a/fs/ubifs/compress.c b/fs/ubifs/compress.c index 3a92e6af69b2..75461777c466 100644 --- a/fs/ubifs/compress.c +++ b/fs/ubifs/compress.c @@ -217,7 +217,6 @@ static void compr_exit(struct ubifs_compressor *compr) { if (compr->capi_name) crypto_free_comp(compr->cc); - return; } /** diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 1505539f6fe9..ef0499edc248 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -358,7 +358,6 @@ static struct inode *create_whiteout(struct inode *dir, struct dentry *dentry) umode_t mode = S_IFCHR | WHITEOUT_MODE; struct inode *inode; struct ubifs_info *c = dir->i_sb->s_fs_info; - struct fscrypt_name nm; /* * Create an inode('nlink = 1') for whiteout without updating journal, @@ -369,10 +368,6 @@ static struct inode *create_whiteout(struct inode *dir, struct dentry *dentry) dbg_gen("dent '%pd', mode %#hx in dir ino %lu", dentry, mode, dir->i_ino); - err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm); - if (err) - return ERR_PTR(err); - inode = ubifs_new_inode(c, dir, mode, false); if (IS_ERR(inode)) { err = PTR_ERR(inode); @@ -395,7 +390,6 @@ out_inode: make_bad_inode(inode); iput(inode); out_free: - fscrypt_free_filename(&nm); ubifs_err(c, "cannot create whiteout file, error %d", err); return ERR_PTR(err); } @@ -492,6 +486,7 @@ static int ubifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir, unlock_2_inodes(dir, inode); ubifs_release_budget(c, &req); + fscrypt_free_filename(&nm); return finish_open_simple(file, 0); diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c index 2469f72eeaab..6b7d95b65f4b 100644 --- a/fs/ubifs/tnc.c +++ b/fs/ubifs/tnc.c @@ -44,6 +44,33 @@ enum { NOT_ON_MEDIA = 3, }; +static void do_insert_old_idx(struct ubifs_info *c, + struct ubifs_old_idx *old_idx) +{ + struct ubifs_old_idx *o; + struct rb_node **p, *parent = NULL; + + p = &c->old_idx.rb_node; + while (*p) { + parent = *p; + o = rb_entry(parent, struct ubifs_old_idx, rb); + if (old_idx->lnum < o->lnum) + p = &(*p)->rb_left; + else if (old_idx->lnum > o->lnum) + p = &(*p)->rb_right; + else if (old_idx->offs < o->offs) + p = &(*p)->rb_left; + else if (old_idx->offs > o->offs) + p = &(*p)->rb_right; + else { + ubifs_err(c, "old idx added twice!"); + kfree(old_idx); + } + } + rb_link_node(&old_idx->rb, parent, p); + rb_insert_color(&old_idx->rb, &c->old_idx); +} + /** * insert_old_idx - record an index node obsoleted since the last commit start. * @c: UBIFS file-system description object @@ -69,35 +96,15 @@ enum { */ static int insert_old_idx(struct ubifs_info *c, int lnum, int offs) { - struct ubifs_old_idx *old_idx, *o; - struct rb_node **p, *parent = NULL; + struct ubifs_old_idx *old_idx; old_idx = kmalloc(sizeof(struct ubifs_old_idx), GFP_NOFS); if (unlikely(!old_idx)) return -ENOMEM; old_idx->lnum = lnum; old_idx->offs = offs; + do_insert_old_idx(c, old_idx); - p = &c->old_idx.rb_node; - while (*p) { - parent = *p; - o = rb_entry(parent, struct ubifs_old_idx, rb); - if (lnum < o->lnum) - p = &(*p)->rb_left; - else if (lnum > o->lnum) - p = &(*p)->rb_right; - else if (offs < o->offs) - p = &(*p)->rb_left; - else if (offs > o->offs) - p = &(*p)->rb_right; - else { - ubifs_err(c, "old idx added twice!"); - kfree(old_idx); - return 0; - } - } - rb_link_node(&old_idx->rb, parent, p); - rb_insert_color(&old_idx->rb, &c->old_idx); return 0; } @@ -199,23 +206,6 @@ static struct ubifs_znode *copy_znode(struct ubifs_info *c, __set_bit(DIRTY_ZNODE, &zn->flags); __clear_bit(COW_ZNODE, &zn->flags); - ubifs_assert(c, !ubifs_zn_obsolete(znode)); - __set_bit(OBSOLETE_ZNODE, &znode->flags); - - if (znode->level != 0) { - int i; - const int n = zn->child_cnt; - - /* The children now have new parent */ - for (i = 0; i < n; i++) { - struct ubifs_zbranch *zbr = &zn->zbranch[i]; - - if (zbr->znode) - zbr->znode->parent = zn; - } - } - - atomic_long_inc(&c->dirty_zn_cnt); return zn; } @@ -234,6 +224,42 @@ static int add_idx_dirt(struct ubifs_info *c, int lnum, int dirt) } /** + * replace_znode - replace old znode with new znode. + * @c: UBIFS file-system description object + * @new_zn: new znode + * @old_zn: old znode + * @zbr: the branch of parent znode + * + * Replace old znode with new znode in TNC. + */ +static void replace_znode(struct ubifs_info *c, struct ubifs_znode *new_zn, + struct ubifs_znode *old_zn, struct ubifs_zbranch *zbr) +{ + ubifs_assert(c, !ubifs_zn_obsolete(old_zn)); + __set_bit(OBSOLETE_ZNODE, &old_zn->flags); + + if (old_zn->level != 0) { + int i; + const int n = new_zn->child_cnt; + + /* The children now have new parent */ + for (i = 0; i < n; i++) { + struct ubifs_zbranch *child = &new_zn->zbranch[i]; + + if (child->znode) + child->znode->parent = new_zn; + } + } + + zbr->znode = new_zn; + zbr->lnum = 0; + zbr->offs = 0; + zbr->len = 0; + + atomic_long_inc(&c->dirty_zn_cnt); +} + +/** * dirty_cow_znode - ensure a znode is not being committed. * @c: UBIFS file-system description object * @zbr: branch of znode to check @@ -265,28 +291,32 @@ static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c, return zn; if (zbr->len) { - err = insert_old_idx(c, zbr->lnum, zbr->offs); - if (unlikely(err)) - /* - * Obsolete znodes will be freed by tnc_destroy_cnext() - * or free_obsolete_znodes(), copied up znodes should - * be added back to tnc and freed by - * ubifs_destroy_tnc_subtree(). - */ + struct ubifs_old_idx *old_idx; + + old_idx = kmalloc(sizeof(struct ubifs_old_idx), GFP_NOFS); + if (unlikely(!old_idx)) { + err = -ENOMEM; goto out; + } + old_idx->lnum = zbr->lnum; + old_idx->offs = zbr->offs; + err = add_idx_dirt(c, zbr->lnum, zbr->len); - } else - err = 0; + if (err) { + kfree(old_idx); + goto out; + } -out: - zbr->znode = zn; - zbr->lnum = 0; - zbr->offs = 0; - zbr->len = 0; + do_insert_old_idx(c, old_idx); + } + + replace_znode(c, zn, znode, zbr); - if (unlikely(err)) - return ERR_PTR(err); return zn; + +out: + kfree(zn); + return ERR_PTR(err); } /** |