/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
- * Copyright (c) 2001-2003 Cluster File Systems, Inc.
+ * GPL HEADER START
*
- * This file is part of Lustre, http://www.lustre.org.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
- * Lustre is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
*
- * Lustre is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
*
- * You should have received a copy of the GNU General Public License
- * along with Lustre; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 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.
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved
+ * Use is subject to license terms.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ * Lustre is a trademark of Sun Microsystems, Inc.
*/
#include <linux/fs.h>
#include "llite_internal.h"
+spinlock_t ll_lookup_lock = SPIN_LOCK_UNLOCKED;
+
/* should NOT be called with the dcache lock, see fs/dcache.c */
static void ll_release(struct dentry *de)
{
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,
atomic_read(&de->d_count));
- lock_kernel();
+
if (de->d_fsdata == NULL) {
- OBD_ALLOC(de->d_fsdata, sizeof(struct ll_dentry_data));
+ struct ll_dentry_data *lld;
+
+ OBD_ALLOC_PTR(lld);
+ if (likely(lld != NULL)) {
+ lock_dentry(de);
+ if (likely(de->d_fsdata == NULL))
+ de->d_fsdata = lld;
+ else
+ OBD_FREE_PTR(lld);
+ unlock_dentry(de);
+ }
}
- unlock_kernel();
EXIT;
}
__d_drop(dentry);
unlock_dentry(dentry);
spin_unlock(&dcache_lock);
+ spin_unlock(&ll_lookup_lock);
dput(dentry);
+ spin_lock(&ll_lookup_lock);
spin_lock(&dcache_lock);
return 1;
}
- /* disconected dentry can not be find without lookup, because we
+ /* disconected dentry can not be find without lookup, because we
* not need his to unhash or mark invalid. */
if (dentry->d_flags & DCACHE_DISCONNECTED) {
unlock_dentry(dentry);
inode->i_ino, inode->i_generation, inode);
head = &inode->i_dentry;
+ spin_lock(&ll_lookup_lock);
spin_lock(&dcache_lock);
restart:
tmp = head;
goto restart;
}
spin_unlock(&dcache_lock);
+ spin_unlock(&ll_lookup_lock);
+
EXIT;
}
if (!request)
RETURN(0);
- if (it_disposition(it, DISP_LOOKUP_NEG))
+ if (it_disposition(it, DISP_LOOKUP_NEG))
RETURN(-ENOENT);
rc = ll_prep_inode(&de->d_inode, request, NULL);
struct lookup_intent *it = *itp;
#ifdef HAVE_VFS_INTENT_PATCHES
if (it) {
- LASSERTF(it->it_magic == INTENT_MAGIC,
+ LASSERTF(it->it_magic == INTENT_MAGIC,
"%p has bad intent magic: %x\n",
it, it->it_magic);
}
int ll_revalidate_it(struct dentry *de, int lookup_flags,
struct lookup_intent *it)
{
- int rc;
struct md_op_data *op_data;
struct ptlrpc_request *req = NULL;
struct lookup_intent lookup_it = { .it_op = IT_LOOKUP };
struct obd_export *exp;
struct inode *parent;
+ int rc, first = 0;
ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:name=%s,intent=%s\n", de->d_name.name,
rc = ll_have_md_lock(de->d_parent->d_inode,
MDS_INODELOCK_UPDATE);
- RETURN(rc);
+ GOTO(out_sa, rc);
}
exp = ll_i2mdexp(de->d_inode);
/* Never execute intents for mount points.
* Attributes will be fixed up in ll_inode_revalidate_it */
if (d_mountpoint(de))
- RETURN(1);
+ GOTO(out_sa, rc = 1);
/* Root of the lustre tree. Always valid.
* Attributes will be fixed up in ll_inode_revalidate_it */
if (de == de->d_sb->s_root)
- RETURN(1);
+ GOTO(out_sa, rc = 1);
OBD_FAIL_TIMEOUT(OBD_FAIL_MDC_REVALIDATE_PAUSE, 5);
ll_frob_intent(&it, &lookup_it);
}
}
+ if (it->it_op == IT_GETATTR)
+ first = ll_statahead_enter(de->d_parent->d_inode, &de, 0);
+
do_lock:
it->it_create_mode &= ~current->fs->umask;
it->it_flags |= O_CHECK_STALE;
&req, ll_md_blocking_ast, 0);
it->it_flags &= ~O_CHECK_STALE;
ll_finish_md_op_data(op_data);
+ if (it->it_op == IT_GETATTR && !first)
+ /* If there are too many locks on client-side, then some
+ * locks taken by statahead maybe dropped automatically
+ * before the real "revalidate" using them. */
+ ll_statahead_exit(de, req == NULL ? rc : 0);
+ else if (first == -EEXIST)
+ ll_statahead_mark(de);
+
/* If req is NULL, then md_intent_lock only tried to do a lock match;
* if all was well, it will return 1 if it found locks, 0 otherwise. */
if (req == NULL && rc >= 0) {
if (rc != -ESTALE) {
CDEBUG(D_INFO, "ll_intent_lock: rc %d : it->it_status "
"%d\n", rc, it->d.lustre.it_status);
+ } else {
+#ifndef HAVE_VFS_INTENT_PATCHES
+ if (it_disposition(it, DISP_OPEN_OPEN) &&
+ !it_open_error(DISP_OPEN_OPEN, it))
+ /* server have valid open - close file first*/
+ ll_release_openhandle(de, it);
+#endif
}
GOTO(out, rc = 0);
}
GOTO(out, rc = 0);
}
- if ((it->it_op & IT_OPEN) && de->d_inode &&
- !S_ISREG(de->d_inode->i_mode) &&
+ if ((it->it_op & IT_OPEN) && de->d_inode &&
+ !S_ISREG(de->d_inode->i_mode) &&
!S_ISDIR(de->d_inode->i_mode)) {
ll_release_openhandle(de, it);
}
/* unfortunately ll_intent_lock may cause a callback and revoke our
* dentry */
+ spin_lock(&ll_lookup_lock);
spin_lock(&dcache_lock);
lock_dentry(de);
__d_drop(de);
unlock_dentry(de);
- __d_rehash(de, 0);
+ d_rehash_cond(de, 0);
spin_unlock(&dcache_lock);
+ spin_unlock(&ll_lookup_lock);
out:
/* We do not free request as it may be reused during following lookup
}
ll_finish_md_op_data(op_data);
GOTO(out, rc = 0);
+
+out_sa:
+ /*
+ * For rc == 1 case, should not return directly to prevent losing
+ * statahead windows; for rc == 0 case, the "lookup" will be done later.
+ */
+ if (it && it->it_op == IT_GETATTR && rc == 1) {
+ first = ll_statahead_enter(de->d_parent->d_inode, &de, 0);
+ if (!first)
+ ll_statahead_exit(de, 1);
+ else if (first == -EEXIST)
+ ll_statahead_mark(de);
+ }
+
+ return rc;
}
/*static*/ void ll_pin(struct dentry *de, struct vfsmount *mnt, int flag)
* nd->intent.open.file for error, so we need to return it as lookup's result
* instead */
if (IS_ERR(filp))
- rc = 0;
+ rc = PTR_ERR(filp);
#endif
}
#else