struct vfsmount *(*d_automount)(struct path *path);
        int (*d_manage)(const struct path *, bool);
        struct dentry *(*d_real)(struct dentry *, enum d_real_type type);
+       bool (*d_unalias_trylock)(const struct dentry *);
+       void (*d_unalias_unlock)(const struct dentry *);
 
 locking rules:
 
 d_automount:      no           no              yes             no
 d_manage:         no           no              yes (ref-walk)  maybe
 d_real            no           no              yes             no
+d_unalias_trylock  yes         no              no              no
+d_unalias_unlock   yes         no              no              no
 ================== =========== ========        ==============  ========
 
 inode_operations
 
                struct vfsmount *(*d_automount)(struct path *);
                int (*d_manage)(const struct path *, bool);
                struct dentry *(*d_real)(struct dentry *, enum d_real_type type);
+               bool (*d_unalias_trylock)(const struct dentry *);
+               void (*d_unalias_unlock)(const struct dentry *);
        };
 
 ``d_revalidate``
 
        For non-regular files, the 'dentry' argument is returned.
 
+``d_unalias_trylock``
+       if present, will be called by d_splice_alias() before moving a
+       preexisting attached alias.  Returning false prevents __d_move(),
+       making d_splice_alias() fail with -ESTALE.
+
+       Rationale: setting FS_RENAME_DOES_D_MOVE will prevent d_move()
+       and d_exchange() calls from the outside of filesystem methods;
+       however, it does not guarantee that attached dentries won't
+       be renamed or moved by d_splice_alias() finding a preexisting
+       alias for a directory inode.  Normally we would not care;
+       however, something that wants to stabilize the entire path to
+       root over a blocking operation might need that.  See 9p for one
+       (and hopefully only) example.
+
+``d_unalias_unlock``
+       should be paired with ``d_unalias_trylock``; that one is called after
+       __d_move() call in __d_unalias().
+
+
 Each dentry has a pointer to its parent dentry, as well as a hash list
 of child dentries.  Child dentries are basically like files in a
 directory.
 
        return inode->i_sb->s_fs_info;
 }
 
-static inline struct v9fs_session_info *v9fs_dentry2v9ses(struct dentry *dentry)
+static inline struct v9fs_session_info *v9fs_dentry2v9ses(const struct dentry *dentry)
 {
        return dentry->d_sb->s_fs_info;
 }
 
        return __v9fs_lookup_revalidate(dentry, flags);
 }
 
+static bool v9fs_dentry_unalias_trylock(const struct dentry *dentry)
+{
+       struct v9fs_session_info *v9ses = v9fs_dentry2v9ses(dentry);
+       return down_write_trylock(&v9ses->rename_sem);
+}
+
+static void v9fs_dentry_unalias_unlock(const struct dentry *dentry)
+{
+       struct v9fs_session_info *v9ses = v9fs_dentry2v9ses(dentry);
+       up_write(&v9ses->rename_sem);
+}
+
 const struct dentry_operations v9fs_cached_dentry_operations = {
        .d_revalidate = v9fs_lookup_revalidate,
        .d_weak_revalidate = __v9fs_lookup_revalidate,
        .d_delete = v9fs_cached_dentry_delete,
        .d_release = v9fs_dentry_release,
+       .d_unalias_trylock = v9fs_dentry_unalias_trylock,
+       .d_unalias_unlock = v9fs_dentry_unalias_unlock,
 };
 
 const struct dentry_operations v9fs_dentry_operations = {
        .d_delete = always_delete_dentry,
        .d_release = v9fs_dentry_release,
+       .d_unalias_trylock = v9fs_dentry_unalias_trylock,
+       .d_unalias_unlock = v9fs_dentry_unalias_unlock,
 };
 
                goto out_err;
        m2 = &alias->d_parent->d_inode->i_rwsem;
 out_unalias:
+       if (alias->d_op->d_unalias_trylock &&
+           !alias->d_op->d_unalias_trylock(alias))
+               goto out_err;
        __d_move(alias, dentry, false);
+       if (alias->d_op->d_unalias_unlock)
+               alias->d_op->d_unalias_unlock(alias);
        ret = 0;
 out_err:
        if (m2)
 
        struct vfsmount *(*d_automount)(struct path *);
        int (*d_manage)(const struct path *, bool);
        struct dentry *(*d_real)(struct dentry *, enum d_real_type type);
+       bool (*d_unalias_trylock)(const struct dentry *);
+       void (*d_unalias_unlock)(const struct dentry *);
 } ____cacheline_aligned;
 
 /*