--- fs/overlayfs/dir.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -819,6 +819,20 @@ static bool ovl_pure_upper(struct dentry !ovl_test_flag(OVL_WHITEOUTS, d_inode(dentry)); } +static void ovl_drop_nlink(struct inode *inode) +{ + struct dentry *alias = d_find_alias(inode); + + dput(alias); + /* + * Changes to underlying layers may cause i_nlink to lose sync with + * reality. In this case prevent the link count from going to zero + * prematurely. + */ + if (inode->i_nlink > !!alias) + drop_nlink(inode); +} + static int ovl_do_remove(struct dentry *dentry, bool is_dir) { int err; @@ -856,7 +870,7 @@ static int ovl_do_remove(struct dentry * if (is_dir) clear_nlink(dentry->d_inode); else - drop_nlink(dentry->d_inode); + ovl_drop_nlink(dentry->d_inode); } ovl_nlink_end(dentry); @@ -1201,7 +1215,7 @@ static int ovl_rename(struct inode *oldd if (new_is_dir) clear_nlink(d_inode(new)); else - drop_nlink(d_inode(new)); + ovl_drop_nlink(d_inode(new)); } ovl_dir_modified(old->d_parent, ovl_type_origin(old) ||