regression2.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /*
  2. * Regression2
  3. * Description:
  4. * Toshiyuki Okajima describes the following radix-tree bug:
  5. *
  6. * In the following case, we can get a hangup on
  7. * radix_radix_tree_gang_lookup_tag_slot.
  8. *
  9. * 0. The radix tree contains RADIX_TREE_MAP_SIZE items. And the tag of
  10. * a certain item has PAGECACHE_TAG_DIRTY.
  11. * 1. radix_tree_range_tag_if_tagged(, start, end, , PAGECACHE_TAG_DIRTY,
  12. * PAGECACHE_TAG_TOWRITE) is called to add PAGECACHE_TAG_TOWRITE tag
  13. * for the tag which has PAGECACHE_TAG_DIRTY. However, there is no tag with
  14. * PAGECACHE_TAG_DIRTY within the range from start to end. As the result,
  15. * There is no tag with PAGECACHE_TAG_TOWRITE but the root tag has
  16. * PAGECACHE_TAG_TOWRITE.
  17. * 2. An item is added into the radix tree and then the level of it is
  18. * extended into 2 from 1. At that time, the new radix tree node succeeds
  19. * the tag status of the root tag. Therefore the tag of the new radix tree
  20. * node has PAGECACHE_TAG_TOWRITE but there is not slot with
  21. * PAGECACHE_TAG_TOWRITE tag in the child node of the new radix tree node.
  22. * 3. The tag of a certain item is cleared with PAGECACHE_TAG_DIRTY.
  23. * 4. All items within the index range from 0 to RADIX_TREE_MAP_SIZE - 1 are
  24. * released. (Only the item which index is RADIX_TREE_MAP_SIZE exist in the
  25. * radix tree.) As the result, the slot of the radix tree node is NULL but
  26. * the tag which corresponds to the slot has PAGECACHE_TAG_TOWRITE.
  27. * 5. radix_tree_gang_lookup_tag_slot(PAGECACHE_TAG_TOWRITE) calls
  28. * __lookup_tag. __lookup_tag returns with 0. And __lookup_tag doesn't
  29. * change the index that is the input and output parameter. Because the 1st
  30. * slot of the radix tree node is NULL, but the tag which corresponds to
  31. * the slot has PAGECACHE_TAG_TOWRITE.
  32. * Therefore radix_tree_gang_lookup_tag_slot tries to get some items by
  33. * calling __lookup_tag, but it cannot get any items forever.
  34. *
  35. * The fix is to change that radix_tree_tag_if_tagged doesn't tag the root tag
  36. * if it doesn't set any tags within the specified range.
  37. *
  38. * Running:
  39. * This test should run to completion immediately. The above bug would cause it
  40. * to hang indefinitely.
  41. *
  42. * Upstream commit:
  43. * Not yet
  44. */
  45. #include <linux/kernel.h>
  46. #include <linux/gfp.h>
  47. #include <linux/slab.h>
  48. #include <linux/radix-tree.h>
  49. #include <stdlib.h>
  50. #include <stdio.h>
  51. #include "regression.h"
  52. #include "test.h"
  53. #define PAGECACHE_TAG_DIRTY 0
  54. #define PAGECACHE_TAG_WRITEBACK 1
  55. #define PAGECACHE_TAG_TOWRITE 2
  56. static RADIX_TREE(mt_tree, GFP_KERNEL);
  57. unsigned long page_count = 0;
  58. struct page {
  59. unsigned long index;
  60. };
  61. static struct page *page_alloc(void)
  62. {
  63. struct page *p;
  64. p = malloc(sizeof(struct page));
  65. p->index = page_count++;
  66. return p;
  67. }
  68. void regression2_test(void)
  69. {
  70. int i;
  71. struct page *p;
  72. int max_slots = RADIX_TREE_MAP_SIZE;
  73. unsigned long int start, end;
  74. struct page *pages[1];
  75. printf("running regression test 2 (should take milliseconds)\n");
  76. /* 0. */
  77. for (i = 0; i <= max_slots - 1; i++) {
  78. p = page_alloc();
  79. radix_tree_insert(&mt_tree, i, p);
  80. }
  81. radix_tree_tag_set(&mt_tree, max_slots - 1, PAGECACHE_TAG_DIRTY);
  82. /* 1. */
  83. start = 0;
  84. end = max_slots - 2;
  85. tag_tagged_items(&mt_tree, NULL, start, end, 1,
  86. PAGECACHE_TAG_DIRTY, PAGECACHE_TAG_TOWRITE);
  87. /* 2. */
  88. p = page_alloc();
  89. radix_tree_insert(&mt_tree, max_slots, p);
  90. /* 3. */
  91. radix_tree_tag_clear(&mt_tree, max_slots - 1, PAGECACHE_TAG_DIRTY);
  92. /* 4. */
  93. for (i = max_slots - 1; i >= 0; i--)
  94. radix_tree_delete(&mt_tree, i);
  95. /* 5. */
  96. // NOTE: start should not be 0 because radix_tree_gang_lookup_tag_slot
  97. // can return.
  98. start = 1;
  99. end = max_slots - 2;
  100. radix_tree_gang_lookup_tag_slot(&mt_tree, (void ***)pages, start, end,
  101. PAGECACHE_TAG_TOWRITE);
  102. /* We remove all the remained nodes */
  103. radix_tree_delete(&mt_tree, max_slots);
  104. printf("regression test 2, done\n");
  105. }