+out:
+ /* We do not free request as it may be reused during following lookup
+ * (see comment in mdc/mdc_locks.c::mdc_intent_lock()), request will
+ * be freed in ll_lookup_it or in ll_intent_release. But if
+ * request was not completed, we need to free it. (bug 5154, 9903) */
+ if (req != NULL && !it_disposition(it, DISP_ENQ_COMPLETE))
+ ptlrpc_req_finished(req);
+ if (rc == 0) {
+#ifdef LUSTRE_KERNEL_VERSION
+ ll_unhash_aliases(de->d_inode);
+ /* done in ll_unhash_aliases()
+ dentry->d_flags |= DCACHE_LUSTRE_INVALID; */
+#else
+ /* We do not want d_invalidate to kill all child dentries too */
+ d_drop(de);
+#endif
+ } else {
+ 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));
+ ll_lookup_finish_locks(it, de);
+#ifdef LUSTRE_KERNEL_VERSION
+ lock_dentry(de);
+ de->d_flags &= ~DCACHE_LUSTRE_INVALID;
+ unlock_dentry(de);
+#endif
+ }
+ RETURN(rc);
+
+ /*
+ * This part is here to combat evil-evil race in real_lookup on 2.6
+ * kernels. The race details are: We enter do_lookup() looking for some
+ * name, there is nothing in dcache for this name yet and d_lookup()
+ * returns NULL. We proceed to real_lookup(), and while we do this,
+ * another process does open on the same file we looking up (most simple
+ * reproducer), open succeeds and the dentry is added. Now back to
+ * us. In real_lookup() we do d_lookup() again and suddenly find the
+ * dentry, so we call d_revalidate on it, but there is no lock, so
+ * without this code we would return 0, but unpatched real_lookup just
+ * returns -ENOENT in such a case instead of retrying the lookup. Once
+ * this is dealt with in real_lookup(), all of this ugly mess can go and
+ * we can just check locks in ->d_revalidate without doing any RPCs
+ * ever.
+ */
+do_lookup:
+ if (it != &lookup_it) {
+ /* MDS_INODELOCK_UPDATE needed for IT_GETATTR case. */
+ if (it->it_op == IT_GETATTR)
+ lookup_it.it_op = IT_GETATTR;
+ ll_lookup_finish_locks(it, de);
+ it = &lookup_it;
+ }
+
+ /* Do real lookup here. */
+ op_data = ll_prep_md_op_data(NULL, parent, NULL, de->d_name.name,
+ de->d_name.len, 0, (it->it_op & IT_CREAT ?
+ LUSTRE_OPC_CREATE :
+ LUSTRE_OPC_ANY), NULL);
+ if (IS_ERR(op_data))
+ RETURN(PTR_ERR(op_data));
+
+ rc = md_intent_lock(exp, op_data, NULL, 0, it, 0, &req,
+ ll_md_blocking_ast, 0);
+ if (rc >= 0) {
+ struct mdt_body *mdt_body = lustre_msg_buf(req->rq_repmsg,
+ DLM_REPLY_REC_OFF,
+ sizeof(*mdt_body));
+ struct lu_fid fid = {.f_seq = 0, .f_oid = 0, .f_ver = 0};
+
+ if (de->d_inode)
+ fid = *ll_inode2fid(de->d_inode);
+
+ /* see if we got same inode, if not - return error */
+ if (lu_fid_eq(&fid, &mdt_body->fid1)) {
+ ll_finish_md_op_data(op_data);
+ op_data = NULL;
+ goto revalidate_finish;
+ }
+ ll_intent_release(it);
+ }
+ ll_finish_md_op_data(op_data);
+ 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;
+ struct obd_capa *oc;
+ 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;
+ oc = ll_mdscapa_get(inode);
+ rc = obd_pin(sbi->ll_md_exp, ll_inode2fid(inode), oc, handle, flag);
+ capa_put(oc);
+ 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;
+ return;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+#ifdef LUSTRE_KERNEL_VERSION
+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->intent);
+ else
+ rc = ll_revalidate_it(dentry, 0, NULL);
+
+ RETURN(rc);
+}
+#else
+int ll_revalidate_nd(struct dentry *dentry, struct nameidata *nd)
+{
+ int rc;
+ ENTRY;
+
+ if (nd && !(nd->flags & (LOOKUP_CONTINUE|LOOKUP_PARENT))) {
+ struct lookup_intent *it;
+ it = ll_convert_intent(&nd->intent.open, nd->flags);
+ if (IS_ERR(it))
+ RETURN(0);
+ if (it->it_op == (IT_OPEN|IT_CREAT))
+ if (nd->intent.open.flags & O_EXCL) {
+ CDEBUG(D_VFSTRACE, "create O_EXCL, returning 0\n");
+ rc = 0;
+ goto out_it;
+ }
+
+ rc = ll_revalidate_it(dentry, nd->flags, it);
+
+ if (rc && (nd->flags & LOOKUP_OPEN) &&
+ it_disposition(it, DISP_OPEN_OPEN)) {/*Open*/
+#ifdef HAVE_FILE_IN_STRUCT_INTENT
+// XXX Code duplication with ll_lookup_nd
+ if (S_ISFIFO(dentry->d_inode->i_mode)) {
+ // We cannot call open here as it would
+ // deadlock.
+ ptlrpc_req_finished(
+ (struct ptlrpc_request *)
+ it->d.lustre.it_data);
+ } else {
+ struct file *filp;
+
+ nd->intent.open.file->private_data = it;
+ filp = lookup_instantiate_filp(nd, dentry,NULL);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17))
+/* 2.6.1[456] have a bug in open_namei() that forgets to check
+ * nd->intent.open.file for error, so we need to return it as lookup's result
+ * instead */
+ if (IS_ERR(filp))
+ rc = 0;
+#endif
+ }
+#else
+ ll_release_openhandle(dentry, it);
+#endif /* HAVE_FILE_IN_STRUCT_INTENT */
+ }
+ if (!rc && (nd->flags & LOOKUP_CREATE) &&
+ it_disposition(it, DISP_OPEN_CREATE)) {
+ /* We created something but we may only return
+ * negative dentry here, so save request in dentry,
+ * if lookup will be called later on, it will
+ * pick the request, otherwise it would be freed
+ * with dentry */
+ ll_d2d(dentry)->lld_it = it;
+ it = NULL; /* avoid freeing */
+ }
+
+out_it:
+ if (it) {
+ ll_intent_release(it);
+ OBD_FREE(it, sizeof(*it));
+ }
+ } else {
+ rc = ll_revalidate_it(dentry, 0, NULL);
+ }
+
+ RETURN(rc);