diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 35bdb62944a2..0cebcaf82426 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -963,6 +963,16 @@ int fat_dir_empty(struct inode *dir) } EXPORT_SYMBOL_GPL(fat_dir_empty); +void fat_dir_drop_nlink(struct inode *dir) +{ + if (dir->i_nlink >= 3) + drop_nlink(dir); + else + fat_fs_error(dir->i_sb, "parent dir link count too low (%u)", + dir->i_nlink); +} +EXPORT_SYMBOL_GPL(fat_dir_drop_nlink); + /* * fat_subdirs counts the number of sub-directories of dir. It can be run * on directories being created. diff --git a/fs/fat/fat.h b/fs/fat/fat.h index 76978a268410..a8a3ca4f465b 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h @@ -332,6 +332,7 @@ extern const struct file_operations fat_dir_operations; extern int fat_search_long(struct inode *inode, const unsigned char *name, int name_len, struct fat_slot_info *sinfo); extern int fat_dir_empty(struct inode *dir); +void fat_dir_drop_nlink(struct inode *dir); extern int fat_subdirs(struct inode *dir); extern int fat_scan(struct inode *dir, const unsigned char *name, struct fat_slot_info *sinfo); diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index c7500c2859e0..5a43d042eb01 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -333,12 +333,7 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) err = fat_remove_entries(dir, &sinfo); /* and releases bh */ if (err) goto out; - if (dir->i_nlink >= 3) - drop_nlink(dir); - else { - fat_fs_error(sb, "parent dir link count too low (%u)", - dir->i_nlink); - } + fat_dir_drop_nlink(dir); clear_nlink(inode); fat_detach(inode); @@ -565,6 +560,8 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name, (void)sync_inode_metadata(old_dir, 1); if (new_inode) { + if (is_dir && old_dir == new_dir) + fat_dir_drop_nlink(old_dir); drop_nlink(new_inode); if (is_dir) drop_nlink(new_inode); diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index ff7652bf0410..791f2d7b8509 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -809,12 +809,7 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry) err = fat_remove_entries(dir, &sinfo); /* and releases bh */ if (err) goto out; - if (dir->i_nlink >= 3) - drop_nlink(dir); - else { - fat_fs_error(sb, "parent dir link count too low (%u)", - dir->i_nlink); - } + fat_dir_drop_nlink(dir); clear_nlink(inode); fat_truncate_time(inode, NULL, FAT_UPDATE_ATIME | FAT_UPDATE_CMTIME); @@ -1011,6 +1006,8 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry, vfat_update_dir_metadata(old_dir, &ts); if (new_inode) { + if (is_dir && old_dir == new_dir) + fat_dir_drop_nlink(old_dir); drop_nlink(new_inode); if (is_dir) drop_nlink(new_inode);