+/*
+ * For cached negative dentry and new dentry, handle lookup/create/open
+ * together.
+ */
+static int ll_atomic_open(struct inode *dir, struct dentry *dentry,
+ struct file *file, unsigned open_flags,
+ umode_t mode, int *opened)
+{
+ struct lookup_intent *it;
+ struct dentry *de;
+ long long lookup_flags = LOOKUP_OPEN;
+ int rc = 0;
+ ENTRY;
+
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),file %p,"
+ "open_flags %x,mode %x opened %d\n",
+ dentry->d_name.len, dentry->d_name.name, dir->i_ino,
+ dir->i_generation, dir, file, open_flags, mode, *opened);
+
+ OBD_ALLOC(it, sizeof(*it));
+ if (!it)
+ RETURN(-ENOMEM);
+
+ it->it_op = IT_OPEN;
+ if (mode) {
+ it->it_op |= IT_CREAT;
+ lookup_flags |= LOOKUP_CREATE;
+ }
+ it->it_create_mode = (mode & S_IALLUGO) | S_IFREG;
+ it->it_flags = (open_flags & ~O_ACCMODE) | OPEN_FMODE(open_flags);
+
+ /* Dentry added to dcache tree in ll_lookup_it */
+ de = ll_lookup_it(dir, dentry, it, lookup_flags);
+ if (IS_ERR(de))
+ rc = PTR_ERR(de);
+ else if (de != NULL)
+ dentry = de;
+
+ if (!rc) {
+ if (it_disposition(it, DISP_OPEN_CREATE)) {
+ /* Dentry instantiated in ll_create_it. */
+ rc = ll_create_it(dir, dentry, mode, it);
+ if (rc) {
+ /* We dget in ll_splice_alias. */
+ if (de != NULL)
+ dput(de);
+ goto out_release;
+ }
+
+ *opened |= FILE_CREATED;
+ }
+ if (dentry->d_inode && it_disposition(it, DISP_OPEN_OPEN)) {
+ /* Open dentry. */
+ if (S_ISFIFO(dentry->d_inode->i_mode)) {
+ /* We cannot call open here as it would
+ * deadlock.
+ */
+ if (it_disposition(it, DISP_ENQ_OPEN_REF))
+ ptlrpc_req_finished(
+ (struct ptlrpc_request *)
+ it->d.lustre.it_data);
+ rc = finish_no_open(file, de);
+ } else {
+ file->private_data = it;
+ rc = finish_open(file, dentry, NULL, opened);
+ /* We dget in ll_splice_alias. finish_open takes
+ * care of dget for fd open.
+ */
+ if (de != NULL)
+ dput(de);
+ }
+ } else {
+ rc = finish_no_open(file, de);
+ }
+ }
+
+out_release:
+ ll_intent_release(it);
+ OBD_FREE(it, sizeof(*it));
+
+ RETURN(rc);