Changeset 0ebfac19 in rtems


Ignore:
Timestamp:
03/07/06 21:26:23 (18 years ago)
Author:
Joel Sherrill <joel.sherrill@…>
Branches:
4.10, 4.11, 4.8, 4.9, 5, master
Children:
bea51c0
Parents:
ab8394f6
Message:

2006-03-07 Thomas Doerfler <Thomas.Doerfler@…>

PR 852/filesystem

  • libblock/src/bdbuf.c: Increase performance of MSDOS file accesses by using a simple read-ahead and write-combining scheme. Improvement is dramatic.
Location:
cpukit
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • cpukit/ChangeLog

    rab8394f6 r0ebfac19  
     12006-03-07      Thomas Doerfler <Thomas.Doerfler@embedded-brains.de>
     2
     3        PR 852/filesystem
     4        * libblock/src/bdbuf.c: Increase performance of MSDOS file accesses by
     5        using a simple read-ahead and write-combining scheme. Improvement is
     6        dramatic.
     7
    182006-03-07      Till Strauman <strauman@slac.stanford.edu>
    29
  • cpukit/libblock/src/bdbuf.c

    rab8394f6 r0ebfac19  
    3232#define SWAPOUT_STACK_SIZE (RTEMS_MINIMUM_STACK_SIZE * 2)
    3333
     34#define READ_MULTIPLE
     35
     36#if defined(READ_MULTIPLE)
     37#define READ_AHEAD_MAX_BLK_CNT 32
     38typedef struct {
     39  blkdev_request   req;
     40  blkdev_sg_buffer sg[READ_AHEAD_MAX_BLK_CNT];
     41} blkdev_request_read_ahead;
     42/*
     43 * list of bd_bufs related to one transfer request
     44 */
     45typedef struct {
     46  int cnt;
     47  bdbuf_buffer *bd_bufs[READ_AHEAD_MAX_BLK_CNT];
     48} read_ahead_bd_buf_group;
     49#endif
     50
     51typedef struct {
     52  blkdev_request *req;
     53  bdbuf_buffer   **write_store;
     54} write_tfer_done_arg_t;
     55
    3456static rtems_task bdbuf_swapout_task(rtems_task_argument unused);
    3557
     58static rtems_status_code bdbuf_release(bdbuf_buffer *bd_buf);
    3659/*
    3760 * The groups of the blocks with the same size are collected in the
     
    6891    rtems_id       swapout_task; /* Swapout task ID */
    6992};
     93/*
     94 * maximum number of blocks that might be chained together to one
     95 * write driver call
     96 */
     97#define SWAP_OUT_MAX_BLK_CNT 32
     98/*#define SWAP_OUT_MAX_BLK_CNT 1 */
     99/*
     100 * XXX: this is a global buffer. It is used in the swapout task
     101 * and currently will be reused only after it is no longer in use
     102 *
     103 */
     104static bdbuf_buffer *bd_buf_write_store[SWAP_OUT_MAX_BLK_CNT];
    70105
    71106/* Block device request with a single buffer provided */
     
    229264
    230265    bdbuf_buffer *p = *root;
    231     bdbuf_buffer *q = NULL;
    232     bdbuf_buffer *p1, *p2;
     266    bdbuf_buffer *q, *p1, *p2;
    233267    bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT];
    234268    bdbuf_buffer **buf_prev = buf_stack;
     
    11161150bdbuf_write_transfer_done(void *arg, rtems_status_code status, int error)
    11171151{
    1118     bdbuf_buffer *bd_buf = arg;
    1119     bd_buf->status = status;
    1120     bd_buf->error = RTEMS_IO_ERROR;
    1121     bd_buf->in_progress = bd_buf->modified = FALSE;
    1122     _CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL);
    1123     _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
    1124                       CORE_MUTEX_STATUS_SUCCESSFUL);
     1152    int i;
     1153    write_tfer_done_arg_t *wtd_arg = arg;
     1154    blkdev_request *req = wtd_arg->req;
     1155    bdbuf_buffer **bd_buf_write_store = wtd_arg->write_store;
     1156    bdbuf_buffer *bd_buf;
     1157    for (i = 0;i < req->count;i++) {
     1158      bd_buf = bd_buf_write_store[i];
     1159      bd_buf->status = status;
     1160      bd_buf->error = RTEMS_IO_ERROR;
     1161     
     1162      bd_buf->in_progress = FALSE;
     1163      _CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL);
     1164      _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
     1165                        CORE_MUTEX_STATUS_SUCCESSFUL);
     1166    }
    11251167}
    11261168
     
    11431185bdbuf_read_transfer_done(void *arg, rtems_status_code status, int error)
    11441186{
     1187#if defined(READ_MULTIPLE) 
     1188 
     1189  read_ahead_bd_buf_group *bd_buf_group = arg;
     1190  bdbuf_buffer *bd_buf;
     1191  int i;
     1192  for (i = 0;i < bd_buf_group->cnt;i++) {
     1193    bd_buf = bd_buf_group->bd_bufs[i];
     1194
     1195    bd_buf->status = status;
     1196    bd_buf->error = RTEMS_IO_ERROR;
     1197    _CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL);
     1198    _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
     1199                      CORE_MUTEX_STATUS_SUCCESSFUL);
     1200  }
     1201#else
    11451202    bdbuf_buffer *bd_buf = arg;
    11461203    bd_buf->status = status;
     
    11491206    _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
    11501207                      CORE_MUTEX_STATUS_SUCCESSFUL);
     1208#endif
    11511209}
    11521210
     
    11721230 *     bufget_sema and transfer_sema semaphores obtained by this primitive.
    11731231 */
     1232#if !defined(READ_MULTIPLE)
    11741233rtems_status_code
    11751234rtems_bdbuf_read(dev_t device,
     
    12451304
    12461305    *bd = bd_buf;
    1247 
     1306           
    12481307    return RTEMS_SUCCESSFUL;
    12491308}
     1309#else /* READ_MULTIPLE */
     1310rtems_status_code
     1311rtems_bdbuf_read(dev_t device,
     1312                 blkdev_bnum block,
     1313                 bdbuf_buffer **bd)
     1314{
     1315    preemption_key key;
     1316    ISR_Level level;
     1317
     1318    bdbuf_buffer *bd_buf,*first_bd_buf;
     1319    rtems_status_code rc;
     1320    int result;
     1321    disk_device *dd;
     1322    disk_device *pdd;
     1323    blkdev_request_read_ahead req;
     1324    read_ahead_bd_buf_group bd_buf_group;
     1325    boolean find_more_buffers;
     1326    int i;
     1327
     1328    dd = rtems_disk_lookup(device);
     1329    if (dd == NULL)
     1330        return RTEMS_INVALID_ID;
     1331     
     1332    if (block >= dd->size)
     1333    {
     1334        rtems_disk_release(dd);
     1335        return RTEMS_INVALID_NUMBER;
     1336    }
     1337   
     1338    pdd = dd->phys_dev;
     1339    block += dd->start;
     1340
     1341    DISABLE_PREEMPTION(key);
     1342    rc = find_or_assign_buffer(pdd, block, &first_bd_buf);
     1343
     1344    if (rc != RTEMS_SUCCESSFUL)
     1345    {
     1346        ENABLE_PREEMPTION(key);
     1347        rtems_disk_release(dd);
     1348        return rc;
     1349    }
     1350    if (!first_bd_buf->actual)
     1351    {
     1352
     1353        bd_buf_group.bd_bufs[0] = first_bd_buf;
     1354        bd_buf_group.cnt = 1;
     1355
     1356        first_bd_buf->in_progress = TRUE;
     1357
     1358        req.req.req = BLKDEV_REQ_READ;
     1359        req.req.req_done = bdbuf_read_transfer_done;
     1360        req.req.done_arg = &bd_buf_group;
     1361        req.req.start = block;
     1362        req.req.count = 1;
     1363        req.req.bufnum = 1;
     1364        req.req.bufs[0].length = dd->block_size;
     1365        req.req.bufs[0].buffer = first_bd_buf->buffer;
     1366       
     1367        bdbuf_initialize_transfer_sema(first_bd_buf);
     1368        /*
     1369         * FIXME: check for following blocks to be:
     1370         *   - still in range of partition size
     1371         *   - not yet assigned
     1372         *   - buffer available
     1373         * allocate for read call, if possible
     1374         */
     1375        find_more_buffers = TRUE;
     1376        while (find_more_buffers) {       
     1377          block++;
     1378          /*
     1379           * still bd_buf_group entries free and
     1380           * still in range of this disk?
     1381           */
     1382          if ((bd_buf_group.cnt >= READ_AHEAD_MAX_BLK_CNT) ||
     1383              (block >= dd->size)) {
     1384            find_more_buffers = FALSE;
     1385          }
     1386          if (find_more_buffers) {
     1387            rc = find_or_assign_buffer(pdd, block, &bd_buf);
     1388            if (rc != RTEMS_SUCCESSFUL) {
     1389              find_more_buffers = FALSE;
     1390            }     
     1391            else if (bd_buf->actual) {
     1392              find_more_buffers = FALSE;
     1393          bdbuf_release(bd_buf);
     1394            }     
     1395          }
     1396          if (find_more_buffers) {
     1397            bdbuf_initialize_transfer_sema(bd_buf);
     1398            bd_buf->in_progress = TRUE;
     1399
     1400            req.req.bufs[req.req.count].length = dd->block_size;
     1401            req.req.bufs[req.req.count].buffer = bd_buf->buffer;
     1402            req.req.count++;
     1403            req.req.bufnum++;
     1404            bd_buf_group.bd_bufs[bd_buf_group.cnt] = bd_buf;
     1405            bd_buf_group.cnt++;
     1406          }
     1407        }           
     1408
     1409        /* do the actual read call here
     1410         */
     1411        result = dd->ioctl(pdd->dev, BLKIO_REQUEST, &req);
     1412
     1413        /*
     1414         * cleanup:
     1415         * wait, until all bd_bufs are processed
     1416         * set status in all bd_bufs
     1417         */
     1418        for (i = 0;i < bd_buf_group.cnt;i++) {
     1419          bd_buf = bd_buf_group.bd_bufs[i];
     1420          if (result == -1)
     1421            {
     1422              bd_buf->status = RTEMS_IO_ERROR;
     1423              bd_buf->error = errno;
     1424              bd_buf->actual = FALSE;
     1425            }
     1426          else
     1427            {
     1428              rtems_interrupt_disable(level);
     1429              _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
     1430                                WATCHDOG_NO_TIMEOUT, level);
     1431              bd_buf->actual = TRUE;
     1432            }   
     1433          bd_buf->in_progress = FALSE;
     1434          /* release any pre-read buffers */
     1435          if (i > 0) {
     1436            bdbuf_release(bd_buf);
     1437          }
     1438        }
     1439    }
     1440    rtems_disk_release(dd);
     1441   
     1442    ENABLE_PREEMPTION(key);
     1443
     1444    *bd = first_bd_buf;
     1445           
     1446    return RTEMS_SUCCESSFUL;
     1447}
     1448#endif /* READ_MULTIPLE */
    12501449
    12511450
     
    14851684    rtems_status_code rc;
    14861685    int result;
     1686    int i;
    14871687    ISR_Level level;
    14881688    bdbuf_buffer *bd_buf;
    1489     bdbuf_pool *bd_pool;
    1490     disk_device *dd;
    1491     blkdev_request1 req;
    1492 
     1689    bdbuf_buffer *nxt_bd_buf;
     1690    bdbuf_pool *bd_pool = NULL;
     1691    disk_device *dd = NULL;
     1692    struct {
     1693      blkdev_request   req;
     1694      blkdev_sg_buffer sg[SWAP_OUT_MAX_BLK_CNT];
     1695    } req;
     1696    write_tfer_done_arg_t write_tfer_done_arg;
     1697
     1698    /*
     1699     * provide info needed for write_transfer_done function
     1700     */
     1701    write_tfer_done_arg.req         = (blkdev_request *)&req.req;
     1702    write_tfer_done_arg.write_store =  bd_buf_write_store;
     1703    nxt_bd_buf = NULL;
    14931704    while (1)
    14941705    {
    1495         rc = rtems_semaphore_obtain(bd_ctx.flush_sema, RTEMS_WAIT, 0);
    1496         if (rc != RTEMS_SUCCESSFUL)
    1497         {
    1498             rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_SWAPOUT);
    1499         }
    1500 
    1501         bd_buf = (bdbuf_buffer *)Chain_Get(&bd_ctx.mod);
    1502         if (bd_buf == NULL)
    1503         {
    1504             /* It is possible that flush_sema semaphore will be released, but
    1505              * buffer to be removed from mod chain before swapout task start
    1506              * its processing. */
    1507             continue;
    1508         }
    1509 
    1510         bd_buf->in_progress = TRUE;
    1511         bd_buf->use_count++;
    1512         bd_pool = bd_ctx.pool + bd_buf->pool;
    1513         dd = rtems_disk_lookup(bd_buf->dev);
    1514 
    1515         req.req.req = BLKDEV_REQ_WRITE;
    1516         req.req.req_done = bdbuf_write_transfer_done;
    1517         req.req.done_arg = bd_buf;
    1518         req.req.start = bd_buf->block + dd->start;
    1519         req.req.count = 1;
    1520         req.req.bufnum = 1;
    1521         req.req.bufs[0].length = dd->block_size;
    1522         req.req.bufs[0].buffer = bd_buf->buffer;
    1523 
    1524         /* transfer_sema initialized when bd_buf inserted in the mod chain
     1706        req.req.req = BLKDEV_REQ_WRITE;
     1707        req.req.req_done = bdbuf_write_transfer_done;
     1708        req.req.done_arg = &write_tfer_done_arg;
     1709        req.req.count = 0;
     1710        req.req.bufnum = 0;
     1711        bd_buf = NULL;
     1712        do {
     1713          /*
     1714           * if a buffer was left over from last loop, then use this buffer
     1715           * otherwise fetch new buffer from chain.
     1716           * Wait for buffer, if this is the first one of the request,
     1717           * otherwise do not wait, if no buffer available
     1718           */
     1719          if (nxt_bd_buf == NULL) {
     1720            rc = rtems_semaphore_obtain(bd_ctx.flush_sema,
     1721                                        (req.req.count == 0)
     1722                                        ? RTEMS_WAIT
     1723                                        : RTEMS_NO_WAIT,
     1724                                        0);
     1725            if (rc == RTEMS_SUCCESSFUL) {
     1726              nxt_bd_buf = (bdbuf_buffer *)Chain_Get(&bd_ctx.mod);
     1727          if (nxt_bd_buf != NULL) {
     1728                nxt_bd_buf->in_progress = TRUE;
     1729            /* IMD try: clear "modified" bit early             */
     1730            /* (and not in bdbuf_write_transfer_done) to allow */
     1731            /* another modification during write processing    */
     1732            nxt_bd_buf->modified    = FALSE;
     1733
     1734                nxt_bd_buf->use_count++;
     1735                  }
     1736            }
     1737            else if ((rc != RTEMS_UNSATISFIED) &&
     1738                     (rc != RTEMS_TIMEOUT)) {
     1739              rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_SWAPOUT);
     1740            }
     1741          }
     1742          /*
     1743           * It is possible that flush_sema semaphore will be released, but
     1744           * buffer to be removed from mod chain before swapout task start
     1745           * its processing.
     1746           */
     1747          if ((req.req.count == 0)  || /* first bd_buf for this request */
     1748              ((nxt_bd_buf        != NULL)            &&
     1749               (nxt_bd_buf->dev   == bd_buf->dev)     && /* same device */
     1750               (nxt_bd_buf->block == bd_buf->block+1))) {/* next block  */
     1751            bd_buf     = nxt_bd_buf;
     1752            nxt_bd_buf = NULL;
     1753          }
     1754          else {
     1755            bd_buf = NULL;
     1756          }
     1757          /*
     1758           * here we have three possible states:
     1759           * bd_buf == NULL, nxt_bd_buf == NULL: no further block available
     1760           * bd_buf != NULL, nxt_bd_buf == NULL: append bd_buf to request
     1761           * bd_buf == NULL, nxt_bd_buf != NULL: nxt_bd_buf canot be appended
     1762           *                                     to current request, keep it
     1763           *                                     for next main loop
     1764           */
     1765          if (bd_buf != NULL) {
     1766            bd_pool = bd_ctx.pool + bd_buf->pool;
     1767            if (req.req.count == 0) {
     1768              /*
     1769               * this is the first block, so use its address
     1770               */
     1771              dd = rtems_disk_lookup(bd_buf->dev);
     1772              req.req.start = bd_buf->block + dd->start;
     1773            }
     1774            req.req.bufs[req.req.bufnum].length = dd->block_size;
     1775            req.req.bufs[req.req.bufnum].buffer = bd_buf->buffer;
     1776            /*
     1777             * keep bd_buf for postprocessing
     1778             */
     1779            bd_buf_write_store[req.req.bufnum] = bd_buf;
     1780            req.req.count++;
     1781            req.req.bufnum++;
     1782          }
     1783        } while ((bd_buf != NULL) &&
     1784                 (req.req.count < SWAP_OUT_MAX_BLK_CNT));
     1785                 
     1786        /* transfer_sema initialized when bd_buf inserted in the mod chain
    15251787           first time */
    15261788        result = dd->ioctl(dd->phys_dev->dev, BLKIO_REQUEST, &req);
    15271789
    15281790        rtems_disk_release(dd);
    1529 
    1530         if (result == -1)
    1531         {
    1532             bd_buf->status = RTEMS_IO_ERROR;
    1533             bd_buf->error = errno;
    1534             /* Release tasks waiting on syncing this buffer */
    1535             _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
    1536                               CORE_MUTEX_STATUS_SUCCESSFUL);
    1537         }
    1538         else
    1539         {
    1540             if (bd_buf->in_progress)
    1541             {
    1542                 rtems_interrupt_disable(level);
    1543                 _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE, 0, level);
    1544             }
    1545         }
    1546         bd_buf->use_count--;
    1547 
    1548         /* Another task have chance to use this buffer, or even
    1549          * modify it. If buffer is not in use, insert it in appropriate chain
    1550          * and release semaphore */
    1551         if (bd_buf->use_count == 0)
    1552         {
    1553             if (bd_buf->modified)
    1554             {
    1555                 Chain_Append(&bd_ctx.mod, &bd_buf->link);
    1556                 rc = rtems_semaphore_release(bd_ctx.flush_sema);
    1557             }
    1558             else
    1559             {
    1560                 Chain_Append(&bd_pool->lru, &bd_buf->link);
    1561                 rc = rtems_semaphore_release(bd_pool->bufget_sema);
    1562             }
     1791       
     1792        for (i = 0;i < req.req.count;i++) {
     1793          bd_buf = bd_buf_write_store[i];
     1794          if (result == -1)
     1795            {
     1796             
     1797              bd_buf->status = RTEMS_IO_ERROR;
     1798              bd_buf->error = errno;
     1799              /* Release tasks waiting on syncing this buffer */
     1800              _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
     1801                                CORE_MUTEX_STATUS_SUCCESSFUL);
     1802            }
     1803          else
     1804            {
     1805              if (bd_buf->in_progress)
     1806                {
     1807                  rtems_interrupt_disable(level);
     1808                  _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE, 0, level);
     1809                }
     1810            }
     1811          bd_buf->use_count--;
     1812
     1813          /* Another task have chance to use this buffer, or even
     1814           * modify it. If buffer is not in use, insert it in appropriate chain
     1815           * and release semaphore */
     1816          if (bd_buf->use_count == 0)
     1817            {
     1818              if (bd_buf->modified)
     1819                {
     1820                  Chain_Append(&bd_ctx.mod, &bd_buf->link);
     1821                  rc = rtems_semaphore_release(bd_ctx.flush_sema);
     1822                }
     1823              else
     1824                {
     1825                  Chain_Append(&bd_pool->lru, &bd_buf->link);
     1826                  rc = rtems_semaphore_release(bd_pool->bufget_sema);
     1827                }
     1828            }
    15631829        }
    15641830    }
Note: See TracChangeset for help on using the changeset viewer.