From: Jeff Mahoney <jeffm@xxxxxxxx> In reiserfs_rename, we check to ensure that the old directory entry is pointing to the expected inode but we don't check the new directory entry or the .. entry. Typically this isn't a problem, but in the retry loop we check to see if the entry is pointing to the expected inode after scheduling and assume that we must repeat the search if it doesn't match. If the directory entry has been corrupted, we will loop forever. This patch performs the check immediately after performing the search so that if there is an error, we can return appropriately. Signed-off-by: Jeff Mahoney <jeffm@xxxxxxxx> --- fs/reiserfs/namei.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index 97f3fc4fdd79..5be509a9204f 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -1282,7 +1282,7 @@ static int entry_points_to_object(const char *name, int len, /* this must be added hidden entry */ if (de_visible(de->de_deh + de->de_entry_num)) - reiserfs_panic(NULL, "vs-7043", "entry must be visible"); + reiserfs_panic(NULL, "vs-7043", "entry must be invisible"); return 1; } @@ -1389,7 +1389,8 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry, reiserfs_find_entry(old_inode, "..", 2, &dot_dot_entry_path, &dot_dot_de); pathrelse(&dot_dot_entry_path); - if (retval != NAME_FOUND) { + if (retval != NAME_FOUND || + dot_dot_de.de_objectid != old_dir->i_ino) { reiserfs_write_unlock(old_dir->i_sb); return -EIO; } @@ -1473,6 +1474,33 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry, return -EIO; } + /* + * If this entry is corrupted and points somewhere else, + * we'll loop forever as we check to ensure it points to + * the expected object in the sanity check below. Since + * we can't have scheduled yet after finding this one, + * check it now so we can bail early. + */ + if (new_dentry_inode && + new_de.de_objectid != new_dentry_inode->i_ino) { + struct reiserfs_key *key = INODE_PKEY(new_dentry_inode); + + reiserfs_error(old_inode->i_sb, "namei-7055", +"directory entry for %.*s points to [%u, %u]; expected [%u, %u], ino %lu", + new_dentry->d_name.len, + new_dentry->d_name.name, + new_de.de_dir_id, new_de.de_objectid, + le32_to_cpu(key->k_dir_id), + le32_to_cpu(key->k_objectid), + new_dentry_inode->i_ino); + + pathrelse(&new_entry_path); + pathrelse(&old_entry_path); + journal_end(&th); + reiserfs_write_unlock(old_dir->i_sb); + return -EIO; + } + copy_item_head(&new_entry_ih, tp_item_head(&new_entry_path)); reiserfs_prepare_for_journal(old_inode->i_sb, new_de.de_bh, 1); -- 2.16.4