X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Fllite%2Fdcache.c;h=0faaaea6cb4851f0c6bc2b4f640544175b126815;hp=22861ca8d334399a63f9f22e3c349677321bf728;hb=36b1e4c4142f8a7251aa3b6b1ec9ecce4799114f;hpb=500f334631c6ebec72f5791472f21603da3e0ef9 diff --git a/lustre/llite/dcache.c b/lustre/llite/dcache.c index 22861ca..0faaaea 100644 --- a/lustre/llite/dcache.c +++ b/lustre/llite/dcache.c @@ -15,11 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ @@ -27,7 +23,7 @@ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. * - * Copyright (c) 2011, 2015, Intel Corporation. + * Copyright (c) 2011, 2017, Intel Corporation. */ /* * This file is part of Lustre, http://www.lustre.org/ @@ -42,7 +38,6 @@ #define DEBUG_SUBSYSTEM S_LLITE #include -#include #include #include "llite_internal.h" @@ -65,11 +60,6 @@ static void ll_release(struct dentry *de) if (lld == NULL) /* NFS copies the de->d_op methods (bug 4655) */ RETURN_EXIT; - if (lld->lld_it) { - ll_intent_release(lld->lld_it); - OBD_FREE(lld->lld_it, sizeof(*lld->lld_it)); - } - de->d_fsdata = NULL; call_rcu(&lld->lld_rcu_head, free_dentry_data); @@ -82,27 +72,23 @@ static void ll_release(struct dentry *de) * This avoids a race where ll_lookup_it() instantiates a dentry, but we get * an AST before calling d_revalidate_it(). The dentry still exists (marked * INVALID) so d_lookup() matches it, but we have no lock on it (so - * lock_match() fails) and we spin around real_lookup(). */ -#ifdef HAVE_D_COMPARE_7ARGS -static int ll_dcompare(const struct dentry *parent, const struct inode *pinode, - const struct dentry *dentry, const struct inode *inode, - unsigned int len, const char *str, - const struct qstr *name) -#elif defined(HAVE_D_COMPARE_5ARGS) + * lock_match() fails) and we spin around real_lookup(). + * + * This race doesn't apply to lookups in d_alloc_parallel(), and for + * those we want to ensure that only one dentry with a given name is + * in ll_lookup_nd() at a time. So allow invalid dentries to match + * while d_in_lookup(). We will be called again when the lookup + * completes, and can give a different answer then. + */ +#if defined(HAVE_D_COMPARE_5ARGS) static int ll_dcompare(const struct dentry *parent, const struct dentry *dentry, unsigned int len, const char *str, const struct qstr *name) -#else -static int ll_dcompare(struct dentry *parent, struct qstr *d_name, - struct qstr *name) +#elif defined(HAVE_D_COMPARE_4ARGS) +static int ll_dcompare(const struct dentry *dentry, unsigned int len, + const char *str, const struct qstr *name) #endif { -#if !defined(HAVE_D_COMPARE_7ARGS) && !defined(HAVE_D_COMPARE_5ARGS) - /* XXX: (ugh !) d_name must be in-dentry structure */ - struct dentry *dentry = container_of(d_name, struct dentry, d_name); - unsigned int len = d_name->len; - const char *str = d_name->name; -#endif ENTRY; if (len != name->len) @@ -119,6 +105,10 @@ static int ll_dcompare(struct dentry *parent, struct qstr *d_name, if (d_mountpoint((struct dentry *)dentry)) RETURN(0); + /* ensure exclusion against parallel lookup of the same name */ + if (d_in_lookup((struct dentry *)dentry)) + return 0; + if (d_lustre_invalid(dentry)) RETURN(1); @@ -132,25 +122,21 @@ static int ll_dcompare(struct dentry *parent, struct qstr *d_name, * - return 0 to cache the dentry * Should NOT be called with the dcache lock, see fs/dcache.c */ -static int ll_ddelete(HAVE_D_DELETE_CONST struct dentry *de) +static int ll_ddelete(const struct dentry *de) { ENTRY; LASSERT(de); - CDEBUG(D_DENTRY, "%s dentry %.*s (%p, parent %p, inode %p) %s%s\n", - d_lustre_invalid((struct dentry *)de) ? "deleting" : "keeping", - de->d_name.len, de->d_name.name, de, de->d_parent, de->d_inode, + CDEBUG(D_DENTRY, "%s dentry %pd (%p, parent %p, inode %p) %s%s\n", + d_lustre_invalid(de) ? "deleting" : "keeping", + de, de, de->d_parent, de->d_inode, d_unhashed((struct dentry *)de) ? "" : "hashed,", list_empty(&de->d_subdirs) ? "" : "subdirs"); -#ifdef HAVE_DCACHE_LOCK - LASSERT(ll_d_count(de) == 0); -#else /* kernel >= 2.6.38 last refcount is decreased after this function. */ LASSERT(ll_d_count(de) == 1); -#endif - if (d_lustre_invalid((struct dentry *)de)) + if (d_lustre_invalid(de)) RETURN(1); RETURN(0); } @@ -160,9 +146,9 @@ int ll_d_init(struct dentry *de) ENTRY; LASSERT(de != NULL); - CDEBUG(D_DENTRY, "ldd on dentry %.*s (%p) parent %p inode %p refc %d\n", - de->d_name.len, de->d_name.name, de, de->d_parent, de->d_inode, - ll_d_count(de)); + CDEBUG(D_DENTRY, "ldd on dentry %pd (%p) parent %p inode %p refc %d\n", + de, de, de->d_parent, de->d_inode, + ll_d_count(de)); if (de->d_fsdata == NULL) { struct ll_dentry_data *lld; @@ -173,10 +159,6 @@ int ll_d_init(struct dentry *de) if (likely(de->d_fsdata == NULL)) { de->d_fsdata = lld; __d_lustre_invalidate(de); -#ifdef HAVE_DCACHE_LOCK - /* kernel >= 2.6.38 d_op is set in d_alloc() */ - de->d_op = &ll_d_ops; -#endif } else { OBD_FREE_PTR(lld); } @@ -207,8 +189,9 @@ void ll_intent_drop_lock(struct lookup_intent *it) if (it->it_remote_lock_mode != 0) { handle.cookie = it->it_remote_lock_handle; - CDEBUG(D_DLMTRACE, "releasing remote lock with cookie" - "%#llx from it %p\n", handle.cookie, it); + CDEBUG(D_DLMTRACE, + "releasing remote lock with cookie %#llx from it %p\n", + handle.cookie, it); ldlm_lock_decref(&handle, it->it_remote_lock_mode); it->it_remote_lock_mode = 0; @@ -234,10 +217,10 @@ void ll_intent_release(struct lookup_intent *it) EXIT; } -void ll_invalidate_aliases(struct inode *inode) +/* mark aliases invalid and prune unused aliases */ +void ll_prune_aliases(struct inode *inode) { struct dentry *dentry; - DECLARE_LL_D_HLIST_NODE_PTR(p); ENTRY; LASSERT(inode != NULL); @@ -245,24 +228,12 @@ void ll_invalidate_aliases(struct inode *inode) CDEBUG(D_INODE, "marking dentries for inode "DFID"(%p) invalid\n", PFID(ll_inode2fid(inode)), inode); - ll_lock_dcache(inode); - ll_d_hlist_for_each_entry(dentry, p, &inode->i_dentry) { - CDEBUG(D_DENTRY, "dentry in drop %.*s (%p) parent %p " - "inode %p flags %d\n", dentry->d_name.len, - dentry->d_name.name, dentry, dentry->d_parent, - dentry->d_inode, dentry->d_flags); - - if (unlikely(dentry == dentry->d_sb->s_root)) { - CERROR("%s: called on root dentry=%p, fid="DFID"\n", - ll_get_fsname(dentry->d_sb, NULL, 0), - dentry, PFID(ll_inode2fid(inode))); - lustre_dump_dentry(dentry, 1); - libcfs_debug_dumpstack(NULL); - } - - d_lustre_invalidate(dentry, 0); - } - ll_unlock_dcache(inode); + spin_lock(&inode->i_lock); + hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) + d_lustre_invalidate(dentry); + spin_unlock(&inode->i_lock); + + d_prune_aliases(inode); EXIT; } @@ -287,25 +258,21 @@ int ll_revalidate_it_finish(struct ptlrpc_request *request, void ll_lookup_finish_locks(struct lookup_intent *it, struct dentry *dentry) { - LASSERT(it != NULL); - LASSERT(dentry != NULL); + LASSERT(it != NULL); + LASSERT(dentry != NULL); if (it->it_lock_mode && dentry->d_inode != NULL) { - struct inode *inode = dentry->d_inode; - struct ll_sb_info *sbi = ll_i2sbi(dentry->d_inode); + struct inode *inode = dentry->d_inode; + struct ll_sb_info *sbi = ll_i2sbi(inode); CDEBUG(D_DLMTRACE, "setting l_data to inode "DFID"(%p)\n", PFID(ll_inode2fid(inode)), inode); - ll_set_lock_data(sbi->ll_md_exp, inode, it, NULL); - } - - /* drop lookup or getattr locks immediately */ - if (it->it_op == IT_LOOKUP || it->it_op == IT_GETATTR) { - /* on 2.6 there are situation when several lookups and - * revalidations may be requested during single operation. - * therefore, we don't release intent here -bzzz */ - ll_intent_drop_lock(it); - } + ll_set_lock_data(sbi->ll_md_exp, inode, it, NULL); + } + + /* drop lookup or getattr locks immediately */ + if (it->it_op == IT_LOOKUP || it->it_op == IT_GETATTR) + ll_intent_drop_lock(it); } static int ll_revalidate_dentry(struct dentry *dentry, @@ -313,6 +280,9 @@ static int ll_revalidate_dentry(struct dentry *dentry, { struct inode *dir = dentry->d_parent->d_inode; + CDEBUG(D_VFSTRACE, "VFS Op:name=%s, flags=%u\n", + dentry->d_name.name, lookup_flags); + /* If this is intermediate component path lookup and we were able to get * to this dentry, then its lock has not been revoked and the * path component is valid. */ @@ -320,72 +290,39 @@ static int ll_revalidate_dentry(struct dentry *dentry, return 1; /* Symlink - always valid as long as the dentry was found */ -#ifdef HAVE_IOP_GET_LINK - if (dentry->d_inode && dentry->d_inode->i_op->get_link) -#else - if (dentry->d_inode && dentry->d_inode->i_op->follow_link) -#endif - return 1; + /* only special case is to prevent ELOOP error from VFS during open + * of a foreign symlink file/dir with O_NOFOLLOW, like it happens for + * real symlinks. This will allow to open foreign symlink file/dir + * for get[dir]stripe/unlock ioctl()s. + */ + if (d_is_symlink(dentry)) { + if (!S_ISLNK(dentry->d_inode->i_mode) && + !(lookup_flags & LOOKUP_FOLLOW)) + return 0; + else + return 1; + } /* - * if open&create is set, talk to MDS to make sure file is created if - * necessary, because we can't do this in ->open() later since that's - * called on an inode. return 0 here to let lookup to handle this. + * VFS warns us that this is the second go around and previous + * operation failed (most likely open|creat), so this time + * we better talk to the server via the lookup path by name, + * not by fid. */ - if ((lookup_flags & (LOOKUP_OPEN | LOOKUP_CREATE)) == - (LOOKUP_OPEN | LOOKUP_CREATE)) + if (lookup_flags & LOOKUP_REVAL) return 0; - if (!dentry_may_statahead(dir, dentry)) - return 1; - -#ifndef HAVE_DCACHE_LOCK if (lookup_flags & LOOKUP_RCU) return -ECHILD; -#endif - - ll_statahead(dir, &dentry, dentry->d_inode == NULL); - return 1; -} - -/* - * Always trust cached dentries. Update statahead window if necessary. - */ -#ifdef HAVE_IOP_ATOMIC_OPEN -static int ll_revalidate_nd(struct dentry *dentry, unsigned int flags) -{ - int rc; - ENTRY; - - CDEBUG(D_VFSTRACE, "VFS Op:name=%s, flags=%u\n", - dentry->d_name.name, flags); - rc = ll_revalidate_dentry(dentry, flags); - RETURN(rc); -} -#else -static int ll_revalidate_nd(struct dentry *dentry, struct nameidata *nd) -{ - int rc; - ENTRY; + if (dentry_may_statahead(dir, dentry)) + ll_revalidate_statahead(dir, &dentry, dentry->d_inode == NULL); - /* - * this is normally called from NFS export, and we don't know whether - * this is the last component. - */ - if (nd == NULL) - RETURN(1); - - CDEBUG(D_VFSTRACE, "VFS Op:name=%s, flags=%u\n", - dentry->d_name.name, nd->flags); - - rc = ll_revalidate_dentry(dentry, nd->flags); - RETURN(rc); + return 1; } -#endif const struct dentry_operations ll_d_ops = { - .d_revalidate = ll_revalidate_nd, + .d_revalidate = ll_revalidate_dentry, .d_release = ll_release, .d_delete = ll_ddelete, .d_compare = ll_dcompare,