EXIT;
}
-void ll_intent_free(struct lookup_intent *it)
-{
- if (it->d.fs_data) {
- OBD_SLAB_FREE(it->d.fs_data, ll_intent_slab,
- sizeof(struct lustre_intent_data));
- it->d.fs_data = NULL;
- }
-}
-
void ll_unhash_aliases(struct inode *inode)
{
struct list_head *tmp, *head;
return 0;
}
OBD_SLAB_ALLOC(it->d.fs_data, ll_intent_slab, SLAB_KERNEL,
- sizeof(struct lustre_intent_data));
+ sizeof(struct lustre_intent_data));
if (!it->d.fs_data) {
CERROR("Failed to allocate memory for lustre specific intent "
"data\n");
}
it->it_op_release = ll_intent_release;
-
return 0;
}
+void ll_intent_free(struct lookup_intent *it)
+{
+ if (it->d.fs_data) {
+ OBD_SLAB_FREE(it->d.fs_data, ll_intent_slab,
+ sizeof(struct lustre_intent_data));
+ it->d.fs_data = NULL;
+ }
+}
+
+static inline int
+ll_special_name(struct dentry *de)
+{
+ if (de->d_name.name[0] == '.') switch (de->d_name.len) {
+ case 2:
+ if (de->d_name.name[1] == '.')
+ return 1;
+ case 1:
+ return 1;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
int ll_revalidate_it(struct dentry *de, int flags, struct nameidata *nd,
struct lookup_intent *it)
{
struct lookup_intent lookup_it = { .it_op = IT_LOOKUP };
struct ptlrpc_request *req = NULL;
+ int gns_it, gns_flags, rc = 0;
struct obd_export *exp;
struct it_cb_data icbd;
struct lustre_id pid;
struct lustre_id cid;
- int orig_it, rc = 0;
ENTRY;
- spin_lock(&de->d_lock);
-
- if ((de->d_flags & DCACHE_GNS_PENDING) &&
- !(de->d_flags & DCACHE_GNS_MOUNTING))
- {
- spin_unlock(&de->d_lock);
-
- if (nd) {
- int err = ll_gns_mount_object(de, nd->mnt);
- if (err)
- CERROR("can't mount %s, err = %d\n",
- de->d_name.name, err);
- }
- RETURN(1);
- }
- spin_unlock(&de->d_lock);
-
CDEBUG(D_VFSTRACE, "VFS Op:name=%s (%p), intent=%s\n", de->d_name.name,
de, LL_IT2STR(it));
if (de->d_inode == NULL)
RETURN(0);
- /* Root of the tree is always valid, attributes would be fixed in
- ll_inode_revalidate_it */
+ /*
+ * root of the tree is always valid, attributes would be fixed in
+ * ll_inode_revalidate_it()
+ */
if (de->d_sb->s_root == de)
RETURN(1);
nd->mnt->mnt_last_used = jiffies;
OBD_FAIL_TIMEOUT(OBD_FAIL_MDC_REVALIDATE_PAUSE, 5);
- orig_it = it ? it->it_op : IT_OPEN;
- ll_frob_intent(&it, &lookup_it);
- LASSERT(it != NULL);
-
- if (it->it_op == IT_GETATTR) { /* We need to check for LOOKUP lock as
- well */
- rc = ll_intent_alloc(&lookup_it);
- if (rc)
- LBUG(); /* Can't think of better idea just yet */
-
- rc = md_intent_lock(exp, &pid, de->d_name.name,
- de->d_name.len, NULL, 0, &cid, &lookup_it,
- flags, &req, ll_mdc_blocking_ast);
- /* If there was no lookup lock, no point in even checking for
- UPDATE lock */
- if (!rc) {
- it = &lookup_it;
- if (!req) {
- ll_intent_free(it);
- goto do_lookup;
- }
- GOTO(out, rc);
- }
- if (it_disposition(&lookup_it, DISP_LOOKUP_NEG)) {
- it = &lookup_it;
- ll_intent_free(it);
- GOTO(out, rc = 0);
- }
-
- if (req)
- ptlrpc_req_finished(req);
- req = NULL;
- ll_lookup_finish_locks(&lookup_it, de);
- /* XXX: on 2.6 ll_lookup_finish_locks does not call ll_intent_release */
- ll_intent_release(&lookup_it);
- }
+ gns_it = nd ? nd->intent.open.it_op : IT_OPEN;
+ gns_flags = nd ? nd->flags : LOOKUP_CONTINUE;
-#if 1
- if ((it->it_op == IT_OPEN) && de->d_inode) {
+ if (it && it->it_op == IT_GETATTR)
+ it = NULL; /* will use it_lookup */
+ else if (it && (it->it_op == IT_OPEN) && de->d_inode) {
+ /* open lock stuff */
struct inode *inode = de->d_inode;
struct ll_inode_info *lli = ll_i2info(inode);
struct obd_client_handle **och_p;
if it would be, we'll reopen the open request to
MDS later during file open path */
up(&lli->lli_och_sem);
+ if (ll_intent_alloc(it))
+ LBUG();
memcpy(&LUSTRE_IT(it)->it_lock_handle, &lockh,
sizeof(lockh));
LUSTRE_IT(it)->it_lock_mode = lockmode;
+
+ /*
+ * we do not check here for possible GNS dentry as if
+ * file is opened on it, it is mounted already and we do
+ * not need do anything. --umka
+ */
RETURN(1);
} else {
/* Hm, interesting. Lock is present, but no open
ldlm_lock_decref(&lockh, lockmode);
}
}
-#endif
do_lock:
- rc = md_intent_lock(exp, &pid, de->d_name.name, de->d_name.len,
+ ll_frob_intent(&it, &lookup_it);
+ LASSERT(it != NULL);
+
+ rc = md_intent_lock(exp, &pid, (char *)de->d_name.name, de->d_name.len,
NULL, 0, &cid, it, flags, &req, ll_mdc_blocking_ast);
/* 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. */
GOTO(out, rc);
out:
- if (req != NULL && rc == 1)
+ /* If we had succesful it lookup on mds, but it happened to be negative,
+ we do not free request as it will be reused during lookup (see
+ comment in mdc/mdc_locks.c::mdc_intent_lock(). But if
+ request was not completed, we need to free it. (bug 5154) */
+ if (req != NULL && (rc == 1 || !it_disposition(it, DISP_ENQ_COMPLETE))) {
ptlrpc_req_finished(req);
+ req = NULL;
+ }
if (rc == 0) {
- if (it == &lookup_it) {
+ if (it == &lookup_it)
ll_intent_release(it);
- if (req) /* Special case: We did lookup and it failed,
- need to free request */
- ptlrpc_req_finished(req);
- }
+
ll_unhash_aliases(de->d_inode);
- return 0;
+ RETURN(0);
+ }
+
+ /*
+ * if we found that this is possible GNS mount and dentry is still valid
+ * and may be used by system, we drop the lock and return 0, that means
+ * that re-lookup is needed. Such a way we cause real mounting only in
+ * lookup control path, which is always made with parent's i_sem taken.
+ * --umka
+ */
+ if (nd && atomic_read(&ll_i2sbi(de->d_inode)->ll_gns_enabled) &&
+ (de->d_inode->i_mode & S_ISUID) && S_ISDIR(de->d_inode->i_mode) &&
+ (gns_flags & LOOKUP_CONTINUE || (gns_it & (IT_CHDIR | IT_OPEN)))) {
+ /*
+ * special "." and ".." has to be always revalidated because
+ * they never should be passed to lookup()
+ */
+ if (!ll_special_name(de)) {
+ CDEBUG(D_DENTRY, "possible GNS dentry %*s %p found, "
+ "causing mounting\n", (int)de->d_name.len,
+ de->d_name.name, de);
+
+ LASSERT(req == NULL);
+ if (it == &lookup_it) {
+ ll_intent_release(it);
+ } else {
+ ll_intent_drop_lock(it);
+ }
+ ll_unhash_aliases(de->d_inode);
+ RETURN(0);
+ }
}
CDEBUG(D_DENTRY, "revalidated dentry %*s (%p) parent %p "
de->d_name.name, de, de->d_parent, de->d_inode,
atomic_read(&de->d_count));
- ll_lookup_finish_locks(it, de);
- de->d_flags &= ~DCACHE_LUSTRE_INVALID;
if (it == &lookup_it)
ll_intent_release(it);
-
- if (!((de->d_inode->i_mode & S_ISUID) && S_ISDIR(de->d_inode->i_mode)) ||
- !(flags & LOOKUP_CONTINUE || (orig_it & (IT_CHDIR | IT_OPEN))))
- return rc;
-
- if (nd && !(de->d_flags & DCACHE_GNS_MOUNTING)) {
- int err = ll_gns_mount_object(de, nd->mnt);
- if (err)
- CERROR("can't mount %s, err = %d\n",
- de->d_name.name, err);
- }
+ else
+ ll_lookup_finish_locks(it, de);
+
+ de->d_flags &= ~DCACHE_LUSTRE_INVALID;
return rc;
+
do_lookup:
- it = &lookup_it;
- if (ll_intent_alloc(it))
- LBUG();
-// We did that already, right? ll_inode2id(&pid, de->d_parent->d_inode);
- rc = md_intent_lock(exp, &pid, de->d_name.name,
- de->d_name.len, NULL, 0, NULL,
- it, 0, &req, ll_mdc_blocking_ast);
+ if (it != &lookup_it) {
+ ll_intent_release(it);
+ it = &lookup_it;
+ if (ll_intent_alloc(it))
+ LBUG();
+ }
+
+ rc = md_intent_lock(exp, &pid, (char *)de->d_name.name, de->d_name.len,
+ NULL, 0, NULL, it, 0, &req, ll_mdc_blocking_ast);
if (rc >= 0) {
- struct mds_body *mds_body = lustre_msg_buf(req->rq_repmsg, 1, sizeof(*mds_body));
+ struct mds_body *mds_body = lustre_msg_buf(req->rq_repmsg, 1,
+ sizeof(*mds_body));
- /* See if we got same inode, if not - return error */
+ /* see if we got same inode, if not - return error */
if (id_equal_stc(&cid, &mds_body->id1))
goto revalidate_finish;
}
.d_revalidate_it = ll_revalidate_it,
#endif
.d_release = ll_release,
- .d_iput = ll_dentry_iput,
+ /*.d_iput = ll_dentry_iput,*/
.d_delete = ll_ddelete,
.d_compare = ll_dcompare,
#if 0