Changeset 0ebfac19 in rtems
- Timestamp:
- 03/07/06 21:26:23 (18 years ago)
- Branches:
- 4.10, 4.11, 4.8, 4.9, 5, master
- Children:
- bea51c0
- Parents:
- ab8394f6
- Location:
- cpukit
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
cpukit/ChangeLog
rab8394f6 r0ebfac19 1 2006-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 1 8 2006-03-07 Till Strauman <strauman@slac.stanford.edu> 2 9 -
cpukit/libblock/src/bdbuf.c
rab8394f6 r0ebfac19 32 32 #define SWAPOUT_STACK_SIZE (RTEMS_MINIMUM_STACK_SIZE * 2) 33 33 34 #define READ_MULTIPLE 35 36 #if defined(READ_MULTIPLE) 37 #define READ_AHEAD_MAX_BLK_CNT 32 38 typedef 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 */ 45 typedef struct { 46 int cnt; 47 bdbuf_buffer *bd_bufs[READ_AHEAD_MAX_BLK_CNT]; 48 } read_ahead_bd_buf_group; 49 #endif 50 51 typedef struct { 52 blkdev_request *req; 53 bdbuf_buffer **write_store; 54 } write_tfer_done_arg_t; 55 34 56 static rtems_task bdbuf_swapout_task(rtems_task_argument unused); 35 57 58 static rtems_status_code bdbuf_release(bdbuf_buffer *bd_buf); 36 59 /* 37 60 * The groups of the blocks with the same size are collected in the … … 68 91 rtems_id swapout_task; /* Swapout task ID */ 69 92 }; 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 */ 104 static bdbuf_buffer *bd_buf_write_store[SWAP_OUT_MAX_BLK_CNT]; 70 105 71 106 /* Block device request with a single buffer provided */ … … 229 264 230 265 bdbuf_buffer *p = *root; 231 bdbuf_buffer *q = NULL; 232 bdbuf_buffer *p1, *p2; 266 bdbuf_buffer *q, *p1, *p2; 233 267 bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT]; 234 268 bdbuf_buffer **buf_prev = buf_stack; … … 1116 1150 bdbuf_write_transfer_done(void *arg, rtems_status_code status, int error) 1117 1151 { 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 } 1125 1167 } 1126 1168 … … 1143 1185 bdbuf_read_transfer_done(void *arg, rtems_status_code status, int error) 1144 1186 { 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 1145 1202 bdbuf_buffer *bd_buf = arg; 1146 1203 bd_buf->status = status; … … 1149 1206 _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL, 1150 1207 CORE_MUTEX_STATUS_SUCCESSFUL); 1208 #endif 1151 1209 } 1152 1210 … … 1172 1230 * bufget_sema and transfer_sema semaphores obtained by this primitive. 1173 1231 */ 1232 #if !defined(READ_MULTIPLE) 1174 1233 rtems_status_code 1175 1234 rtems_bdbuf_read(dev_t device, … … 1245 1304 1246 1305 *bd = bd_buf; 1247 1306 1248 1307 return RTEMS_SUCCESSFUL; 1249 1308 } 1309 #else /* READ_MULTIPLE */ 1310 rtems_status_code 1311 rtems_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 */ 1250 1449 1251 1450 … … 1485 1684 rtems_status_code rc; 1486 1685 int result; 1686 int i; 1487 1687 ISR_Level level; 1488 1688 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; 1493 1704 while (1) 1494 1705 { 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 1525 1787 first time */ 1526 1788 result = dd->ioctl(dd->phys_dev->dev, BLKIO_REQUEST, &req); 1527 1789 1528 1790 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 } 1563 1829 } 1564 1830 }
Note: See TracChangeset
for help on using the changeset viewer.