diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 5dc2fd843ae3..08cc7407ec6e 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2991,8 +2991,8 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
 	err = btrfs_delete_subvolume(dir, dentry);
 	btrfs_inode_unlock(inode, 0);
 	if (!err) {
-		fsnotify_rmdir(dir, dentry);
 		d_delete(dentry);
+		fsnotify_rmdir(dir, inode, dentry);
 	}
 
 out_dput:
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index ac5e0c0e9181..3714791a3dd9 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -1792,6 +1792,7 @@ void configfs_unregister_group(struct config_group *group)
 	struct dentry *parent = group->cg_item.ci_parent->ci_dentry;
 	struct configfs_dirent *sd = dentry->d_fsdata;
 	struct configfs_fragment *frag = sd->s_frag;
+	struct inode *inode;
 
 	down_write(&frag->frag_sem);
 	frag->frag_dead = true;
@@ -1803,10 +1804,13 @@ void configfs_unregister_group(struct config_group *group)
 	spin_unlock(&configfs_dirent_lock);
 
 	configfs_detach_group(&group->cg_item);
-	d_inode(dentry)->i_flags |= S_DEAD;
+	inode = d_inode(dentry);
+	ihold(inode);
+	inode->i_flags |= S_DEAD;
 	dont_mount(dentry);
-	fsnotify_rmdir(d_inode(parent), dentry);
 	d_delete(dentry);
+	fsnotify_rmdir(d_inode(parent), inode, dentry);
+	iput(inode);
 	inode_unlock(d_inode(parent));
 
 	dput(dentry);
@@ -1924,6 +1928,7 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys)
 	struct dentry *root = dentry->d_sb->s_root;
 	struct configfs_dirent *sd = dentry->d_fsdata;
 	struct configfs_fragment *frag = sd->s_frag;
+	struct inode *inode;
 
 	if (dentry->d_parent != root) {
 		pr_err("Tried to unregister non-subsystem!\n");
@@ -1945,12 +1950,15 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys)
 	spin_unlock(&configfs_dirent_lock);
 	mutex_unlock(&configfs_symlink_mutex);
 	configfs_detach_group(&group->cg_item);
-	d_inode(dentry)->i_flags |= S_DEAD;
+	inode = d_inode(dentry);
+	ihold(inode);
+	inode->i_flags |= S_DEAD;
 	dont_mount(dentry);
-	fsnotify_rmdir(d_inode(root), dentry);
 	inode_unlock(d_inode(dentry));
 
 	d_delete(dentry);
+	fsnotify_rmdir(d_inode(root), inode, dentry);
+	iput(inode);
 
 	inode_unlock(d_inode(root));
 
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 42e5a766d33c..59a0420b04e3 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -617,12 +617,16 @@ void *devpts_get_priv(struct dentry *dentry)
  */
 void devpts_pty_kill(struct dentry *dentry)
 {
+	struct inode *inode;
 	WARN_ON_ONCE(dentry->d_sb->s_magic != DEVPTS_SUPER_MAGIC);
 
 	dentry->d_fsdata = NULL;
-	drop_nlink(dentry->d_inode);
-	fsnotify_unlink(d_inode(dentry->d_parent), dentry);
+	inode = dentry->d_inode;
+	ihold(inode);
+	drop_nlink(inode);
 	d_drop(dentry);
+	fsnotify_unlink(d_inode(dentry->d_parent), inode, dentry);
+	iput(inode);
 	dput(dentry);	/* d_alloc_name() in devpts_pty_new() */
 }
 
