From: Jeff Mahoney <jeffm@xxxxxxxx> If a directory entry has been corrupted such that the flags reflect a different visibility state than expected, we will panic the node. This patch instead returns -EIO and sets the file system read-only. Signed-off-by: Jeff Mahoney <jeffm@xxxxxxxx> --- fs/reiserfs/namei.c | 108 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 67 insertions(+), 41 deletions(-) diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index 5be509a9204f..01e788f91a1d 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -1254,7 +1254,7 @@ static int reiserfs_link(struct dentry *old_dentry, struct inode *dir, /* de contains information pointing to an entry which */ static int de_still_valid(const char *name, int len, - struct reiserfs_dir_entry *de) + const struct reiserfs_dir_entry *de) { struct reiserfs_dir_entry tmp = *de; @@ -1266,23 +1266,31 @@ static int de_still_valid(const char *name, int len, return 1; } -static int entry_points_to_object(const char *name, int len, - struct reiserfs_dir_entry *de, - struct inode *inode) +static int entry_points_to_object(const struct inode *dir, + const char *name, int len, + const struct reiserfs_dir_entry *de, + const struct inode *inode) { if (!de_still_valid(name, len, de)) return 0; if (inode) { - if (!de_visible(de->de_deh + de->de_entry_num)) - reiserfs_panic(inode->i_sb, "vs-7042", - "entry must be visible"); + if (!de_visible(de->de_deh + de->de_entry_num)) { + reiserfs_error(dir->i_sb, "vs-7042", + "entry must be visible (%.*s in dir %k", + len, name, INODE_PKEY(dir)); + return -EIO; + } return (de->de_objectid == inode->i_ino) ? 1 : 0; } /* this must be added hidden entry */ - if (de_visible(de->de_deh + de->de_entry_num)) - reiserfs_panic(NULL, "vs-7043", "entry must be invisible"); + if (de_visible(de->de_deh + de->de_entry_num)) { + reiserfs_error(dir->i_sb, "vs-7043", + "entry must be invisible (%.*s in dir %k", + len, name, INODE_PKEY(dir)); + return -EIO; + } return 1; } @@ -1541,47 +1549,65 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry, * of the above checks could have scheduled. We have to be * sure our items haven't been shifted by another process. */ - if (item_moved(&new_entry_ih, &new_entry_path) || - !entry_points_to_object(new_dentry->d_name.name, - new_dentry->d_name.len, - &new_de, new_dentry_inode) || - item_moved(&old_entry_ih, &old_entry_path) || - !entry_points_to_object(old_dentry->d_name.name, - old_dentry->d_name.len, - &old_de, old_inode)) { - reiserfs_restore_prepared_buffer(old_inode->i_sb, - new_de.de_bh); - reiserfs_restore_prepared_buffer(old_inode->i_sb, - old_de.de_bh); - if (S_ISDIR(old_inode_mode)) - reiserfs_restore_prepared_buffer(old_inode-> - i_sb, - dot_dot_de. - de_bh); - continue; + if (item_moved(&new_entry_ih, &new_entry_path)) { + retval = 0; + goto restore; } + + retval = entry_points_to_object(new_dir, + new_dentry->d_name.name, + new_dentry->d_name.len, + &new_de, new_dentry_inode); + if (retval != 1) + goto restore; + + if (item_moved(&old_entry_ih, &old_entry_path)) { + retval = 0; + goto restore; + } + + retval = entry_points_to_object(old_dir, + old_dentry->d_name.name, + old_dentry->d_name.len, + &old_de, old_inode); + if (retval != 1) + goto restore; + if (S_ISDIR(old_inode_mode)) { - if (item_moved(&dot_dot_ih, &dot_dot_entry_path) || - !entry_points_to_object("..", 2, &dot_dot_de, - old_dir)) { - reiserfs_restore_prepared_buffer(old_inode-> - i_sb, - old_de.de_bh); - reiserfs_restore_prepared_buffer(old_inode-> - i_sb, - new_de.de_bh); - reiserfs_restore_prepared_buffer(old_inode-> - i_sb, - dot_dot_de. - de_bh); - continue; + if (item_moved(&dot_dot_ih, &dot_dot_entry_path)) { + retval = 0; + goto restore; } + + retval = entry_points_to_object(old_dir, "..", 2, + &dot_dot_de, old_dir); + if (retval != 1) + goto restore; } + retval = 0; + RFALSE(S_ISDIR(old_inode_mode) && !buffer_journal_prepared(dot_dot_de.de_bh), ""); break; + +restore: + reiserfs_restore_prepared_buffer(old_inode->i_sb, + new_de.de_bh); + reiserfs_restore_prepared_buffer(old_inode->i_sb, + old_de.de_bh); + if (S_ISDIR(old_inode_mode)) + reiserfs_restore_prepared_buffer(old_inode->i_sb, + dot_dot_de.de_bh); + if (retval) { + pathrelse(&dot_dot_entry_path); + pathrelse(&new_entry_path); + pathrelse(&old_entry_path); + journal_end(&th, old_dir->i_sb, jbegin_count); + reiserfs_write_unlock(old_dir->i_sb); + return retval; + } } /* -- 2.16.4