+ GOTO(out, rc);
+out:
+ /* 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)
+ ll_intent_release(it);
+
+ ll_unhash_aliases(de->d_inode);
+ 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 "
+ "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));
+
+ if (it == &lookup_it)
+ ll_intent_release(it);
+ else
+ ll_lookup_finish_locks(it, de);
+
+ de->d_flags &= ~DCACHE_LUSTRE_INVALID;
+ return rc;
+
+do_lookup:
+ 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));
+
+ /* see if we got same inode, if not - return error */
+ if (id_equal_stc(&cid, &mds_body->id1))
+ goto revalidate_finish;
+ }
+
+ GOTO(out, rc = 0);
+}
+
+/*static*/ void ll_pin(struct dentry *de, struct vfsmount *mnt, int flag)
+{
+ struct inode *inode= de->d_inode;
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
+ struct ll_dentry_data *ldd = ll_d2d(de);
+ struct obd_client_handle *handle;
+ int rc = 0;
+ ENTRY;
+ LASSERT(ldd);
+
+ lock_kernel();
+ /* Strictly speaking this introduces an additional race: the
+ * increments should wait until the rpc has returned.
+ * However, given that at present the function is void, this
+ * issue is moot. */
+ if (flag == 1 && (++ldd->lld_mnt_count) > 1) {
+ unlock_kernel();
+ EXIT;
+ return;
+ }
+
+ if (flag == 0 && (++ldd->lld_cwd_count) > 1) {
+ unlock_kernel();
+ EXIT;
+ return;
+ }
+ unlock_kernel();
+
+ handle = (flag) ? &ldd->lld_mnt_och : &ldd->lld_cwd_och;
+ rc = obd_pin(sbi->ll_md_exp, inode->i_ino, inode->i_generation,
+ inode->i_mode & S_IFMT, handle, flag);
+
+ if (rc) {
+ lock_kernel();
+ memset(handle, 0, sizeof(*handle));
+ if (flag == 0)
+ ldd->lld_cwd_count--;
+ else
+ ldd->lld_mnt_count--;
+ unlock_kernel();
+ }
+
+ EXIT;
+ return;
+}
+
+/*static*/ void ll_unpin(struct dentry *de, struct vfsmount *mnt, int flag)
+{
+ struct ll_sb_info *sbi = ll_i2sbi(de->d_inode);
+ struct ll_dentry_data *ldd = ll_d2d(de);
+ struct obd_client_handle handle;
+ int count, rc = 0;
+ ENTRY;
+ LASSERT(ldd);
+
+ lock_kernel();
+ /* Strictly speaking this introduces an additional race: the
+ * increments should wait until the rpc has returned.
+ * However, given that at present the function is void, this
+ * issue is moot. */
+ handle = (flag) ? ldd->lld_mnt_och : ldd->lld_cwd_och;
+ if (handle.och_magic != OBD_CLIENT_HANDLE_MAGIC) {
+ /* the "pin" failed */
+ unlock_kernel();
+ EXIT;
+ return;
+ }
+
+ if (flag)
+ count = --ldd->lld_mnt_count;
+ else
+ count = --ldd->lld_cwd_count;
+ unlock_kernel();
+
+ if (count != 0) {
+ EXIT;
+ return;
+ }
+
+ rc = obd_unpin(sbi->ll_md_exp, &handle, flag);
+ EXIT;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int ll_revalidate_nd(struct dentry *dentry, struct nameidata *nd)
+{
+ int rc;
+ ENTRY;
+
+ if (nd && nd->flags & LOOKUP_LAST && !(nd->flags & LOOKUP_LINK_NOTLAST))
+ rc = ll_revalidate_it(dentry, nd->flags, nd, &nd->intent.open);
+ else
+ rc = ll_revalidate_it(dentry, 0, nd, NULL);
+
+ RETURN(rc);
+}
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+static void ll_dentry_iput(struct dentry *dentry, struct inode *inode)
+{
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
+ struct lustre_id parent, child;
+
+ LASSERT(dentry->d_parent && dentry->d_parent->d_inode);
+ ll_inode2id(&parent, dentry->d_parent->d_inode);
+ ll_inode2id(&child, inode);
+ md_change_cbdata_name(sbi->ll_md_exp, &parent,
+ (char *)dentry->d_name.name,
+ dentry->d_name.len, &child,
+ null_if_equal, inode);
+ iput(inode);
+}
+#else
+static void ll_dentry_iput(struct dentry *dentry, struct inode *inode)
+{
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
+ struct lustre_id parent, child;
+
+ if (dentry->d_parent != dentry) {
+ /* Do not do this for root of the tree */
+ LASSERT(dentry->d_parent && dentry->d_parent->d_inode);
+ ll_inode2id(&parent, dentry->d_parent->d_inode);
+ ll_inode2id(&child, inode);
+ md_change_cbdata_name(sbi->ll_md_exp, &parent,
+ (char *)dentry->d_name.name,
+ dentry->d_name.len, &child,
+ null_if_equal, inode);
+ }
+ iput(inode);
+