aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ubifs/dir.c
diff options
context:
space:
mode:
authorArtem Bityutskiy <artem.bityutskiy@linux.intel.com>2012-02-07 03:58:51 -0500
committerArtem Bityutskiy <artem.bityutskiy@linux.intel.com>2012-02-29 09:10:20 -0500
commitc43be1085f8480ab36d5c8c76a08e67bdf6d2e18 (patch)
tree5d77b528c065e6d5c542c631634cd440ae3938ac /fs/ubifs/dir.c
parentb06283c7df35b5a49ab141ed38e0280821379096 (diff)
UBIFS: do not use inc_link when i_nlink is zero
This patch changes the 'i_nlink' counter handling in 'ubifs_unlink()', 'ubifs_rmdir()' and 'ubifs_rename()'. In these function 'i_nlink' may become 0, and if 'ubifs_jnl_update()' failed, we would use 'inc_nlink()' to restore the previous 'i_nlink' value, which is incorrect from the VFS point of view and would cause a 'WARN_ON()' (see 'inc_nlink() implementation). This patches saves the previous 'i_nlink' value in a local variable and uses it at the error path instead of calling 'inc_nlink()'. We do this only for the inodes where 'i_nlink' may potentially become zero. This change has been requested by Al Viro <viro@ZenIV.linux.org.uk>. Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Diffstat (limited to 'fs/ubifs/dir.c')
-rw-r--r--fs/ubifs/dir.c18
1 files changed, 9 insertions, 9 deletions
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index d6fe1c79f18b..ec9f1870ab7f 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -566,6 +566,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
566 int sz_change = CALC_DENT_SIZE(dentry->d_name.len); 566 int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
567 int err, budgeted = 1; 567 int err, budgeted = 1;
568 struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 }; 568 struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 };
569 unsigned int saved_nlink = inode->i_nlink;
569 570
570 /* 571 /*
571 * Budget request settings: deletion direntry, deletion inode (+1 for 572 * Budget request settings: deletion direntry, deletion inode (+1 for
@@ -613,7 +614,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
613out_cancel: 614out_cancel:
614 dir->i_size += sz_change; 615 dir->i_size += sz_change;
615 dir_ui->ui_size = dir->i_size; 616 dir_ui->ui_size = dir->i_size;
616 inc_nlink(inode); 617 set_nlink(inode, saved_nlink);
617 unlock_2_inodes(dir, inode); 618 unlock_2_inodes(dir, inode);
618 if (budgeted) 619 if (budgeted)
619 ubifs_release_budget(c, &req); 620 ubifs_release_budget(c, &req);
@@ -704,8 +705,7 @@ out_cancel:
704 dir->i_size += sz_change; 705 dir->i_size += sz_change;
705 dir_ui->ui_size = dir->i_size; 706 dir_ui->ui_size = dir->i_size;
706 inc_nlink(dir); 707 inc_nlink(dir);
707 inc_nlink(inode); 708 set_nlink(inode, 2);
708 inc_nlink(inode);
709 unlock_2_inodes(dir, inode); 709 unlock_2_inodes(dir, inode);
710 if (budgeted) 710 if (budgeted)
711 ubifs_release_budget(c, &req); 711 ubifs_release_budget(c, &req);
@@ -977,6 +977,7 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
977 struct ubifs_budget_req ino_req = { .dirtied_ino = 1, 977 struct ubifs_budget_req ino_req = { .dirtied_ino = 1,
978 .dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) }; 978 .dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) };
979 struct timespec time; 979 struct timespec time;
980 unsigned int saved_nlink;
980 981
981 /* 982 /*
982 * Budget request settings: deletion direntry, new direntry, removing 983 * Budget request settings: deletion direntry, new direntry, removing
@@ -1059,13 +1060,14 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
1059 if (unlink) { 1060 if (unlink) {
1060 /* 1061 /*
1061 * Directories cannot have hard-links, so if this is a 1062 * Directories cannot have hard-links, so if this is a
1062 * directory, decrement its @i_nlink twice because an empty 1063 * directory, just clear @i_nlink.
1063 * directory has @i_nlink 2.
1064 */ 1064 */
1065 saved_nlink = new_inode->i_nlink;
1065 if (is_dir) 1066 if (is_dir)
1067 clear_nlink(new_inode);
1068 else
1066 drop_nlink(new_inode); 1069 drop_nlink(new_inode);
1067 new_inode->i_ctime = time; 1070 new_inode->i_ctime = time;
1068 drop_nlink(new_inode);
1069 } else { 1071 } else {
1070 new_dir->i_size += new_sz; 1072 new_dir->i_size += new_sz;
1071 ubifs_inode(new_dir)->ui_size = new_dir->i_size; 1073 ubifs_inode(new_dir)->ui_size = new_dir->i_size;
@@ -1102,9 +1104,7 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
1102 1104
1103out_cancel: 1105out_cancel:
1104 if (unlink) { 1106 if (unlink) {
1105 if (is_dir) 1107 set_nlink(new_inode, saved_nlink);
1106 inc_nlink(new_inode);
1107 inc_nlink(new_inode);
1108 } else { 1108 } else {
1109 new_dir->i_size -= new_sz; 1109 new_dir->i_size -= new_sz;
1110 ubifs_inode(new_dir)->ui_size = new_dir->i_size; 1110 ubifs_inode(new_dir)->ui_size = new_dir->i_size;