vfs: rename parent_ino to d_parent_ino and make it use RCU
authorMateusz Guzik <mjguzik@gmail.com>
Thu, 27 Jun 2024 16:11:52 +0000 (18:11 +0200)
committerChristian Brauner <brauner@kernel.org>
Thu, 27 Jun 2024 16:34:21 +0000 (18:34 +0200)
The routine is used by procfs through dir_emit_dots.

The combined RCU and lock fallback implementation is too big for an
inline. Given that the routine takes a dentry argument fs/dcache.c seems
like the place to put it in.

Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Link: https://lore.kernel.org/r/20240627161152.802567-1-mjguzik@gmail.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/dcache.c
fs/f2fs/file.c
fs/hfsplus/ioctl.c
include/linux/dcache.h
include/linux/fs.h

index 58b89c9e9b0c8bc9af03df00b19fa666752d20b5..68e843e78337d7ca2c058b13c8f78f5172872400 100644 (file)
@@ -3099,6 +3099,34 @@ void d_tmpfile(struct file *file, struct inode *inode)
 }
 EXPORT_SYMBOL(d_tmpfile);
 
+/*
+ * Obtain inode number of the parent dentry.
+ */
+ino_t d_parent_ino(struct dentry *dentry)
+{
+       struct dentry *parent;
+       struct inode *iparent;
+       unsigned seq;
+       ino_t ret;
+
+       scoped_guard(rcu) {
+               seq = raw_seqcount_begin(&dentry->d_seq);
+               parent = READ_ONCE(dentry->d_parent);
+               iparent = d_inode_rcu(parent);
+               if (likely(iparent)) {
+                       ret = iparent->i_ino;
+                       if (!read_seqcount_retry(&dentry->d_seq, seq))
+                               return ret;
+               }
+       }
+
+       spin_lock(&dentry->d_lock);
+       ret = dentry->d_parent->d_inode->i_ino;
+       spin_unlock(&dentry->d_lock);
+       return ret;
+}
+EXPORT_SYMBOL(d_parent_ino);
+
 static __initdata unsigned long dhash_entries;
 static int __init set_dhash_entries(char *str)
 {
index 7a23434963d1711f22964a8ae591df8bdcbb65b8..c1ad9b278c477dbd1275cba187e01e43b5514343 100644 (file)
@@ -185,7 +185,7 @@ static int get_parent_ino(struct inode *inode, nid_t *pino)
        if (!dentry)
                return 0;
 
-       *pino = parent_ino(dentry);
+       *pino = d_parent_ino(dentry);
        dput(dentry);
        return 1;
 }
index 5661a2e24d036ff19290b5a016a3f8a952fbfda7..40d04dba13ac86a757cf0283f123274e52c0b739 100644 (file)
@@ -40,7 +40,7 @@ static int hfsplus_ioctl_bless(struct file *file, int __user *user_flags)
 
        /* Directory containing the bootable system */
        vh->finder_info[0] = bvh->finder_info[0] =
-               cpu_to_be32(parent_ino(dentry));
+               cpu_to_be32(d_parent_ino(dentry));
 
        /*
         * Bootloader. Just using the inode here breaks in the case of
@@ -51,7 +51,7 @@ static int hfsplus_ioctl_bless(struct file *file, int __user *user_flags)
 
        /* Per spec, the OS X system folder - same as finder_info[0] here */
        vh->finder_info[5] = bvh->finder_info[5] =
-               cpu_to_be32(parent_ino(dentry));
+               cpu_to_be32(d_parent_ino(dentry));
 
        mutex_unlock(&sbi->vh_mutex);
        return 0;
index bf53e3894aae33ef15218463db3c9f85985b9e26..ea58843942b968dd8be4c430e9d018fdd10068d1 100644 (file)
@@ -278,6 +278,8 @@ static inline unsigned d_count(const struct dentry *dentry)
        return dentry->d_lockref.count;
 }
 
+ino_t d_parent_ino(struct dentry *dentry);
+
 /*
  * helper function for dentry_operations.d_dname() members
  */
index 5ff362277834cdafd6b0a1310fc8e7e043deac4c..2fa06a4d197a70ce1669a6dec984b094960b0e57 100644 (file)
@@ -3454,20 +3454,6 @@ static inline int kiocb_set_rw_flags(struct kiocb *ki, rwf_t flags)
        return 0;
 }
 
-static inline ino_t parent_ino(struct dentry *dentry)
-{
-       ino_t res;
-
-       /*
-        * Don't strictly need d_lock here? If the parent ino could change
-        * then surely we'd have a deeper race in the caller?
-        */
-       spin_lock(&dentry->d_lock);
-       res = dentry->d_parent->d_inode->i_ino;
-       spin_unlock(&dentry->d_lock);
-       return res;
-}
-
 /* Transaction based IO helpers */
 
 /*
@@ -3592,7 +3578,7 @@ static inline bool dir_emit_dot(struct file *file, struct dir_context *ctx)
 static inline bool dir_emit_dotdot(struct file *file, struct dir_context *ctx)
 {
        return ctx->actor(ctx, "..", 2, ctx->pos,
-                         parent_ino(file->f_path.dentry), DT_DIR);
+                         d_parent_ino(file->f_path.dentry), DT_DIR);
 }
 static inline bool dir_emit_dots(struct file *file, struct dir_context *ctx)
 {