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 / io / buffer / state.c < prev    next >
C/C++ Source or Header  |  2006-05-15  |  13KB  |  540 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. #include "internal.h"
  5. #include "state.h"
  6. #include "cache.h"
  7. #include "flags.h"
  8. #include "ncac-trove.h"
  9.  
  10.  
  11. /* this file contains state transition of an extent */
  12.  
  13. static int NCAC_move_inactive_to_active(struct cache_stack *cache_stack,struct extent *page);
  14. int  data_sync_inode(struct inode *inode);
  15.  
  16. /* NCAC_extent_read_access(): when a cached extent is accessed by a read
  17.  * request, its flags are changing.
  18.  *
  19.  */
  20. int NCAC_extent_read_access(NCAC_req_t *ncac_req, struct extent *page, unsigned long offset, unsigned long size)
  21.     int error;
  22.     struct cache_stack *cache_stack;
  23.     int ret;
  24.  
  25.     cache_stack = ncac_req->mapping->cache_stack;
  26.  
  27.     IncReadCount(page);
  28.  
  29.     if ( !PageActive(page) && PageLRU(page) )
  30.     {
  31.         cache_lock(&(cache_stack->lock));
  32.  
  33.         cache_stack = get_extent_cache_stack(page);
  34.         NCAC_move_inactive_to_active(cache_stack, page);
  35.         SetPageActive(page);
  36.  
  37.         cache_unlock(&(cache_stack->lock));
  38.  
  39.     }
  40.  
  41.     /* if there is any write on this extent before this access,
  42.      * there is nothing we can do at this moment.
  43.      */
  44.     if ( page->writes > page->wcmp ) {
  45.         ret = 0;
  46.         goto out;
  47.     }
  48.  
  49.     /* in active list */
  50.     if (PageLRU(page) && PageActive(page)){
  51.  
  52.         if (PageRcomm(page)){ /* read communication pending */
  53.             ret = 1;
  54.             goto out;
  55.         }
  56.  
  57.         /* write communication is pending. 
  58.          * A write is ahead of this read. wait!!!
  59.          */
  60.         if (PageWcomm(page)) {
  61.             ret = 0; goto out;
  62.         }
  63.  
  64.         /************************************/
  65.         /* The following cases are those without pending communication */
  66.  
  67.         /* clean or dirty extent */
  68.         if (PageClean(page) || PageDirty(page) ) {
  69.             SetPageRcomm(page);    ret = 1; 
  70.             goto out;
  71.         }
  72.  
  73.         /* read pending: Trove read operation is pending.  */
  74.         /* write pending: for example flushing daemon is working on it */
  75.         if (PageReadPending(page) || PageWritePending(page)) {
  76.             error = NCAC_check_ioreq(page);
  77.             if (error <0) {
  78.                 NCAC_error("%s:%d NCAC_check_ioreq error\n", __FILE__, __LINE__);
  79.                 ret = 0; goto out;
  80.             }
  81.  
  82.             if (error) {
  83.                 /* set all other related extents */
  84.                 list_set_clean_page(page);
  85.  
  86.                 /* the request is done and the read is finished.
  87.                  * Note that NCAC_check_ioreq sets page flags in this case.*/
  88.                 SetPageRcomm(page);    
  89.                 ret = 0; 
  90.                 goto out;
  91.             }
  92.             ret = 0; goto out;
  93.         }
  94.                 
  95.     }
  96.  
  97.     /* invalid flags */
  98.     ret = NCAC_INVAL_FLAGS;
  99.  
  100. out:
  101.     return ret;
  102.  
  103. }
  104.  
  105. /* NCAC_extent_write_access(): when a cached extent is accessed by a write
  106.  * request, its flags are changing.
  107.  * According to Linux 2.6, if the extent is cached in the inactive
  108.  * list, it is not moved to the active list.
  109.  */
  110. int NCAC_extent_write_access(NCAC_req_t *ncac_req, struct extent *page, unsigned long offset, unsigned long size)
  111.     int error;
  112.  
  113.     IncWriteCount(page);
  114.  
  115.     /* the first write */
  116.     if ( PageLRU(page) && page->writes - page->wcmp ==1 ){
  117.  
  118.         if (PageRcomm(page) || PageWcomm(page)) 
  119.             return 0;
  120.  
  121.  
  122.         if (PageReadPending(page) || PageWritePending(page)) {
  123.             error = NCAC_check_ioreq(page);
  124.             if (error <0) {
  125.                 NCAC_error("%s:%d NCAC_check_ioreq error\n", __FILE__, __LINE__);
  126.                 return error;
  127.             }
  128.             if (error) { /* completion */
  129.  
  130.             /* set all other related extents */
  131.             list_set_clean_page(page);
  132.  
  133.             /* the request is done and the read is finished.
  134.              * Note that NCAC_check_ioreq sets page flags in 
  135.              * this case.*/
  136.  
  137.             SetPageWcomm(page);    
  138.                 return 1;
  139.             }
  140.             return 0;    
  141.         }
  142.  
  143.         /* No pending comm, clean or dirty extent */
  144.         if (PageClean(page) || PageDirty(page) ) {
  145.             SetPageWcomm(page);    
  146.             return 1;
  147.         }
  148.     }
  149.  
  150.     /* it is not the first write */
  151.     if ( page->writes - page->wcmp >1 ){
  152.         return 0;
  153.     }
  154.  
  155.     /* there is pending reads */
  156.     if ( page->reads != page->rcmp  ){
  157.         return 0;
  158.     }
  159.  
  160.     /* invalid flags */
  161.     return NCAC_INVAL_FLAGS;
  162. }
  163.  
  164.  
  165. /* NCAC_extent_first_read_access(): when a new extent is allocated
  166.  * for read, this function is called. It is called before we
  167.  * put it into cache and after we initiate a Trove read request.
  168.  */
  169. int NCAC_extent_first_read_access(NCAC_req_t *ncac_req, struct extent *page)
  170. {
  171.     SetPageReadPending(page); 
  172.     IncReadCount(page);
  173.     return 0;
  174. }
  175.  
  176. /* NCAC_extent_first_write_access(): when a new extent is allocated
  177.  * for write, this function is called. It is called before we
  178.  * put it into cache.
  179.  */
  180. int NCAC_extent_first_write_access(NCAC_req_t *ncac_req, struct extent *page)
  181. {
  182.     ClearPageBlank(page);
  183.        SetPageWcomm(page); 
  184.     IncWriteCount(page);
  185.     return 1;
  186. }
  187.  
  188. /* NCAC_extent_done_access(): when communication is done, we mark
  189.  * each extent to clean/dirty. When it is dirty, add it to the
  190.  * inode dirty list.
  191.  *
  192.  * TODO: buffer information cannot not be changed by the outside.
  193.  * */
  194. int NCAC_extent_done_access(NCAC_req_t *ncac_req)
  195. {
  196.     int  i;
  197.     struct inode *inode;
  198.     struct list_head *dirty_list = NULL;
  199.     struct cache_stack *cache;
  200.     int nr_dirty = 0;
  201.     int ret = 0;
  202.  
  203.     inode = ncac_req->mapping;
  204.  
  205.     inode_lock (&inode->lock);
  206.  
  207.     if (ncac_req->optype == NCAC_READ)
  208.     {
  209.         for (i = 0; i < ncac_req->cbufcnt; i++)
  210.         {
  211.             if (ncac_req->cbufflag[i] && ncac_req->cbufhash[i])
  212.             {
  213.                 NCAC_extent_read_comm_done (ncac_req->cbufhash[i]);
  214.                 //DecReadCount(ncac_req->cbufhash[i]);
  215.                 ncac_req->cbufhash[i]->rcmp++;
  216.                 ncac_req->cbufhash[i]->reads--;
  217.             }
  218.         }
  219.       }
  220.  
  221.     if (ncac_req->optype == NCAC_WRITE)
  222.     {
  223.         dirty_list = &(inode->dirty_pages);
  224.         for (i = 0; i < ncac_req->cbufcnt; i++)
  225.         {
  226.             if (ncac_req->cbufflag[i] && ncac_req->cbufhash[i])
  227.             {
  228.                 NCAC_extent_write_comm_done (ncac_req->cbufhash[i]);
  229.                 //DecWriteCount(ncac_req->cbufhash[i]);
  230.                 ncac_req->cbufhash[i]->wcmp++;
  231.  
  232.                 /* add dirty pages */
  233.                 list_add_tail (&ncac_req->cbufhash[i]->list, dirty_list);
  234.                 nr_dirty++;
  235.  
  236.             }
  237.         }
  238.         inode->nr_dirty += nr_dirty;
  239.  
  240.         /* handle sync stuff: there are three cases:
  241.          * 1) if a file is opend with O_SYNC, we should do sync
  242.          * 2) if we define aggressive flush, we do sync here.
  243.          * 3) otherwise, sync depends on our flush policy.
  244.          * TODO: currently we don't know O_SYNC flag 
  245.          */
  246.  
  247.         /* if ( ncac_req->f_flags & O_SYNC || IS_SYNC(inode) ) {
  248.             data_sync(inode);
  249.            }
  250.          */
  251.  
  252. #if defined(LAZY_SYNC)
  253.         ret = balance_dirty_extents (ncac_req->mapping->cache_stack);
  254.  
  255. #else /* aggressive sync */
  256.         ret = data_sync_inode (inode);
  257. #endif
  258.     }
  259.  
  260.     inode_unlock (&inode->lock);
  261.  
  262.     if (dirty_list)
  263.     {                /* atomic add */
  264.         cache = inode->cache_stack;
  265.  
  266.         cache_lock (&cache->lock);
  267.         cache->nr_dirty += (nr_dirty - ret);
  268.         cache_unlock (&cache->lock);
  269.         DPRINT ("-------nr_dirty=%d, flush=%d\n", nr_dirty, ret);
  270.     }
  271.  
  272.     return 0;
  273. }
  274.  
  275. /* read commnication is done */
  276. int NCAC_extent_read_comm_done(struct extent *page)
  277. {
  278.     ClearPageRcomm(page);
  279.     return 0;
  280. }
  281.  
  282. /* read commnication is done */
  283. int NCAC_extent_write_comm_done(struct extent *page)
  284. {
  285.     ClearPageWcomm(page);
  286.     ClearPageClean(page);
  287.        SetPageDirty(page); 
  288.     return 0;
  289. }
  290.  
  291. void list_set_clean_page(struct extent *page)
  292.  
  293. {
  294.     struct extent *next;
  295.  
  296.     int cnt = 0;  
  297.  
  298.     DPRINT("iodone before: flags:%lx\n", page->flags);
  299.     ClearPageDirty(page);
  300.     SetPageClean(page);
  301.     ClearPageReadPending(page);
  302.     ClearPageWritePending(page);
  303.  
  304.     page->ioreq = INVAL_IOREQ; 
  305.     next = page->ioreq_next;
  306.  
  307.     cnt ++;
  308.  
  309.     while ( next != page ) {
  310.         SetPageClean (next);
  311.         ClearPageDirty (next);
  312.         ClearPageReadPending (next);
  313.         ClearPageWritePending (next);
  314.  
  315.         next->ioreq = INVAL_IOREQ;
  316.  
  317.         cnt++;
  318.  
  319.         next = next->ioreq_next;
  320.     }
  321.  
  322.     DPRINT("clean_page: %d\n", cnt);
  323.  
  324.     return;
  325. }
  326.  
  327.  
  328. static int NCAC_move_inactive_to_active(struct cache_stack *cache_stack,struct extent *page)
  329. {
  330.     del_page_from_inactive_list(cache_stack, page);
  331.     add_page_to_active_list(cache_stack, page);
  332.     return 0;
  333. }
  334.  
  335.  
  336. int NCAC_extent_read_access_recheck(NCAC_req_t *req, struct extent *page, unsigned int offset, unsigned int size)
  337. {
  338.     int error;
  339.  
  340.     if ( PageLRU(page) ){
  341.         if (PageRcomm(page)) 
  342.             return 1;
  343.  
  344.         /* write communication is pending. 
  345.          * A write is ahead of this read. wait!!! 
  346.          */
  347.         if (PageWcomm(page)) return 0;
  348.  
  349.         /* clean or dirty extent */
  350.         if (PageClean(page) || PageDirty(page)) {
  351.             SetPageRcomm(page); return 1;
  352.         }
  353.  
  354.         /* read pending: Trove read operation is pending.  */
  355.         /* write pending: for example flushing daemon is working on it */
  356.  
  357.         if (PageReadPending(page) || PageWritePending(page)) {
  358.             error = NCAC_check_ioreq(page);
  359.             if (error <0) {
  360.                 NCAC_error("%s:%d NCAC_check_ioreq error\n", __FILE__, __LINE__);
  361.                 return error;
  362.             }
  363.             if (error) {
  364.  
  365.                 /* set all other related extents */
  366.                 list_set_clean_page(page);
  367.  
  368.                 /* the request is done and the read is finished.
  369.                  * Note that NCAC_check_ioreq sets page flags in this case.*/
  370.                 SetPageRcomm(page); return 1; 
  371.             }
  372.             return 0;
  373.         }
  374.     }
  375.  
  376.     /* invalid flags */
  377.     return NCAC_INVAL_FLAGS;
  378. }
  379.  
  380.  
  381. int NCAC_extent_write_access_recheck(NCAC_req_t *ncac_req, struct extent *page, unsigned int offset, unsigned int size)
  382. {
  383.     int error;
  384.  
  385.     if ( PageLRU(page) ){
  386.         if ( PageRMW(page) ) {
  387.             error = NCAC_check_ioreq(page);
  388.             if (error <0) {
  389.                 NCAC_error("NCAC_check_ioreq error\n");
  390.                 return error;
  391.             }
  392.             if ( !error ) 
  393.                 return 2;  /* 2 for rmw */
  394.             else {
  395.                 ClearPageRMW(page);
  396.                 return 1;
  397.             }
  398.         }
  399.  
  400.         if (PageRcomm(page) || PageWcomm(page))
  401.             return 0;
  402.  
  403.  
  404.         if (PageReadPending(page) || PageWritePending(page)) {
  405.             error = NCAC_check_ioreq(page);
  406.             if (error <0) {
  407.                 NCAC_error("NCAC_check_ioreq error\n");
  408.                 return error;
  409.             }
  410.             if (error) {
  411.                 /* set all other related extents */
  412.                 list_set_clean_page(page);
  413.  
  414.                 /* the request is done and the read is finished.
  415.                  * Note that NCAC_check_ioreq sets page flags in this case.*/
  416.                 SetPageWcomm(page);
  417.                 return 1;
  418.             }
  419.             return 0;
  420.         }
  421.  
  422.  
  423.         /* No pending comm, clean or dirty extent */
  424.         if (PageClean(page) || PageDirty(page)) {
  425.             SetPageWcomm(page);
  426.             return 1;
  427.         }
  428.  
  429.         return 0;
  430.     }
  431.  
  432.     /* invalid flags */
  433.     return NCAC_INVAL_FLAGS;
  434. }
  435.  
  436.  
  437. #if 0
  438. static void    balance_dirty_extents( struct cache_stack *cache_stack)
  439. {
  440.     fprintf(stderr, "balance_dirty_extents is not implemented yet\n");
  441. }
  442. #endif
  443.  
  444. /* data_sync_inode(): initiate sync operation on all dirty extents so far. 
  445.  * problem here: the file offset is increasing?
  446.  * The caller holds the inode lock.
  447.  * 
  448.  * TODO: is it useful to order extents in the dirty list?
  449.  */
  450.  
  451. int data_sync_inode(struct inode *inode)
  452. {
  453.     struct list_head  *list, *tail;
  454.     struct extent *extent, *prev, *first;
  455.     int nr_dirty;
  456.     PVFS_offset *offset;
  457.     char **mem;
  458.     PVFS_size *offsize, *memsize;
  459.     int cnt = 0;
  460.     int ioreq;
  461.     int ret;
  462.     int i;
  463.  
  464.     nr_dirty = inode->nr_dirty;
  465.  
  466.     DPRINT("data_sync_inode: nr_dirty=%d\n", nr_dirty);
  467.     if ( !nr_dirty ) return 0;
  468.  
  469.     /* allocate Trove parameters */
  470.     offset = (PVFS_offset *)malloc(nr_dirty*(sizeof(PVFS_offset) + sizeof(char*) + 2*sizeof(PVFS_size)) );
  471.     mem = (char**)&offset[nr_dirty];
  472.     offsize = (PVFS_size*)&mem[nr_dirty];
  473.     memsize = &offsize[nr_dirty];
  474.     
  475.     list = &(inode->dirty_pages);
  476.     
  477.     /* from the head to the tail to keep the order */
  478.     tail = list->next; 
  479.     while ( tail != list ){
  480.         extent = list_entry(tail, struct extent, list);
  481.         offset[cnt] = extent->index * NCAC_dev.extsize;
  482.         offsize[cnt] = NCAC_dev.extsize;
  483.         mem[cnt] = extent->addr;
  484.         memsize[cnt] = NCAC_dev.extsize;
  485.  
  486.         DPRINT("to write: pos:%lld, size=%lld, buf=%p\n", 
  487.              offset[cnt], offsize[cnt], mem[cnt]);
  488.         cnt ++;
  489.         tail = tail->next;
  490.     }
  491.  
  492.     ret = NCAC_aio_write(inode->coll_id, inode->handle, 
  493.             inode->context_id, nr_dirty, 
  494.             offset, offsize, mem, memsize, &ioreq);
  495.     if ( ret < 0 ) {
  496.         NCAC_error("data_sync_inode: NCAC_aio_write error \n");
  497.         return ret;
  498.     }else{
  499.         /* we need to associate all extents to an IOreq */
  500.  
  501.         tail = list->next; 
  502.         extent = list_entry(tail, struct extent, list);
  503.  
  504.         SetPageWritePending(extent);
  505.         extent->ioreq_next = extent;
  506.         prev = first = extent;
  507.  
  508.         extent->ioreq = ioreq;
  509.         list_del(&extent->list);
  510.         tail = list->next;
  511.  
  512.         for ( i = 1; i < nr_dirty; i ++ ) { 
  513.             extent = list_entry(tail, struct extent, list);
  514.             SetPageWritePending(extent);
  515.             prev->ioreq_next = extent;
  516.             extent->ioreq = ioreq;
  517.  
  518.             prev = extent;
  519.             list_del(&extent->list);
  520.             tail = list->next;
  521.         }
  522.         extent->ioreq_next = first;
  523.  
  524.         inode->nr_dirty = 0;
  525.     }
  526.  
  527.     return nr_dirty;
  528. }
  529.  
  530.  
  531.  
  532. void mark_extent_rmw_lock(struct extent *extent, int ioreq)
  533. {
  534.     SetPageRMW(extent);
  535.     extent->ioreq = ioreq;
  536.     extent->ioreq_next = extent;
  537. }
  538.