| From 92a8aec1258caacf4dbb222020649affae3e5e55 Mon Sep 17 00:00:00 2001 |
| From: Zhihao Cheng <chengzhihao1@huawei.com> |
| Date: Tue, 7 Jul 2020 20:51:40 +0800 |
| Subject: [PATCH] ubifs: Fix wrong orphan node deletion in |
| ubifs_jnl_update|rename |
| |
| commit 094b6d1295474f338201b846a1f15e72eb0b12cf upstream. |
| |
| There a wrong orphan node deleting in error handling path in |
| ubifs_jnl_update() and ubifs_jnl_rename(), which may cause |
| following error msg: |
| |
| UBIFS error (ubi0:0 pid 1522): ubifs_delete_orphan [ubifs]: |
| missing orphan ino 65 |
| |
| Fix this by checking whether the node has been operated for |
| adding to orphan list before being deleted, |
| |
| Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com> |
| Fixes: 823838a486888cf484e ("ubifs: Add hashes to the tree node cache") |
| Signed-off-by: Richard Weinberger <richard@nod.at> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c |
| index 826dad0243dc..a6ae2428e4c9 100644 |
| --- a/fs/ubifs/journal.c |
| +++ b/fs/ubifs/journal.c |
| @@ -539,7 +539,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, |
| const struct fscrypt_name *nm, const struct inode *inode, |
| int deletion, int xent) |
| { |
| - int err, dlen, ilen, len, lnum, ino_offs, dent_offs; |
| + int err, dlen, ilen, len, lnum, ino_offs, dent_offs, orphan_added = 0; |
| int aligned_dlen, aligned_ilen, sync = IS_DIRSYNC(dir); |
| int last_reference = !!(deletion && inode->i_nlink == 0); |
| struct ubifs_inode *ui = ubifs_inode(inode); |
| @@ -630,6 +630,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, |
| goto out_finish; |
| } |
| ui->del_cmtno = c->cmt_no; |
| + orphan_added = 1; |
| } |
| |
| err = write_head(c, BASEHD, dent, len, &lnum, &dent_offs, sync); |
| @@ -702,7 +703,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, |
| kfree(dent); |
| out_ro: |
| ubifs_ro_mode(c, err); |
| - if (last_reference) |
| + if (orphan_added) |
| ubifs_delete_orphan(c, inode->i_ino); |
| finish_reservation(c); |
| return err; |
| @@ -1217,7 +1218,7 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, |
| void *p; |
| union ubifs_key key; |
| struct ubifs_dent_node *dent, *dent2; |
| - int err, dlen1, dlen2, ilen, lnum, offs, len; |
| + int err, dlen1, dlen2, ilen, lnum, offs, len, orphan_added = 0; |
| int aligned_dlen1, aligned_dlen2, plen = UBIFS_INO_NODE_SZ; |
| int last_reference = !!(new_inode && new_inode->i_nlink == 0); |
| int move = (old_dir != new_dir); |
| @@ -1333,6 +1334,7 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, |
| goto out_finish; |
| } |
| new_ui->del_cmtno = c->cmt_no; |
| + orphan_added = 1; |
| } |
| |
| err = write_head(c, BASEHD, dent, len, &lnum, &offs, sync); |
| @@ -1414,7 +1416,7 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, |
| release_head(c, BASEHD); |
| out_ro: |
| ubifs_ro_mode(c, err); |
| - if (last_reference) |
| + if (orphan_added) |
| ubifs_delete_orphan(c, new_inode->i_ino); |
| out_finish: |
| finish_reservation(c); |
| -- |
| 2.27.0 |
| |