Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
bitmap.c
Go to the documentation of this file.
1 /*
2  * bitmap.c - NTFS kernel bitmap handling. Part of the Linux-NTFS project.
3  *
4  * Copyright (c) 2004-2005 Anton Altaparmakov
5  *
6  * This program/include file is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as published
8  * by the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program/include file is distributed in the hope that it will be
12  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program (in the main directory of the Linux-NTFS
18  * distribution in the file COPYING); if not, write to the Free Software
19  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21 
22 #ifdef NTFS_RW
23 
24 #include <linux/pagemap.h>
25 
26 #include "bitmap.h"
27 #include "debug.h"
28 #include "aops.h"
29 #include "ntfs.h"
30 
47 int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit,
48  const s64 count, const u8 value, const bool is_rollback)
49 {
50  s64 cnt = count;
51  pgoff_t index, end_index;
52  struct address_space *mapping;
53  struct page *page;
54  u8 *kaddr;
55  int pos, len;
56  u8 bit;
57 
58  BUG_ON(!vi);
59  ntfs_debug("Entering for i_ino 0x%lx, start_bit 0x%llx, count 0x%llx, "
60  "value %u.%s", vi->i_ino, (unsigned long long)start_bit,
61  (unsigned long long)cnt, (unsigned int)value,
62  is_rollback ? " (rollback)" : "");
63  BUG_ON(start_bit < 0);
64  BUG_ON(cnt < 0);
65  BUG_ON(value > 1);
66  /*
67  * Calculate the indices for the pages containing the first and last
68  * bits, i.e. @start_bit and @start_bit + @cnt - 1, respectively.
69  */
70  index = start_bit >> (3 + PAGE_CACHE_SHIFT);
71  end_index = (start_bit + cnt - 1) >> (3 + PAGE_CACHE_SHIFT);
72 
73  /* Get the page containing the first bit (@start_bit). */
74  mapping = vi->i_mapping;
75  page = ntfs_map_page(mapping, index);
76  if (IS_ERR(page)) {
77  if (!is_rollback)
78  ntfs_error(vi->i_sb, "Failed to map first page (error "
79  "%li), aborting.", PTR_ERR(page));
80  return PTR_ERR(page);
81  }
82  kaddr = page_address(page);
83 
84  /* Set @pos to the position of the byte containing @start_bit. */
85  pos = (start_bit >> 3) & ~PAGE_CACHE_MASK;
86 
87  /* Calculate the position of @start_bit in the first byte. */
88  bit = start_bit & 7;
89 
90  /* If the first byte is partial, modify the appropriate bits in it. */
91  if (bit) {
92  u8 *byte = kaddr + pos;
93  while ((bit & 7) && cnt) {
94  cnt--;
95  if (value)
96  *byte |= 1 << bit++;
97  else
98  *byte &= ~(1 << bit++);
99  }
100  /* If we are done, unmap the page and return success. */
101  if (!cnt)
102  goto done;
103 
104  /* Update @pos to the new position. */
105  pos++;
106  }
107  /*
108  * Depending on @value, modify all remaining whole bytes in the page up
109  * to @cnt.
110  */
111  len = min_t(s64, cnt >> 3, PAGE_CACHE_SIZE - pos);
112  memset(kaddr + pos, value ? 0xff : 0, len);
113  cnt -= len << 3;
114 
115  /* Update @len to point to the first not-done byte in the page. */
116  if (cnt < 8)
117  len += pos;
118 
119  /* If we are not in the last page, deal with all subsequent pages. */
120  while (index < end_index) {
121  BUG_ON(cnt <= 0);
122 
123  /* Update @index and get the next page. */
124  flush_dcache_page(page);
125  set_page_dirty(page);
126  ntfs_unmap_page(page);
127  page = ntfs_map_page(mapping, ++index);
128  if (IS_ERR(page))
129  goto rollback;
130  kaddr = page_address(page);
131  /*
132  * Depending on @value, modify all remaining whole bytes in the
133  * page up to @cnt.
134  */
135  len = min_t(s64, cnt >> 3, PAGE_CACHE_SIZE);
136  memset(kaddr, value ? 0xff : 0, len);
137  cnt -= len << 3;
138  }
139  /*
140  * The currently mapped page is the last one. If the last byte is
141  * partial, modify the appropriate bits in it. Note, @len is the
142  * position of the last byte inside the page.
143  */
144  if (cnt) {
145  u8 *byte;
146 
147  BUG_ON(cnt > 7);
148 
149  bit = cnt;
150  byte = kaddr + len;
151  while (bit--) {
152  if (value)
153  *byte |= 1 << bit;
154  else
155  *byte &= ~(1 << bit);
156  }
157  }
158 done:
159  /* We are done. Unmap the page and return success. */
160  flush_dcache_page(page);
161  set_page_dirty(page);
162  ntfs_unmap_page(page);
163  ntfs_debug("Done.");
164  return 0;
165 rollback:
166  /*
167  * Current state:
168  * - no pages are mapped
169  * - @count - @cnt is the number of bits that have been modified
170  */
171  if (is_rollback)
172  return PTR_ERR(page);
173  if (count != cnt)
174  pos = __ntfs_bitmap_set_bits_in_run(vi, start_bit, count - cnt,
175  value ? 0 : 1, true);
176  else
177  pos = 0;
178  if (!pos) {
179  /* Rollback was successful. */
180  ntfs_error(vi->i_sb, "Failed to map subsequent page (error "
181  "%li), aborting.", PTR_ERR(page));
182  } else {
183  /* Rollback failed. */
184  ntfs_error(vi->i_sb, "Failed to map subsequent page (error "
185  "%li) and rollback failed (error %i). "
186  "Aborting and leaving inconsistent metadata. "
187  "Unmount and run chkdsk.", PTR_ERR(page), pos);
188  NVolSetErrors(NTFS_SB(vi->i_sb));
189  }
190  return PTR_ERR(page);
191 }
192 
193 #endif /* NTFS_RW */