Skip to content

Commit

Permalink
Allow d_manage() to be used in RCU-walk mode
Browse files Browse the repository at this point in the history
Allow d_manage() to be called from pathwalk when it is in RCU-walk mode as well
as when it is in Ref-walk mode.  This permits __follow_mount_rcu() to call
d_manage() directly.  d_manage() needs a parameter to indicate that it is in
RCU-walk mode as it isn't allowed to sleep if in that mode (but should return
-ECHILD instead).

autofs4_d_manage() can then be set to retain RCU-walk mode if the daemon
accesses it and otherwise request dropping back to ref-walk mode.

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
  • Loading branch information
dhowells authored and Al Viro committed Jan 16, 2011
1 parent 87556ef commit ab90911
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 12 deletions.
2 changes: 1 addition & 1 deletion Documentation/filesystems/Locking
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ d_release: no no yes no
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:
Expand Down
7 changes: 6 additions & 1 deletion Documentation/filesystems/vfs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,7 @@ struct dentry_operations {
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
Expand Down Expand Up @@ -960,6 +960,11 @@ struct dentry_operations {
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.

Expand Down
8 changes: 6 additions & 2 deletions fs/autofs4/root.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ static long autofs4_root_compat_ioctl(struct file *,unsigned int,unsigned long);
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,
Expand Down Expand Up @@ -450,7 +450,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
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);

Expand All @@ -464,6 +464,10 @@ int autofs4_d_manage(struct dentry *dentry, bool mounting_here)
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);

Expand Down
15 changes: 8 additions & 7 deletions fs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -987,7 +987,8 @@ static int follow_managed(struct path *path, unsigned flags)
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;
}
Expand Down Expand Up @@ -1048,13 +1049,12 @@ int follow_down_one(struct path *path)
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;
Expand Down Expand Up @@ -1132,7 +1132,8 @@ int follow_down(struct path *path, bool mounting_here)
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;
}
Expand Down
2 changes: 1 addition & 1 deletion include/linux/dcache.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ struct dentry_operations {
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;

/*
Expand Down

0 comments on commit ab90911

Please sign in to comment.