Loading fs/namei.c +46 −67 Original line number Original line Diff line number Diff line Loading @@ -1108,6 +1108,51 @@ static struct dentry *d_inode_lookup(struct dentry *parent, struct dentry *dentr return dentry; return dentry; } } static struct dentry *__lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd) { struct dentry *dentry; /* * Don't bother with __d_lookup: callers are for creat as * well as unlink, so a lot of the time it would cost * a double lookup. */ dentry = d_lookup(base, name); if (dentry && d_need_lookup(dentry)) { /* * __lookup_hash is called with the parent dir's i_mutex already * held, so we are good to go here. */ return d_inode_lookup(base, dentry, nd); } if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE)) { int status = d_revalidate(dentry, nd); if (unlikely(status <= 0)) { /* * The dentry failed validation. * If d_revalidate returned 0 attempt to invalidate * the dentry otherwise d_revalidate is asking us * to return a fail status. */ if (status < 0) { dput(dentry); return ERR_PTR(status); } else if (!d_invalidate(dentry)) { dput(dentry); dentry = NULL; } } } if (!dentry) dentry = d_alloc_and_lookup(base, name, nd); return dentry; } /* /* * It's more convoluted than I'd like it to be, but... it's still fairly * It's more convoluted than I'd like it to be, but... it's still fairly * small and for now I'd prefer to have fast path as straight as possible. * small and for now I'd prefer to have fast path as straight as possible. Loading Loading @@ -1173,28 +1218,7 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, BUG_ON(nd->inode != dir); BUG_ON(nd->inode != dir); mutex_lock(&dir->i_mutex); mutex_lock(&dir->i_mutex); dentry = d_lookup(parent, name); dentry = __lookup_hash(name, parent, nd); if (dentry && d_need_lookup(dentry)) { dentry = d_inode_lookup(parent, dentry, nd); goto l; } if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE)) { status = d_revalidate(dentry, nd); if (unlikely(status <= 0)) { if (status < 0) { dput(dentry); dentry = ERR_PTR(status); goto l; } if (!d_invalidate(dentry)) { dput(dentry); dentry = NULL; } } } if (!dentry) dentry = d_alloc_and_lookup(parent, name, nd); l: mutex_unlock(&dir->i_mutex); mutex_unlock(&dir->i_mutex); if (IS_ERR(dentry)) if (IS_ERR(dentry)) return PTR_ERR(dentry); return PTR_ERR(dentry); Loading Loading @@ -1850,51 +1874,6 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, return err; return err; } } static struct dentry *__lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd) { struct dentry *dentry; /* * Don't bother with __d_lookup: callers are for creat as * well as unlink, so a lot of the time it would cost * a double lookup. */ dentry = d_lookup(base, name); if (dentry && d_need_lookup(dentry)) { /* * __lookup_hash is called with the parent dir's i_mutex already * held, so we are good to go here. */ return d_inode_lookup(base, dentry, nd); } if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE)) { int status = d_revalidate(dentry, nd); if (unlikely(status <= 0)) { /* * The dentry failed validation. * If d_revalidate returned 0 attempt to invalidate * the dentry otherwise d_revalidate is asking us * to return a fail status. */ if (status < 0) { dput(dentry); return ERR_PTR(status); } else if (!d_invalidate(dentry)) { dput(dentry); dentry = NULL; } } } if (!dentry) dentry = d_alloc_and_lookup(base, name, nd); return dentry; } /* /* * Restricted form of lookup. Doesn't follow links, single-component only, * Restricted form of lookup. Doesn't follow links, single-component only, * needs parent already locked. Doesn't follow mounts. * needs parent already locked. Doesn't follow mounts. Loading Loading
fs/namei.c +46 −67 Original line number Original line Diff line number Diff line Loading @@ -1108,6 +1108,51 @@ static struct dentry *d_inode_lookup(struct dentry *parent, struct dentry *dentr return dentry; return dentry; } } static struct dentry *__lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd) { struct dentry *dentry; /* * Don't bother with __d_lookup: callers are for creat as * well as unlink, so a lot of the time it would cost * a double lookup. */ dentry = d_lookup(base, name); if (dentry && d_need_lookup(dentry)) { /* * __lookup_hash is called with the parent dir's i_mutex already * held, so we are good to go here. */ return d_inode_lookup(base, dentry, nd); } if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE)) { int status = d_revalidate(dentry, nd); if (unlikely(status <= 0)) { /* * The dentry failed validation. * If d_revalidate returned 0 attempt to invalidate * the dentry otherwise d_revalidate is asking us * to return a fail status. */ if (status < 0) { dput(dentry); return ERR_PTR(status); } else if (!d_invalidate(dentry)) { dput(dentry); dentry = NULL; } } } if (!dentry) dentry = d_alloc_and_lookup(base, name, nd); return dentry; } /* /* * It's more convoluted than I'd like it to be, but... it's still fairly * It's more convoluted than I'd like it to be, but... it's still fairly * small and for now I'd prefer to have fast path as straight as possible. * small and for now I'd prefer to have fast path as straight as possible. Loading Loading @@ -1173,28 +1218,7 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, BUG_ON(nd->inode != dir); BUG_ON(nd->inode != dir); mutex_lock(&dir->i_mutex); mutex_lock(&dir->i_mutex); dentry = d_lookup(parent, name); dentry = __lookup_hash(name, parent, nd); if (dentry && d_need_lookup(dentry)) { dentry = d_inode_lookup(parent, dentry, nd); goto l; } if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE)) { status = d_revalidate(dentry, nd); if (unlikely(status <= 0)) { if (status < 0) { dput(dentry); dentry = ERR_PTR(status); goto l; } if (!d_invalidate(dentry)) { dput(dentry); dentry = NULL; } } } if (!dentry) dentry = d_alloc_and_lookup(parent, name, nd); l: mutex_unlock(&dir->i_mutex); mutex_unlock(&dir->i_mutex); if (IS_ERR(dentry)) if (IS_ERR(dentry)) return PTR_ERR(dentry); return PTR_ERR(dentry); Loading Loading @@ -1850,51 +1874,6 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, return err; return err; } } static struct dentry *__lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd) { struct dentry *dentry; /* * Don't bother with __d_lookup: callers are for creat as * well as unlink, so a lot of the time it would cost * a double lookup. */ dentry = d_lookup(base, name); if (dentry && d_need_lookup(dentry)) { /* * __lookup_hash is called with the parent dir's i_mutex already * held, so we are good to go here. */ return d_inode_lookup(base, dentry, nd); } if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE)) { int status = d_revalidate(dentry, nd); if (unlikely(status <= 0)) { /* * The dentry failed validation. * If d_revalidate returned 0 attempt to invalidate * the dentry otherwise d_revalidate is asking us * to return a fail status. */ if (status < 0) { dput(dentry); return ERR_PTR(status); } else if (!d_invalidate(dentry)) { dput(dentry); dentry = NULL; } } } if (!dentry) dentry = d_alloc_and_lookup(base, name, nd); return dentry; } /* /* * Restricted form of lookup. Doesn't follow links, single-component only, * Restricted form of lookup. Doesn't follow links, single-component only, * needs parent already locked. Doesn't follow mounts. * needs parent already locked. Doesn't follow mounts. Loading