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 / client-state-machine.c < prev    next >
C/C++ Source or Header  |  2010-05-24  |  34KB  |  1,153 lines

  1. /* 
  2.  * (C) 2003 Clemson University and The University of Chicago 
  3.  *
  4.  * See COPYING in top-level directory.
  5.  */
  6.  
  7. /** \file
  8.  *  Routines for state machine processing on clients.
  9.  */
  10. #include <string.h>
  11. #include <assert.h>
  12.  
  13. #include "pvfs2-sysint.h"
  14. #include "pint-sysint-utils.h"
  15. #include "pvfs2-internal.h"
  16. #include "pint-cached-config.h"
  17. #include "PINT-reqproto-encode.h"
  18.  
  19. #include "state-machine.h"
  20. #include "client-state-machine.h"
  21. #include "pvfs2-debug.h"
  22. #include "job.h"
  23. #include "gossip.h"
  24. #include "pvfs2-util.h"
  25. #include "id-generator.h"
  26. #include "ncache.h"
  27. #include "acache.h"
  28. #include "pint-event.h"
  29. #include "pint-hint.h"
  30.  
  31. #define MAX_RETURNED_JOBS   256
  32.  
  33. job_context_id pint_client_sm_context = -1;
  34.  
  35. extern int pint_client_pid;
  36.  
  37. extern PINT_event_id PINT_client_sys_event_id;
  38.  
  39. /*
  40.   used for locally storing completed operations from test() call so
  41.   that we can retrieve them in testsome() while still making progress
  42.   (and possible completing operations in the test() call
  43. */
  44. static int s_completion_list_index = 0;
  45. static PINT_smcb *s_completion_list[MAX_RETURNED_JOBS] = {NULL};
  46. static gen_mutex_t s_completion_list_mutex = GEN_MUTEX_INITIALIZER;
  47. static gen_mutex_t test_mutex = GEN_MUTEX_INITIALIZER;
  48.  
  49. static void PINT_sys_release_smcb(PINT_smcb *smcb);
  50.  
  51. #define CLIENT_SM_ASSERT_INITIALIZED()  \
  52. do { assert(pint_client_sm_context != -1); } while(0)
  53.  
  54. int PINT_client_state_machine_initialize(void)
  55. {
  56.     return job_open_context(&pint_client_sm_context);
  57. }
  58.  
  59. void PINT_client_state_machine_finalize(void)
  60. {
  61.     job_close_context(pint_client_sm_context);
  62. }
  63.  
  64. job_context_id PINT_client_get_sm_context(void)
  65. {
  66.     return pint_client_sm_context;
  67. }
  68.  
  69. static PVFS_error add_sm_to_completion_list(PINT_smcb *smcb)
  70. {
  71.     gen_mutex_lock(&s_completion_list_mutex);
  72.     assert(s_completion_list_index < MAX_RETURNED_JOBS);
  73.     if (!smcb->op_completed)
  74.     {
  75.         smcb->op_completed = 1;
  76.         s_completion_list[s_completion_list_index++] = smcb;
  77.     }
  78.     gen_mutex_unlock(&s_completion_list_mutex);
  79.     return 0;
  80. }
  81.  
  82. /*
  83.   this method is used in the case of calling test() on an sm that was
  84.   already completed by a previous call to testsome().  in this case,
  85.   if the sm was added to the completion list, it MUST be removed
  86.   before returning from test()
  87. */
  88. static int conditional_remove_sm_if_in_completion_list(PINT_smcb *smcb)
  89. {
  90.     int found = 0, i = 0;
  91.  
  92.     gen_mutex_lock(&s_completion_list_mutex);
  93.     for(i = 0; i < s_completion_list_index; i++)
  94.     {
  95.         if (s_completion_list[i] == smcb)
  96.         {
  97.             if(i == (s_completion_list_index - 1))
  98.             {
  99.                 /* we're at the end, so just set last sm to null */
  100.                 s_completion_list[i] = NULL;
  101.             }
  102.             else
  103.             {
  104.                 memmove(&s_completion_list[i],
  105.                         &s_completion_list[i+1],
  106.                         (s_completion_list_index - (i + 1)) *
  107.                         sizeof(PINT_smcb *));
  108.             }
  109.             s_completion_list_index--;
  110.             found = 1;
  111.             break;
  112.         }
  113.     }
  114.     gen_mutex_unlock(&s_completion_list_mutex);
  115.     return found;
  116. }
  117.  
  118. static PVFS_error completion_list_retrieve_completed(
  119.     PVFS_sys_op_id *op_id_array,
  120.     void **user_ptr_array,
  121.     int *error_code_array,
  122.     int limit,
  123.     int *out_count)  /* what exactly is this supposed to return */
  124. {
  125.     int i = 0, new_list_index = 0;
  126.     PINT_smcb *smcb = NULL;
  127.     PINT_smcb *tmp_completion_list[MAX_RETURNED_JOBS] = {NULL};
  128.     PINT_client_sm *sm_p;
  129.  
  130.     assert(op_id_array);
  131.     assert(error_code_array);
  132.     assert(out_count);
  133.  
  134.     memset(tmp_completion_list, 0,
  135.            (MAX_RETURNED_JOBS * sizeof(PINT_smcb *)));
  136.  
  137.     gen_mutex_lock(&s_completion_list_mutex);
  138.     for(i = 0; i < s_completion_list_index; i++)
  139.     {
  140.         if (s_completion_list[i] == NULL)
  141.         {
  142.             continue;
  143.         }
  144.  
  145.         smcb = s_completion_list[i];
  146.         assert(smcb);
  147.  
  148.         if (i < limit)
  149.         {
  150.             sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  151.             op_id_array[i] = sm_p->sys_op_id;
  152.             error_code_array[i] = sm_p->error_code;
  153.  
  154.             if (user_ptr_array)
  155.             {
  156.                 /* if this smcb has been set cancelled and is a PVFS_SYS_IO
  157.                  * state machine then stick the user_ptr of the base frame
  158.                  * in to the user_ptr_array instead of the standard sm_p 
  159.                  * user_ptr. This prevents segfaults back in 
  160.                  * process_vfs_requests which expects the pointer to be a 
  161.                  * vfs_request.
  162.                  */
  163.                 if( smcb->op_cancelled && smcb->op == PVFS_SYS_IO )
  164.                 {
  165.                     PINT_client_sm *sm_base_p = PINT_sm_frame(smcb,
  166.                                                  (-(smcb->frame_count -1)));
  167.                     assert(sm_base_p);
  168.                     gossip_debug(GOSSIP_CANCEL_DEBUG, "%s: assignment of "
  169.                                  "PVFS_SYS_IO user_ptr from sm_base_p(%p), "
  170.                                  "user_ptr(%p)\n", __func__, sm_base_p, 
  171.                                  sm_base_p->user_ptr);
  172.                     user_ptr_array[i] = sm_base_p->user_ptr;
  173.                 }
  174.                 else
  175.                 {
  176.                     user_ptr_array[i] = (void *)sm_p->user_ptr;
  177.                 }
  178.             }
  179.             s_completion_list[i] = NULL;
  180.  
  181.             PINT_sys_release(sm_p->sys_op_id);
  182.         }
  183.         else
  184.         {
  185.             tmp_completion_list[new_list_index++] = smcb;
  186.         }
  187.     }
  188.     *out_count = PVFS_util_min(i, limit);
  189.  
  190.     /* clean up and adjust the list and it's book keeping */
  191.     s_completion_list_index = new_list_index;
  192.     memcpy(s_completion_list, tmp_completion_list,
  193.            (MAX_RETURNED_JOBS * sizeof(struct PINT_smcb *)));
  194.     
  195.     gen_mutex_unlock(&s_completion_list_mutex);
  196.     return 0;
  197. }
  198.  
  199. static inline int cancelled_io_jobs_are_pending(PINT_smcb *smcb)
  200. {
  201.     PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  202.     /*
  203.       NOTE: if the I/O cancellation has properly completed, the
  204.       cancelled contextual jobs within that I/O operation will be
  205.       popping out of the testcontext calls (in our testsome() or
  206.       test()).  to avoid passing out the same completed op mutliple
  207.       times, do not add the operation to the completion list until all
  208.       cancellations on the I/O operation are accounted for
  209.     */
  210.     assert(sm_p);
  211.     
  212.     PINT_client_sm *sm_base_p = 
  213.         PINT_sm_frame(smcb, (-(smcb->frame_count -1)));
  214.  
  215.     assert(sm_base_p);
  216.  
  217.     /*
  218.       this *can* possibly be 0 in the case that the I/O has already
  219.       completed and no job cancellation were issued at I/O cancel time
  220.     */
  221.     if (sm_base_p->u.io.total_cancellations_remaining > 0)
  222.     {
  223.         sm_base_p->u.io.total_cancellations_remaining--;
  224.     }
  225.  
  226.     gossip_debug(
  227.         GOSSIP_IO_DEBUG, "(%p) cancelled_io_jobs_are_pending: %d "
  228.         "remaining (op %s)\n", sm_base_p,
  229.         sm_base_p->u.io.total_cancellations_remaining,
  230.         (PINT_smcb_complete(smcb) ? "complete" : "NOT complete"));
  231.  
  232.     return (sm_base_p->u.io.total_cancellations_remaining != 0);
  233. }
  234.  
  235. /* this array must be ordered to match the enum in client-state-machine.h */ 
  236. struct PINT_client_op_entry_s PINT_client_sm_sys_table[] =
  237. {
  238.     {&pvfs2_client_remove_sm},
  239.     {&pvfs2_client_create_sm},
  240.     {&pvfs2_client_mkdir_sm},
  241.     {&pvfs2_client_symlink_sm},
  242.     {&pvfs2_client_sysint_getattr_sm},
  243.     {&pvfs2_client_io_sm},
  244.     {&pvfs2_client_flush_sm},
  245.     {&pvfs2_client_truncate_sm},
  246.     {&pvfs2_client_sysint_readdir_sm},
  247.     {&pvfs2_client_setattr_sm},
  248.     {&pvfs2_client_lookup_sm},
  249.     {&pvfs2_client_rename_sm},
  250.     {&pvfs2_client_get_eattr_sm},
  251.     {&pvfs2_client_set_eattr_sm},
  252.     {&pvfs2_client_del_eattr_sm},
  253.     {&pvfs2_client_list_eattr_sm},
  254.     {&pvfs2_client_small_io_sm},
  255.     {&pvfs2_client_statfs_sm},
  256.     {&pvfs2_fs_add_sm},
  257.     {&pvfs2_client_readdirplus_sm},
  258. };
  259.  
  260. struct PINT_client_op_entry_s PINT_client_sm_mgmt_table[] =
  261. {
  262.     {&pvfs2_client_mgmt_setparam_list_sm},
  263.     {&pvfs2_client_mgmt_noop_sm},
  264.     {&pvfs2_client_mgmt_statfs_list_sm},
  265.     {&pvfs2_client_mgmt_perf_mon_list_sm},
  266.     {&pvfs2_client_mgmt_iterate_handles_list_sm},
  267.     {&pvfs2_client_mgmt_get_dfile_array_sm},
  268.     {&pvfs2_client_mgmt_event_mon_list_sm},
  269.     {&pvfs2_client_mgmt_remove_object_sm},
  270.     {&pvfs2_client_mgmt_remove_dirent_sm},
  271.     {&pvfs2_client_mgmt_create_dirent_sm},
  272.     {&pvfs2_client_mgmt_get_dirdata_handle_sm}
  273. };
  274.  
  275.  
  276. /* This function allows the generic state-machine-fns.c locate function
  277.  * to access the appropriate sm struct based on the client operation index
  278.  * from the above enum.  Because the enum starts management operations at
  279.  * 70, the management table was separated out from the sys table and the
  280.  * necessary checks and subtractions are made in this macro.
  281.  * Pointer to this func is put in SM control block for client SMs.
  282.  */
  283. /* NOTE; appears to be a latent bug that does not catch op values
  284.  * between largest sys op and lowest mgmt op - need to check on this
  285.  * WBL
  286.  */
  287. struct PINT_state_machine_s *client_op_state_get_machine(int op)
  288. {
  289.     gossip_debug(GOSSIP_CLIENT_DEBUG,
  290.                  "client_op_state_get_machine %d\n",op);
  291.  
  292.     switch (op)
  293.     {
  294.     /* special cases first */
  295.     case PVFS_SERVER_GET_CONFIG :
  296.         return &pvfs2_server_get_config_sm;
  297.     case PVFS_CLIENT_JOB_TIMER :
  298.         return &pvfs2_client_job_timer_sm;
  299.     case PVFS_CLIENT_PERF_COUNT_TIMER :
  300.         return &pvfs2_client_perf_count_timer_sm;
  301.     case PVFS_DEV_UNEXPECTED :
  302.         return &pvfs2_sysdev_unexp_sm;
  303.     default:
  304.         /* now check range for sys functions */
  305.         if (op <= PVFS_OP_SYS_MAXVAL)
  306.         {
  307.             return PINT_client_sm_sys_table[op-1].sm;
  308.         }
  309.         else
  310.         {
  311.             /* now checjk range for mgmt functions */
  312.             if (op <= PVFS_OP_MGMT_MAXVAL)
  313.             {
  314.                 return PINT_client_sm_mgmt_table[op-PVFS_OP_SYS_MAXVAL-1].sm;
  315.             }
  316.             else
  317.             {
  318.                 /* otherwise its out of range */
  319.                 return NULL;
  320.             }
  321.         }
  322.     }
  323. }
  324.  
  325. /* callback for a terminating state machine
  326.  * the client adds terminted jobs to a completion list, unless
  327.  * they were cancelled.
  328.  */
  329.  
  330. int client_state_machine_terminate(
  331.         struct PINT_smcb *smcb, job_status_s *js_p)
  332. {
  333.     int ret;
  334.     PINT_client_sm *sm_p;
  335.  
  336.     sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  337.  
  338.     gossip_debug(GOSSIP_CLIENT_DEBUG,
  339.                  "client_state_machine_terminate smcb %p\n",smcb);
  340.  
  341.     if (!((PINT_smcb_op(smcb) == PVFS_SYS_IO) &&
  342.             (PINT_smcb_cancelled(smcb)) &&
  343.             (cancelled_io_jobs_are_pending(smcb))) &&
  344.         !PINT_smcb_immediate_completion(smcb))
  345.     {
  346.         gossip_debug(GOSSIP_CLIENT_DEBUG,
  347.                  "client_state_machine_terminate smcb %p completing\n",smcb);
  348.  
  349.         PINT_EVENT_END(PINT_client_sys_event_id, pint_client_pid, NULL, sm_p->event_id, 0);
  350.  
  351.         PVFS_hint_free(sm_p->hints);
  352.         sm_p->hints = NULL;
  353.  
  354.         gossip_debug(GOSSIP_CLIENT_DEBUG, 
  355.                 "add smcb %p to completion list\n", smcb);
  356.         ret = add_sm_to_completion_list(smcb);
  357.         assert(ret == 0);
  358.     }
  359.     else
  360.     {
  361.         gossip_debug(GOSSIP_CLIENT_DEBUG,
  362.                  "client_state_machine_terminate smcb %p waiting for cancelled jobs\n",smcb);
  363.     }
  364.     return SM_ACTION_TERMINATE;
  365. }
  366.  
  367. /*
  368.   NOTE: important usage notes regarding post(), test(), and testsome()
  369.  
  370.   thread safety: test() and testsome() can be called in any order by
  371.   the same thread.  if you need to call test() and testsome()
  372.   simultaneously from different threads, you need to serialize the
  373.   calls yourself.
  374.  
  375.   calling semantics: the non-blocking calls (i.e. PVFS_isys_* or
  376.   PVFS_imgmt_* calls) allocate the state machine control block (smcb) used
  377.   for each operation.  the blocking calls DO NOT allocate this, but
  378.   call the non-blocking method (which does allocate it) and waits for
  379.   completion.  On completion, the blocking call frees the state
  380.   machine control block (via PINT_sys_release).  the blocking calls only
  381.   ever call the test() function, which does not free the state machine
  382.   control block on completion.
  383.  
  384.   the testsome() function frees the state machine pointers allocated
  385.   from the non-blocking calls on completion because any caller of
  386.   testsome() *should* be using the non-blocking calls with it.  this
  387.   means that if you are calling test() with a non-blocking operation
  388.   that you manually issued (with a PVFS_isys* or PVFS_imgmt* call),
  389.   you need to call PINT_sys_release on your own when the operation
  390.   completes.
  391.  
  392.   If the posted operation completes immediately, post will return 0,
  393.   and set the op_id to -1
  394. */
  395.  
  396. /** Adds a state machine into the list of machines that are being
  397.  *  actively serviced.
  398.  */
  399. PVFS_error PINT_client_state_machine_post(
  400.     PINT_smcb *smcb,
  401.     PVFS_sys_op_id *op_id,
  402.     void *user_ptr /* in */)
  403. {
  404.     PINT_sm_action sm_ret;
  405.     PVFS_error ret = -PVFS_EINVAL;
  406.     job_status_s js;
  407.     int pvfs_sys_op = PINT_smcb_op(smcb);
  408.     PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  409.  
  410.     PVFS_hint_add_internal(&sm_p->hints, PINT_HINT_OP_ID, sizeof(pvfs_sys_op), &pvfs_sys_op);
  411.  
  412.     PINT_EVENT_START(PINT_client_sys_event_id, pint_client_pid, NULL, &sm_p->event_id,
  413.                      PINT_HINT_GET_CLIENT_ID(sm_p->hints),
  414.                      PINT_HINT_GET_RANK(sm_p->hints),
  415.                      PINT_HINT_GET_REQUEST_ID(sm_p->hints),
  416.                      PINT_HINT_GET_HANDLE(sm_p->hints),
  417.                      pvfs_sys_op);
  418.  
  419.     gossip_debug(GOSSIP_CLIENT_DEBUG,
  420.                  "PINT_client_state_machine_post smcb %p, op: %s\n",
  421.                  smcb, PINT_client_get_name_str(smcb->op));
  422.  
  423.     CLIENT_SM_ASSERT_INITIALIZED();
  424.  
  425.     if (!smcb)
  426.     {
  427.         /* give back the hint added above */
  428.         PVFS_hint_free( sm_p->hints );
  429.         sm_p->hints = NULL;
  430.         return ret;
  431.     }
  432.  
  433.     memset(&js, 0, sizeof(js));
  434.  
  435.     /* save operation type; mark operation as unfinished */
  436.     sm_p->user_ptr = user_ptr;
  437.  
  438.     gen_mutex_lock(&test_mutex);
  439.     /*
  440.       start state machine and continue advancing while we're getting
  441.       immediate completions
  442.     */
  443.     sm_ret = PINT_state_machine_start(smcb, &js);
  444.     assert(SM_ACTION_ISVALID(sm_ret));
  445.  
  446.     if(sm_ret < 0)
  447.     {
  448.         /* state machine code failed */
  449.         gen_mutex_unlock(&test_mutex);
  450.  
  451.         /* give back the hint added above */
  452.         PVFS_hint_free( sm_p->hints );
  453.         sm_p->hints = NULL;
  454.  
  455.         return sm_ret;
  456.     }
  457.  
  458.     if (PINT_smcb_complete(smcb))
  459.     {
  460.         assert(sm_ret == SM_ACTION_TERMINATE);
  461.  
  462.         PINT_EVENT_END(PINT_client_sys_event_id, pint_client_pid, NULL, sm_p->event_id, 0);
  463.  
  464.         *op_id = -1;
  465.  
  466.         /* free the smcb and any other extra data allocated there */
  467.         PINT_sys_release_smcb(smcb);
  468.  
  469.         gossip_debug(
  470.             GOSSIP_CLIENT_DEBUG, "Posted %s (%llu) "
  471.                     "(ran to termination)(%d)\n",
  472.                     PINT_client_get_name_str(pvfs_sys_op),
  473.                     llu((op_id ? *op_id : -1)),
  474.                     js.error_code);
  475.  
  476.     }
  477.     else
  478.     {
  479.         assert(sm_ret == SM_ACTION_DEFERRED);
  480.  
  481.         PINT_id_gen_safe_register(&sm_p->sys_op_id, (void *)smcb);
  482.         if (op_id)
  483.         {
  484.             *op_id = sm_p->sys_op_id;
  485.         }
  486.  
  487.         gossip_debug(
  488.             GOSSIP_CLIENT_DEBUG, "Posted %s (%lld) "
  489.                     "(waiting for test)(%d)\n",
  490.                     PINT_client_get_name_str(pvfs_sys_op),
  491.                     lld((op_id ? *op_id : -1)),
  492.                     ret);
  493.     }
  494.     gen_mutex_unlock(&test_mutex);
  495.     return js.error_code;
  496. }
  497.  
  498. PVFS_error PINT_client_state_machine_release(
  499.     PINT_smcb * smcb)
  500. {
  501.     PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  502.  
  503.     if( sm_p )
  504.     {
  505.         PVFS_hint_free( sm_p->hints );
  506.         sm_p->hints = NULL;
  507.     }
  508.  
  509.     PINT_smcb_set_complete(smcb);
  510.  
  511.     PINT_id_gen_safe_unregister(sm_p->sys_op_id);
  512.  
  513.     /* free the internal hint list */
  514.     PVFS_hint_free(sm_p->hints);
  515.  
  516.     PINT_smcb_free(smcb);
  517.     return 0;
  518. }
  519.  
  520. /** Cancels in progress I/O operations.
  521.  *
  522.  * \return 0 on success, -PVFS_error on failure.
  523.  */
  524. PVFS_error PINT_client_io_cancel(PVFS_sys_op_id id)
  525. {
  526.     int i = 0;
  527.     PVFS_error ret = -PVFS_EINVAL;
  528.     PINT_smcb *smcb = NULL;
  529.     PINT_client_sm *sm_p = NULL;
  530.     PINT_client_sm *sm_base_p = NULL;
  531.  
  532.     gossip_debug(GOSSIP_CLIENT_DEBUG,
  533.             "PINT_client_io_cancel id %lld\n",lld(id));
  534.  
  535.     smcb = PINT_id_gen_safe_lookup(id);
  536.     if (!smcb)
  537.     {
  538.     /* if we can't find it, it may have already completed */
  539.         return 0;
  540.     }
  541.     sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  542.     if (!sm_p)
  543.     {
  544.     /* if we can't find it, it may have already completed */
  545.         return 0;
  546.     }
  547.  
  548.     /* we can't cancel any arbitrary operation */
  549.     assert(PINT_smcb_op(smcb) == PVFS_SYS_IO);
  550.  
  551.     if (PINT_smcb_complete(smcb))
  552.     {
  553.     /* op already completed; nothing to cancel. */
  554.         return 0;
  555.     }
  556.     
  557.     /* We also don't cancel small I/O operations as posted by
  558.      * sys-small-io.sm.  Check the corresponding flag.  We have 
  559.      * to jump to the base frame rather than the current frame for this
  560.      * information because small-io may have pushed a msgpairarray.
  561.      *
  562.      * sm_base_p is used below instead of sm_p since it contains the correct
  563.      * counters and context pointers. In the event the control block only
  564.      * has one frame it behaves as it did previously. If the cancellation is 
  565.      * occuring when a non-IO frame has been pushed on the stack, which doesn't
  566.      * have the expected structure, it doesn't cause a segfault but leaves
  567.      * it on the state machines stack.
  568.      */ 
  569.     sm_base_p = PINT_sm_frame(smcb, (-(smcb->frame_count -1)));
  570.     assert(sm_base_p);
  571.     if(sm_base_p->u.io.small_io)
  572.     {
  573.         gossip_debug(GOSSIP_CANCEL_DEBUG,  "skipping cancellation of small I/O operation.\n");
  574.         return(0);
  575.     }
  576.  
  577.     /* if we fall to here, the I/O operation is still in flight */
  578.     /* first, set a flag informing the sys_io state machine that the
  579.      * operation has been cancelled so it doesn't post any new jobs 
  580.      */
  581.     PINT_smcb_set_cancelled(smcb);
  582.  
  583.     /*
  584.       don't return an error if nothing is cancelled, because
  585.       everything may have completed already
  586.     */
  587.     ret = 0;
  588.  
  589.     /* now run through and cancel the outstanding jobs */
  590.     for(i = 0; i < sm_base_p->u.io.context_count; i++)
  591.     {
  592.         PINT_client_io_ctx *cur_ctx = &sm_base_p->u.io.contexts[i];
  593.         assert(cur_ctx);
  594.  
  595.         if (cur_ctx->msg_send_in_progress)
  596.         {
  597.             gossip_debug(GOSSIP_CANCEL_DEBUG,  "[%d] Posting "
  598.                          "cancellation of type: BMI Send "
  599.                          "(Request)\n",i);
  600.  
  601.             ret = job_bmi_cancel(cur_ctx->msg.send_id,
  602.                                  pint_client_sm_context);
  603.             if (ret < 0)
  604.             {
  605.                 PVFS_perror_gossip("job_bmi_cancel failed", ret);
  606.                 break;
  607.             }
  608.             sm_base_p->u.io.total_cancellations_remaining++;
  609.         }
  610.  
  611.         if (cur_ctx->msg_recv_in_progress)
  612.         {
  613.             gossip_debug(GOSSIP_CANCEL_DEBUG,  "[%d] Posting "
  614.                          "cancellation of type: BMI Recv "
  615.                          "(Response)\n",i);
  616.  
  617.             ret = job_bmi_cancel(cur_ctx->msg.recv_id,
  618.                                  pint_client_sm_context);
  619.             if (ret < 0)
  620.             {
  621.                 PVFS_perror_gossip("job_bmi_cancel failed", ret);
  622.                 break;
  623.             }
  624.             sm_base_p->u.io.total_cancellations_remaining++;
  625.         }
  626.  
  627.         if (cur_ctx->flow_in_progress)
  628.         {
  629.             gossip_debug(GOSSIP_CANCEL_DEBUG,
  630.                          "[%d] Posting cancellation of type: FLOW\n",i);
  631.  
  632.             ret = job_flow_cancel(
  633.                 cur_ctx->flow_job_id, pint_client_sm_context);
  634.             if (ret < 0)
  635.             {
  636.                 PVFS_perror_gossip("job_flow_cancel failed", ret);
  637.                 break;
  638.             }
  639.             sm_base_p->u.io.total_cancellations_remaining++;
  640.         }
  641.  
  642.         if (cur_ctx->write_ack_in_progress)
  643.         {
  644.             gossip_debug(GOSSIP_CANCEL_DEBUG,  "[%d] Posting "
  645.                          "cancellation of type: BMI Recv "
  646.                          "(Write Ack)\n",i);
  647.  
  648.             ret = job_bmi_cancel(cur_ctx->write_ack.recv_id,
  649.                                  pint_client_sm_context);
  650.             if (ret < 0)
  651.             {
  652.                 PVFS_perror_gossip("job_bmi_cancel failed", ret);
  653.                 break;
  654.             }
  655.             sm_base_p->u.io.total_cancellations_remaining++;
  656.         }
  657.     }
  658.     gossip_debug(GOSSIP_CANCEL_DEBUG, "(%p) Total cancellations "
  659.                  "remaining: %d\n", sm_base_p,
  660.                  sm_base_p->u.io.total_cancellations_remaining);
  661.     return ret;
  662. }
  663.  
  664. /** Checks for completion of a specific state machine.
  665.  *
  666.  *  If specific state machine has not completed, progress is made on
  667.  *  all posted state machines.
  668.  */
  669. PVFS_error PINT_client_state_machine_test(
  670.     PVFS_sys_op_id op_id,
  671.     int *error_code)
  672. {
  673.     int i = 0, job_count = 0;
  674.     PVFS_error ret = -PVFS_EINVAL;
  675.     PINT_smcb *smcb, *tmp_smcb = NULL;
  676.     PINT_client_sm *sm_p = NULL;
  677.     job_id_t job_id_array[MAX_RETURNED_JOBS];
  678.     job_status_s job_status_array[MAX_RETURNED_JOBS];
  679.     void *smcb_p_array[MAX_RETURNED_JOBS] = {NULL};
  680.  
  681.     gossip_debug(GOSSIP_STATE_MACHINE_DEBUG,
  682.                  "PINT_client_state_machine_test id %lld\n",lld(op_id));
  683.  
  684.     gen_mutex_lock(&test_mutex);
  685.  
  686.     CLIENT_SM_ASSERT_INITIALIZED();
  687.  
  688.     job_count = MAX_RETURNED_JOBS;
  689.  
  690.     if (!error_code)
  691.     {
  692.         gen_mutex_unlock(&test_mutex);
  693.         return ret;
  694.     }
  695.  
  696.     smcb = PINT_id_gen_safe_lookup(op_id);
  697.     if (!smcb)
  698.     {
  699.         gen_mutex_unlock(&test_mutex);
  700.         return ret;
  701.     }
  702.  
  703.     if (PINT_smcb_complete(smcb))
  704.     {
  705.         sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  706.         *error_code = sm_p->error_code;
  707.         conditional_remove_sm_if_in_completion_list(smcb);
  708.         gen_mutex_unlock(&test_mutex);
  709.         return 0;
  710.     }
  711.  
  712.     ret = job_testcontext(job_id_array,
  713.               &job_count, /* in/out parameter */
  714.               smcb_p_array,
  715.               job_status_array,
  716.               10,
  717.               pint_client_sm_context);
  718.     assert(ret > -1);
  719.  
  720.     /* do as much as we can on every job that has completed */
  721.     for(i = 0; i < job_count; i++)
  722.     {
  723.     tmp_smcb = (PINT_smcb *)smcb_p_array[i];
  724.         assert(tmp_smcb);
  725.  
  726.         if (PINT_smcb_invalid_op(tmp_smcb))
  727.         {
  728.             gossip_err("Invalid sm control block op %d\n", PINT_smcb_op(tmp_smcb));
  729.             continue;
  730.         }
  731.         gossip_debug(GOSSIP_CLIENT_DEBUG, "sm control op %d\n", PINT_smcb_op(tmp_smcb));
  732.  
  733.         if (!PINT_smcb_complete(tmp_smcb))
  734.         {
  735.             ret = PINT_state_machine_continue(tmp_smcb, &job_status_array[i]);
  736.  
  737.             if (ret != SM_ACTION_DEFERRED &&
  738.                     ret != SM_ACTION_TERMINATE); /* ret == 0 */
  739.             {
  740.                 continue;
  741.             }
  742.         }
  743.     }
  744.  
  745.     if (PINT_smcb_complete(smcb))
  746.     {
  747.         sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  748.         *error_code = sm_p->error_code;
  749.         conditional_remove_sm_if_in_completion_list(smcb);
  750.     }
  751.     gen_mutex_unlock(&test_mutex);
  752.     return 0;
  753. }
  754.  
  755. /** Checks completion of one or more state machines.
  756.  *
  757.  *  If none of the state machines listed in op_id_array have completed,
  758.  *  then progress is made on all posted state machines.
  759.  */
  760. PVFS_error PINT_client_state_machine_testsome(
  761.     PVFS_sys_op_id *op_id_array,
  762.     int *op_count, /* in/out */
  763.     void **user_ptr_array,
  764.     int *error_code_array,
  765.     int timeout_ms)
  766. {
  767.     PVFS_error ret = -PVFS_EINVAL;
  768.     int i = 0, limit = 0, job_count = 0;
  769.     PINT_smcb *smcb = NULL;
  770.     job_id_t job_id_array[MAX_RETURNED_JOBS];
  771.     job_status_s job_status_array[MAX_RETURNED_JOBS];
  772.     void *smcb_p_array[MAX_RETURNED_JOBS] = {NULL};
  773.  
  774.     gen_mutex_lock(&test_mutex);
  775.  
  776.     CLIENT_SM_ASSERT_INITIALIZED();
  777.  
  778.     if (!op_id_array || !op_count || !error_code_array)
  779.     {
  780.         PVFS_perror_gossip("PINT_client_state_machine_testsome", ret);
  781.         gen_mutex_unlock(&test_mutex);
  782.         return ret;
  783.     }
  784.  
  785.     if ((*op_count < 1) || (*op_count > MAX_RETURNED_JOBS))
  786.     {
  787.         PVFS_perror_gossip("testsome() got invalid op_count", ret);
  788.         gen_mutex_unlock(&test_mutex);
  789.         return ret;
  790.     }
  791.  
  792.     job_count = MAX_RETURNED_JOBS;
  793.     limit = *op_count;
  794.     *op_count = 0;
  795.  
  796.     /* check for requests completed previously */
  797.     ret = completion_list_retrieve_completed(
  798.         op_id_array, user_ptr_array, error_code_array, limit, op_count);
  799.  
  800.     /* return them if found */
  801.     if ((ret == 0) && (*op_count > 0))
  802.     {
  803.         gen_mutex_unlock(&test_mutex);
  804.         return ret;
  805.     }
  806.  
  807.     /* see if there are requests ready to make progress */
  808.     ret = job_testcontext(job_id_array,
  809.               &job_count, /* in/out parameter */
  810.               smcb_p_array,
  811.               job_status_array,
  812.               timeout_ms,
  813.               pint_client_sm_context);
  814.     assert(ret > -1);
  815.  
  816.     /* do as much as we can on every job that has completed */
  817.     for(i = 0; i < job_count; i++)
  818.     {
  819.     smcb = (PINT_smcb *)smcb_p_array[i];
  820.         assert(smcb);
  821.  
  822.         if (!PINT_smcb_complete(smcb))
  823.         {
  824.             ret = PINT_state_machine_continue(smcb, &job_status_array[i]);
  825.  
  826.             /* (ret < 0) indicates a problem from the job system
  827.              * itself; the return value of the underlying operation is
  828.              * kept in the job status structure.
  829.              */
  830.             if (ret != SM_ACTION_DEFERRED &&
  831.                     ret != SM_ACTION_TERMINATE)
  832.             {
  833.                 continue;
  834.             }
  835.         }
  836.     }
  837.  
  838.     /* terminated SMs have added themselves to the completion list */
  839.     ret = completion_list_retrieve_completed(
  840.         op_id_array, user_ptr_array, error_code_array, limit, op_count);
  841.     gen_mutex_unlock(&test_mutex);
  842.     return(ret);
  843. }
  844.  
  845. /** Continually test on a specific state machine until it completes.
  846.  *
  847.  * This is what is called when PINT_sys_wait or PINT_mgmt_wait is used.
  848.  */
  849. PVFS_error PINT_client_wait_internal(
  850.     PVFS_sys_op_id op_id,
  851.     const char *in_op_str,
  852.     int *out_error,
  853.     const char *in_class_str)
  854. {
  855.     PVFS_error ret = -PVFS_EINVAL;
  856.     PINT_smcb *smcb = NULL;
  857.     PINT_client_sm *sm_p;
  858.  
  859.     if (in_op_str && out_error && in_class_str)
  860.     {
  861.         smcb = PINT_id_gen_safe_lookup(op_id);
  862.         assert(smcb);
  863.  
  864.         do
  865.         {
  866.             /*
  867.             gossip_debug(GOSSIP_CLIENT_DEBUG,
  868.               "%s: PVFS_i%s_%s calling test()\n",
  869.               __func__, in_class_str, in_op_str);
  870.             */
  871.             ret = PINT_client_state_machine_test(op_id, out_error);
  872.  
  873.         } while (!PINT_smcb_complete(smcb) && (ret == 0));
  874.  
  875.         sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  876.  
  877.         if (ret)
  878.         {
  879.             PVFS_perror_gossip("PINT_client_state_machine_test()", ret);
  880.         }
  881.         else
  882.         {
  883.             *out_error = sm_p->error_code;
  884.         }
  885.     }
  886.     return ret;
  887. }
  888.  
  889. /** Finds state machine referenced by op_id and releases resources
  890.  * associated with it
  891.  */
  892. void PINT_sys_release(PVFS_sys_op_id op_id)
  893. {
  894.     PINT_smcb *smcb; 
  895.  
  896.     gossip_debug(GOSSIP_CLIENT_DEBUG, "%s: id %lld\n", __func__, lld(op_id));
  897.     smcb = PINT_id_gen_safe_lookup(op_id);
  898.     if (smcb == NULL) 
  899.     {
  900.         return;
  901.     }
  902.     PINT_id_gen_safe_unregister(op_id);
  903.     PINT_sys_release_smcb(smcb);
  904.  
  905.     return;
  906. }
  907.  
  908. /** releases resources associated with an smcb.  Can be used both on
  909.  * immediate completion and asynchronous completion
  910.  */
  911. static void PINT_sys_release_smcb(PINT_smcb *smcb)
  912. {
  913.     PINT_client_sm *sm_p; 
  914.     PVFS_credentials *cred_p; 
  915.  
  916.     sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  917.     if (sm_p == NULL) 
  918.     {
  919.         cred_p = NULL;
  920.     }
  921.     else 
  922.     {
  923.         cred_p = sm_p->cred_p;
  924.         /* free the hint if sm_p isn't null */
  925.         PVFS_hint_free( sm_p->hints );
  926.         sm_p->hints = NULL;
  927.     }
  928.  
  929.     if (PINT_smcb_op(smcb) && cred_p)
  930.     {
  931.         PVFS_util_release_credentials(cred_p);
  932.         if (sm_p) sm_p->cred_p = NULL;
  933.     }
  934.  
  935.     PINT_smcb_free(smcb);
  936. }
  937.  
  938. void PINT_mgmt_release(PVFS_mgmt_op_id op_id)
  939. {
  940.     PINT_sys_release(op_id);
  941. }
  942.  
  943. /*
  944.  * TODO: fill these out so that operations can be cancelled by users.
  945.  * First though there needs to be better tracking of posted jobs for
  946.  * a client state machine (right now we just throw away the job id),
  947.  * so that we know which jobs need to be cancelled.
  948.  */
  949. int PVFS_sys_cancel(PVFS_sys_op_id op_id)
  950. {
  951.     return -PVFS_ENOSYS;
  952. }
  953.  
  954. int PVFS_mgmt_cancel(PVFS_mgmt_op_id op_id)
  955. {
  956.     return -PVFS_ENOSYS;
  957. }
  958.  
  959. const char *PINT_client_get_name_str(int op_type)
  960. {
  961.     typedef struct
  962.     {
  963.         int type;
  964.         const char *type_str;
  965.     } __sys_op_info_t;
  966.  
  967.     static __sys_op_info_t op_info[] =
  968.     {
  969.         { PVFS_SYS_REMOVE, "PVFS_SYS_REMOVE" },
  970.         { PVFS_SYS_CREATE, "PVFS_SYS_CREATE" },
  971.         { PVFS_SYS_MKDIR, "PVFS_SYS_MKDIR" },
  972.         { PVFS_SYS_SYMLINK, "PVFS_SYS_SYMLINK" },
  973.         { PVFS_SYS_READDIR, "PVFS_SYS_READDIR" },
  974.         { PVFS_SYS_LOOKUP, "PVFS_SYS_LOOKUP" },
  975.     { PVFS_SYS_RENAME, "PVFS_SYS_RENAME" },
  976.         { PVFS_SYS_GETATTR, "PVFS_SYS_GETATTR" },
  977.         { PVFS_SYS_SETATTR, "PVFS_SYS_SETATTR" },
  978.         { PVFS_SYS_IO, "PVFS_SYS_IO" },
  979.         { PVFS_SYS_FLUSH, "PVFS_SYS_FLUSH" },
  980.         { PVFS_SYS_READDIRPLUS, "PVFS_SYS_READDIR_PLUS" },
  981.         { PVFS_MGMT_SETPARAM_LIST, "PVFS_MGMT_SETPARAM_LIST" },
  982.         { PVFS_MGMT_NOOP, "PVFS_MGMT_NOOP" },
  983.         { PVFS_SYS_TRUNCATE, "PVFS_SYS_TRUNCATE" },
  984.         { PVFS_MGMT_STATFS_LIST, "PVFS_MGMT_STATFS_LIST" },
  985.         { PVFS_MGMT_PERF_MON_LIST, "PVFS_MGMT_PERF_MON_LIST" },
  986.         { PVFS_MGMT_EVENT_MON_LIST, "PVFS_MGMT_EVENT_MON_LIST" },
  987.         { PVFS_MGMT_ITERATE_HANDLES_LIST,
  988.           "PVFS_MGMT_ITERATE_HANDLES_LIST" },
  989.         { PVFS_MGMT_GET_DFILE_ARRAY, "PVFS_MGMT_GET_DFILE_ARRAY" },
  990.         { PVFS_MGMT_REMOVE_OBJECT, "PVFS_MGMT_REMOVE_OBJECT" },
  991.         { PVFS_MGMT_REMOVE_DIRENT, "PVFS_MGMT_REMOVE_DIRENT" },
  992.         { PVFS_MGMT_CREATE_DIRENT, "PVFS_MGMT_CREATE_DIRENT" },
  993.         { PVFS_MGMT_GET_DIRDATA_HANDLE,
  994.           "PVFS_MGMT_GET_DIRDATA_HANDLE" },
  995.         { PVFS_SYS_GETEATTR, "PVFS_SYS_GETEATTR" },
  996.         { PVFS_SYS_SETEATTR, "PVFS_SYS_SETEATTR" },
  997.         { PVFS_SYS_DELEATTR, "PVFS_SYS_DELEATTR" },
  998.         { PVFS_SYS_LISTEATTR, "PVFS_SYS_LISTEATTR" },
  999.         { PVFS_SERVER_GET_CONFIG, "PVFS_SERVER_GET_CONFIG" },
  1000.         { PVFS_CLIENT_JOB_TIMER, "PVFS_CLIENT_JOB_TIMER" },
  1001.         { PVFS_DEV_UNEXPECTED, "PVFS_DEV_UNEXPECTED" },
  1002.         { PVFS_SYS_FS_ADD, "PVFS_SYS_FS_ADD" },
  1003.         { PVFS_SYS_STATFS, "PVFS_SYS_STATFS" },
  1004.         { 0, "UNKNOWN" }
  1005.     };
  1006.  
  1007.     int i = 0, limit = (int)(sizeof(op_info) / sizeof(__sys_op_info_t));
  1008.     for(i = 0; i < limit; i++)
  1009.     {
  1010.         if (op_info[i].type == op_type)
  1011.         {
  1012.             return op_info[i].type_str;
  1013.         }
  1014.     }
  1015.     return op_info[limit-1].type_str;
  1016. }
  1017.  
  1018. /* exposed wrapper around the client-state-machine testsome function */
  1019. int PVFS_sys_testsome(
  1020.     PVFS_sys_op_id *op_id_array,
  1021.     int *op_count, /* in/out */
  1022.     void **user_ptr_array,
  1023.     int *error_code_array,
  1024.     int timeout_ms)
  1025. {
  1026.     return PINT_client_state_machine_testsome(
  1027.         op_id_array, op_count, user_ptr_array,
  1028.         error_code_array, timeout_ms);
  1029. }
  1030.  
  1031. int PVFS_sys_wait(
  1032.     PVFS_sys_op_id op_id,
  1033.     const char *in_op_str,
  1034.     int *out_error)
  1035. {
  1036.     return PINT_client_wait_internal(
  1037.         op_id,
  1038.         in_op_str,
  1039.         out_error,
  1040.         "sys");
  1041. }
  1042.  
  1043. int PVFS_mgmt_testsome(
  1044.     PVFS_mgmt_op_id *op_id_array,
  1045.     int *op_count, /* in/out */
  1046.     void **user_ptr_array,
  1047.     int *error_code_array,
  1048.     int timeout_ms)
  1049. {
  1050.     return PINT_client_state_machine_testsome(
  1051.         op_id_array, op_count, user_ptr_array,
  1052.         error_code_array, timeout_ms);
  1053. }
  1054.  
  1055. int PVFS_mgmt_wait(
  1056.     PVFS_mgmt_op_id op_id,
  1057.     const char *in_op_str,
  1058.     int *out_error)
  1059. {
  1060.     return PINT_client_wait_internal(
  1061.         op_id,
  1062.         in_op_str,
  1063.         out_error,
  1064.         "mgmt");
  1065. }
  1066.  
  1067. PVFS_error PVFS_sys_set_info(
  1068.     enum PVFS_sys_setinfo_opt option,
  1069.     unsigned int arg)
  1070. {
  1071.     PVFS_error ret = -PVFS_ENOSYS;
  1072.  
  1073.     switch(option)
  1074.     {
  1075.         case PVFS_SYS_NCACHE_TIMEOUT_MSECS:
  1076.             ret = PINT_ncache_set_info(NCACHE_TIMEOUT_MSECS, arg);
  1077.             break;
  1078.         case PVFS_SYS_ACACHE_TIMEOUT_MSECS:
  1079.             ret = PINT_acache_set_info(ACACHE_TIMEOUT_MSECS, arg);
  1080.             break;
  1081.         case PVFS_SYS_MSG_TIMEOUT_SECS:
  1082.         case PVFS_SYS_MSG_RETRY_LIMIT:
  1083.         case PVFS_SYS_MSG_RETRY_DELAY_MSECS:
  1084.             ret = -PVFS_ENOSYS;
  1085.             break;
  1086. #if 0
  1087.         /* need some other code cleanup before these can be implemented */
  1088.         case PVFS_SYS_MSG_TIMEOUT_SECS:
  1089.             PINT_sys_msg_timeout_secs = arg;
  1090.             ret = 0;
  1091.             break;
  1092.         case PVFS_SYS_MSG_RETRY_LIMIT:
  1093.             PINT_sys_msg_retry_limit = arg;
  1094.             ret = 0;
  1095.             break;
  1096.         case PVFS_SYS_MSG_RETRY_DELAY_MSECS:
  1097.             PINT_sys_msg_retry_delay_msecs = arg;
  1098.             ret = 0;
  1099.             break;
  1100. #endif
  1101.     }
  1102.  
  1103.     return(ret);
  1104. }
  1105.  
  1106. PVFS_error PVFS_sys_get_info(
  1107.     enum PVFS_sys_setinfo_opt option,
  1108.     unsigned int* arg)
  1109. {
  1110.     PVFS_error ret = -PVFS_ENOSYS;
  1111.  
  1112.     switch(option)
  1113.     {
  1114.         case PVFS_SYS_NCACHE_TIMEOUT_MSECS:
  1115.             ret = PINT_ncache_get_info(NCACHE_TIMEOUT_MSECS, arg);
  1116.             break;
  1117.         case PVFS_SYS_ACACHE_TIMEOUT_MSECS:
  1118.             ret = PINT_acache_get_info(ACACHE_TIMEOUT_MSECS, arg);
  1119.             break;
  1120.         case PVFS_SYS_MSG_TIMEOUT_SECS:
  1121.         case PVFS_SYS_MSG_RETRY_LIMIT:
  1122.         case PVFS_SYS_MSG_RETRY_DELAY_MSECS:
  1123.             ret = -PVFS_ENOSYS;
  1124.             break;
  1125. #if 0
  1126.         case PVFS_SYS_MSG_TIMEOUT_SECS:
  1127.             *arg = PINT_sys_msg_timeout_secs;
  1128.             ret = 0;
  1129.             break;
  1130.         case PVFS_SYS_MSG_RETRY_LIMIT:
  1131.             *arg = PINT_sys_msg_retry_limit;
  1132.             ret = 0;
  1133.             break;
  1134.         case PVFS_SYS_MSG_RETRY_DELAY_MSECS:
  1135.             *arg = PINT_sys_msg_retry_delay_msecs;
  1136.             ret = 0;
  1137.             break;
  1138. #endif
  1139.     }
  1140.  
  1141.     return(ret);
  1142. }
  1143.  
  1144.  
  1145. /*
  1146.  * Local variables:
  1147.  *  c-indent-level: 4
  1148.  *  c-basic-offset: 4
  1149.  * End:
  1150.  *
  1151.  * vim: ts=8 sts=4 sw=4 expandtab
  1152.  */
  1153.