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-truncate.sm < prev   
Text File  |  2010-04-30  |  13KB  |  486 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.  *  \ingroup sysint
  9.  *
  10.  *  PVFS2 system interface routines for modifying the size of a file,
  11.  *  either growing or shrinking.
  12.  */
  13. #include <string.h>
  14. #include <assert.h>
  15.  
  16. #include "client-state-machine.h"
  17. #include "pvfs2-debug.h"
  18. #include "job.h"
  19. #include "gossip.h"
  20. #include "str-utils.h"
  21. #include "pint-util.h"
  22. #include "pint-request.h"
  23. #include "pint-cached-config.h"
  24. #include "PINT-reqproto-encode.h"
  25. #include "acache.h"
  26. #include "pvfs2-internal.h"
  27.  
  28. #define TRUNCATE_UNSTUFF 100
  29.  
  30. extern job_context_id pint_client_sm_context;
  31.  
  32. static int unstuff_needed(
  33.     PVFS_size size,
  34.     PINT_dist *dist_p,
  35.     uint32_t mask);
  36.  
  37. static int unstuff_comp_fn(
  38.     void *v_p,
  39.     struct PVFS_server_resp *resp_p,
  40.     int i);
  41.  
  42. %% 
  43.  
  44. machine pvfs2_client_truncate_sm
  45. {
  46.     state truncate_getattr
  47.     {
  48.         jump pvfs2_client_getattr_sm;
  49.         success => inspect_attr;
  50.         default => cleanup;
  51.     }
  52.  
  53.     state inspect_attr
  54.     {
  55.         run truncate_inspect_attr;
  56.         TRUNCATE_UNSTUFF => unstuff_setup_msgpair;
  57.         success => truncate_datafile_setup_msgpairarray;
  58.         default => cleanup;
  59.     }
  60.  
  61.     state unstuff_setup_msgpair
  62.     {
  63.         run truncate_unstuff_setup_msgpair;
  64.         success => unstuff_xfer_msgpair;
  65.         default => cleanup;
  66.     }
  67.  
  68.     state unstuff_xfer_msgpair
  69.     {
  70.         jump pvfs2_msgpairarray_sm;
  71.         success => truncate_datafile_setup_msgpairarray;
  72.         default => cleanup;
  73.     }
  74.  
  75.     state truncate_datafile_setup_msgpairarray
  76.     {
  77.         run truncate_datafile_setup_msgpairarray;
  78.         success => truncate_datafile_xfer_msgpairarray;
  79.         default => cleanup;
  80.     }
  81.  
  82.     state truncate_datafile_xfer_msgpairarray
  83.     {
  84.         jump pvfs2_msgpairarray_sm;
  85.         success => cleanup;
  86.         default => truncate_datafile_failure;
  87.     }
  88.  
  89.     state truncate_datafile_failure
  90.     {
  91.         run truncate_datafile_failure;
  92.         default => cleanup;
  93.     }
  94.  
  95.     state cleanup
  96.     {
  97.         run truncate_cleanup;
  98.         default => terminate;
  99.     }
  100. }
  101.  
  102. %%
  103.  
  104. /** Initiate resizing of a file.
  105.  */
  106. PVFS_error PVFS_isys_truncate(
  107.     PVFS_object_ref ref,
  108.     PVFS_size size,
  109.     const PVFS_credentials *credentials,
  110.     PVFS_sys_op_id *op_id,
  111.     PVFS_hint hints,
  112.     void *user_ptr)
  113. {
  114.     PVFS_error ret = -PVFS_EINVAL;
  115.     PINT_smcb *smcb = NULL;
  116.     PINT_client_sm *sm_p = NULL;
  117.  
  118.     if ((ref.fs_id == PVFS_FS_ID_NULL) ||
  119.         (ref.handle == PVFS_HANDLE_NULL))
  120.     {
  121.         gossip_err("invalid (NULL) required argument\n");
  122.         return ret;
  123.     }
  124.  
  125.     if (size < 0)
  126.     {
  127.         gossip_err("invalid size (negative) specified: %lld\n", lld(size));
  128.         return ret;
  129.     }
  130.  
  131.     gossip_debug(GOSSIP_CLIENT_DEBUG,
  132.                  "PVFS_isys_truncate entered with %lld\n", lld(size));
  133.  
  134.     PINT_smcb_alloc(&smcb, PVFS_SYS_TRUNCATE,
  135.              sizeof(struct PINT_client_sm),
  136.              client_op_state_get_machine,
  137.              client_state_machine_terminate,
  138.              pint_client_sm_context);
  139.     if (smcb == NULL)
  140.     {
  141.         return -PVFS_ENOMEM;
  142.     }
  143.     sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  144.  
  145.     PINT_init_msgarray_params(sm_p, ref.fs_id);
  146.     PINT_init_sysint_credentials(sm_p->cred_p, credentials);
  147.     sm_p->u.truncate.size = size;
  148.     sm_p->object_ref = ref;
  149.     PVFS_hint_copy(hints, &sm_p->hints);
  150.  
  151.     PINT_SM_GETATTR_STATE_FILL(
  152.         sm_p->getattr,
  153.         sm_p->object_ref,
  154.         PVFS_ATTR_META_ALL|PVFS_ATTR_COMMON_TYPE,
  155.         PVFS_TYPE_METAFILE,
  156.         PINT_SM_GETATTR_BYPASS_CACHE);
  157.  
  158.     return PINT_client_state_machine_post(
  159.         smcb,  op_id, user_ptr);
  160. }
  161.  
  162. PVFS_error PVFS_sys_truncate(
  163.     PVFS_object_ref ref,
  164.     PVFS_size size,
  165.     const PVFS_credentials *credentials,
  166.     PVFS_hint hints)
  167. {
  168.     PVFS_error ret = -PVFS_EINVAL, error = 0;
  169.     PVFS_sys_op_id op_id;
  170.  
  171.     gossip_debug(GOSSIP_CLIENT_DEBUG,
  172.                  "PVFS_sys_truncate entered with %lld\n", lld(size));
  173.  
  174.     ret = PVFS_isys_truncate(ref, size, credentials, &op_id, hints, NULL);
  175.     if (ret)
  176.     {
  177.         PVFS_perror_gossip("PVFS_isys_truncate call", ret);
  178.         error = ret;
  179.     }
  180.     else
  181.     {
  182.         ret = PVFS_sys_wait(op_id, "truncate", &error);
  183.         if (ret)
  184.         {
  185.             PVFS_perror_gossip("PVFS_sys_wait call", ret);
  186.             error = ret;
  187.         }
  188.     }
  189.  
  190.     PINT_sys_release(op_id);
  191.     return error;
  192. }
  193.  
  194. /** Resize a file.
  195.  */
  196. static PINT_sm_action truncate_datafile_setup_msgpairarray(
  197.     struct PINT_smcb *smcb, job_status_s *js_p)
  198. {
  199.     struct PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  200.     int ret = -PVFS_EINVAL, i = 0;
  201.     PVFS_object_attr *attr = NULL;
  202.     PINT_sm_msgpair_state *msg_p = NULL;
  203.     PVFS_size new_dfile_size = 0;
  204.     PINT_request_file_data file_data;
  205.     
  206.     js_p->error_code = 0;
  207.  
  208.     attr = &sm_p->getattr.attr;
  209.     assert(attr);
  210.  
  211.     assert(attr->mask & PVFS_ATTR_META_DFILES);
  212.     assert(attr->mask & PVFS_ATTR_META_DIST);
  213.     assert(attr->u.meta.dfile_count > 0);
  214.     assert(attr->u.meta.dist_size > 0);
  215.     /* cannot truncate an append-only or immutable file */
  216.     if ((attr->u.meta.hint.flags & PVFS_IMMUTABLE_FL)
  217.         || (attr->u.meta.hint.flags & PVFS_APPEND_FL))
  218.     {
  219.         js_p->error_code = -PVFS_EPERM;
  220.         return 1;
  221.     }
  222.  
  223.     ret = PINT_msgpairarray_init(&sm_p->msgarray_op, attr->u.meta.dfile_count);
  224.     if(ret != 0)
  225.     {
  226.         gossip_err("Failed to initialize %d msgpairs\n", attr->u.meta.dfile_count);
  227.         js_p->error_code = ret;
  228.         return SM_ACTION_COMPLETE;
  229.     }
  230.  
  231.     /* Initialize the file data struct */
  232.     memset(&file_data, 0, sizeof(file_data));
  233.     file_data.dist = attr->u.meta.dist;
  234.     file_data.server_ct = attr->u.meta.dfile_count;
  235.     file_data.extend_flag = 1;
  236.  
  237.     /* Construct truncate messages */
  238.     foreach_msgpair(&sm_p->msgarray_op, msg_p, i)
  239.     {
  240.         file_data.server_nr = i;
  241.         new_dfile_size = 
  242.             attr->u.meta.dist->methods->logical_to_physical_offset(
  243.                 attr->u.meta.dist->params,
  244.                 &file_data,
  245.                 sm_p->u.truncate.size);
  246.        
  247.         gossip_debug(GOSSIP_CLIENT_DEBUG,
  248.             "  %s: client requests %lld: resizing %lld to %lld bytes\n",
  249.             __func__, lld(sm_p->u.truncate.size),
  250.             llu(attr->u.meta.dfile_array[i]), lld(new_dfile_size));
  251.  
  252.         PINT_SERVREQ_TRUNCATE_FILL(
  253.             msg_p->req,
  254.             *sm_p->cred_p,
  255.             sm_p->object_ref.fs_id,
  256.             new_dfile_size,
  257.             attr->u.meta.dfile_array[i],
  258.             sm_p->hints);
  259.         /*
  260.           no callback. the status will be in the generic response
  261.           structure
  262.         */
  263.         msg_p->fs_id = sm_p->object_ref.fs_id;
  264.         msg_p->handle = attr->u.meta.dfile_array[i];
  265.         msg_p->retry_flag = PVFS_MSGPAIR_RETRY;
  266.         msg_p->comp_fn = NULL;
  267.     }
  268.  
  269.     sm_p->getattr.size = sm_p->u.truncate.size;
  270.     ret = PINT_serv_msgpairarray_resolve_addrs(&sm_p->msgarray_op);
  271.  
  272.     if (ret)
  273.     {
  274.         gossip_err("Error: failed to resolve server addresses.\n");
  275.         js_p->error_code = ret;
  276.     }
  277.  
  278.     PINT_sm_push_frame(smcb, 0, &sm_p->msgarray_op);
  279.     return SM_ACTION_COMPLETE;
  280. }
  281.  
  282. static PINT_sm_action truncate_datafile_failure(
  283.     struct PINT_smcb *smcb, job_status_s *js_p)
  284. {
  285.     return SM_ACTION_COMPLETE;
  286. }
  287.  
  288. static PINT_sm_action truncate_cleanup(
  289.     struct PINT_smcb *smcb, job_status_s *js_p)
  290. {
  291.     struct PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  292.     sm_p->error_code = js_p->error_code;
  293.  
  294.     PINT_msgpairarray_destroy(&sm_p->msgarray_op);
  295.  
  296.     if(sm_p->error_code == 0)
  297.     {
  298.         PINT_acache_invalidate_size(sm_p->object_ref);
  299.     }
  300.     else
  301.     {
  302.         PINT_acache_invalidate(sm_p->object_ref);
  303.     }
  304.  
  305.     PINT_SM_GETATTR_STATE_CLEAR(sm_p->getattr);
  306.  
  307.     PINT_SET_OP_COMPLETE;
  308.     return SM_ACTION_TERMINATE;
  309. }
  310.  
  311. static PINT_sm_action truncate_inspect_attr(
  312.         struct PINT_smcb *smcb, job_status_s *js_p)
  313. {
  314.     struct PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  315.  
  316.     /* check for write access */
  317.     js_p->error_code = PINT_check_mode(
  318.         &sm_p->getattr.attr, sm_p->cred_p->uid, sm_p->cred_p->gid, PINT_ACCESS_WRITABLE);
  319.     if(js_p->error_code)
  320.     {
  321.         return 1;
  322.     }
  323.  
  324.     /* determine if we need to unstuff or not to service this request */
  325.     if(unstuff_needed(
  326.         sm_p->u.truncate.size,
  327.         sm_p->getattr.attr.u.meta.dist,
  328.         sm_p->getattr.attr.mask))
  329.     {
  330.         js_p->error_code = TRUNCATE_UNSTUFF;
  331.         return SM_ACTION_COMPLETE;
  332.     }
  333.  
  334.     js_p->error_code = 0;
  335.     return SM_ACTION_COMPLETE;
  336. }
  337.  
  338. /* unstuff_needed()
  339.  *
  340.  * looks at the I/O pattern requested and compares against the distribution
  341.  * to determine if a stuffed file would have to be "unstuffed" in order to
  342.  * service the request
  343.  *
  344.  * returns 1 if unstuff is needed, 0 otherwise.
  345.  */
  346. static int unstuff_needed(
  347.     PVFS_size size,
  348.     PINT_dist *dist_p,
  349.     uint32_t mask)
  350. {
  351.     PVFS_offset first_unstuffed_offset = 0;
  352.     PINT_request_file_data fake_file_data;
  353.  
  354.     gossip_debug(GOSSIP_CLIENT_DEBUG, "sys-truncate checking to see if file should be unstuffed.\n");
  355.  
  356.     /* check the flag first to see if file is already explicitly marked as
  357.      * unstuffed
  358.      */
  359.     if(mask & PVFS_ATTR_META_UNSTUFFED)
  360.     {
  361.         gossip_debug(GOSSIP_CLIENT_DEBUG, "sys-truncate detected file is already unstuffed.\n");
  362.         return(0);
  363.     }
  364.  
  365.     /* we need to query the distribution to determine what the first offset
  366.      * is that does not belong to the first server/datafile.  We construct a
  367.      * fake server data struct for 2 servers and find out what the first
  368.      * offset (above zero) is that hits the second server */
  369.     fake_file_data.dist = dist_p;
  370.     fake_file_data.server_ct = 2;
  371.     fake_file_data.extend_flag = 1;
  372.     fake_file_data.fsize = 0;  
  373.     fake_file_data.server_nr = 1;
  374.  
  375.     /* call next mapped offset to find the next logical offset that appears
  376.      * on the 2nd server 
  377.      */
  378.     first_unstuffed_offset = dist_p->methods->next_mapped_offset(
  379.         dist_p->params,
  380.         &fake_file_data,
  381.         0);
  382.     
  383.     gossip_debug(GOSSIP_CLIENT_DEBUG, "sys-truncate calculated first unstuffed offset as %lld.\n", lld(first_unstuffed_offset));
  384.  
  385.     /* compare to see if the file needs to be unstuffed yet */
  386.     if(size > first_unstuffed_offset)
  387.     {
  388.         gossip_debug(GOSSIP_CLIENT_DEBUG, "sys-truncate will unstuff the file.\n");
  389.         return(1);
  390.     }
  391.  
  392.     gossip_debug(GOSSIP_CLIENT_DEBUG, "sys-truncate will not unstuff the file.\n");
  393.     return(0);
  394. }
  395.  
  396. static PINT_sm_action truncate_unstuff_setup_msgpair(
  397.         struct PINT_smcb *smcb, job_status_s *js_p)
  398. {
  399.     struct PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  400.     int ret = -PVFS_EINVAL;
  401.     PINT_sm_msgpair_state *msg_p = NULL;
  402.  
  403.     js_p->error_code = 0;
  404.  
  405.     PINT_msgpair_init(&sm_p->msgarray_op);
  406.     msg_p = &sm_p->msgarray_op.msgpair;
  407.  
  408.     /* note that unstuff must request the same attr mask that we requested
  409.      * earlier.  If the file has already been unstuffed then we need an 
  410.      * updated authoritative copy of all of the attrs relevant to I/O.
  411.      */
  412.     PINT_SERVREQ_UNSTUFF_FILL(
  413.             msg_p->req,
  414.             (*sm_p->cred_p),
  415.             sm_p->object_ref.fs_id,
  416.             sm_p->object_ref.handle,
  417.             PVFS_ATTR_META_ALL|PVFS_ATTR_COMMON_TYPE);
  418.  
  419.     msg_p->fs_id = sm_p->object_ref.fs_id;
  420.     msg_p->handle = sm_p->object_ref.handle;
  421.     msg_p->retry_flag = PVFS_MSGPAIR_RETRY;
  422.     msg_p->comp_fn = unstuff_comp_fn;
  423.  
  424.     ret = PINT_cached_config_map_to_server(
  425.             &msg_p->svr_addr,
  426.             msg_p->handle,
  427.             msg_p->fs_id);
  428.     if (ret)
  429.     {
  430.         gossip_err("Failed to map meta server address\n");
  431.         js_p->error_code = ret;
  432.     }
  433.  
  434.     PINT_sm_push_frame(smcb, 0, &sm_p->msgarray_op);
  435.     return SM_ACTION_COMPLETE;
  436. }
  437.  
  438. /* unstuff_comp_fn()
  439.  *
  440.  * completion function for unstuff msgpair array
  441.  */
  442. static int unstuff_comp_fn(
  443.     void *v_p,
  444.     struct PVFS_server_resp *resp_p,
  445.     int i)
  446. {
  447.     PINT_smcb *smcb = v_p;
  448.     PINT_client_sm *sm_p = PINT_sm_frame(smcb, PINT_MSGPAIR_PARENT_SM);
  449.  
  450.     gossip_debug(GOSSIP_CLIENT_DEBUG,
  451.         "unstuff completion fn: unstuff_comp_fn\n");
  452.  
  453.     /* only posted one msgpair */
  454.     assert(i==0);
  455.  
  456.     if (resp_p->status != 0)
  457.     {
  458.         gossip_debug(GOSSIP_CLIENT_DEBUG,
  459.             "unstuff negative response with error code: %d\n", 
  460.             resp_p->status);
  461.         return resp_p->status;
  462.     }
  463.  
  464.     assert(resp_p->op == PVFS_SERV_UNSTUFF);
  465.     
  466.     PINT_acache_update(sm_p->object_ref,
  467.         &resp_p->u.unstuff.attr,
  468.         NULL);
  469.  
  470.     /* replace attrs found by getattr */
  471.     /* PINT_copy_object_attr() takes care of releasing old memory */
  472.     PINT_copy_object_attr(&sm_p->getattr.attr, &resp_p->u.unstuff.attr);
  473.  
  474.     return(0);
  475. }
  476.  
  477. /*
  478.  * Local variables:
  479.  *  mode: c
  480.  *  c-indent-level: 4
  481.  *  c-basic-offset: 4
  482.  * End:
  483.  *
  484.  * vim: ft=c ts=8 sts=4 sw=4 expandtab
  485.  */
  486.