+ struct dentry *de = NULL;
+ struct mds_obd *mds = &req->rq_obd->u.mds;
+ struct dentry *dchild = NULL;
+ struct inode *dir;
+ void *handle;
+ int rc = 0, type = rec->ur_mode & S_IFMT;
+ ENTRY;
+
+ de = mds_fid2dentry(mds, rec->ur_fid1, NULL);
+ if (IS_ERR(de) || OBD_FAIL_CHECK(OBD_FAIL_MDS_REINT_CREATE)) {
+ LBUG();
+ GOTO(out_create_de, rc = -ESTALE);
+ }
+ dir = de->d_inode;
+ CDEBUG(D_INODE, "ino %ld\n", dir->i_ino);
+
+ down(&dir->i_sem);
+ dchild = lookup_one_len(rec->ur_name, de, rec->ur_namelen - 1);
+ if (IS_ERR(dchild)) {
+ CERROR("child lookup error %ld\n", PTR_ERR(dchild));
+ up(&dir->i_sem);
+ LBUG();
+ GOTO(out_create_dchild, rc = -ESTALE);
+ }
+
+ if (dchild->d_inode) {
+ CERROR("child exists (dir %ld, name %s)\n",
+ dir->i_ino, rec->ur_name);
+ LBUG();
+ GOTO(out_create_dchild, rc = -EEXIST);
+ }
+
+ OBD_FAIL_WRITE(OBD_FAIL_MDS_REINT_CREATE_WRITE, dir->i_sb->s_dev);
+
+ switch (type) {
+ case S_IFREG: {
+ handle = mds_fs_start(mds, dir, MDS_FSOP_CREATE);
+ if (!handle)
+ GOTO(out_create_dchild, PTR_ERR(handle));
+ rc = vfs_create(dir, dchild, rec->ur_mode);
+ EXIT;
+ break;
+ }
+ case S_IFDIR: {
+ handle = mds_fs_start(mds, dir, MDS_FSOP_MKDIR);
+ if (!handle)
+ GOTO(out_create_dchild, PTR_ERR(handle));
+ rc = vfs_mkdir(dir, dchild, rec->ur_mode);
+ EXIT;
+ break;
+ }
+ case S_IFLNK: {
+ handle = mds_fs_start(mds, dir, MDS_FSOP_SYMLINK);
+ if (!handle)
+ GOTO(out_create_dchild, PTR_ERR(handle));
+ rc = vfs_symlink(dir, dchild, rec->ur_tgt);
+ EXIT;
+ break;
+ }
+ case S_IFCHR:
+ case S_IFBLK:
+ case S_IFIFO:
+ case S_IFSOCK: {
+ int rdev = rec->ur_id;
+ handle = mds_fs_start(mds, dir, MDS_FSOP_MKNOD);
+ if (!handle)
+ GOTO(out_create_dchild, PTR_ERR(handle));
+ rc = vfs_mknod(dir, dchild, rec->ur_mode, rdev);
+ EXIT;
+ break;
+ }
+ default:
+ CERROR("bad file type %d for create of %s\n",type,rec->ur_name);
+ GOTO(out_create_dchild, rc = -EINVAL);
+ }
+
+ if (rc) {
+ CERROR("error during create: %d\n", rc);
+ LBUG();
+ GOTO(out_create_commit, rc);
+ } else {
+ struct iattr iattr;
+ struct inode *inode = dchild->d_inode;
+ struct mds_body *body;
+
+ if (type == S_IFREG) {
+ rc = mds_fs_set_objid(mds, inode, handle, rec->ur_id);
+ if (rc)
+ CERROR("error %d setting objid for %ld\n",
+ rc, inode->i_ino);
+ }
+
+ iattr.ia_atime = rec->ur_time;
+ iattr.ia_ctime = rec->ur_time;
+ iattr.ia_mtime = rec->ur_time;
+ iattr.ia_uid = rec->ur_uid;
+ iattr.ia_gid = rec->ur_gid;
+ iattr.ia_valid = ATTR_UID | ATTR_GID | ATTR_ATIME |
+ ATTR_MTIME | ATTR_CTIME;
+
+ rc = mds_fs_setattr(mds, dchild, handle, &iattr);
+ /* XXX should we abort here in case of error? */
+
+ body = lustre_msg_buf(req->rq_repmsg, 0);
+ body->ino = inode->i_ino;
+ body->generation = inode->i_generation;
+ }
+
+ if (!rc)
+ rc = mds_update_last_rcvd(mds, req);
+
+out_create_commit:
+ /* FIXME: keep rc intact */
+ rc = mds_fs_commit(mds, dir, handle);
+out_create_dchild:
+ l_dput(dchild);
+ up(&dir->i_sem);
+out_create_de:
+ l_dput(de);
+ req->rq_status = rc;
+ return 0;