diff --git a/fs/libfs.c b/fs/libfs.c
index e9b29c6ffccb..2006d340a58d 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -272,6 +272,7 @@ void simple_recursive_removal(struct dentry *dentry,
 	while (true) {
 		struct dentry *victim = NULL, *child;
 		struct inode *inode = this->d_inode;
+		struct inode *victim_inode = NULL;
 
 		inode_lock(inode);
 		if (d_is_dir(this))
@@ -283,19 +284,24 @@ void simple_recursive_removal(struct dentry *dentry,
 			clear_nlink(inode);
 			inode_unlock(inode);
 			victim = this;
+			victim_inode = victim->d_inode;
+			ihold(victim_inode);
 			this = this->d_parent;
 			inode = this->d_inode;
 			inode_lock(inode);
 			if (simple_positive(victim)) {
 				d_invalidate(victim);	// avoid lost mounts
 				if (d_is_dir(victim))
-					fsnotify_rmdir(inode, victim);
+					fsnotify_rmdir(inode, victim_inode,
+						       victim);
 				else
-					fsnotify_unlink(inode, victim);
+					fsnotify_unlink(inode, victim_inode,
+							victim);
 				if (callback)
 					callback(victim);
 				dput(victim);		// unpin it
 			}
+			iput(victim_inode);
 			if (victim == dentry) {
 				inode->i_ctime = inode->i_mtime =
 					current_time(inode);
diff --git a/fs/namei.c b/fs/namei.c
index 79b0ff9b151e..23ce7aab43a5 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3873,6 +3873,7 @@ SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode)
 int vfs_rmdir(struct user_namespace *mnt_userns, struct inode *dir,
 		     struct dentry *dentry)
 {
+	struct inode *inode;
 	int error = may_delete(mnt_userns, dir, dentry, 1);
 
 	if (error)
@@ -3882,7 +3883,9 @@ int vfs_rmdir(struct user_namespace *mnt_userns, struct inode *dir,
 		return -EPERM;
 
 	dget(dentry);
-	inode_lock(dentry->d_inode);
+	inode = dentry->d_inode;
+	ihold(inode);
+	inode_lock(inode);
 
 	error = -EBUSY;
 	if (is_local_mountpoint(dentry))
@@ -3897,16 +3900,18 @@ int vfs_rmdir(struct user_namespace *mnt_userns, struct inode *dir,
 		goto out;
 
 	shrink_dcache_parent(dentry);
-	dentry->d_inode->i_flags |= S_DEAD;
+	inode->i_flags |= S_DEAD;
 	dont_mount(dentry);
 	detach_mounts(dentry);
-	fsnotify_rmdir(dir, dentry);
 
 out:
-	inode_unlock(dentry->d_inode);
+	inode_unlock(inode);
 	dput(dentry);
-	if (!error)
+	if (!error) {
 		d_delete(dentry);
+		fsnotify_rmdir(dir, inode, dentry);
+	}
+	iput(inode);
 	return error;
 }
 EXPORT_SYMBOL(vfs_rmdir);
@@ -4026,7 +4031,6 @@ int vfs_unlink(struct user_namespace *mnt_userns, struct inode *dir,
 			if (!error) {
 				dont_mount(dentry);
 				detach_mounts(dentry);
-				fsnotify_unlink(dir, dentry);
 			}
 		}
 	}
@@ -4037,6 +4041,7 @@ int vfs_unlink(struct user_namespace *mnt_userns, struct inode *dir,
 	if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) {
 		fsnotify_link_count(target);
 		d_delete(dentry);
+		fsnotify_unlink(dir, target, dentry);
 	}
 
 	return error;
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index f8acddcf54fb..40303704cec1 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -208,12 +208,10 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode,
  *
  * Caller must make sure that dentry->d_name is stable.
  */
-static inline void fsnotify_unlink(struct inode *dir, struct dentry *dentry)
+static inline void fsnotify_unlink(struct inode *dir, struct inode *inode,
+				   struct dentry *dentry)
 {
-	/* Expected to be called before d_delete() */
-	WARN_ON_ONCE(d_is_negative(dentry));
-
-	fsnotify_dirent(dir, dentry, FS_DELETE);
+	fsnotify_name(dir, FS_DELETE, inode, &dentry->d_name, 0);
 }
 
 /*
@@ -231,12 +229,10 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
  *
  * Caller must make sure that dentry->d_name is stable.
  */
-static inline void fsnotify_rmdir(struct inode *dir, struct dentry *dentry)
+static inline void fsnotify_rmdir(struct inode *dir, struct inode *inode,
+				  struct dentry *dentry)
 {
-	/* Expected to be called before d_delete() */
-	WARN_ON_ONCE(d_is_negative(dentry));
-
-	fsnotify_dirent(dir, dentry, FS_DELETE | FS_ISDIR);
+	fsnotify_name(dir, FS_DELETE | FS_ISDIR, inode, &dentry->d_name, 0);
 }
 
 /*
