diff options
-rw-r--r-- | fs/xfs/xfs_log_recover.c | 205 | ||||
-rw-r--r-- | fs/xfs/xfs_log_recover.h | 23 |
2 files changed, 81 insertions, 147 deletions
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 48a7ab1e6311..65f1f137d789 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c | |||
@@ -50,8 +50,6 @@ | |||
50 | 50 | ||
51 | STATIC int xlog_find_zeroed(xlog_t *, xfs_daddr_t *); | 51 | STATIC int xlog_find_zeroed(xlog_t *, xfs_daddr_t *); |
52 | STATIC int xlog_clear_stale_blocks(xlog_t *, xfs_lsn_t); | 52 | STATIC int xlog_clear_stale_blocks(xlog_t *, xfs_lsn_t); |
53 | STATIC void xlog_recover_insert_item_backq(xlog_recover_item_t **q, | ||
54 | xlog_recover_item_t *item); | ||
55 | #if defined(DEBUG) | 53 | #if defined(DEBUG) |
56 | STATIC void xlog_recover_check_summary(xlog_t *); | 54 | STATIC void xlog_recover_check_summary(xlog_t *); |
57 | #else | 55 | #else |
@@ -1367,36 +1365,45 @@ xlog_clear_stale_blocks( | |||
1367 | 1365 | ||
1368 | STATIC xlog_recover_t * | 1366 | STATIC xlog_recover_t * |
1369 | xlog_recover_find_tid( | 1367 | xlog_recover_find_tid( |
1370 | xlog_recover_t *q, | 1368 | struct hlist_head *head, |
1371 | xlog_tid_t tid) | 1369 | xlog_tid_t tid) |
1372 | { | 1370 | { |
1373 | xlog_recover_t *p = q; | 1371 | xlog_recover_t *trans; |
1372 | struct hlist_node *n; | ||
1374 | 1373 | ||
1375 | while (p != NULL) { | 1374 | hlist_for_each_entry(trans, n, head, r_list) { |
1376 | if (p->r_log_tid == tid) | 1375 | if (trans->r_log_tid == tid) |
1377 | break; | 1376 | return trans; |
1378 | p = p->r_next; | ||
1379 | } | 1377 | } |
1380 | return p; | 1378 | return NULL; |
1381 | } | 1379 | } |
1382 | 1380 | ||
1383 | STATIC void | 1381 | STATIC void |
1384 | xlog_recover_put_hashq( | 1382 | xlog_recover_new_tid( |
1385 | xlog_recover_t **q, | 1383 | struct hlist_head *head, |
1386 | xlog_recover_t *trans) | 1384 | xlog_tid_t tid, |
1385 | xfs_lsn_t lsn) | ||
1387 | { | 1386 | { |
1388 | trans->r_next = *q; | 1387 | xlog_recover_t *trans; |
1389 | *q = trans; | 1388 | |
1389 | trans = kmem_zalloc(sizeof(xlog_recover_t), KM_SLEEP); | ||
1390 | trans->r_log_tid = tid; | ||
1391 | trans->r_lsn = lsn; | ||
1392 | INIT_LIST_HEAD(&trans->r_itemq); | ||
1393 | |||
1394 | INIT_HLIST_NODE(&trans->r_list); | ||
1395 | hlist_add_head(&trans->r_list, head); | ||
1390 | } | 1396 | } |
1391 | 1397 | ||
1392 | STATIC void | 1398 | STATIC void |
1393 | xlog_recover_add_item( | 1399 | xlog_recover_add_item( |
1394 | xlog_recover_item_t **itemq) | 1400 | struct list_head *head) |
1395 | { | 1401 | { |
1396 | xlog_recover_item_t *item; | 1402 | xlog_recover_item_t *item; |
1397 | 1403 | ||
1398 | item = kmem_zalloc(sizeof(xlog_recover_item_t), KM_SLEEP); | 1404 | item = kmem_zalloc(sizeof(xlog_recover_item_t), KM_SLEEP); |
1399 | xlog_recover_insert_item_backq(itemq, item); | 1405 | INIT_LIST_HEAD(&item->ri_list); |
1406 | list_add_tail(&item->ri_list, head); | ||
1400 | } | 1407 | } |
1401 | 1408 | ||
1402 | STATIC int | 1409 | STATIC int |
@@ -1409,8 +1416,7 @@ xlog_recover_add_to_cont_trans( | |||
1409 | xfs_caddr_t ptr, old_ptr; | 1416 | xfs_caddr_t ptr, old_ptr; |
1410 | int old_len; | 1417 | int old_len; |
1411 | 1418 | ||
1412 | item = trans->r_itemq; | 1419 | if (list_empty(&trans->r_itemq)) { |
1413 | if (item == NULL) { | ||
1414 | /* finish copying rest of trans header */ | 1420 | /* finish copying rest of trans header */ |
1415 | xlog_recover_add_item(&trans->r_itemq); | 1421 | xlog_recover_add_item(&trans->r_itemq); |
1416 | ptr = (xfs_caddr_t) &trans->r_theader + | 1422 | ptr = (xfs_caddr_t) &trans->r_theader + |
@@ -1418,7 +1424,8 @@ xlog_recover_add_to_cont_trans( | |||
1418 | memcpy(ptr, dp, len); /* d, s, l */ | 1424 | memcpy(ptr, dp, len); /* d, s, l */ |
1419 | return 0; | 1425 | return 0; |
1420 | } | 1426 | } |
1421 | item = item->ri_prev; | 1427 | /* take the tail entry */ |
1428 | item = list_entry(trans->r_itemq.prev, xlog_recover_item_t, ri_list); | ||
1422 | 1429 | ||
1423 | old_ptr = item->ri_buf[item->ri_cnt-1].i_addr; | 1430 | old_ptr = item->ri_buf[item->ri_cnt-1].i_addr; |
1424 | old_len = item->ri_buf[item->ri_cnt-1].i_len; | 1431 | old_len = item->ri_buf[item->ri_cnt-1].i_len; |
@@ -1455,8 +1462,7 @@ xlog_recover_add_to_trans( | |||
1455 | 1462 | ||
1456 | if (!len) | 1463 | if (!len) |
1457 | return 0; | 1464 | return 0; |
1458 | item = trans->r_itemq; | 1465 | if (list_empty(&trans->r_itemq)) { |
1459 | if (item == NULL) { | ||
1460 | /* we need to catch log corruptions here */ | 1466 | /* we need to catch log corruptions here */ |
1461 | if (*(uint *)dp != XFS_TRANS_HEADER_MAGIC) { | 1467 | if (*(uint *)dp != XFS_TRANS_HEADER_MAGIC) { |
1462 | xlog_warn("XFS: xlog_recover_add_to_trans: " | 1468 | xlog_warn("XFS: xlog_recover_add_to_trans: " |
@@ -1474,12 +1480,15 @@ xlog_recover_add_to_trans( | |||
1474 | memcpy(ptr, dp, len); | 1480 | memcpy(ptr, dp, len); |
1475 | in_f = (xfs_inode_log_format_t *)ptr; | 1481 | in_f = (xfs_inode_log_format_t *)ptr; |
1476 | 1482 | ||
1477 | if (item->ri_prev->ri_total != 0 && | 1483 | /* take the tail entry */ |
1478 | item->ri_prev->ri_total == item->ri_prev->ri_cnt) { | 1484 | item = list_entry(trans->r_itemq.prev, xlog_recover_item_t, ri_list); |
1485 | if (item->ri_total != 0 && | ||
1486 | item->ri_total == item->ri_cnt) { | ||
1487 | /* tail item is in use, get a new one */ | ||
1479 | xlog_recover_add_item(&trans->r_itemq); | 1488 | xlog_recover_add_item(&trans->r_itemq); |
1489 | item = list_entry(trans->r_itemq.prev, | ||
1490 | xlog_recover_item_t, ri_list); | ||
1480 | } | 1491 | } |
1481 | item = trans->r_itemq; | ||
1482 | item = item->ri_prev; | ||
1483 | 1492 | ||
1484 | if (item->ri_total == 0) { /* first region to be added */ | 1493 | if (item->ri_total == 0) { /* first region to be added */ |
1485 | if (in_f->ilf_size == 0 || | 1494 | if (in_f->ilf_size == 0 || |
@@ -1504,96 +1513,29 @@ xlog_recover_add_to_trans( | |||
1504 | return 0; | 1513 | return 0; |
1505 | } | 1514 | } |
1506 | 1515 | ||
1507 | STATIC void | 1516 | /* |
1508 | xlog_recover_new_tid( | 1517 | * Sort the log items in the transaction. Cancelled buffers need |
1509 | xlog_recover_t **q, | 1518 | * to be put first so they are processed before any items that might |
1510 | xlog_tid_t tid, | 1519 | * modify the buffers. If they are cancelled, then the modifications |
1511 | xfs_lsn_t lsn) | 1520 | * don't need to be replayed. |
1512 | { | 1521 | */ |
1513 | xlog_recover_t *trans; | ||
1514 | |||
1515 | trans = kmem_zalloc(sizeof(xlog_recover_t), KM_SLEEP); | ||
1516 | trans->r_log_tid = tid; | ||
1517 | trans->r_lsn = lsn; | ||
1518 | xlog_recover_put_hashq(q, trans); | ||
1519 | } | ||
1520 | |||
1521 | STATIC int | ||
1522 | xlog_recover_unlink_tid( | ||
1523 | xlog_recover_t **q, | ||
1524 | xlog_recover_t *trans) | ||
1525 | { | ||
1526 | xlog_recover_t *tp; | ||
1527 | int found = 0; | ||
1528 | |||
1529 | ASSERT(trans != NULL); | ||
1530 | if (trans == *q) { | ||
1531 | *q = (*q)->r_next; | ||
1532 | } else { | ||
1533 | tp = *q; | ||
1534 | while (tp) { | ||
1535 | if (tp->r_next == trans) { | ||
1536 | found = 1; | ||
1537 | break; | ||
1538 | } | ||
1539 | tp = tp->r_next; | ||
1540 | } | ||
1541 | if (!found) { | ||
1542 | xlog_warn( | ||
1543 | "XFS: xlog_recover_unlink_tid: trans not found"); | ||
1544 | ASSERT(0); | ||
1545 | return XFS_ERROR(EIO); | ||
1546 | } | ||
1547 | tp->r_next = tp->r_next->r_next; | ||
1548 | } | ||
1549 | return 0; | ||
1550 | } | ||
1551 | |||
1552 | STATIC void | ||
1553 | xlog_recover_insert_item_backq( | ||
1554 | xlog_recover_item_t **q, | ||
1555 | xlog_recover_item_t *item) | ||
1556 | { | ||
1557 | if (*q == NULL) { | ||
1558 | item->ri_prev = item->ri_next = item; | ||
1559 | *q = item; | ||
1560 | } else { | ||
1561 | item->ri_next = *q; | ||
1562 | item->ri_prev = (*q)->ri_prev; | ||
1563 | (*q)->ri_prev = item; | ||
1564 | item->ri_prev->ri_next = item; | ||
1565 | } | ||
1566 | } | ||
1567 | |||
1568 | STATIC void | ||
1569 | xlog_recover_insert_item_frontq( | ||
1570 | xlog_recover_item_t **q, | ||
1571 | xlog_recover_item_t *item) | ||
1572 | { | ||
1573 | xlog_recover_insert_item_backq(q, item); | ||
1574 | *q = item; | ||
1575 | } | ||
1576 | |||
1577 | STATIC int | 1522 | STATIC int |
1578 | xlog_recover_reorder_trans( | 1523 | xlog_recover_reorder_trans( |
1579 | xlog_recover_t *trans) | 1524 | xlog_recover_t *trans) |
1580 | { | 1525 | { |
1581 | xlog_recover_item_t *first_item, *itemq, *itemq_next; | 1526 | xlog_recover_item_t *item, *n; |
1582 | xfs_buf_log_format_t *buf_f; | 1527 | LIST_HEAD(sort_list); |
1583 | ushort flags = 0; | 1528 | |
1529 | list_splice_init(&trans->r_itemq, &sort_list); | ||
1530 | list_for_each_entry_safe(item, n, &sort_list, ri_list) { | ||
1531 | xfs_buf_log_format_t *buf_f; | ||
1584 | 1532 | ||
1585 | first_item = itemq = trans->r_itemq; | 1533 | buf_f = (xfs_buf_log_format_t *)item->ri_buf[0].i_addr; |
1586 | trans->r_itemq = NULL; | ||
1587 | do { | ||
1588 | itemq_next = itemq->ri_next; | ||
1589 | buf_f = (xfs_buf_log_format_t *)itemq->ri_buf[0].i_addr; | ||
1590 | 1534 | ||
1591 | switch (ITEM_TYPE(itemq)) { | 1535 | switch (ITEM_TYPE(item)) { |
1592 | case XFS_LI_BUF: | 1536 | case XFS_LI_BUF: |
1593 | flags = buf_f->blf_flags; | 1537 | if (!(buf_f->blf_flags & XFS_BLI_CANCEL)) { |
1594 | if (!(flags & XFS_BLI_CANCEL)) { | 1538 | list_move(&item->ri_list, &trans->r_itemq); |
1595 | xlog_recover_insert_item_frontq(&trans->r_itemq, | ||
1596 | itemq); | ||
1597 | break; | 1539 | break; |
1598 | } | 1540 | } |
1599 | case XFS_LI_INODE: | 1541 | case XFS_LI_INODE: |
@@ -1601,7 +1543,7 @@ xlog_recover_reorder_trans( | |||
1601 | case XFS_LI_QUOTAOFF: | 1543 | case XFS_LI_QUOTAOFF: |
1602 | case XFS_LI_EFD: | 1544 | case XFS_LI_EFD: |
1603 | case XFS_LI_EFI: | 1545 | case XFS_LI_EFI: |
1604 | xlog_recover_insert_item_backq(&trans->r_itemq, itemq); | 1546 | list_move_tail(&item->ri_list, &trans->r_itemq); |
1605 | break; | 1547 | break; |
1606 | default: | 1548 | default: |
1607 | xlog_warn( | 1549 | xlog_warn( |
@@ -1609,8 +1551,8 @@ xlog_recover_reorder_trans( | |||
1609 | ASSERT(0); | 1551 | ASSERT(0); |
1610 | return XFS_ERROR(EIO); | 1552 | return XFS_ERROR(EIO); |
1611 | } | 1553 | } |
1612 | itemq = itemq_next; | 1554 | } |
1613 | } while (first_item != itemq); | 1555 | ASSERT(list_empty(&sort_list)); |
1614 | return 0; | 1556 | return 0; |
1615 | } | 1557 | } |
1616 | 1558 | ||
@@ -2814,14 +2756,13 @@ xlog_recover_do_trans( | |||
2814 | int pass) | 2756 | int pass) |
2815 | { | 2757 | { |
2816 | int error = 0; | 2758 | int error = 0; |
2817 | xlog_recover_item_t *item, *first_item; | 2759 | xlog_recover_item_t *item; |
2818 | 2760 | ||
2819 | error = xlog_recover_reorder_trans(trans); | 2761 | error = xlog_recover_reorder_trans(trans); |
2820 | if (error) | 2762 | if (error) |
2821 | return error; | 2763 | return error; |
2822 | 2764 | ||
2823 | first_item = item = trans->r_itemq; | 2765 | list_for_each_entry(item, &trans->r_itemq, ri_list) { |
2824 | do { | ||
2825 | switch (ITEM_TYPE(item)) { | 2766 | switch (ITEM_TYPE(item)) { |
2826 | case XFS_LI_BUF: | 2767 | case XFS_LI_BUF: |
2827 | error = xlog_recover_do_buffer_trans(log, item, pass); | 2768 | error = xlog_recover_do_buffer_trans(log, item, pass); |
@@ -2854,8 +2795,7 @@ xlog_recover_do_trans( | |||
2854 | 2795 | ||
2855 | if (error) | 2796 | if (error) |
2856 | return error; | 2797 | return error; |
2857 | item = item->ri_next; | 2798 | } |
2858 | } while (first_item != item); | ||
2859 | 2799 | ||
2860 | return 0; | 2800 | return 0; |
2861 | } | 2801 | } |
@@ -2869,21 +2809,18 @@ STATIC void | |||
2869 | xlog_recover_free_trans( | 2809 | xlog_recover_free_trans( |
2870 | xlog_recover_t *trans) | 2810 | xlog_recover_t *trans) |
2871 | { | 2811 | { |
2872 | xlog_recover_item_t *first_item, *item, *free_item; | 2812 | xlog_recover_item_t *item, *n; |
2873 | int i; | 2813 | int i; |
2874 | 2814 | ||
2875 | item = first_item = trans->r_itemq; | 2815 | list_for_each_entry_safe(item, n, &trans->r_itemq, ri_list) { |
2876 | do { | 2816 | /* Free the regions in the item. */ |
2877 | free_item = item; | 2817 | list_del(&item->ri_list); |
2878 | item = item->ri_next; | 2818 | for (i = 0; i < item->ri_cnt; i++) |
2879 | /* Free the regions in the item. */ | 2819 | kmem_free(item->ri_buf[i].i_addr); |
2880 | for (i = 0; i < free_item->ri_cnt; i++) { | ||
2881 | kmem_free(free_item->ri_buf[i].i_addr); | ||
2882 | } | ||
2883 | /* Free the item itself */ | 2820 | /* Free the item itself */ |
2884 | kmem_free(free_item->ri_buf); | 2821 | kmem_free(item->ri_buf); |
2885 | kmem_free(free_item); | 2822 | kmem_free(item); |
2886 | } while (first_item != item); | 2823 | } |
2887 | /* Free the transaction recover structure */ | 2824 | /* Free the transaction recover structure */ |
2888 | kmem_free(trans); | 2825 | kmem_free(trans); |
2889 | } | 2826 | } |
@@ -2891,14 +2828,12 @@ xlog_recover_free_trans( | |||
2891 | STATIC int | 2828 | STATIC int |
2892 | xlog_recover_commit_trans( | 2829 | xlog_recover_commit_trans( |
2893 | xlog_t *log, | 2830 | xlog_t *log, |
2894 | xlog_recover_t **q, | ||
2895 | xlog_recover_t *trans, | 2831 | xlog_recover_t *trans, |
2896 | int pass) | 2832 | int pass) |
2897 | { | 2833 | { |
2898 | int error; | 2834 | int error; |
2899 | 2835 | ||
2900 | if ((error = xlog_recover_unlink_tid(q, trans))) | 2836 | hlist_del(&trans->r_list); |
2901 | return error; | ||
2902 | if ((error = xlog_recover_do_trans(log, trans, pass))) | 2837 | if ((error = xlog_recover_do_trans(log, trans, pass))) |
2903 | return error; | 2838 | return error; |
2904 | xlog_recover_free_trans(trans); /* no error */ | 2839 | xlog_recover_free_trans(trans); /* no error */ |
@@ -2926,7 +2861,7 @@ xlog_recover_unmount_trans( | |||
2926 | STATIC int | 2861 | STATIC int |
2927 | xlog_recover_process_data( | 2862 | xlog_recover_process_data( |
2928 | xlog_t *log, | 2863 | xlog_t *log, |
2929 | xlog_recover_t *rhash[], | 2864 | struct hlist_head rhash[], |
2930 | xlog_rec_header_t *rhead, | 2865 | xlog_rec_header_t *rhead, |
2931 | xfs_caddr_t dp, | 2866 | xfs_caddr_t dp, |
2932 | int pass) | 2867 | int pass) |
@@ -2960,7 +2895,7 @@ xlog_recover_process_data( | |||
2960 | } | 2895 | } |
2961 | tid = be32_to_cpu(ohead->oh_tid); | 2896 | tid = be32_to_cpu(ohead->oh_tid); |
2962 | hash = XLOG_RHASH(tid); | 2897 | hash = XLOG_RHASH(tid); |
2963 | trans = xlog_recover_find_tid(rhash[hash], tid); | 2898 | trans = xlog_recover_find_tid(&rhash[hash], tid); |
2964 | if (trans == NULL) { /* not found; add new tid */ | 2899 | if (trans == NULL) { /* not found; add new tid */ |
2965 | if (ohead->oh_flags & XLOG_START_TRANS) | 2900 | if (ohead->oh_flags & XLOG_START_TRANS) |
2966 | xlog_recover_new_tid(&rhash[hash], tid, | 2901 | xlog_recover_new_tid(&rhash[hash], tid, |
@@ -2978,7 +2913,7 @@ xlog_recover_process_data( | |||
2978 | switch (flags) { | 2913 | switch (flags) { |
2979 | case XLOG_COMMIT_TRANS: | 2914 | case XLOG_COMMIT_TRANS: |
2980 | error = xlog_recover_commit_trans(log, | 2915 | error = xlog_recover_commit_trans(log, |
2981 | &rhash[hash], trans, pass); | 2916 | trans, pass); |
2982 | break; | 2917 | break; |
2983 | case XLOG_UNMOUNT_TRANS: | 2918 | case XLOG_UNMOUNT_TRANS: |
2984 | error = xlog_recover_unmount_trans(trans); | 2919 | error = xlog_recover_unmount_trans(trans); |
@@ -3517,7 +3452,7 @@ xlog_do_recovery_pass( | |||
3517 | int error = 0, h_size; | 3452 | int error = 0, h_size; |
3518 | int bblks, split_bblks; | 3453 | int bblks, split_bblks; |
3519 | int hblks, split_hblks, wrapped_hblks; | 3454 | int hblks, split_hblks, wrapped_hblks; |
3520 | xlog_recover_t *rhash[XLOG_RHASH_SIZE]; | 3455 | struct hlist_head rhash[XLOG_RHASH_SIZE]; |
3521 | 3456 | ||
3522 | ASSERT(head_blk != tail_blk); | 3457 | ASSERT(head_blk != tail_blk); |
3523 | 3458 | ||
diff --git a/fs/xfs/xfs_log_recover.h b/fs/xfs/xfs_log_recover.h index b22545555301..75d749207258 100644 --- a/fs/xfs/xfs_log_recover.h +++ b/fs/xfs/xfs_log_recover.h | |||
@@ -35,22 +35,21 @@ | |||
35 | * item headers are in ri_buf[0]. Additional buffers follow. | 35 | * item headers are in ri_buf[0]. Additional buffers follow. |
36 | */ | 36 | */ |
37 | typedef struct xlog_recover_item { | 37 | typedef struct xlog_recover_item { |
38 | struct xlog_recover_item *ri_next; | 38 | struct list_head ri_list; |
39 | struct xlog_recover_item *ri_prev; | 39 | int ri_type; |
40 | int ri_type; | 40 | int ri_cnt; /* count of regions found */ |
41 | int ri_cnt; /* count of regions found */ | 41 | int ri_total; /* total regions */ |
42 | int ri_total; /* total regions */ | 42 | xfs_log_iovec_t *ri_buf; /* ptr to regions buffer */ |
43 | xfs_log_iovec_t *ri_buf; /* ptr to regions buffer */ | ||
44 | } xlog_recover_item_t; | 43 | } xlog_recover_item_t; |
45 | 44 | ||
46 | struct xlog_tid; | 45 | struct xlog_tid; |
47 | typedef struct xlog_recover { | 46 | typedef struct xlog_recover { |
48 | struct xlog_recover *r_next; | 47 | struct hlist_node r_list; |
49 | xlog_tid_t r_log_tid; /* log's transaction id */ | 48 | xlog_tid_t r_log_tid; /* log's transaction id */ |
50 | xfs_trans_header_t r_theader; /* trans header for partial */ | 49 | xfs_trans_header_t r_theader; /* trans header for partial */ |
51 | int r_state; /* not needed */ | 50 | int r_state; /* not needed */ |
52 | xfs_lsn_t r_lsn; /* xact lsn */ | 51 | xfs_lsn_t r_lsn; /* xact lsn */ |
53 | xlog_recover_item_t *r_itemq; /* q for items */ | 52 | struct list_head r_itemq; /* q for items */ |
54 | } xlog_recover_t; | 53 | } xlog_recover_t; |
55 | 54 | ||
56 | #define ITEM_TYPE(i) (*(ushort *)(i)->ri_buf[0].i_addr) | 55 | #define ITEM_TYPE(i) (*(ushort *)(i)->ri_buf[0].i_addr) |