bitmap.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * bitmap.c - NTFS kernel bitmap handling. Part of the Linux-NTFS project.
  4. *
  5. * Copyright (c) 2004-2005 Anton Altaparmakov
  6. */
  7. #ifdef NTFS_RW
  8. #include <linux/pagemap.h>
  9. #include "bitmap.h"
  10. #include "debug.h"
  11. #include "aops.h"
  12. #include "ntfs.h"
  13. /**
  14. * __ntfs_bitmap_set_bits_in_run - set a run of bits in a bitmap to a value
  15. * @vi: vfs inode describing the bitmap
  16. * @start_bit: first bit to set
  17. * @count: number of bits to set
  18. * @value: value to set the bits to (i.e. 0 or 1)
  19. * @is_rollback: if 'true' this is a rollback operation
  20. *
  21. * Set @count bits starting at bit @start_bit in the bitmap described by the
  22. * vfs inode @vi to @value, where @value is either 0 or 1.
  23. *
  24. * @is_rollback should always be 'false', it is for internal use to rollback
  25. * errors. You probably want to use ntfs_bitmap_set_bits_in_run() instead.
  26. *
  27. * Return 0 on success and -errno on error.
  28. */
  29. int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit,
  30. const s64 count, const u8 value, const bool is_rollback)
  31. {
  32. s64 cnt = count;
  33. pgoff_t index, end_index;
  34. struct address_space *mapping;
  35. struct page *page;
  36. u8 *kaddr;
  37. int pos, len;
  38. u8 bit;
  39. BUG_ON(!vi);
  40. ntfs_debug("Entering for i_ino 0x%lx, start_bit 0x%llx, count 0x%llx, "
  41. "value %u.%s", vi->i_ino, (unsigned long long)start_bit,
  42. (unsigned long long)cnt, (unsigned int)value,
  43. is_rollback ? " (rollback)" : "");
  44. BUG_ON(start_bit < 0);
  45. BUG_ON(cnt < 0);
  46. BUG_ON(value > 1);
  47. /*
  48. * Calculate the indices for the pages containing the first and last
  49. * bits, i.e. @start_bit and @start_bit + @cnt - 1, respectively.
  50. */
  51. index = start_bit >> (3 + PAGE_SHIFT);
  52. end_index = (start_bit + cnt - 1) >> (3 + PAGE_SHIFT);
  53. /* Get the page containing the first bit (@start_bit). */
  54. mapping = vi->i_mapping;
  55. page = ntfs_map_page(mapping, index);
  56. if (IS_ERR(page)) {
  57. if (!is_rollback)
  58. ntfs_error(vi->i_sb, "Failed to map first page (error "
  59. "%li), aborting.", PTR_ERR(page));
  60. return PTR_ERR(page);
  61. }
  62. kaddr = page_address(page);
  63. /* Set @pos to the position of the byte containing @start_bit. */
  64. pos = (start_bit >> 3) & ~PAGE_MASK;
  65. /* Calculate the position of @start_bit in the first byte. */
  66. bit = start_bit & 7;
  67. /* If the first byte is partial, modify the appropriate bits in it. */
  68. if (bit) {
  69. u8 *byte = kaddr + pos;
  70. while ((bit & 7) && cnt) {
  71. cnt--;
  72. if (value)
  73. *byte |= 1 << bit++;
  74. else
  75. *byte &= ~(1 << bit++);
  76. }
  77. /* If we are done, unmap the page and return success. */
  78. if (!cnt)
  79. goto done;
  80. /* Update @pos to the new position. */
  81. pos++;
  82. }
  83. /*
  84. * Depending on @value, modify all remaining whole bytes in the page up
  85. * to @cnt.
  86. */
  87. len = min_t(s64, cnt >> 3, PAGE_SIZE - pos);
  88. memset(kaddr + pos, value ? 0xff : 0, len);
  89. cnt -= len << 3;
  90. /* Update @len to point to the first not-done byte in the page. */
  91. if (cnt < 8)
  92. len += pos;
  93. /* If we are not in the last page, deal with all subsequent pages. */
  94. while (index < end_index) {
  95. BUG_ON(cnt <= 0);
  96. /* Update @index and get the next page. */
  97. flush_dcache_page(page);
  98. set_page_dirty(page);
  99. ntfs_unmap_page(page);
  100. page = ntfs_map_page(mapping, ++index);
  101. if (IS_ERR(page))
  102. goto rollback;
  103. kaddr = page_address(page);
  104. /*
  105. * Depending on @value, modify all remaining whole bytes in the
  106. * page up to @cnt.
  107. */
  108. len = min_t(s64, cnt >> 3, PAGE_SIZE);
  109. memset(kaddr, value ? 0xff : 0, len);
  110. cnt -= len << 3;
  111. }
  112. /*
  113. * The currently mapped page is the last one. If the last byte is
  114. * partial, modify the appropriate bits in it. Note, @len is the
  115. * position of the last byte inside the page.
  116. */
  117. if (cnt) {
  118. u8 *byte;
  119. BUG_ON(cnt > 7);
  120. bit = cnt;
  121. byte = kaddr + len;
  122. while (bit--) {
  123. if (value)
  124. *byte |= 1 << bit;
  125. else
  126. *byte &= ~(1 << bit);
  127. }
  128. }
  129. done:
  130. /* We are done. Unmap the page and return success. */
  131. flush_dcache_page(page);
  132. set_page_dirty(page);
  133. ntfs_unmap_page(page);
  134. ntfs_debug("Done.");
  135. return 0;
  136. rollback:
  137. /*
  138. * Current state:
  139. * - no pages are mapped
  140. * - @count - @cnt is the number of bits that have been modified
  141. */
  142. if (is_rollback)
  143. return PTR_ERR(page);
  144. if (count != cnt)
  145. pos = __ntfs_bitmap_set_bits_in_run(vi, start_bit, count - cnt,
  146. value ? 0 : 1, true);
  147. else
  148. pos = 0;
  149. if (!pos) {
  150. /* Rollback was successful. */
  151. ntfs_error(vi->i_sb, "Failed to map subsequent page (error "
  152. "%li), aborting.", PTR_ERR(page));
  153. } else {
  154. /* Rollback failed. */
  155. ntfs_error(vi->i_sb, "Failed to map subsequent page (error "
  156. "%li) and rollback failed (error %i). "
  157. "Aborting and leaving inconsistent metadata. "
  158. "Unmount and run chkdsk.", PTR_ERR(page), pos);
  159. NVolSetErrors(NTFS_SB(vi->i_sb));
  160. }
  161. return PTR_ERR(page);
  162. }
  163. #endif /* NTFS_RW */