diff mbox series

[RFC,1/4] fs: create simple_remove() helper

Message ID 20190514221901.29125-2-amir73il@gmail.com (mailing list archive)
State New, archived
Headers show
Series Sort out fsnotify_nameremove() mess | expand

Commit Message

Amir Goldstein May 14, 2019, 10:18 p.m. UTC
There is a common pattern among pseudo filesystems for removing a dentry
from code paths that are NOT coming from vfs_{unlink,rmdir}, using a
combination of simple_{unlink,rmdir} and d_delete().

Create an helper to perform this common operation.  This helper is going
to be used as a place holder for the new fsnotify_remove() hook.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/libfs.c         | 22 ++++++++++++++++++++++
 include/linux/fs.h |  1 +
 2 files changed, 23 insertions(+)

Comments

Jan Kara May 15, 2019, 7:51 a.m. UTC | #1
On Wed 15-05-19 01:18:58, Amir Goldstein wrote:
> There is a common pattern among pseudo filesystems for removing a dentry
> from code paths that are NOT coming from vfs_{unlink,rmdir}, using a
> combination of simple_{unlink,rmdir} and d_delete().
> 
> Create an helper to perform this common operation.  This helper is going
> to be used as a place holder for the new fsnotify_remove() hook.
> 
> Signed-off-by: Amir Goldstein <amir73il@gmail.com>

Looks like a good idea. One comment below:

> +/*
> + * Unlike simple_unlink/rmdir, this helper is NOT called from vfs_unlink/rmdir.
> + * Caller must guaranty that d_parent and d_name are stable.
> + */
> +int simple_remove(struct inode *dir, struct dentry *dentry)
> +{
> +	int ret;
> +
> +	dget(dentry);
> +	if (d_is_dir(dentry))
> +		ret = simple_rmdir(dir, dentry);
> +	else
> +		ret = simple_unlink(dir, dentry);
> +
> +	if (!ret)
> +		d_delete(dentry);
> +	dput(dentry);

This dget() - dput() pair looks fishy. After some research I understand why
it's needed but I think it deserves a comment like:

	/*
	 * 'simple_' operations get dentry reference on create/mkdir and drop
	 * it on unlink/rmdir. So we have to get dentry reference here to
	 * protect d_delete() from accessing freed dentry.
	 */

								Honza
diff mbox series

Patch

diff --git a/fs/libfs.c b/fs/libfs.c
index 4b59b1816efb..030e67c52b5f 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -353,6 +353,28 @@  int simple_rmdir(struct inode *dir, struct dentry *dentry)
 }
 EXPORT_SYMBOL(simple_rmdir);
 
+/*
+ * Unlike simple_unlink/rmdir, this helper is NOT called from vfs_unlink/rmdir.
+ * Caller must guaranty that d_parent and d_name are stable.
+ */
+int simple_remove(struct inode *dir, struct dentry *dentry)
+{
+	int ret;
+
+	dget(dentry);
+	if (d_is_dir(dentry))
+		ret = simple_rmdir(dir, dentry);
+	else
+		ret = simple_unlink(dir, dentry);
+
+	if (!ret)
+		d_delete(dentry);
+	dput(dentry);
+
+	return ret;
+}
+EXPORT_SYMBOL(simple_remove);
+
 int simple_rename(struct inode *old_dir, struct dentry *old_dentry,
 		  struct inode *new_dir, struct dentry *new_dentry,
 		  unsigned int flags)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index f7fdfe93e25d..74ea5f0b3b9d 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -3245,6 +3245,7 @@  extern int simple_open(struct inode *inode, struct file *file);
 extern int simple_link(struct dentry *, struct inode *, struct dentry *);
 extern int simple_unlink(struct inode *, struct dentry *);
 extern int simple_rmdir(struct inode *, struct dentry *);
+extern int simple_remove(struct inode *, struct dentry *);
 extern int simple_rename(struct inode *, struct dentry *,
 			 struct inode *, struct dentry *, unsigned int);
 extern int noop_fsync(struct file *, loff_t, loff_t, int);