d_iput: no no yes no
d_dname: no no no no
d_automount: no no yes no
-d_manage: no no yes no
+d_manage: no no yes (ref-walk) maybe
--------------------------- inode_operations ---------------------------
prototypes:
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
struct vfsmount *(*d_automount)(struct path *);
- int (*d_manage)(struct dentry *, bool);
+ int (*d_manage)(struct dentry *, bool, bool);
};
d_revalidate: called when the VFS needs to revalidate a dentry. This
held by the caller and the function should not initiate any mounts or
unmounts that it will then wait for.
+ If the 'rcu_walk' parameter is true, then the caller is doing a
+ pathwalk in RCU-walk mode. Sleeping is not permitted in this mode,
+ and the caller can be asked to leave it and call again by returing
+ -ECHILD.
+
This function is only used if DCACHE_MANAGE_TRANSIT is set on the
dentry being transited from.
static int autofs4_dir_open(struct inode *inode, struct file *file);
static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *);
static struct vfsmount *autofs4_d_automount(struct path *);
-static int autofs4_d_manage(struct dentry *, bool);
+static int autofs4_d_manage(struct dentry *, bool, bool);
const struct file_operations autofs4_root_operations = {
.open = dcache_dir_open,
return NULL;
}
-int autofs4_d_manage(struct dentry *dentry, bool mounting_here)
+int autofs4_d_manage(struct dentry *dentry, bool mounting_here, bool rcu_walk)
{
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
return 0;
}
+ /* We need to sleep, so we need pathwalk to be in ref-mode */
+ if (rcu_walk)
+ return -ECHILD;
+
/* Wait for pending expires */
do_expire_wait(dentry);
if (managed & DCACHE_MANAGE_TRANSIT) {
BUG_ON(!path->dentry->d_op);
BUG_ON(!path->dentry->d_op->d_manage);
- ret = path->dentry->d_op->d_manage(path->dentry, false);
+ ret = path->dentry->d_op->d_manage(path->dentry,
+ false, false);
if (ret < 0)
return ret == -EISDIR ? 0 : ret;
}
static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
struct inode **inode, bool reverse_transit)
{
- unsigned abort_mask =
- reverse_transit ? 0 : DCACHE_MANAGE_TRANSIT;
-
while (d_mountpoint(path->dentry)) {
struct vfsmount *mounted;
- if (path->dentry->d_flags & abort_mask)
- return true;
+ if (unlikely(path->dentry->d_flags & DCACHE_MANAGE_TRANSIT) &&
+ !reverse_transit &&
+ path->dentry->d_op->d_manage(path->dentry, false, true) < 0)
+ return false;
mounted = __lookup_mnt(path->mnt, path->dentry, 1);
if (!mounted)
break;
if (managed & DCACHE_MANAGE_TRANSIT) {
BUG_ON(!path->dentry->d_op);
BUG_ON(!path->dentry->d_op->d_manage);
- ret = path->dentry->d_op->d_manage(path->dentry, mounting_here);
+ ret = path->dentry->d_op->d_manage(
+ path->dentry, mounting_here, false);
if (ret < 0)
return ret == -EISDIR ? 0 : ret;
}
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
struct vfsmount *(*d_automount)(struct path *);
- int (*d_manage)(struct dentry *, bool);
+ int (*d_manage)(struct dentry *, bool, bool);
} ____cacheline_aligned;
/*