diff --git a/src/client/sysint/sys-osd-dir.sm b/src/client/sysint/sys-osd-dir.sm index cdc60cf..1805bd9 100644 --- a/src/client/sysint/sys-osd-dir.sm +++ b/src/client/sysint/sys-osd-dir.sm @@ -36,7 +36,8 @@ extern job_context_id pint_client_sm_context; enum { OSD_DIROPS_RETRY = 191, OSD_PVFS_REMOVE = 192, - OSD_PVFS_LOCK_FAILED = 193 + OSD_PVFS_LOCK_FAILED = 193, + OSD_PVFS_ATOMIC_FAILED = 194 }; /* OSD directory completion function prototypes */ @@ -114,6 +115,7 @@ nested machine pvfs2_client_osd_dirops_attr1_sm { jump pvfs2_osd_msgpairarray_sm; success => osd_dirops_attr1_cleanup; + OSD_PVFS_ATOMIC_FAILED => osd_dirops_attr1_init; default => osd_dirops_attr1_failure; } @@ -528,26 +530,66 @@ static int osd_dirops_attr1_comp_fn(void *v_p, struct PVFS_server_resp *resp_p, int index) { - PVFS_error status = 0; + int ret = 0; PINT_smcb *smcb = v_p; PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT); + struct osd_command *command = &sm_p->msgpair.osd_command; gossip_debug(GOSSIP_CLIENT_DEBUG, "osd_dirops_attr1_comp_fn\n"); - status = osd_errno_from_status(sm_p->msgpair.osd_command.status); - if (status != 0) { + ret = osd_errno_from_status(sm_p->msgpair.osd_command.status); + if (ret != 0) { gossip_debug(GOSSIP_CLIENT_DEBUG, "osd_command_set_gen_cas failed %d\n", index); - return status; + goto out; + } + + ret = osd_command_attr_resolve(command); + if (ret) { + osd_error_xerrno(ret, "%s: osd_command_attr_resolve failed", __func__); + goto out; + } + + if (smcb->op == PVFS_SYS_CREATE || smcb->op == PVFS_SYS_MKDIR) { + /* insert dirent operation */ + if (command->attr[2].val == NULL) { + /* successful insert operation */ + ret = 0; + goto out; + } else { + /* + * insert operation failed. either the name is already being + * used or we have a hash collision. + */ + gossip_debug(GOSSIP_CLIENT_DEBUG, "Atomic CAS: insert failed\n"); + ret = OSD_PVFS_ATOMIC_FAILED; + goto out; + } + } else { + /* remove dirent operation */ + assert(command->attr[0].val && command->attr[2].val); + + if (get_ntohll(command->attr[0].val) == + get_ntohll(command->attr[2].val)) { + /* successful remove operation */ + ret = 0; + goto out; + } else { + /* remove operation failed */ + gossip_debug(GOSSIP_CLIENT_DEBUG, "Atomic CAS: remove failed\n"); + ret = OSD_PVFS_ATOMIC_FAILED; + goto out; + } } +out: /* free data alloced for the create, if this was an insert */ if (sm_p->msgpair.osd_command.attr->len) { free(sm_p->msgpair.osd_command.attr->val); } osd_command_attr_free(&sm_p->msgpair.osd_command); - return status; + return ret; } static PINT_sm_action osd_dirops_attr1_cleanup(