ceph: make ceph_msdc_build_path use ref-walk
authorJeff Layton <jlayton@kernel.org>
Wed, 5 Aug 2020 18:50:48 +0000 (14:50 -0400)
committerIlya Dryomov <idryomov@gmail.com>
Tue, 22 Aug 2023 07:01:48 +0000 (09:01 +0200)
Encryption potentially requires allocation, at which point we'll need to
be in a non-atomic context. Convert ceph_msdc_build_path to take dentry
spinlocks and references instead of using rcu_read_lock to walk the
path.

This is slightly less efficient, and we may want to eventually allow
using RCU when the leaf dentry isn't encrypted.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Xiubo Li <xiubli@redhat.com>
Reviewed-and-tested-by: Luís Henriques <lhenriques@suse.de>
Reviewed-by: Milind Changire <mchangir@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
fs/ceph/mds_client.c

index 73dfea8..77b5e7b 100644 (file)
@@ -2387,7 +2387,8 @@ static inline  u64 __get_oldest_tid(struct ceph_mds_client *mdsc)
 char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *pbase,
                           int stop_on_nosnap)
 {
-       struct dentry *temp;
+       struct dentry *cur;
+       struct inode *inode;
        char *path;
        int pos;
        unsigned seq;
@@ -2404,34 +2405,35 @@ retry:
        path[pos] = '\0';
 
        seq = read_seqbegin(&rename_lock);
-       rcu_read_lock();
-       temp = dentry;
+       cur = dget(dentry);
        for (;;) {
-               struct inode *inode;
+               struct dentry *temp;
 
-               spin_lock(&temp->d_lock);
-               inode = d_inode(temp);
+               spin_lock(&cur->d_lock);
+               inode = d_inode(cur);
                if (inode && ceph_snap(inode) == CEPH_SNAPDIR) {
                        dout("build_path path+%d: %p SNAPDIR\n",
-                            pos, temp);
-               } else if (stop_on_nosnap && inode && dentry != temp &&
+                            pos, cur);
+               } else if (stop_on_nosnap && inode && dentry != cur &&
                           ceph_snap(inode) == CEPH_NOSNAP) {
-                       spin_unlock(&temp->d_lock);
+                       spin_unlock(&cur->d_lock);
                        pos++; /* get rid of any prepended '/' */
                        break;
                } else {
-                       pos -= temp->d_name.len;
+                       pos -= cur->d_name.len;
                        if (pos < 0) {
-                               spin_unlock(&temp->d_lock);
+                               spin_unlock(&cur->d_lock);
                                break;
                        }
-                       memcpy(path + pos, temp->d_name.name, temp->d_name.len);
+                       memcpy(path + pos, cur->d_name.name, cur->d_name.len);
                }
+               temp = cur;
                spin_unlock(&temp->d_lock);
-               temp = READ_ONCE(temp->d_parent);
+               cur = dget_parent(temp);
+               dput(temp);
 
                /* Are we at the root? */
-               if (IS_ROOT(temp))
+               if (IS_ROOT(cur))
                        break;
 
                /* Are we out of buffer? */
@@ -2440,8 +2442,9 @@ retry:
 
                path[pos] = '/';
        }
-       base = ceph_ino(d_inode(temp));
-       rcu_read_unlock();
+       inode = d_inode(cur);
+       base = inode ? ceph_ino(inode) : 0;
+       dput(cur);
 
        if (read_seqretry(&rename_lock, seq))
                goto retry;