home *** CD-ROM | disk | FTP | other *** search
/ ftp.parl.clemson.edu / 2015-02-07.ftp.parl.clemson.edu.tar / ftp.parl.clemson.edu / pub / pvfs2 / orangefs-2.8.3-20110323.tar.gz / orangefs-2.8.3-20110323.tar / orangefs / src / client / sysint / sys-rename.sm < prev    next >
Text File  |  2011-01-11  |  29KB  |  990 lines

  1. /* 
  2.  * (C) 2003 Clemson University and The University of Chicago 
  3.  *
  4.  * Changes by Acxiom Corporation to add extra safety checks via getattr
  5.  * Copyright ⌐ Acxiom Corporation, 2005.
  6.  *
  7.  * See COPYING in top-level directory.
  8.  */
  9.  
  10. /** \file
  11.  *  \ingroup sysint
  12.  *
  13.  *  PVFS2 system interface routines for renaming an object (file
  14.  *  or directory).
  15.  */
  16.  
  17. #include <string.h>
  18. #include <assert.h>
  19.  
  20. #include "client-state-machine.h"
  21. #include "pvfs2-debug.h"
  22. #include "job.h"
  23. #include "gossip.h"
  24. #include "str-utils.h"
  25. #include "pint-cached-config.h"
  26. #include "PINT-reqproto-encode.h"
  27. #include "pint-util.h"
  28. #include "pvfs2-internal.h"
  29. #include "ncache.h"
  30.  
  31. extern job_context_id pint_client_sm_context;
  32.  
  33. enum
  34. {
  35.     RENAME_CHDIRENT = 130,
  36.     RENAME_REMOVE_REQUIRED,
  37.     RENAME_CRDIRENT_RETRY,
  38.     RENAME_RMDIRENT_RETRY
  39. };
  40.  
  41. static int rename_lookups_comp_fn(
  42.     void *v_p, struct PVFS_server_resp *resp_p, int index);
  43. static int rename_crdirent_comp_fn(
  44.     void *v_p, struct PVFS_server_resp *resp_p, int index);
  45. static int rename_rmdirent_comp_fn(
  46.     void *v_p, struct PVFS_server_resp *resp_p, int index);
  47. static int rename_chdirent_comp_fn(
  48.     void *v_p, struct PVFS_server_resp *resp_p, int index);
  49.  
  50. %%
  51.  
  52. machine pvfs2_client_rename_sm
  53. {
  54.     state init
  55.     {
  56.         run rename_init;
  57.         default => rename_lookups_setup_msgpair_array;
  58.     }
  59.  
  60.     state rename_lookups_setup_msgpair_array
  61.     {
  62.         run rename_lookups_setup_msgpair_array;
  63.         success => rename_lookups_xfer_msgpair_array;
  64.         default => rename_lookups_failure;
  65.     }
  66.  
  67.     state rename_lookups_xfer_msgpair_array
  68.     {
  69.         jump pvfs2_msgpairarray_sm;
  70.         success => rename_crdirent_setup_msgpair;
  71.         RENAME_CHDIRENT => rename_getattr_src;
  72.         default => rename_lookups_failure;
  73.     }
  74.  
  75.     state rename_getattr_src
  76.     {
  77.         jump pvfs2_client_getattr_sm;
  78.         success => rename_getattr_src_interpret;
  79.         default => cleanup;
  80.     }
  81.  
  82.     state rename_getattr_src_interpret
  83.     {
  84.         run rename_getattr_src_interpret;
  85.         default => rename_getattr_dest;
  86.     }
  87.  
  88.     state rename_getattr_dest
  89.     {
  90.         jump pvfs2_client_getattr_sm;
  91.         success => rename_chdirent_setup_msgpair;
  92.         default => cleanup;
  93.     }
  94.  
  95.     state rename_lookups_failure
  96.     {
  97.         run rename_lookups_failure;
  98.         default => cleanup;
  99.     }
  100.  
  101.     state rename_crdirent_setup_msgpair
  102.     {
  103.         run rename_crdirent_setup_msgpair;
  104.         success => rename_crdirent_xfer_msgpair;
  105.         default => rename_crdirent_retry_or_fail;
  106.     }
  107.  
  108.     state rename_crdirent_xfer_msgpair
  109.     {
  110.         jump pvfs2_msgpairarray_sm;
  111.         success => rename_rmdirent_setup_msgpair;
  112.         default => rename_crdirent_retry_or_fail;
  113.     }
  114.  
  115.     state rename_crdirent_retry_or_fail
  116.     {
  117.     run rename_crdirent_retry_or_fail;
  118.     RENAME_CRDIRENT_RETRY => rename_crdirent_timer;
  119.     default => cleanup;
  120.     }
  121.  
  122.     state rename_crdirent_timer
  123.     {
  124.     run rename_generic_timer;
  125.     default => rename_crdirent_setup_msgpair;
  126.     }
  127.  
  128.     state rename_rmdirent_setup_msgpair
  129.     {
  130.         run rename_rmdirent_setup_msgpair;
  131.         success => rename_rmdirent_xfer_msgpair;
  132.         default => rename_rmdirent_retry_or_fail;
  133.     }
  134.  
  135.     state rename_rmdirent_xfer_msgpair
  136.     {
  137.         jump pvfs2_msgpairarray_sm;
  138.         success => rename_check_for_remove;
  139.         default => rename_rmdirent_retry_or_fail;
  140.     }
  141.  
  142.     state rename_rmdirent_retry_or_fail
  143.     {
  144.     run rename_rmdirent_retry_or_fail;
  145.     RENAME_RMDIRENT_RETRY => rename_rmdirent_timer;
  146.     default => rename_rmdirent_failure;
  147.     }
  148.  
  149.     state rename_rmdirent_timer
  150.     {
  151.     run rename_generic_timer;
  152.     default => rename_rmdirent_setup_msgpair;
  153.     }
  154.  
  155.     state rename_rmdirent_failure
  156.     {
  157.         run rename_rmdirent_failure;
  158.         success => rename_rmdirent_setup_msgpair;
  159.     default => rename_warn_user_to_run_fsck;
  160.     }
  161.  
  162.     state rename_check_for_remove
  163.     {
  164.         run rename_check_for_remove;
  165.         RENAME_REMOVE_REQUIRED => rename_do_remove;
  166.         default => cleanup;
  167.     }
  168.  
  169.     state rename_do_remove
  170.     {
  171.         jump pvfs2_client_remove_helper_sm;
  172.         success => cleanup;
  173.         default => rename_warn_user_to_run_fsck;
  174.     }
  175.  
  176.     state rename_warn_user_to_run_fsck
  177.     {
  178.         run rename_warn_user_to_run_fsck;
  179.         default => cleanup;
  180.     }
  181.  
  182.     state rename_chdirent_setup_msgpair
  183.     {
  184.         run rename_chdirent_setup_msgpair;
  185.         success => rename_chdirent_xfer_msgpair;
  186.         default => rename_chdirent_failure;
  187.     }
  188.  
  189.     state rename_chdirent_xfer_msgpair
  190.     {
  191.         jump pvfs2_msgpairarray_sm;
  192.         success => rename_rmdirent_setup_msgpair;
  193.         default => rename_chdirent_failure;
  194.     }
  195.  
  196.     state rename_chdirent_failure
  197.     {
  198.         run rename_chdirent_failure;
  199.         default => cleanup;
  200.     }
  201.  
  202.     state cleanup
  203.     {
  204.         run rename_cleanup;
  205.         default => terminate;
  206.     }
  207. }
  208.  
  209. %%
  210.  
  211. /** Initiate renaming of an object.
  212.  *
  213.  *  \param old_entry original name of object
  214.  *  \param old_parent_ref reference to original parent directory of object
  215.  *  \param new_entry new name for object
  216.  *  \param new_parent_ref reference to new parent directory for object
  217.  *
  218.  *  \return 0 on success, -errno on failure.
  219.  */
  220. PVFS_error PVFS_isys_rename(
  221.     char *old_entry,
  222.     PVFS_object_ref old_parent_ref,
  223.     char *new_entry,
  224.     PVFS_object_ref new_parent_ref,
  225.     const PVFS_credentials *credentials,
  226.     PVFS_sys_op_id *op_id,
  227.     PVFS_hint hints,
  228.     void *user_ptr)
  229. {
  230.     PVFS_error ret = -PVFS_EINVAL;
  231.     PINT_smcb *smcb = NULL;
  232.     PINT_client_sm *sm_p = NULL;
  233.  
  234.     gossip_debug(GOSSIP_CLIENT_DEBUG, "PVFS_isys_rename entered\n");
  235.  
  236.     if ((old_entry == NULL) || (new_entry == NULL) ||
  237.         (old_parent_ref.handle == PVFS_HANDLE_NULL) ||
  238.         (old_parent_ref.fs_id == PVFS_FS_ID_NULL) ||
  239.         (new_parent_ref.handle == PVFS_HANDLE_NULL) ||
  240.         (new_parent_ref.fs_id == PVFS_FS_ID_NULL))
  241.     {
  242.         gossip_err("invalid (NULL) required argument\n");
  243.         return ret;
  244.     }
  245.  
  246.     /* don't even try to rename a file to itself */
  247.     if ((old_parent_ref.handle == new_parent_ref.handle) &&
  248.         (old_parent_ref.fs_id == new_parent_ref.fs_id) &&
  249.         (strcmp(old_entry, new_entry) == 0))
  250.     {
  251.         return ret;
  252.     }
  253.  
  254.     if ((strlen(new_entry) + 1) > PVFS_REQ_LIMIT_SEGMENT_BYTES)
  255.     {
  256.         return -PVFS_ENAMETOOLONG;
  257.     }
  258.  
  259.     PINT_smcb_alloc(&smcb, PVFS_SYS_RENAME,
  260.              sizeof(struct PINT_client_sm),
  261.              client_op_state_get_machine,
  262.              client_state_machine_terminate,
  263.              pint_client_sm_context);
  264.     if (smcb == NULL)
  265.     {
  266.         return -PVFS_ENOMEM;
  267.     }
  268.     sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  269.  
  270.     PINT_init_msgarray_params(sm_p, old_parent_ref.fs_id);
  271.     PINT_init_sysint_credentials(sm_p->cred_p, credentials);
  272.     /*
  273.       this state machine has several hardcoded 2's around because
  274.       we're dealing with 1 'old' entry, 1 'old' handle, 1 'old' parent
  275.       handle, 1 'new' entry, 1 'new' handle, and 1 'new' parent
  276.       handle.  the index of 0 deals with the 'old'; index 1 deals with
  277.       the 'new'.
  278.  
  279.       I've used this arguably confusing array notation so that we can
  280.       do old/new lookups and parent getattrs in parallel using the
  281.       msgarrays rather than doing a longer sequence of serial
  282.       msgpairs.
  283.     */
  284.     sm_p->u.rename.entries[0] = old_entry;
  285.     sm_p->u.rename.entries[1] = new_entry;
  286.     sm_p->u.rename.parent_refns[0] = old_parent_ref;
  287.     sm_p->u.rename.parent_refns[1] = new_parent_ref;
  288.     sm_p->u.rename.rmdirent_index = 0;
  289.     sm_p->u.rename.target_dirent_exists = 0;
  290.     sm_p->u.rename.stored_error_code = 0;
  291.     PVFS_hint_copy(hints, &sm_p->hints);
  292.     PVFS_hint_add(&sm_p->hints, PVFS_HINT_HANDLE_NAME, sizeof(PVFS_handle), &old_parent_ref.handle);
  293.  
  294.     gossip_debug(
  295.         GOSSIP_CLIENT_DEBUG, "Renaming file named %s (under [%llu,%d]\n\t"
  296.         "to %s (under [%llu,%d])\n", old_entry,
  297.         llu(old_parent_ref.handle), old_parent_ref.fs_id, new_entry,
  298.         llu(new_parent_ref.handle), new_parent_ref.fs_id);
  299.  
  300.     return PINT_client_state_machine_post(
  301.         smcb,  op_id, user_ptr);
  302. }
  303.  
  304. /** Rename an object.
  305.  *
  306.  *  \param old_entry original name of object
  307.  *  \param old_parent_ref reference to original parent directory of object
  308.  *  \param new_entry new name for object
  309.  *  \param new_parent_ref reference to new parent directory for object
  310.  *
  311.  *  \return 0 on success, -errno on failure.
  312.  */
  313. PVFS_error PVFS_sys_rename(
  314.     char *old_entry,
  315.     PVFS_object_ref old_parent_ref,
  316.     char *new_entry,
  317.     PVFS_object_ref new_parent_ref,
  318.     const PVFS_credentials *credentials,
  319.     PVFS_hint hints)
  320. {
  321.     PVFS_error ret = -PVFS_EINVAL, error = 0;
  322.     PVFS_sys_op_id op_id;
  323.  
  324.     gossip_debug(GOSSIP_CLIENT_DEBUG, "PVFS_sys_rename entered\n");
  325.  
  326.     ret = PVFS_isys_rename(old_entry, old_parent_ref, new_entry,
  327.                            new_parent_ref, credentials, &op_id, hints, NULL);
  328.     if (ret)
  329.     {
  330.         PVFS_perror_gossip("PVFS_isys_rename call", ret);
  331.         error = ret;
  332.     }
  333.     else
  334.     {
  335.         ret = PVFS_sys_wait(op_id, "rename", &error);
  336.         if (ret)
  337.         {
  338.             PVFS_perror_gossip("PVFS_sys_wait call", ret);
  339.             error = ret;
  340.         }
  341.     }
  342.  
  343.     PINT_sys_release(op_id);
  344.     return error;
  345. }
  346.  
  347. /****************************************************************/
  348.  
  349. static PINT_sm_action rename_init(
  350.         struct PINT_smcb *smcb, job_status_s *js_p)
  351. {
  352.     PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  353.     assert(js_p->error_code == 0);
  354.  
  355.     /* Invalidate the old entry in ncache */
  356.     PINT_ncache_invalidate(
  357.             (const char*) sm_p->u.rename.entries[0],
  358.             (const PVFS_object_ref*) &(sm_p->u.rename.parent_refns[0]));
  359.     /* Invalidate the new entry in ncache in case it already exists */
  360.     PINT_ncache_invalidate(
  361.             (const char*) sm_p->u.rename.entries[1],
  362.             (const PVFS_object_ref*) &(sm_p->u.rename.parent_refns[1]));
  363.  
  364.     return SM_ACTION_COMPLETE;
  365. }
  366.  
  367. static int rename_lookups_comp_fn(
  368.     void *v_p,
  369.     struct PVFS_server_resp *resp_p,
  370.     int index)
  371. {
  372.     PINT_smcb *smcb = v_p;
  373.     PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_MSGPAIR_PARENT_SM);
  374.     
  375.     gossip_debug(GOSSIP_CLIENT_DEBUG, "rename_lookups_comp_fn\n");
  376.  
  377.     assert(resp_p->op == PVFS_SERV_LOOKUP_PATH);
  378.     assert((index > -1) && (index < 2));
  379.  
  380.     gossip_debug(GOSSIP_CLIENT_DEBUG, "lookup[%d] got response %d\n",
  381.                  index, resp_p->status);
  382.  
  383.     /*
  384.      * if the index is 1, this failure just means that
  385.      * the target entry does not already exist, so it's
  386.      * expected and is not an error.
  387.      */
  388.     if(resp_p->status == -PVFS_ENOENT && index == 1)
  389.     {
  390.         /* note: don't change the actual resp structure, because the
  391.          * decoder counts on this to know how to release data structures
  392.          */
  393.         return 0;
  394.     }
  395.  
  396.     if(resp_p->status != 0)
  397.     {
  398.         return resp_p->status;
  399.     }
  400.  
  401.     /* SUCCESS! */
  402.  
  403.     /*
  404.       stash the refns -- 'old' or 'new' based on index;
  405.       generally we won't be here on index == 1, since 'new'
  406.       may not exist
  407.     */
  408.     assert(resp_p->u.lookup_path.handle_count == 1);
  409.     sm_p->u.rename.refns[index].handle =
  410.         resp_p->u.lookup_path.handle_array[0];
  411.     sm_p->u.rename.refns[index].fs_id =
  412.         sm_p->u.rename.parent_refns[index].fs_id;
  413.  
  414.     if (index == 0)
  415.     {
  416.         gossip_debug(
  417.             GOSSIP_CLIENT_DEBUG, "*** Looked up old handle %llu\n",
  418.             llu(sm_p->u.rename.refns[index].handle));
  419.     }
  420.     else
  421.     {
  422.         assert(index == 1);
  423.         /*
  424.           flag the fact that we need to do a dirent exchange on the
  425.           existing dirent, rather than creating a new one.  we flag it
  426.           for later handling, as we know we need to do this, but want
  427.           the getattr to be complete first so that permissions can be
  428.           properly verified before changing anything
  429.         */
  430.         sm_p->u.rename.target_dirent_exists = 1;
  431.         /* set fs_id and handle for getattr nested sm */
  432.         sm_p->object_ref = sm_p->u.rename.refns[0];
  433.  
  434.         if(sm_p->msgarray_op.msgarray[0].op_status == 0)
  435.         {
  436.             PINT_SM_GETATTR_STATE_FILL(
  437.                 sm_p->getattr,
  438.                 sm_p->object_ref,
  439.                 PVFS_ATTR_COMMON_ALL,
  440.                 PVFS_TYPE_NONE,
  441.                 0);
  442.  
  443.             /* if both lookups succeeded, then we need chdirent */
  444.             return RENAME_CHDIRENT;
  445.         }
  446.         else
  447.         {
  448.             /* if the first one failed, maintain its error code */
  449.             return(sm_p->msgarray_op.msgarray[0].op_status);
  450.         }
  451.     }
  452.     return 0;
  453. }
  454.  
  455. static int rename_crdirent_comp_fn(void *v_p,
  456.                                    struct PVFS_server_resp *resp_p,
  457.                                    int index)
  458. {
  459.     gossip_debug(GOSSIP_CLIENT_DEBUG, "rename_crdirent_comp_fn\n");
  460.  
  461.     assert(resp_p->op == PVFS_SERV_CRDIRENT);
  462.     return resp_p->status;
  463. }
  464.  
  465. static int rename_rmdirent_comp_fn(void *v_p,
  466.                                    struct PVFS_server_resp *resp_p,
  467.                                    int index)
  468. {
  469.     PINT_smcb *smcb = v_p;
  470.     PINT_client_sm *sm_p __attribute__((unused)) =
  471.         PINT_sm_frame(smcb, PINT_MSGPAIR_PARENT_SM);
  472.     gossip_debug(GOSSIP_CLIENT_DEBUG, "rename_rmdirent_comp_fn\n");
  473.  
  474.     assert(resp_p->op == PVFS_SERV_RMDIRENT);
  475.  
  476.     if (resp_p->status != 0)
  477.     {
  478.     return resp_p->status;
  479.     }
  480.  
  481.     /*
  482.       rmdirent returns handle of removed dirent; make sure it matches
  483.       the handle we asked to have removed (i.e. the 'old' handle)
  484.     */
  485.     assert(sm_p->u.rename.refns[0].handle ==
  486.            resp_p->u.rmdirent.entry_handle);
  487.  
  488.     return 0;
  489. }
  490.  
  491. static int rename_chdirent_comp_fn(
  492.     void *v_p, struct PVFS_server_resp *resp_p, int index)
  493. {
  494.     PINT_smcb *smcb = v_p;
  495.     PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_MSGPAIR_PARENT_SM);
  496.     
  497.     gossip_debug(GOSSIP_CLIENT_DEBUG, "rename_chdirent_comp_fn\n");
  498.  
  499.     assert(resp_p->op == PVFS_SERV_CHDIRENT);
  500.  
  501.     if (resp_p->status != 0)
  502.     {
  503.     return resp_p->status;
  504.     }
  505.  
  506.     /*
  507.       here we have the 'old' dirent handle that we've just replaced
  508.       with the target name; store it for later removal
  509.     */
  510.     sm_p->u.rename.old_dirent_handle =
  511.         resp_p->u.chdirent.old_dirent_handle;
  512.  
  513.     gossip_debug(GOSSIP_CLIENT_DEBUG, "got back old dirent handle %llu\n",
  514.                  llu(sm_p->u.rename.old_dirent_handle));
  515.  
  516.     return 0;
  517. }
  518.  
  519. static PINT_sm_action rename_lookups_setup_msgpair_array(
  520.         struct PINT_smcb *smcb, job_status_s *js_p)
  521. {
  522.     struct PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  523.     int ret = -PVFS_EINVAL, i = 0;
  524.     PINT_sm_msgpair_state *msg_p;
  525.  
  526.     js_p->error_code = 0;
  527.  
  528.     ret = PINT_msgpairarray_init(&sm_p->msgarray_op, 2);
  529.     if(ret != 0)
  530.     {
  531.         js_p->error_code = ret;
  532.         return SM_ACTION_COMPLETE;
  533.     }
  534.  
  535.     /* prepare to post the lookup send/recv pairs */
  536.     foreach_msgpair(&sm_p->msgarray_op, msg_p, i)
  537.     {
  538.  
  539.         gossip_debug(GOSSIP_CLIENT_DEBUG,
  540.                      "rename: posting lookup[%d] (%lld,%d)\n",
  541.                      i, llu(sm_p->u.rename.parent_refns[i].handle),
  542.                      sm_p->u.rename.parent_refns[i].fs_id);
  543.  
  544.         PINT_SERVREQ_LOOKUP_PATH_FILL(
  545.             msg_p->req,
  546.             *sm_p->cred_p,
  547.             sm_p->u.rename.entries[i],
  548.             sm_p->u.rename.parent_refns[i].fs_id,
  549.             sm_p->u.rename.parent_refns[i].handle,
  550.             PVFS_ATTR_COMMON_ALL,
  551.             sm_p->hints);
  552.  
  553.         /* fill in msgpair structure components */
  554.         msg_p->fs_id = sm_p->u.rename.parent_refns[i].fs_id;
  555.         msg_p->handle = sm_p->u.rename.parent_refns[i].handle;
  556.         msg_p->retry_flag = PVFS_MSGPAIR_RETRY;
  557.         msg_p->comp_fn = rename_lookups_comp_fn;
  558.  
  559.         ret = PINT_cached_config_map_to_server(
  560.             &msg_p->svr_addr, msg_p->handle, msg_p->fs_id);
  561.  
  562.         if (ret)
  563.         {
  564.             gossip_err("Failed to map meta server address\n");
  565.             js_p->error_code = ret;
  566.             break;
  567.         }
  568.     }
  569.  
  570.     PINT_sm_push_frame(smcb, 0, &sm_p->msgarray_op);
  571.     return SM_ACTION_COMPLETE;
  572. }
  573.  
  574. static PINT_sm_action rename_lookups_failure(
  575.         struct PINT_smcb *smcb, job_status_s *js_p)
  576. {
  577.     struct PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  578.     PINT_msgpairarray_destroy(&sm_p->msgarray_op);
  579.     return SM_ACTION_COMPLETE;
  580. }
  581.  
  582. static PINT_sm_action rename_crdirent_setup_msgpair(
  583.         struct PINT_smcb *smcb, job_status_s *js_p)
  584. {
  585.     struct PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  586.     int ret = -PVFS_EINVAL;
  587.     PINT_sm_msgpair_state *msg_p = NULL;
  588.  
  589.     js_p->error_code = 0;
  590.  
  591.     gossip_debug(GOSSIP_CLIENT_DEBUG," rename: posting crdirent req\n");
  592.  
  593.     assert(sm_p->msgarray_op.msgarray);
  594.     PINT_msgpair_init(&sm_p->msgarray_op);
  595.     msg_p = &sm_p->msgarray_op.msgpair;
  596.  
  597.     /*
  598.       hook the 'old' handle up to the new parent with the 'new_entry'
  599.       name -- on success we will have 2 dirents pointing to the same
  600.       metafile; only update the mtime and ctime, leaving atime as 0
  601.     */
  602.     PINT_SERVREQ_CRDIRENT_FILL(
  603.         msg_p->req,
  604.         *sm_p->cred_p,
  605.         sm_p->u.rename.entries[1],
  606.         sm_p->u.rename.refns[0].handle,
  607.         sm_p->u.rename.parent_refns[1].handle,
  608.         sm_p->u.rename.parent_refns[1].fs_id,
  609.         sm_p->hints);
  610.  
  611.     msg_p->fs_id = sm_p->u.rename.parent_refns[1].fs_id;
  612.     msg_p->handle = sm_p->u.rename.parent_refns[1].handle;
  613.     msg_p->retry_flag = PVFS_MSGPAIR_NO_RETRY;
  614.     msg_p->comp_fn = rename_crdirent_comp_fn;
  615.  
  616.     ret = PINT_cached_config_map_to_server(
  617.         &msg_p->svr_addr, msg_p->handle, msg_p->fs_id);
  618.  
  619.     if (ret)
  620.     {
  621.         gossip_err("Failed to map meta server address\n");
  622.         js_p->error_code = ret;
  623.     }
  624.  
  625.     PINT_sm_push_frame(smcb, 0, &sm_p->msgarray_op);
  626.     return SM_ACTION_COMPLETE;
  627. }
  628.  
  629. static PINT_sm_action rename_rmdirent_setup_msgpair(
  630.         struct PINT_smcb *smcb, job_status_s *js_p)
  631. {
  632.     struct PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  633.     int ret = -PVFS_EINVAL;
  634.     PINT_sm_msgpair_state *msg_p = NULL;
  635.  
  636.     js_p->error_code = 0;
  637.  
  638.     gossip_debug(GOSSIP_CLIENT_DEBUG," rename: posting rmdirent req\n");
  639.  
  640.     PINT_msgpair_init(&sm_p->msgarray_op);
  641.     msg_p = &sm_p->msgarray_op.msgpair;
  642.  
  643.     /*
  644.       in the normal case, the state machine will lead us here and we
  645.       need to remove the original dirent pointing to the 'old'
  646.       metafile in the 'old' parent directory.
  647.  
  648.       However, we can also be here on rename_rmdirent_failure.  the
  649.       sm_p->u.rename.rmdirent_index is used to dictate which dirent to
  650.       remove in that case.  (0 is 'old'; 1 is 'new').
  651.  
  652.       This only happens if we fail to rmdirent the 'old' parent.  In
  653.       that case we need to rmdirent the 'new' parent as cleanup.
  654.     */
  655.     PINT_SERVREQ_RMDIRENT_FILL(
  656.         msg_p->req,
  657.         *sm_p->cred_p,
  658.         sm_p->u.rename.parent_refns[sm_p->u.rename.rmdirent_index].fs_id,
  659.         sm_p->u.rename.parent_refns[sm_p->u.rename.rmdirent_index].handle,
  660.         sm_p->u.rename.entries[sm_p->u.rename.rmdirent_index],
  661.         sm_p->hints);
  662.  
  663.     msg_p->fs_id = sm_p->u.rename.parent_refns[
  664.         sm_p->u.rename.rmdirent_index].fs_id;
  665.     msg_p->handle = sm_p->u.rename.parent_refns[
  666.         sm_p->u.rename.rmdirent_index].handle;
  667.     msg_p->retry_flag = PVFS_MSGPAIR_NO_RETRY;
  668.     msg_p->comp_fn = rename_rmdirent_comp_fn;
  669.  
  670.     ret = PINT_cached_config_map_to_server(
  671.         &msg_p->svr_addr, msg_p->handle, msg_p->fs_id);
  672.  
  673.     if (ret)
  674.     {
  675.         gossip_err("Failed to map meta server address\n");
  676.        js_p->error_code = ret;
  677.     }
  678.  
  679.     PINT_sm_push_frame(smcb, 0, &sm_p->msgarray_op);
  680.     return SM_ACTION_COMPLETE;
  681. }
  682.  
  683. static PINT_sm_action rename_rmdirent_failure(
  684.         struct PINT_smcb *smcb, job_status_s *js_p)
  685. {
  686.     struct PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  687.     /*
  688.       in the normal case of failure (i.e. rmdirent_index == 0), we
  689.       need to rmdirent the previously created new dirent we've just
  690.       created.  the state machine already guides us back to
  691.       rmdirent_setup_msgpair, so all we need to is adjust the
  692.       rmdirent_index to point to the 'new' dirent entry.
  693.     */
  694.     if (sm_p->u.rename.rmdirent_index == 0)
  695.     {
  696.         gossip_debug(
  697.             GOSSIP_CLIENT_DEBUG, "cleaning up new dirent because of "
  698.             "previous failure.\n");
  699.         sm_p->u.rename.rmdirent_index++;
  700.     sm_p->u.rename.stored_error_code = js_p->error_code;
  701.     js_p->error_code = 0;
  702.     }
  703.     else
  704.     {
  705.         gossip_debug(
  706.             GOSSIP_CLIENT_DEBUG, "failed to clean up created dirent!\n");
  707.     /* leave error code untouched, fall to next state */
  708.     }
  709.     return SM_ACTION_COMPLETE;
  710. }
  711.  
  712. static PINT_sm_action rename_chdirent_setup_msgpair(
  713.         struct PINT_smcb *smcb, job_status_s *js_p)
  714. {
  715.     struct PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  716.     int ret = -PVFS_EINVAL;
  717.     PINT_sm_msgpair_state *msg_p = NULL;
  718.     PVFS_object_attr *attr = NULL;
  719.  
  720.     /* look at the result of the dest getattr and make sure everything looks
  721.      * ok before we continue
  722.      */
  723.     attr = &sm_p->getattr.attr;
  724.     assert(attr);
  725.     sm_p->u.rename.types[1] = attr->objtype;
  726.  
  727.     gossip_debug(GOSSIP_CLIENT_DEBUG,
  728.                  "rename dest type: %d\n", attr->objtype);
  729.     if(attr->objtype == PVFS_TYPE_DIRECTORY)
  730.     {
  731.         gossip_debug(GOSSIP_CLIENT_DEBUG,
  732.                  "rename dest dirent_count: %lld\n",
  733.                  lld(attr->u.dir.dirent_count));
  734.         gossip_debug(GOSSIP_CLIENT_DEBUG,
  735.                  "rename dest attr mask: %d\n", (int)attr->mask);
  736.         gossip_debug(GOSSIP_CLIENT_DEBUG,
  737.                  "rename dest handle %llu\n", llu(sm_p->object_ref.handle));
  738.     }
  739.  
  740.     /* if the destination is a directory, is it empty? */
  741.     if(attr->objtype == PVFS_TYPE_DIRECTORY && attr->u.dir.dirent_count != 0)
  742.     {
  743.         js_p->error_code = -PVFS_ENOTEMPTY;
  744.         return SM_ACTION_COMPLETE;
  745.     }
  746.     
  747.     /* do the types match? */
  748.     if(sm_p->u.rename.types[0] != sm_p->u.rename.types[1])
  749.     {
  750.         if(sm_p->u.rename.types[1] == PVFS_TYPE_DIRECTORY)
  751.         {
  752.             js_p->error_code = -PVFS_EISDIR;
  753.             return SM_ACTION_COMPLETE;
  754.         }
  755.         if(sm_p->u.rename.types[1] == PVFS_TYPE_DIRECTORY)
  756.         {
  757.             js_p->error_code = -PVFS_ENOTDIR;
  758.             return SM_ACTION_COMPLETE;
  759.         }
  760.         /* TODO: what about other cases? */
  761.         js_p->error_code = -PVFS_EINVAL;
  762.         return SM_ACTION_COMPLETE;
  763.     }
  764.  
  765.     /* do the fsid's match? */
  766.     if(sm_p->u.rename.refns[0].fs_id != sm_p->u.rename.refns[1].fs_id)
  767.     {
  768.         js_p->error_code = -PVFS_ENODEV;
  769.         return SM_ACTION_COMPLETE;
  770.     }
  771.  
  772.     js_p->error_code = 0;
  773.  
  774.     gossip_debug(GOSSIP_CLIENT_DEBUG," rename: posting chdirent req\n");
  775.  
  776.     PINT_msgpair_init(&sm_p->msgarray_op);
  777.     msg_p = &sm_p->msgarray_op.msgpair;
  778.  
  779.     /*
  780.       here, we're exhanging the existing dirent under the 'new' parent
  781.       refn that matches the 'new entry' with the 'old' -- on success
  782.       we will have 2 dirents pointing to the same metafile
  783.     */
  784.     PINT_SERVREQ_CHDIRENT_FILL(
  785.         msg_p->req,
  786.         *sm_p->cred_p,
  787.         sm_p->u.rename.parent_refns[1].fs_id,
  788.         sm_p->u.rename.parent_refns[1].handle,
  789.         sm_p->u.rename.refns[0].handle,
  790.         sm_p->u.rename.entries[1],
  791.         sm_p->hints);
  792.  
  793.     msg_p->fs_id = sm_p->u.rename.parent_refns[1].fs_id;
  794.     msg_p->handle = sm_p->u.rename.parent_refns[1].handle;
  795.     msg_p->retry_flag = PVFS_MSGPAIR_RETRY;
  796.     msg_p->comp_fn = rename_chdirent_comp_fn;
  797.  
  798.     ret = PINT_cached_config_map_to_server(
  799.         &msg_p->svr_addr, msg_p->handle, msg_p->fs_id);
  800.  
  801.     if (ret)
  802.     {
  803.         gossip_err("Failed to map meta server address\n");
  804.         js_p->error_code = ret;
  805.     }
  806.  
  807.     PINT_sm_push_frame(smcb, 0, &sm_p->msgarray_op);
  808.     return SM_ACTION_COMPLETE;
  809. }
  810.  
  811. static PINT_sm_action rename_chdirent_failure(
  812.         struct PINT_smcb *smcb, job_status_s *js_p)
  813. {
  814.     return SM_ACTION_COMPLETE;
  815. }
  816.  
  817. static PINT_sm_action rename_check_for_remove(
  818.         struct PINT_smcb *smcb, job_status_s *js_p)
  819. {
  820.     struct PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  821.  
  822.     js_p->error_code = 0;
  823.  
  824.     if (sm_p->u.rename.target_dirent_exists)
  825.     {
  826.         js_p->error_code = RENAME_REMOVE_REQUIRED;
  827.     }
  828.  
  829.     /* setup the handle to be removed */
  830.     sm_p->object_ref.handle = sm_p->u.rename.old_dirent_handle;
  831.     sm_p->object_ref.fs_id = sm_p->u.rename.parent_refns[1].fs_id;
  832.  
  833.     return SM_ACTION_COMPLETE;
  834. }
  835.  
  836. static PINT_sm_action rename_warn_user_to_run_fsck(
  837.         struct PINT_smcb *smcb, job_status_s *js_p)
  838. {
  839.     gossip_err("WARNING: PVFS_sys_rename() encountered an error which "
  840.                "may lead to inconsistent state.\n");
  841.     gossip_err("WARNING: PVFS2 fsck (if available) may be needed.\n");
  842.  
  843.     return SM_ACTION_COMPLETE;
  844. }
  845.  
  846. static PINT_sm_action rename_cleanup(
  847.         struct PINT_smcb *smcb, job_status_s *js_p)
  848. {
  849.     struct PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  850.     sm_p->error_code = (sm_p->u.rename.stored_error_code ?
  851.                         sm_p->u.rename.stored_error_code :
  852.                         js_p->error_code);
  853.  
  854.     if(sm_p->error_code != 0)
  855.     {
  856.         PINT_acache_invalidate(sm_p->object_ref);
  857.     }
  858.     else
  859.     {
  860.         gossip_debug(GOSSIP_CLIENT_DEBUG,
  861.             "rename state: updating ncache with entry [%s] "
  862.             "ref.handle=%llu ref.fsid=%d\n",
  863.             sm_p->u.rename.entries[1],
  864.             llu(sm_p->u.rename.refns[0].handle),
  865.             sm_p->u.rename.parent_refns[1].fs_id);
  866.  
  867.         PINT_ncache_update((const char*) sm_p->u.rename.entries[1],
  868.             (const PVFS_object_ref*) &(sm_p->u.rename.refns[0]),
  869.             (const PVFS_object_ref*) &(sm_p->u.rename.parent_refns[1]));
  870.     }
  871.  
  872.     PINT_SM_GETATTR_STATE_CLEAR(sm_p->getattr);
  873.  
  874.     PINT_msgpairarray_destroy(&sm_p->msgarray_op);
  875.     PINT_SET_OP_COMPLETE;
  876.     return SM_ACTION_TERMINATE;
  877. }
  878.  
  879. static PINT_sm_action rename_generic_timer(
  880.         struct PINT_smcb *smcb, job_status_s *js_p)
  881. {
  882.     struct PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  883.     int ret = -PVFS_EINVAL;
  884.     job_id_t tmp_id;
  885.  
  886.     ret = job_req_sched_post_timer(
  887.     sm_p->msgarray_op.params.retry_delay, smcb, 0, js_p, &tmp_id,
  888.         pint_client_sm_context);
  889.  
  890.     return ret;
  891. }
  892.  
  893. static PINT_sm_action rename_crdirent_retry_or_fail(
  894.         struct PINT_smcb *smcb, job_status_s *js_p)
  895. {
  896.     struct PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  897.  
  898.     /* try again (up to a point) if we get a comm. failure. */
  899.     if ((PVFS_ERROR_CLASS(-js_p->error_code) == PVFS_ERROR_BMI) &&
  900.     (sm_p->u.rename.retry_count < sm_p->msgarray_op.params.retry_limit))
  901.     {
  902.     sm_p->u.rename.retry_count++;
  903.     js_p->error_code = RENAME_CRDIRENT_RETRY;
  904.     return SM_ACTION_COMPLETE;
  905.     }
  906.  
  907.     if ((js_p->error_code == -PVFS_EEXIST) &&
  908.         (sm_p->u.rename.retry_count > 0))
  909.     {
  910.     /* assume everything worked out ok and we got the right
  911.      * directory entry back.  there was just a transient network
  912.      * problem along the way
  913.      */
  914.     js_p->error_code = 0;
  915.     return SM_ACTION_COMPLETE;
  916.     }
  917.  
  918.     /* let other errors fall through to next state */
  919.     return SM_ACTION_COMPLETE;
  920. }
  921.  
  922. static PINT_sm_action rename_rmdirent_retry_or_fail(
  923.         struct PINT_smcb *smcb, job_status_s *js_p)
  924. {
  925.     struct PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  926.  
  927.     /* try again (up to a point) if we get a comm. failure. */
  928.     if ((PVFS_ERROR_CLASS(-js_p->error_code) == PVFS_ERROR_BMI) &&
  929.     (sm_p->u.rename.retry_count < sm_p->msgarray_op.params.retry_limit))
  930.     {
  931.     sm_p->u.rename.retry_count++;
  932.     js_p->error_code = RENAME_RMDIRENT_RETRY;
  933.     return SM_ACTION_COMPLETE;
  934.     }
  935.  
  936.     if ((js_p->error_code == -PVFS_ENOENT) &&
  937.         (sm_p->u.rename.retry_count > 0))
  938.     {
  939.     /* tricky error case.  The rmdirent failed, but it wasn't our
  940.      * first try.  Assume that a previous one was successful and
  941.      * we just didn't get the response.  This particular case
  942.      * isn't as dangerous in rename as it is in remove.  Just let
  943.      * it go without warning.
  944.      */
  945.     js_p->error_code = 0;
  946.     return SM_ACTION_COMPLETE;
  947.     }
  948.  
  949.     /* let other errors fall through to next state */
  950.     return SM_ACTION_COMPLETE;
  951. }
  952.  
  953. static PINT_sm_action rename_getattr_src_interpret(
  954.         struct PINT_smcb *smcb, job_status_s *js_p)
  955. {
  956.     struct PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  957.     PVFS_object_attr *attr = NULL;
  958.  
  959.     attr = &sm_p->getattr.attr;
  960.     assert(attr);
  961.  
  962.     sm_p->u.rename.types[0] = attr->objtype;
  963.  
  964.      /* setup for destination getattr */
  965.     sm_p->object_ref = sm_p->u.rename.refns[1];
  966.  
  967.     PINT_SM_GETATTR_STATE_CLEAR(sm_p->getattr);
  968.     /* NOTE: we ask for the dirent count on the destination.  This is
  969.      * important so that we can confirm that the destination is empty if it
  970.      * happens to be a directory rather than a file.
  971.      */
  972.     PINT_SM_GETATTR_STATE_FILL(sm_p->getattr,
  973.                                sm_p->object_ref,
  974.                                (PVFS_ATTR_COMMON_ALL|PVFS_ATTR_DIR_DIRENT_COUNT),
  975.                                PVFS_TYPE_NONE,
  976.                                PINT_SM_GETATTR_BYPASS_CACHE);
  977.     js_p->error_code = 0;
  978.     return SM_ACTION_COMPLETE;
  979. }
  980.  
  981. /*
  982.  * Local variables:
  983.  *  mode: c
  984.  *  c-indent-level: 4
  985.  *  c-basic-offset: 4
  986.  * End:
  987.  *
  988.  * vim: ft=c ts=8 sts=4 sw=4 expandtab
  989.  */
  990.