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 / server / crdirent.sm < prev    next >
Text File  |  2010-04-30  |  11KB  |  388 lines

  1. /* 
  2.  * (C) 2001 Clemson University and The University of Chicago 
  3.  *
  4.  * See COPYING in top-level directory.
  5.  */
  6.  
  7. #include <ctype.h>
  8. #include <string.h>
  9. #include <assert.h>
  10.  
  11. #include "server-config.h"
  12. #include "pvfs2-server.h"
  13. #include "pvfs2-attr.h"
  14. #include "pvfs2-util.h"
  15. #include "pvfs2-internal.h"
  16. #include "pint-util.h"
  17.  
  18. enum
  19. {
  20.     INVALID_OBJECT = 131,
  21.     UPDATE_DIR_ATTR_REQUIRED
  22. };
  23.  
  24. %%
  25.  
  26. machine pvfs2_crdirent_sm
  27. {
  28.     state prelude
  29.     {
  30.         jump pvfs2_prelude_sm;
  31.         success => setup_op;
  32.         default => final_response;
  33.     }
  34.  
  35.     state setup_op
  36.     {
  37.         run crdirent_setup_op;
  38.         default => validate;
  39.     }
  40.  
  41.     state validate
  42.     {
  43.         run crdirent_validate;
  44.         success => read_directory_entry_handle;
  45.         INVALID_OBJECT => validation_object_type_failure;
  46.         default => final_response;
  47.     }
  48.  
  49.     state validation_object_type_failure
  50.     {
  51.         run validation_object_type_failure;
  52.         default => final_response;
  53.     }
  54.  
  55.     state read_directory_entry_handle
  56.     {
  57.         run crdirent_read_directory_entry_handle;
  58.         success => write_directory_entry;
  59.         default => final_response;
  60.     }
  61.  
  62.     state write_directory_entry
  63.     {
  64.         run crdirent_write_directory_entry;
  65.         success => check_for_req_dir_update;
  66.         default => final_response;
  67.     }
  68.  
  69.     state check_for_req_dir_update
  70.     {
  71.         run crdirent_check_for_req_dir_update;
  72.         UPDATE_DIR_ATTR_REQUIRED => update_directory_attr;
  73.         default => final_response;
  74.     }
  75.  
  76.     state update_directory_attr
  77.     {
  78.         run crdirent_update_directory_attr;
  79.         default => final_response;
  80.     }
  81.  
  82.     state final_response
  83.     {
  84.         jump pvfs2_final_response_sm;
  85.         default => cleanup;
  86.     }
  87.  
  88.     state cleanup
  89.     {
  90.         run crdirent_cleanup;
  91.         default => terminate;
  92.     }
  93. }
  94.  
  95. %%
  96.  
  97. /*
  98.  * Function: crdirent_validate
  99.  *
  100.  * Synopsis: verifies that entry name and object type is valid
  101.  */
  102. static PINT_sm_action crdirent_validate(
  103.         struct PINT_smcb *smcb, job_status_s *js_p)
  104. {
  105.     struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  106.     char *ptr = NULL;
  107.  
  108.     if ((s_op->u.crdirent.name == NULL) ||
  109.         (s_op->u.crdirent.parent_handle == PVFS_HANDLE_NULL))
  110.     {
  111.         js_p->error_code = -PVFS_EINVAL;
  112.         return SM_ACTION_COMPLETE;
  113.     }
  114.  
  115.     gossip_debug(GOSSIP_SERVER_DEBUG,
  116.             "  got crdirent for %s (with handle %llu) in %llu\n",
  117.             s_op->u.crdirent.name,
  118.             llu(s_op->u.crdirent.new_handle),
  119.             llu(s_op->u.crdirent.parent_handle));
  120.  
  121.     /* check for invalid characters in name */
  122.     ptr = s_op->u.crdirent.name;
  123.     while (*ptr != '\0' && *ptr != '/' ) ptr++;
  124.  
  125.     if (*ptr != '\0')
  126.     {
  127.         /* found an invalid character -- report it and send error response */
  128.         gossip_lerr("crdirent: error: invalid character (%s)"
  129.                 "in name (%s); sending error response.\n",
  130.                 ptr, s_op->u.crdirent.name);
  131.         /* for parity with linux VFS, allow any character except / in 
  132.          * filenames.   */
  133.         
  134.         js_p->error_code = -PVFS_EINVAL;
  135.  
  136.          /* Do not zero the scheduled_id, as this operation was
  137.           * scheduled before we checked the filename */
  138.         return SM_ACTION_COMPLETE;
  139.     }
  140.  
  141.     /* make sure we're dealing with a directory */
  142.     if (!(s_op->attr.mask & PVFS_ATTR_COMMON_TYPE) ||
  143.         !(s_op->attr.objtype == PVFS_TYPE_DIRECTORY))
  144.     {
  145.         gossip_debug(GOSSIP_SERVER_DEBUG, " Cannot read dirent on "
  146.                      "a non-directory!  Returning error.\n");
  147.  
  148.         js_p->error_code = INVALID_OBJECT;
  149.         return SM_ACTION_COMPLETE;
  150.     }
  151.  
  152.     js_p->error_code = 0;
  153.     return SM_ACTION_COMPLETE;
  154. }
  155.  
  156. /*
  157.  * Function: crdirent_read_directory_entry_handle
  158.  *
  159.  * Params:   server_op *s_op, 
  160.  *           job_status_s *js_p
  161.  *
  162.  * Pre:      s_op->u.crdirent.parent_handle is handle of directory
  163.  *
  164.  * Post:     s_op->val.buffer is the directory entry k/v space OR NULL
  165.  *           if first entry
  166.  *
  167.  * Returns:  int
  168.  *
  169.  * Synopsis: Given a directory handle, look up the handle used to store
  170.  * directory entries for this directory.
  171.  *
  172.  * Get the directory entry handle for the directory entry k/v space.
  173.  * Recall that directories have two key-val spaces, one of which is
  174.  * synonymous with files where the metadata is stored.  The other
  175.  * space holds the filenames and their handles.  In this function, we
  176.  * attempt to retrieve the handle for the filename/handle key/val
  177.  * space and if it does not exist, we need to create it.
  178.  *
  179.  */
  180. static PINT_sm_action crdirent_read_directory_entry_handle(
  181.         struct PINT_smcb *smcb, job_status_s *js_p)
  182. {
  183.     struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  184.     int ret = -PVFS_EINVAL;
  185.     job_id_t i;
  186.  
  187.     /* get the key and key size out of our list of common keys */
  188.     s_op->key.buffer = Trove_Common_Keys[DIR_ENT_KEY].key;
  189.     s_op->key.buffer_sz = Trove_Common_Keys[DIR_ENT_KEY].size;
  190.  
  191.     /* store the handle in the crdirent-specific space in s_op */
  192.     s_op->val.buffer = &s_op->u.crdirent.dirent_handle;
  193.     s_op->val.buffer_sz = sizeof(PVFS_handle);
  194.  
  195.     ret = job_trove_keyval_read(
  196.         s_op->u.crdirent.fs_id,
  197.         s_op->u.crdirent.parent_handle,
  198.         &s_op->key,
  199.         &s_op->val,
  200.         0,
  201.         NULL,
  202.         smcb,
  203.         0,
  204.         js_p,
  205.         &i,
  206.         server_job_context, s_op->req->hints);
  207.  
  208.     return ret;
  209. }
  210.  
  211. static PINT_sm_action validation_object_type_failure(
  212.         struct PINT_smcb *smcb, job_status_s *js_p)
  213. {
  214.     gossip_debug(GOSSIP_SERVER_DEBUG, "crdirent: validation_object_"
  215.                  "type_failure called\n");
  216.  
  217.     js_p->error_code = -PVFS_ENOTDIR;
  218.     return SM_ACTION_COMPLETE;
  219. }
  220.  
  221. /*
  222.  * Function: crdirent_write_directory_entry
  223.  *
  224.  * Params:   server_op *s_op, 
  225.  *           job_status_s *js_p
  226.  *
  227.  * Pre:      s_op->u.crdirent.dirent_handle is the directory entry k/v space
  228.  *           s_op->u.crdirent.name != NULL
  229.  *           s_op->u.crdirent.new_handle != NULL
  230.  *
  231.  * Post:     key/val pair stored
  232.  *
  233.  * Returns:  int
  234.  *
  235.  * Synopsis: We are now ready to store the name/handle pair in the k/v
  236.  *           space for directory handles.
  237.  */
  238. static PINT_sm_action crdirent_write_directory_entry(
  239.         struct PINT_smcb *smcb, job_status_s *js_p)
  240. {
  241.     struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  242.     int ret = -PVFS_EINVAL;
  243.     job_id_t i;
  244.     TROVE_ds_flags keyval_flags;
  245.  
  246.     assert(s_op->u.crdirent.dirent_handle);
  247.  
  248.     js_p->error_code = 0;
  249.  
  250.     /* This buffer came from one of two places, either phase two of
  251.      * creating the directory space when we wrote the value back to
  252.      * trove, or from the initial read from trove.
  253.      */
  254.  
  255.     /* this is the name for the parent entry */
  256.     s_op->key.buffer = s_op->u.crdirent.name;
  257.     s_op->key.buffer_sz = strlen(s_op->u.crdirent.name) + 1;
  258.  
  259.     s_op->val.buffer = &s_op->u.crdirent.new_handle;
  260.     s_op->val.buffer_sz = sizeof(PVFS_handle);
  261.  
  262.     gossip_debug(GOSSIP_SERVER_DEBUG, "  writing new directory entry "
  263.                  "for %s (handle = %llu) to dirdata dspace %llu\n",
  264.                  s_op->u.crdirent.name, llu(s_op->u.crdirent.new_handle),
  265.                  llu(s_op->u.crdirent.dirent_handle));
  266.  
  267.     keyval_flags = TROVE_SYNC;
  268.         
  269.     /* Specify that we want an error returned if the entry already exists.
  270.      * This allows us to return an EEXIST error back to the client
  271.      */
  272.     keyval_flags |= TROVE_NOOVERWRITE;
  273.  
  274.     /* We also want to keep track of the keyval entries added on this
  275.      * handle, which allows us to get the size of the directory later
  276.      */
  277.     keyval_flags |= TROVE_KEYVAL_HANDLE_COUNT;
  278.  
  279.     ret = job_trove_keyval_write(
  280.         s_op->u.crdirent.fs_id, s_op->u.crdirent.dirent_handle,
  281.         &s_op->key, &s_op->val, 
  282.         keyval_flags,
  283.         NULL, smcb, 0, js_p, &i, server_job_context, s_op->req->hints);
  284.  
  285.     /*
  286.      * creating an entry will cause directory times to be updated.
  287.      */
  288.     s_op->u.crdirent.dir_attr_update_required = 1;
  289.     return ret;
  290. }
  291.  
  292. static PINT_sm_action crdirent_check_for_req_dir_update(
  293.         struct PINT_smcb *smcb, job_status_s *js_p)
  294. {
  295.     struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  296.     if ((js_p->error_code == 0) &&
  297.         (s_op->u.crdirent.dir_attr_update_required))
  298.     {
  299.         js_p->error_code = UPDATE_DIR_ATTR_REQUIRED;
  300.     }
  301.     return SM_ACTION_COMPLETE;
  302. }
  303.     
  304. static PINT_sm_action crdirent_update_directory_attr(
  305.         struct PINT_smcb *smcb, job_status_s *js_p)
  306. {
  307.     struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  308.     int ret = -1;
  309.     job_id_t j_id;
  310.     PVFS_object_attr tmp_attr, *tmp_attr_ptr = &tmp_attr;
  311.     PVFS_object_attr *dspace_attr = NULL;
  312.     PVFS_ds_attributes *ds_attr = NULL;
  313.  
  314.     if (js_p->error_code != UPDATE_DIR_ATTR_REQUIRED)
  315.     {
  316.         PVFS_perror_gossip("previous keyval write failed",
  317.                            js_p->error_code);
  318.         return SM_ACTION_COMPLETE;
  319.     }
  320.  
  321.     memset(&tmp_attr, 0, sizeof(PVFS_object_attr));
  322.     dspace_attr = &s_op->attr;
  323.     dspace_attr->mask |= (PVFS_ATTR_COMMON_ATIME | PVFS_ATTR_COMMON_MTIME | PVFS_ATTR_COMMON_CTIME);
  324.  
  325.     PVFS_object_attr_overwrite_setable(tmp_attr_ptr, dspace_attr);
  326.     ds_attr = &(s_op->ds_attr);
  327.     PVFS_object_attr_to_ds_attr(tmp_attr_ptr, ds_attr);
  328.  
  329.     ret = job_trove_dspace_setattr(
  330.         s_op->req->u.crdirent.fs_id, s_op->req->u.crdirent.handle,
  331.         ds_attr, 
  332.         TROVE_SYNC,
  333.         smcb, 0, js_p, &j_id, server_job_context, s_op->req->hints);
  334.  
  335.     return ret;
  336. }
  337.  
  338. static PINT_sm_action crdirent_cleanup(
  339.         struct PINT_smcb *smcb, job_status_s *js_p)
  340. {
  341.     return(server_state_machine_complete(smcb));
  342. }
  343.  
  344. /* crdirent_setup_op()
  345.  *
  346.  * prepare some state machine fields for later processing; mainly just
  347.  * storing request structure fields in state machine so that nested
  348.  * machines are not dependent on request type
  349.  */
  350. static PINT_sm_action crdirent_setup_op(
  351.         struct PINT_smcb *smcb, job_status_s *js_p)
  352. {
  353.     struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  354.     PINT_ACCESS_DEBUG(s_op, GOSSIP_ACCESS_DEBUG, "crdirent entry: %s points to %llu\n",
  355.         s_op->req->u.crdirent.name, llu(s_op->req->u.crdirent.new_handle));
  356.  
  357.     s_op->u.crdirent.name = s_op->req->u.crdirent.name;
  358.     s_op->u.crdirent.new_handle = s_op->req->u.crdirent.new_handle;
  359.     s_op->u.crdirent.parent_handle = s_op->req->u.crdirent.handle;
  360.     s_op->u.crdirent.fs_id = s_op->req->u.crdirent.fs_id;
  361.     s_op->u.crdirent.dir_attr_update_required = 0;
  362.  
  363.     js_p->error_code = 0;
  364.     return SM_ACTION_COMPLETE;
  365. }
  366.  
  367. PINT_GET_OBJECT_REF_DEFINE(crdirent);
  368.  
  369. struct PINT_server_req_params pvfs2_crdirent_params =
  370. {
  371.     .string_name = "crdirent",
  372.     .perm = PINT_SERVER_CHECK_CRDIRENT,
  373.     .access_type = PINT_server_req_modify,
  374.     .sched_policy = PINT_SERVER_REQ_SCHEDULE,
  375.     .get_object_ref = PINT_get_object_ref_crdirent,
  376.     .state_machine = &pvfs2_crdirent_sm
  377. };
  378.  
  379. /*
  380.  * Local variables:
  381.  *  mode: c
  382.  *  c-indent-level: 4
  383.  *  c-basic-offset: 4
  384.  * End:
  385.  *
  386.  * vim: ft=c ts=8 sts=4 sw=4 expandtab
  387.  */
  388.