+/* do NOT or the MAY_*'s, you'll get the weakest */
+static int accmode(int flags)
+{
+ int res = 0;
+
+ if (flags & FMODE_READ)
+ res = MAY_READ;
+ if (flags & (FMODE_WRITE|MDS_OPEN_TRUNC))
+ res |= MAY_WRITE;
+ if (flags & FMODE_EXEC)
+ res = MAY_EXEC;
+ return res;
+}
+
+/* Handles object creation, actual opening, and I/O epoch */
+static int mds_finish_open(struct ptlrpc_request *req, struct dentry *dchild,
+ struct mds_body *body, int flags, void **handle,
+ struct mds_update_record *rec,struct ldlm_reply *rep)
+{
+ struct mds_obd *mds = mds_req2mds(req);
+ struct obd_device *obd = req->rq_export->exp_obd;
+ struct mds_file_data *mfd = NULL;
+ obd_id *ids = NULL; /* object IDs created */
+ int rc = 0;
+ ENTRY;
+
+ /* atomically create objects if necessary */
+ down(&dchild->d_inode->i_sem);
+ if (S_ISREG(dchild->d_inode->i_mode) &&
+ !(body->valid & OBD_MD_FLEASIZE)) {
+ rc = mds_pack_md(obd, req->rq_repmsg, 2, body,
+ dchild->d_inode, 0);
+ if (rc) {
+ up(&dchild->d_inode->i_sem);
+ RETURN(rc);
+ }
+ }
+ if (rec != NULL) {
+ /* no EA: create objects */
+ rc = mds_create_objects(req, 2, rec, mds, obd,
+ dchild->d_inode, handle, &ids);
+ if (rc) {
+ CERROR("mds_create_objects: rc = %d\n", rc);
+ up(&dchild->d_inode->i_sem);
+ RETURN(rc);
+ }
+ }
+ /* If the inode has EA data, then OSTs hold size, mtime */
+ if (S_ISREG(dchild->d_inode->i_mode) &&
+ !(body->valid & OBD_MD_FLEASIZE)) {
+ body->valid |= (OBD_MD_FLSIZE | OBD_MD_FLBLOCKS |
+ OBD_MD_FLATIME | OBD_MD_FLMTIME);
+ }
+ up(&dchild->d_inode->i_sem);
+
+ intent_set_disposition(rep, DISP_OPEN_OPEN);
+ mfd = mds_dentry_open(dchild, mds->mds_vfsmnt, flags, req);
+ if (IS_ERR(mfd))
+ RETURN(PTR_ERR(mfd));
+
+ CDEBUG(D_INODE, "mfd %p, cookie "LPX64"\n", mfd,
+ mfd->mfd_handle.h_cookie);
+ if (ids != NULL) {
+ mds_lov_update_objids(obd, ids);
+ OBD_FREE(ids, sizeof(*ids) * mds->mds_lov_desc.ld_tgt_count);
+ }
+ //if (rc)
+ // mds_mfd_destroy(mfd);
+ RETURN(rc);
+}
+
+static int mds_open_by_fid(struct ptlrpc_request *req, struct ll_fid *fid,
+ struct mds_body *body, int flags,
+ struct mds_update_record *rec,struct ldlm_reply *rep)
+{
+ struct mds_obd *mds = mds_req2mds(req);
+ struct inode *pending_dir = mds->mds_pending_dir->d_inode;
+ struct dentry *dchild;
+ char fidname[LL_FID_NAMELEN];
+ int fidlen = 0, rc;
+ void *handle = NULL;
+ ENTRY;
+
+ down(&pending_dir->i_sem);
+ fidlen = ll_fid2str(fidname, fid->id, fid->generation);
+ dchild = lookup_one_len(fidname, mds->mds_pending_dir, fidlen);
+ if (IS_ERR(dchild)) {
+ up(&pending_dir->i_sem);
+ rc = PTR_ERR(dchild);
+ CERROR("error looking up %s in PENDING: rc = %d\n",fidname, rc);
+ RETURN(rc);
+ }
+
+ if (dchild->d_inode != NULL) {
+ up(&pending_dir->i_sem);
+ mds_inode_set_orphan(dchild->d_inode);
+ mds_pack_inode2fid(&body->fid1, dchild->d_inode);
+ mds_pack_inode2body(body, dchild->d_inode);
+ intent_set_disposition(rep, DISP_LOOKUP_EXECD);
+ intent_set_disposition(rep, DISP_LOOKUP_POS);
+ CWARN("Orphan %s found and opened in PENDING directory\n",
+ fidname);
+ goto open;
+ }
+ dput(dchild);
+ up(&pending_dir->i_sem);
+
+ /* We didn't find it in PENDING so it isn't an orphan. See
+ * if it was a regular inode that was previously created. */
+ dchild = mds_fid2dentry(mds, fid, NULL);
+ if (IS_ERR(dchild))
+ RETURN(PTR_ERR(dchild));
+
+ mds_pack_inode2fid(&body->fid1, dchild->d_inode);
+ mds_pack_inode2body(body, dchild->d_inode);
+ intent_set_disposition(rep, DISP_LOOKUP_EXECD);
+ intent_set_disposition(rep, DISP_LOOKUP_POS);
+
+ open:
+ rc = mds_finish_open(req, dchild, body, flags, &handle, rec, rep);
+ rc = mds_finish_transno(mds, dchild ? dchild->d_inode : NULL, handle,
+ req, rc, rep ? rep->lock_policy_res1 : 0);
+ /* XXX what do we do here if mds_finish_transno itself failed? */
+
+ l_dput(dchild);
+ RETURN(rc);
+}
+
+int mds_pin(struct ptlrpc_request *req)
+{
+ struct obd_device *obd = req->rq_export->exp_obd;
+ struct mds_body *request_body, *reply_body;
+ struct obd_run_ctxt saved;
+ int rc, size = sizeof(*reply_body);
+ ENTRY;
+
+ request_body = lustre_msg_buf(req->rq_reqmsg, 0, sizeof(*request_body));
+
+ rc = lustre_pack_reply(req, 1, &size, NULL);
+ if (rc)
+ RETURN(rc);
+ reply_body = lustre_msg_buf(req->rq_repmsg, 0, sizeof(*reply_body));
+
+ push_ctxt(&saved, &obd->obd_ctxt, NULL);
+ rc = mds_open_by_fid(req, &request_body->fid1, reply_body,
+ request_body->flags, NULL, NULL);
+ pop_ctxt(&saved, &obd->obd_ctxt, NULL);
+
+ RETURN(rc);
+}
+
+/* Get a lock on the ino to sync with creation WRT inode reuse (bug 2029).
+ * If child_lockh is NULL we just get the lock as a barrier to wait for
+ * other holders of this lock, and drop it right away again. */
+int mds_lock_new_child(struct obd_device *obd, struct inode *inode,
+ struct lustre_handle *child_lockh)
+{
+ struct ldlm_res_id child_res_id = { .name = { inode->i_ino, 0, 1, 0 } };
+ struct lustre_handle lockh;
+ int lock_flags = 0;
+ int rc;
+
+ if (child_lockh == NULL)
+ child_lockh = &lockh;
+
+ rc = ldlm_cli_enqueue(NULL, NULL, obd->obd_namespace, child_res_id,
+ LDLM_PLAIN, NULL, LCK_EX, &lock_flags,
+ mds_blocking_ast, ldlm_completion_ast, NULL, NULL,
+ NULL, 0, NULL, child_lockh);
+ if (rc != ELDLM_OK)
+ CERROR("ldlm_cli_enqueue: %d\n", rc);
+ else if (child_lockh == &lockh)
+ ldlm_lock_decref(child_lockh, LCK_EX);
+
+ RETURN(rc);
+}
+