On Tue, 2020-01-07 at 10:00 -0700, Jens Axboe wrote: > If the fast lookup fails, then return -EAGAIN to have the caller retry > the path lookup. Assume that a dentry having any of: > > ->d_revalidate() > ->d_automount() > ->d_manage() > > could block in those callbacks. Preemptively return -EAGAIN if any of > these are present. > > This is in preparation for supporting non-blocking open. > > Signed-off-by: Jens Axboe <axboe@xxxxxxxxx> > --- > fs/namei.c | 21 ++++++++++++++++++++- > include/linux/namei.h | 2 ++ > 2 files changed, 22 insertions(+), 1 deletion(-) > > diff --git a/fs/namei.c b/fs/namei.c > index b367fdb91682..ed108a41634f 100644 > --- a/fs/namei.c > +++ b/fs/namei.c > @@ -1641,6 +1641,17 @@ static struct dentry *__lookup_hash(const struct qstr *name, > return dentry; > } > > +static inline bool lookup_could_block(struct dentry *dentry, unsigned int flags) > +{ > + const struct dentry_operations *ops = dentry->d_op; > + > + if (!ops || !(flags & LOOKUP_NONBLOCK)) > + return 0; > + > + /* assume these dentry ops may block */ > + return ops->d_revalidate || ops->d_automount || ops->d_manage; > +} > + d_revalidate shouldn't block if LOOKUP_RCU is set. > static int lookup_fast(struct nameidata *nd, > struct path *path, struct inode **inode, > unsigned *seqp) > @@ -1665,6 +1676,9 @@ static int lookup_fast(struct nameidata *nd, > return 0; > } > > + if (unlikely(lookup_could_block(dentry, nd->flags))) > + return -EAGAIN; > + > /* > * This sequence count validates that the inode matches > * the dentry name information from lookup. > @@ -1707,7 +1721,10 @@ static int lookup_fast(struct nameidata *nd, > dentry = __d_lookup(parent, &nd->last); > if (unlikely(!dentry)) > return 0; > - status = d_revalidate(dentry, nd->flags); > + if (unlikely(lookup_could_block(dentry, nd->flags))) > + status = -EAGAIN; > + else > + status = d_revalidate(dentry, nd->flags); > } > if (unlikely(status <= 0)) { > if (!status) > @@ -1912,6 +1929,8 @@ static int walk_component(struct nameidata *nd, int flags) > if (unlikely(err <= 0)) { > if (err < 0) > return err; > + if (nd->flags & LOOKUP_NONBLOCK) > + return -EAGAIN; > path.dentry = lookup_slow(&nd->last, nd->path.dentry, > nd->flags); > if (IS_ERR(path.dentry)) > diff --git a/include/linux/namei.h b/include/linux/namei.h > index 4e77068f7a1a..392eb439f88b 100644 > --- a/include/linux/namei.h > +++ b/include/linux/namei.h > @@ -49,6 +49,8 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; > /* LOOKUP_* flags which do scope-related checks based on the dirfd. */ > #define LOOKUP_IS_SCOPED (LOOKUP_BENEATH | LOOKUP_IN_ROOT) > > +#define LOOKUP_NONBLOCK 0x200000 /* don't block for lookup */ > + > extern int path_pts(struct path *path); > > extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty); -- Jeff Layton <jlayton@xxxxxxxxxx>