diff options
Diffstat (limited to 'fs/ntfs')
-rw-r--r-- | fs/ntfs/ChangeLog | 70 | ||||
-rw-r--r-- | fs/ntfs/Makefile | 2 | ||||
-rw-r--r-- | fs/ntfs/aops.c | 293 | ||||
-rw-r--r-- | fs/ntfs/attrib.c | 125 | ||||
-rw-r--r-- | fs/ntfs/attrib.h | 2 | ||||
-rw-r--r-- | fs/ntfs/compress.c | 8 | ||||
-rw-r--r-- | fs/ntfs/dir.c | 3 | ||||
-rw-r--r-- | fs/ntfs/file.c | 9 | ||||
-rw-r--r-- | fs/ntfs/index.c | 1 | ||||
-rw-r--r-- | fs/ntfs/inode.c | 227 | ||||
-rw-r--r-- | fs/ntfs/lcnalloc.c | 39 | ||||
-rw-r--r-- | fs/ntfs/lcnalloc.h | 21 | ||||
-rw-r--r-- | fs/ntfs/logfile.c | 251 | ||||
-rw-r--r-- | fs/ntfs/logfile.h | 8 | ||||
-rw-r--r-- | fs/ntfs/malloc.h | 48 | ||||
-rw-r--r-- | fs/ntfs/mft.c | 4 | ||||
-rw-r--r-- | fs/ntfs/runlist.c | 374 | ||||
-rw-r--r-- | fs/ntfs/runlist.h | 3 | ||||
-rw-r--r-- | fs/ntfs/super.c | 16 | ||||
-rw-r--r-- | fs/ntfs/unistr.c | 3 |
20 files changed, 1062 insertions, 445 deletions
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 9eecc9939dfe..e4fd6134244d 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog | |||
@@ -22,6 +22,76 @@ ToDo/Notes: | |||
22 | - Enable the code for setting the NT4 compatibility flag when we start | 22 | - Enable the code for setting the NT4 compatibility flag when we start |
23 | making NTFS 1.2 specific modifications. | 23 | making NTFS 1.2 specific modifications. |
24 | 24 | ||
25 | 2.1.24 - Lots of bug fixes and support more clean journal states. | ||
26 | |||
27 | - Support journals ($LogFile) which have been modified by chkdsk. This | ||
28 | means users can boot into Windows after we marked the volume dirty. | ||
29 | The Windows boot will run chkdsk and then reboot. The user can then | ||
30 | immediately boot into Linux rather than having to do a full Windows | ||
31 | boot first before rebooting into Linux and we will recognize such a | ||
32 | journal and empty it as it is clean by definition. | ||
33 | - Support journals ($LogFile) with only one restart page as well as | ||
34 | journals with two different restart pages. We sanity check both and | ||
35 | either use the only sane one or the more recent one of the two in the | ||
36 | case that both are valid. | ||
37 | - Modify fs/ntfs/malloc.h::ntfs_malloc_nofs() to do the kmalloc() based | ||
38 | allocations with __GFP_HIGHMEM, analogous to how the vmalloc() based | ||
39 | allocations are done. | ||
40 | - Add fs/ntfs/malloc.h::ntfs_malloc_nofs_nofail() which is analogous to | ||
41 | ntfs_malloc_nofs() but it performs allocations with __GFP_NOFAIL and | ||
42 | hence cannot fail. | ||
43 | - Use ntfs_malloc_nofs_nofail() in the two critical regions in | ||
44 | fs/ntfs/runlist.c::ntfs_runlists_merge(). This means we no longer | ||
45 | need to panic() if the allocation fails as it now cannot fail. | ||
46 | - Fix two nasty runlist merging bugs that had gone unnoticed so far. | ||
47 | Thanks to Stefano Picerno for the bug report. | ||
48 | - Remove two bogus BUG_ON()s from fs/ntfs/mft.c. | ||
49 | - Fix handling of valid but empty mapping pairs array in | ||
50 | fs/ntfs/runlist.c::ntfs_mapping_pairs_decompress(). | ||
51 | - Report unrepresentable inodes during ntfs_readdir() as KERN_WARNING | ||
52 | messages and include the inode number. Thanks to Yura Pakhuchiy for | ||
53 | pointing this out. | ||
54 | - Change ntfs_rl_truncate_nolock() to throw away the runlist if the new | ||
55 | length is zero. | ||
56 | - Add runlist.[hc]::ntfs_rl_punch_nolock() which punches a caller | ||
57 | specified hole into a runlist. | ||
58 | - Fix a bug in fs/ntfs/index.c::ntfs_index_lookup(). When the returned | ||
59 | index entry is in the index root, we forgot to set the @ir pointer in | ||
60 | the index context. Thanks to Yura Pakhuchiy for finding this bug. | ||
61 | - Remove bogus setting of PageError in ntfs_read_compressed_block(). | ||
62 | - Add fs/ntfs/attrib.[hc]::ntfs_resident_attr_value_resize(). | ||
63 | - Fix a bug in ntfs_map_runlist_nolock() where we forgot to protect | ||
64 | access to the allocated size in the ntfs inode with the size lock. | ||
65 | - Fix ntfs_attr_vcn_to_lcn_nolock() and ntfs_attr_find_vcn_nolock() to | ||
66 | return LCN_ENOENT when there is no runlist and the allocated size is | ||
67 | zero. | ||
68 | - Fix load_attribute_list() to handle the case of a NULL runlist. | ||
69 | - Fix handling of sparse attributes in ntfs_attr_make_non_resident(). | ||
70 | - Add BUG() checks to ntfs_attr_make_non_resident() and ntfs_attr_set() | ||
71 | to ensure that these functions are never called for compressed or | ||
72 | encrypted attributes. | ||
73 | - Fix cluster (de)allocators to work when the runlist is NULL and more | ||
74 | importantly to take a locked runlist rather than them locking it | ||
75 | which leads to lock reversal. | ||
76 | - Truncate {a,c,m}time to the ntfs supported time granularity when | ||
77 | updating the times in the inode in ntfs_setattr(). | ||
78 | - Fixup handling of sparse, compressed, and encrypted attributes in | ||
79 | fs/ntfs/inode.c::ntfs_read_locked_{,attr_,index_}inode(), | ||
80 | fs/ntfs/aops.c::ntfs_{read,write}page(). | ||
81 | - Make ntfs_write_block() not instantiate sparse blocks if they contain | ||
82 | only zeroes. | ||
83 | - Optimize fs/ntfs/aops.c::ntfs_write_block() by extending the page | ||
84 | lock protection over the buffer submission for i/o which allows the | ||
85 | removal of the get_bh()/put_bh() pairs for each buffer. | ||
86 | - Fix fs/ntfs/aops.c::ntfs_{read,write}_block() to handle the case | ||
87 | where a concurrent truncate has truncated the runlist under our feet. | ||
88 | - Fix page_has_buffers()/page_buffers() handling in fs/ntfs/aops.c. | ||
89 | - In fs/ntfs/aops.c::ntfs_end_buffer_async_read(), use a bit spin lock | ||
90 | in the first buffer head instead of a driver global spin lock to | ||
91 | improve scalability. | ||
92 | - Minor fix to error handling and error message display in | ||
93 | fs/ntfs/aops.c::ntfs_prepare_nonresident_write(). | ||
94 | |||
25 | 2.1.23 - Implement extension of resident files and make writing safe as well as | 95 | 2.1.23 - Implement extension of resident files and make writing safe as well as |
26 | many bug fixes, cleanups, and enhancements... | 96 | many bug fixes, cleanups, and enhancements... |
27 | 97 | ||
diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile index f083f27d8b69..894b2b876d35 100644 --- a/fs/ntfs/Makefile +++ b/fs/ntfs/Makefile | |||
@@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \ | |||
6 | index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \ | 6 | index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \ |
7 | unistr.o upcase.o | 7 | unistr.o upcase.o |
8 | 8 | ||
9 | EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.23\" | 9 | EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.24\" |
10 | 10 | ||
11 | ifeq ($(CONFIG_NTFS_DEBUG),y) | 11 | ifeq ($(CONFIG_NTFS_DEBUG),y) |
12 | EXTRA_CFLAGS += -DDEBUG | 12 | EXTRA_CFLAGS += -DDEBUG |
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 78adad7a988d..545236414d59 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c | |||
@@ -55,9 +55,8 @@ | |||
55 | */ | 55 | */ |
56 | static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) | 56 | static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) |
57 | { | 57 | { |
58 | static DEFINE_SPINLOCK(page_uptodate_lock); | ||
59 | unsigned long flags; | 58 | unsigned long flags; |
60 | struct buffer_head *tmp; | 59 | struct buffer_head *first, *tmp; |
61 | struct page *page; | 60 | struct page *page; |
62 | ntfs_inode *ni; | 61 | ntfs_inode *ni; |
63 | int page_uptodate = 1; | 62 | int page_uptodate = 1; |
@@ -89,11 +88,13 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) | |||
89 | } | 88 | } |
90 | } else { | 89 | } else { |
91 | clear_buffer_uptodate(bh); | 90 | clear_buffer_uptodate(bh); |
91 | SetPageError(page); | ||
92 | ntfs_error(ni->vol->sb, "Buffer I/O error, logical block %llu.", | 92 | ntfs_error(ni->vol->sb, "Buffer I/O error, logical block %llu.", |
93 | (unsigned long long)bh->b_blocknr); | 93 | (unsigned long long)bh->b_blocknr); |
94 | SetPageError(page); | ||
95 | } | 94 | } |
96 | spin_lock_irqsave(&page_uptodate_lock, flags); | 95 | first = page_buffers(page); |
96 | local_irq_save(flags); | ||
97 | bit_spin_lock(BH_Uptodate_Lock, &first->b_state); | ||
97 | clear_buffer_async_read(bh); | 98 | clear_buffer_async_read(bh); |
98 | unlock_buffer(bh); | 99 | unlock_buffer(bh); |
99 | tmp = bh; | 100 | tmp = bh; |
@@ -108,7 +109,8 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) | |||
108 | } | 109 | } |
109 | tmp = tmp->b_this_page; | 110 | tmp = tmp->b_this_page; |
110 | } while (tmp != bh); | 111 | } while (tmp != bh); |
111 | spin_unlock_irqrestore(&page_uptodate_lock, flags); | 112 | bit_spin_unlock(BH_Uptodate_Lock, &first->b_state); |
113 | local_irq_restore(flags); | ||
112 | /* | 114 | /* |
113 | * If none of the buffers had errors then we can set the page uptodate, | 115 | * If none of the buffers had errors then we can set the page uptodate, |
114 | * but we first have to perform the post read mst fixups, if the | 116 | * but we first have to perform the post read mst fixups, if the |
@@ -141,7 +143,8 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) | |||
141 | unlock_page(page); | 143 | unlock_page(page); |
142 | return; | 144 | return; |
143 | still_busy: | 145 | still_busy: |
144 | spin_unlock_irqrestore(&page_uptodate_lock, flags); | 146 | bit_spin_unlock(BH_Uptodate_Lock, &first->b_state); |
147 | local_irq_restore(flags); | ||
145 | return; | 148 | return; |
146 | } | 149 | } |
147 | 150 | ||
@@ -185,13 +188,15 @@ static int ntfs_read_block(struct page *page) | |||
185 | blocksize_bits = VFS_I(ni)->i_blkbits; | 188 | blocksize_bits = VFS_I(ni)->i_blkbits; |
186 | blocksize = 1 << blocksize_bits; | 189 | blocksize = 1 << blocksize_bits; |
187 | 190 | ||
188 | if (!page_has_buffers(page)) | 191 | if (!page_has_buffers(page)) { |
189 | create_empty_buffers(page, blocksize, 0); | 192 | create_empty_buffers(page, blocksize, 0); |
190 | bh = head = page_buffers(page); | 193 | if (unlikely(!page_has_buffers(page))) { |
191 | if (unlikely(!bh)) { | 194 | unlock_page(page); |
192 | unlock_page(page); | 195 | return -ENOMEM; |
193 | return -ENOMEM; | 196 | } |
194 | } | 197 | } |
198 | bh = head = page_buffers(page); | ||
199 | BUG_ON(!bh); | ||
195 | 200 | ||
196 | iblock = (s64)page->index << (PAGE_CACHE_SHIFT - blocksize_bits); | 201 | iblock = (s64)page->index << (PAGE_CACHE_SHIFT - blocksize_bits); |
197 | read_lock_irqsave(&ni->size_lock, flags); | 202 | read_lock_irqsave(&ni->size_lock, flags); |
@@ -204,6 +209,7 @@ static int ntfs_read_block(struct page *page) | |||
204 | nr = i = 0; | 209 | nr = i = 0; |
205 | do { | 210 | do { |
206 | u8 *kaddr; | 211 | u8 *kaddr; |
212 | int err; | ||
207 | 213 | ||
208 | if (unlikely(buffer_uptodate(bh))) | 214 | if (unlikely(buffer_uptodate(bh))) |
209 | continue; | 215 | continue; |
@@ -211,6 +217,7 @@ static int ntfs_read_block(struct page *page) | |||
211 | arr[nr++] = bh; | 217 | arr[nr++] = bh; |
212 | continue; | 218 | continue; |
213 | } | 219 | } |
220 | err = 0; | ||
214 | bh->b_bdev = vol->sb->s_bdev; | 221 | bh->b_bdev = vol->sb->s_bdev; |
215 | /* Is the block within the allowed limits? */ | 222 | /* Is the block within the allowed limits? */ |
216 | if (iblock < lblock) { | 223 | if (iblock < lblock) { |
@@ -252,7 +259,6 @@ lock_retry_remap: | |||
252 | goto handle_hole; | 259 | goto handle_hole; |
253 | /* If first try and runlist unmapped, map and retry. */ | 260 | /* If first try and runlist unmapped, map and retry. */ |
254 | if (!is_retry && lcn == LCN_RL_NOT_MAPPED) { | 261 | if (!is_retry && lcn == LCN_RL_NOT_MAPPED) { |
255 | int err; | ||
256 | is_retry = TRUE; | 262 | is_retry = TRUE; |
257 | /* | 263 | /* |
258 | * Attempt to map runlist, dropping lock for | 264 | * Attempt to map runlist, dropping lock for |
@@ -263,20 +269,30 @@ lock_retry_remap: | |||
263 | if (likely(!err)) | 269 | if (likely(!err)) |
264 | goto lock_retry_remap; | 270 | goto lock_retry_remap; |
265 | rl = NULL; | 271 | rl = NULL; |
266 | lcn = err; | ||
267 | } else if (!rl) | 272 | } else if (!rl) |
268 | up_read(&ni->runlist.lock); | 273 | up_read(&ni->runlist.lock); |
274 | /* | ||
275 | * If buffer is outside the runlist, treat it as a | ||
276 | * hole. This can happen due to concurrent truncate | ||
277 | * for example. | ||
278 | */ | ||
279 | if (err == -ENOENT || lcn == LCN_ENOENT) { | ||
280 | err = 0; | ||
281 | goto handle_hole; | ||
282 | } | ||
269 | /* Hard error, zero out region. */ | 283 | /* Hard error, zero out region. */ |
284 | if (!err) | ||
285 | err = -EIO; | ||
270 | bh->b_blocknr = -1; | 286 | bh->b_blocknr = -1; |
271 | SetPageError(page); | 287 | SetPageError(page); |
272 | ntfs_error(vol->sb, "Failed to read from inode 0x%lx, " | 288 | ntfs_error(vol->sb, "Failed to read from inode 0x%lx, " |
273 | "attribute type 0x%x, vcn 0x%llx, " | 289 | "attribute type 0x%x, vcn 0x%llx, " |
274 | "offset 0x%x because its location on " | 290 | "offset 0x%x because its location on " |
275 | "disk could not be determined%s " | 291 | "disk could not be determined%s " |
276 | "(error code %lli).", ni->mft_no, | 292 | "(error code %i).", ni->mft_no, |
277 | ni->type, (unsigned long long)vcn, | 293 | ni->type, (unsigned long long)vcn, |
278 | vcn_ofs, is_retry ? " even after " | 294 | vcn_ofs, is_retry ? " even after " |
279 | "retrying" : "", (long long)lcn); | 295 | "retrying" : "", err); |
280 | } | 296 | } |
281 | /* | 297 | /* |
282 | * Either iblock was outside lblock limits or | 298 | * Either iblock was outside lblock limits or |
@@ -289,9 +305,10 @@ handle_hole: | |||
289 | handle_zblock: | 305 | handle_zblock: |
290 | kaddr = kmap_atomic(page, KM_USER0); | 306 | kaddr = kmap_atomic(page, KM_USER0); |
291 | memset(kaddr + i * blocksize, 0, blocksize); | 307 | memset(kaddr + i * blocksize, 0, blocksize); |
292 | flush_dcache_page(page); | ||
293 | kunmap_atomic(kaddr, KM_USER0); | 308 | kunmap_atomic(kaddr, KM_USER0); |
294 | set_buffer_uptodate(bh); | 309 | flush_dcache_page(page); |
310 | if (likely(!err)) | ||
311 | set_buffer_uptodate(bh); | ||
295 | } while (i++, iblock++, (bh = bh->b_this_page) != head); | 312 | } while (i++, iblock++, (bh = bh->b_this_page) != head); |
296 | 313 | ||
297 | /* Release the lock if we took it. */ | 314 | /* Release the lock if we took it. */ |
@@ -367,31 +384,38 @@ retry_readpage: | |||
367 | return 0; | 384 | return 0; |
368 | } | 385 | } |
369 | ni = NTFS_I(page->mapping->host); | 386 | ni = NTFS_I(page->mapping->host); |
370 | 387 | /* | |
388 | * Only $DATA attributes can be encrypted and only unnamed $DATA | ||
389 | * attributes can be compressed. Index root can have the flags set but | ||
390 | * this means to create compressed/encrypted files, not that the | ||
391 | * attribute is compressed/encrypted. | ||
392 | */ | ||
393 | if (ni->type != AT_INDEX_ROOT) { | ||
394 | /* If attribute is encrypted, deny access, just like NT4. */ | ||
395 | if (NInoEncrypted(ni)) { | ||
396 | BUG_ON(ni->type != AT_DATA); | ||
397 | err = -EACCES; | ||
398 | goto err_out; | ||
399 | } | ||
400 | /* Compressed data streams are handled in compress.c. */ | ||
401 | if (NInoNonResident(ni) && NInoCompressed(ni)) { | ||
402 | BUG_ON(ni->type != AT_DATA); | ||
403 | BUG_ON(ni->name_len); | ||
404 | return ntfs_read_compressed_block(page); | ||
405 | } | ||
406 | } | ||
371 | /* NInoNonResident() == NInoIndexAllocPresent() */ | 407 | /* NInoNonResident() == NInoIndexAllocPresent() */ |
372 | if (NInoNonResident(ni)) { | 408 | if (NInoNonResident(ni)) { |
373 | /* | 409 | /* Normal, non-resident data stream. */ |
374 | * Only unnamed $DATA attributes can be compressed or | ||
375 | * encrypted. | ||
376 | */ | ||
377 | if (ni->type == AT_DATA && !ni->name_len) { | ||
378 | /* If file is encrypted, deny access, just like NT4. */ | ||
379 | if (NInoEncrypted(ni)) { | ||
380 | err = -EACCES; | ||
381 | goto err_out; | ||
382 | } | ||
383 | /* Compressed data streams are handled in compress.c. */ | ||
384 | if (NInoCompressed(ni)) | ||
385 | return ntfs_read_compressed_block(page); | ||
386 | } | ||
387 | /* Normal data stream. */ | ||
388 | return ntfs_read_block(page); | 410 | return ntfs_read_block(page); |
389 | } | 411 | } |
390 | /* | 412 | /* |
391 | * Attribute is resident, implying it is not compressed or encrypted. | 413 | * Attribute is resident, implying it is not compressed or encrypted. |
392 | * This also means the attribute is smaller than an mft record and | 414 | * This also means the attribute is smaller than an mft record and |
393 | * hence smaller than a page, so can simply zero out any pages with | 415 | * hence smaller than a page, so can simply zero out any pages with |
394 | * index above 0. | 416 | * index above 0. Note the attribute can actually be marked compressed |
417 | * but if it is resident the actual data is not compressed so we are | ||
418 | * ok to ignore the compressed flag here. | ||
395 | */ | 419 | */ |
396 | if (unlikely(page->index > 0)) { | 420 | if (unlikely(page->index > 0)) { |
397 | kaddr = kmap_atomic(page, KM_USER0); | 421 | kaddr = kmap_atomic(page, KM_USER0); |
@@ -511,19 +535,21 @@ static int ntfs_write_block(struct page *page, struct writeback_control *wbc) | |||
511 | BUG_ON(!PageUptodate(page)); | 535 | BUG_ON(!PageUptodate(page)); |
512 | create_empty_buffers(page, blocksize, | 536 | create_empty_buffers(page, blocksize, |
513 | (1 << BH_Uptodate) | (1 << BH_Dirty)); | 537 | (1 << BH_Uptodate) | (1 << BH_Dirty)); |
538 | if (unlikely(!page_has_buffers(page))) { | ||
539 | ntfs_warning(vol->sb, "Error allocating page " | ||
540 | "buffers. Redirtying page so we try " | ||
541 | "again later."); | ||
542 | /* | ||
543 | * Put the page back on mapping->dirty_pages, but leave | ||
544 | * its buffers' dirty state as-is. | ||
545 | */ | ||
546 | redirty_page_for_writepage(wbc, page); | ||
547 | unlock_page(page); | ||
548 | return 0; | ||
549 | } | ||
514 | } | 550 | } |
515 | bh = head = page_buffers(page); | 551 | bh = head = page_buffers(page); |
516 | if (unlikely(!bh)) { | 552 | BUG_ON(!bh); |
517 | ntfs_warning(vol->sb, "Error allocating page buffers. " | ||
518 | "Redirtying page so we try again later."); | ||
519 | /* | ||
520 | * Put the page back on mapping->dirty_pages, but leave its | ||
521 | * buffer's dirty state as-is. | ||
522 | */ | ||
523 | redirty_page_for_writepage(wbc, page); | ||
524 | unlock_page(page); | ||
525 | return 0; | ||
526 | } | ||
527 | 553 | ||
528 | /* NOTE: Different naming scheme to ntfs_read_block()! */ | 554 | /* NOTE: Different naming scheme to ntfs_read_block()! */ |
529 | 555 | ||
@@ -670,6 +696,27 @@ lock_retry_remap: | |||
670 | } | 696 | } |
671 | /* It is a hole, need to instantiate it. */ | 697 | /* It is a hole, need to instantiate it. */ |
672 | if (lcn == LCN_HOLE) { | 698 | if (lcn == LCN_HOLE) { |
699 | u8 *kaddr; | ||
700 | unsigned long *bpos, *bend; | ||
701 | |||
702 | /* Check if the buffer is zero. */ | ||
703 | kaddr = kmap_atomic(page, KM_USER0); | ||
704 | bpos = (unsigned long *)(kaddr + bh_offset(bh)); | ||
705 | bend = (unsigned long *)((u8*)bpos + blocksize); | ||
706 | do { | ||
707 | if (unlikely(*bpos)) | ||
708 | break; | ||
709 | } while (likely(++bpos < bend)); | ||
710 | kunmap_atomic(kaddr, KM_USER0); | ||
711 | if (bpos == bend) { | ||
712 | /* | ||
713 | * Buffer is zero and sparse, no need to write | ||
714 | * it. | ||
715 | */ | ||
716 | bh->b_blocknr = -1; | ||
717 | clear_buffer_dirty(bh); | ||
718 | continue; | ||
719 | } | ||
673 | // TODO: Instantiate the hole. | 720 | // TODO: Instantiate the hole. |
674 | // clear_buffer_new(bh); | 721 | // clear_buffer_new(bh); |
675 | // unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); | 722 | // unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); |
@@ -690,20 +737,37 @@ lock_retry_remap: | |||
690 | if (likely(!err)) | 737 | if (likely(!err)) |
691 | goto lock_retry_remap; | 738 | goto lock_retry_remap; |
692 | rl = NULL; | 739 | rl = NULL; |
693 | lcn = err; | ||
694 | } else if (!rl) | 740 | } else if (!rl) |
695 | up_read(&ni->runlist.lock); | 741 | up_read(&ni->runlist.lock); |
742 | /* | ||
743 | * If buffer is outside the runlist, truncate has cut it out | ||
744 | * of the runlist. Just clean and clear the buffer and set it | ||
745 | * uptodate so it can get discarded by the VM. | ||
746 | */ | ||
747 | if (err == -ENOENT || lcn == LCN_ENOENT) { | ||
748 | u8 *kaddr; | ||
749 | |||
750 | bh->b_blocknr = -1; | ||
751 | clear_buffer_dirty(bh); | ||
752 | kaddr = kmap_atomic(page, KM_USER0); | ||
753 | memset(kaddr + bh_offset(bh), 0, blocksize); | ||
754 | kunmap_atomic(kaddr, KM_USER0); | ||
755 | flush_dcache_page(page); | ||
756 | set_buffer_uptodate(bh); | ||
757 | err = 0; | ||
758 | continue; | ||
759 | } | ||
696 | /* Failed to map the buffer, even after retrying. */ | 760 | /* Failed to map the buffer, even after retrying. */ |
761 | if (!err) | ||
762 | err = -EIO; | ||
697 | bh->b_blocknr = -1; | 763 | bh->b_blocknr = -1; |
698 | ntfs_error(vol->sb, "Failed to write to inode 0x%lx, " | 764 | ntfs_error(vol->sb, "Failed to write to inode 0x%lx, " |
699 | "attribute type 0x%x, vcn 0x%llx, offset 0x%x " | 765 | "attribute type 0x%x, vcn 0x%llx, offset 0x%x " |
700 | "because its location on disk could not be " | 766 | "because its location on disk could not be " |
701 | "determined%s (error code %lli).", ni->mft_no, | 767 | "determined%s (error code %i).", ni->mft_no, |
702 | ni->type, (unsigned long long)vcn, | 768 | ni->type, (unsigned long long)vcn, |
703 | vcn_ofs, is_retry ? " even after " | 769 | vcn_ofs, is_retry ? " even after " |
704 | "retrying" : "", (long long)lcn); | 770 | "retrying" : "", err); |
705 | if (!err) | ||
706 | err = -EIO; | ||
707 | break; | 771 | break; |
708 | } while (block++, (bh = bh->b_this_page) != head); | 772 | } while (block++, (bh = bh->b_this_page) != head); |
709 | 773 | ||
@@ -714,7 +778,7 @@ lock_retry_remap: | |||
714 | /* For the error case, need to reset bh to the beginning. */ | 778 | /* For the error case, need to reset bh to the beginning. */ |
715 | bh = head; | 779 | bh = head; |
716 | 780 | ||
717 | /* Just an optimization, so ->readpage() isn't called later. */ | 781 | /* Just an optimization, so ->readpage() is not called later. */ |
718 | if (unlikely(!PageUptodate(page))) { | 782 | if (unlikely(!PageUptodate(page))) { |
719 | int uptodate = 1; | 783 | int uptodate = 1; |
720 | do { | 784 | do { |
@@ -730,7 +794,6 @@ lock_retry_remap: | |||
730 | 794 | ||
731 | /* Setup all mapped, dirty buffers for async write i/o. */ | 795 | /* Setup all mapped, dirty buffers for async write i/o. */ |
732 | do { | 796 | do { |
733 | get_bh(bh); | ||
734 | if (buffer_mapped(bh) && buffer_dirty(bh)) { | 797 | if (buffer_mapped(bh) && buffer_dirty(bh)) { |
735 | lock_buffer(bh); | 798 | lock_buffer(bh); |
736 | if (test_clear_buffer_dirty(bh)) { | 799 | if (test_clear_buffer_dirty(bh)) { |
@@ -768,14 +831,8 @@ lock_retry_remap: | |||
768 | 831 | ||
769 | BUG_ON(PageWriteback(page)); | 832 | BUG_ON(PageWriteback(page)); |
770 | set_page_writeback(page); /* Keeps try_to_free_buffers() away. */ | 833 | set_page_writeback(page); /* Keeps try_to_free_buffers() away. */ |
771 | unlock_page(page); | ||
772 | 834 | ||
773 | /* | 835 | /* Submit the prepared buffers for i/o. */ |
774 | * Submit the prepared buffers for i/o. Note the page is unlocked, | ||
775 | * and the async write i/o completion handler can end_page_writeback() | ||
776 | * at any time after the *first* submit_bh(). So the buffers can then | ||
777 | * disappear... | ||
778 | */ | ||
779 | need_end_writeback = TRUE; | 836 | need_end_writeback = TRUE; |
780 | do { | 837 | do { |
781 | struct buffer_head *next = bh->b_this_page; | 838 | struct buffer_head *next = bh->b_this_page; |
@@ -783,9 +840,9 @@ lock_retry_remap: | |||
783 | submit_bh(WRITE, bh); | 840 | submit_bh(WRITE, bh); |
784 | need_end_writeback = FALSE; | 841 | need_end_writeback = FALSE; |
785 | } | 842 | } |
786 | put_bh(bh); | ||
787 | bh = next; | 843 | bh = next; |
788 | } while (bh != head); | 844 | } while (bh != head); |
845 | unlock_page(page); | ||
789 | 846 | ||
790 | /* If no i/o was started, need to end_page_writeback(). */ | 847 | /* If no i/o was started, need to end_page_writeback(). */ |
791 | if (unlikely(need_end_writeback)) | 848 | if (unlikely(need_end_writeback)) |
@@ -860,7 +917,6 @@ static int ntfs_write_mst_block(struct page *page, | |||
860 | sync = (wbc->sync_mode == WB_SYNC_ALL); | 917 | sync = (wbc->sync_mode == WB_SYNC_ALL); |
861 | 918 | ||
862 | /* Make sure we have mapped buffers. */ | 919 | /* Make sure we have mapped buffers. */ |
863 | BUG_ON(!page_has_buffers(page)); | ||
864 | bh = head = page_buffers(page); | 920 | bh = head = page_buffers(page); |
865 | BUG_ON(!bh); | 921 | BUG_ON(!bh); |
866 | 922 | ||
@@ -1280,38 +1336,42 @@ retry_writepage: | |||
1280 | ntfs_debug("Write outside i_size - truncated?"); | 1336 | ntfs_debug("Write outside i_size - truncated?"); |
1281 | return 0; | 1337 | return 0; |
1282 | } | 1338 | } |
1339 | /* | ||
1340 | * Only $DATA attributes can be encrypted and only unnamed $DATA | ||
1341 | * attributes can be compressed. Index root can have the flags set but | ||
1342 | * this means to create compressed/encrypted files, not that the | ||
1343 | * attribute is compressed/encrypted. | ||
1344 | */ | ||
1345 | if (ni->type != AT_INDEX_ROOT) { | ||
1346 | /* If file is encrypted, deny access, just like NT4. */ | ||
1347 | if (NInoEncrypted(ni)) { | ||
1348 | unlock_page(page); | ||
1349 | BUG_ON(ni->type != AT_DATA); | ||
1350 | ntfs_debug("Denying write access to encrypted " | ||
1351 | "file."); | ||
1352 | return -EACCES; | ||
1353 | } | ||
1354 | /* Compressed data streams are handled in compress.c. */ | ||
1355 | if (NInoNonResident(ni) && NInoCompressed(ni)) { | ||
1356 | BUG_ON(ni->type != AT_DATA); | ||
1357 | BUG_ON(ni->name_len); | ||
1358 | // TODO: Implement and replace this with | ||
1359 | // return ntfs_write_compressed_block(page); | ||
1360 | unlock_page(page); | ||
1361 | ntfs_error(vi->i_sb, "Writing to compressed files is " | ||
1362 | "not supported yet. Sorry."); | ||
1363 | return -EOPNOTSUPP; | ||
1364 | } | ||
1365 | // TODO: Implement and remove this check. | ||
1366 | if (NInoNonResident(ni) && NInoSparse(ni)) { | ||
1367 | unlock_page(page); | ||
1368 | ntfs_error(vi->i_sb, "Writing to sparse files is not " | ||
1369 | "supported yet. Sorry."); | ||
1370 | return -EOPNOTSUPP; | ||
1371 | } | ||
1372 | } | ||
1283 | /* NInoNonResident() == NInoIndexAllocPresent() */ | 1373 | /* NInoNonResident() == NInoIndexAllocPresent() */ |
1284 | if (NInoNonResident(ni)) { | 1374 | if (NInoNonResident(ni)) { |
1285 | /* | ||
1286 | * Only unnamed $DATA attributes can be compressed, encrypted, | ||
1287 | * and/or sparse. | ||
1288 | */ | ||
1289 | if (ni->type == AT_DATA && !ni->name_len) { | ||
1290 | /* If file is encrypted, deny access, just like NT4. */ | ||
1291 | if (NInoEncrypted(ni)) { | ||
1292 | unlock_page(page); | ||
1293 | ntfs_debug("Denying write access to encrypted " | ||
1294 | "file."); | ||
1295 | return -EACCES; | ||
1296 | } | ||
1297 | /* Compressed data streams are handled in compress.c. */ | ||
1298 | if (NInoCompressed(ni)) { | ||
1299 | // TODO: Implement and replace this check with | ||
1300 | // return ntfs_write_compressed_block(page); | ||
1301 | unlock_page(page); | ||
1302 | ntfs_error(vi->i_sb, "Writing to compressed " | ||
1303 | "files is not supported yet. " | ||
1304 | "Sorry."); | ||
1305 | return -EOPNOTSUPP; | ||
1306 | } | ||
1307 | // TODO: Implement and remove this check. | ||
1308 | if (NInoSparse(ni)) { | ||
1309 | unlock_page(page); | ||
1310 | ntfs_error(vi->i_sb, "Writing to sparse files " | ||
1311 | "is not supported yet. Sorry."); | ||
1312 | return -EOPNOTSUPP; | ||
1313 | } | ||
1314 | } | ||
1315 | /* We have to zero every time due to mmap-at-end-of-file. */ | 1375 | /* We have to zero every time due to mmap-at-end-of-file. */ |
1316 | if (page->index >= (i_size >> PAGE_CACHE_SHIFT)) { | 1376 | if (page->index >= (i_size >> PAGE_CACHE_SHIFT)) { |
1317 | /* The page straddles i_size. */ | 1377 | /* The page straddles i_size. */ |
@@ -1324,14 +1384,16 @@ retry_writepage: | |||
1324 | /* Handle mst protected attributes. */ | 1384 | /* Handle mst protected attributes. */ |
1325 | if (NInoMstProtected(ni)) | 1385 | if (NInoMstProtected(ni)) |
1326 | return ntfs_write_mst_block(page, wbc); | 1386 | return ntfs_write_mst_block(page, wbc); |
1327 | /* Normal data stream. */ | 1387 | /* Normal, non-resident data stream. */ |
1328 | return ntfs_write_block(page, wbc); | 1388 | return ntfs_write_block(page, wbc); |
1329 | } | 1389 | } |
1330 | /* | 1390 | /* |
1331 | * Attribute is resident, implying it is not compressed, encrypted, | 1391 | * Attribute is resident, implying it is not compressed, encrypted, or |
1332 | * sparse, or mst protected. This also means the attribute is smaller | 1392 | * mst protected. This also means the attribute is smaller than an mft |
1333 | * than an mft record and hence smaller than a page, so can simply | 1393 | * record and hence smaller than a page, so can simply return error on |
1334 | * return error on any pages with index above 0. | 1394 | * any pages with index above 0. Note the attribute can actually be |
1395 | * marked compressed but if it is resident the actual data is not | ||
1396 | * compressed so we are ok to ignore the compressed flag here. | ||
1335 | */ | 1397 | */ |
1336 | BUG_ON(page_has_buffers(page)); | 1398 | BUG_ON(page_has_buffers(page)); |
1337 | BUG_ON(!PageUptodate(page)); | 1399 | BUG_ON(!PageUptodate(page)); |
@@ -1380,30 +1442,14 @@ retry_writepage: | |||
1380 | BUG_ON(PageWriteback(page)); | 1442 | BUG_ON(PageWriteback(page)); |
1381 | set_page_writeback(page); | 1443 | set_page_writeback(page); |
1382 | unlock_page(page); | 1444 | unlock_page(page); |
1383 | |||
1384 | /* | 1445 | /* |
1385 | * Here, we don't need to zero the out of bounds area everytime because | 1446 | * Here, we do not need to zero the out of bounds area everytime |
1386 | * the below memcpy() already takes care of the mmap-at-end-of-file | 1447 | * because the below memcpy() already takes care of the |
1387 | * requirements. If the file is converted to a non-resident one, then | 1448 | * mmap-at-end-of-file requirements. If the file is converted to a |
1388 | * the code path use is switched to the non-resident one where the | 1449 | * non-resident one, then the code path use is switched to the |
1389 | * zeroing happens on each ntfs_writepage() invocation. | 1450 | * non-resident one where the zeroing happens on each ntfs_writepage() |
1390 | * | 1451 | * invocation. |
1391 | * The above also applies nicely when i_size is decreased. | ||
1392 | * | ||
1393 | * When i_size is increased, the memory between the old and new i_size | ||
1394 | * _must_ be zeroed (or overwritten with new data). Otherwise we will | ||
1395 | * expose data to userspace/disk which should never have been exposed. | ||
1396 | * | ||
1397 | * FIXME: Ensure that i_size increases do the zeroing/overwriting and | ||
1398 | * if we cannot guarantee that, then enable the zeroing below. If the | ||
1399 | * zeroing below is enabled, we MUST move the unlock_page() from above | ||
1400 | * to after the kunmap_atomic(), i.e. just before the | ||
1401 | * end_page_writeback(). | ||
1402 | * UPDATE: ntfs_prepare/commit_write() do the zeroing on i_size | ||
1403 | * increases for resident attributes so those are ok. | ||
1404 | * TODO: ntfs_truncate(), others? | ||
1405 | */ | 1452 | */ |
1406 | |||
1407 | attr_len = le32_to_cpu(ctx->attr->data.resident.value_length); | 1453 | attr_len = le32_to_cpu(ctx->attr->data.resident.value_length); |
1408 | i_size = i_size_read(vi); | 1454 | i_size = i_size_read(vi); |
1409 | if (unlikely(attr_len > i_size)) { | 1455 | if (unlikely(attr_len > i_size)) { |
@@ -1681,27 +1727,25 @@ lock_retry_remap: | |||
1681 | if (likely(!err)) | 1727 | if (likely(!err)) |
1682 | goto lock_retry_remap; | 1728 | goto lock_retry_remap; |
1683 | rl = NULL; | 1729 | rl = NULL; |
1684 | lcn = err; | ||
1685 | } else if (!rl) | 1730 | } else if (!rl) |
1686 | up_read(&ni->runlist.lock); | 1731 | up_read(&ni->runlist.lock); |
1687 | /* | 1732 | /* |
1688 | * Failed to map the buffer, even after | 1733 | * Failed to map the buffer, even after |
1689 | * retrying. | 1734 | * retrying. |
1690 | */ | 1735 | */ |
1736 | if (!err) | ||
1737 | err = -EIO; | ||
1691 | bh->b_blocknr = -1; | 1738 | bh->b_blocknr = -1; |
1692 | ntfs_error(vol->sb, "Failed to write to inode " | 1739 | ntfs_error(vol->sb, "Failed to write to inode " |
1693 | "0x%lx, attribute type 0x%x, " | 1740 | "0x%lx, attribute type 0x%x, " |
1694 | "vcn 0x%llx, offset 0x%x " | 1741 | "vcn 0x%llx, offset 0x%x " |
1695 | "because its location on disk " | 1742 | "because its location on disk " |
1696 | "could not be determined%s " | 1743 | "could not be determined%s " |
1697 | "(error code %lli).", | 1744 | "(error code %i).", |
1698 | ni->mft_no, ni->type, | 1745 | ni->mft_no, ni->type, |
1699 | (unsigned long long)vcn, | 1746 | (unsigned long long)vcn, |
1700 | vcn_ofs, is_retry ? " even " | 1747 | vcn_ofs, is_retry ? " even " |
1701 | "after retrying" : "", | 1748 | "after retrying" : "", err); |
1702 | (long long)lcn); | ||
1703 | if (!err) | ||
1704 | err = -EIO; | ||
1705 | goto err_out; | 1749 | goto err_out; |
1706 | } | 1750 | } |
1707 | /* We now have a successful remap, i.e. lcn >= 0. */ | 1751 | /* We now have a successful remap, i.e. lcn >= 0. */ |
@@ -2357,6 +2401,7 @@ void mark_ntfs_record_dirty(struct page *page, const unsigned int ofs) { | |||
2357 | buffers_to_free = bh; | 2401 | buffers_to_free = bh; |
2358 | } | 2402 | } |
2359 | bh = head = page_buffers(page); | 2403 | bh = head = page_buffers(page); |
2404 | BUG_ON(!bh); | ||
2360 | do { | 2405 | do { |
2361 | bh_ofs = bh_offset(bh); | 2406 | bh_ofs = bh_offset(bh); |
2362 | if (bh_ofs + bh_size <= ofs) | 2407 | if (bh_ofs + bh_size <= ofs) |
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index cd0f9e740b14..3f9a4ff42ee5 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c | |||
@@ -43,6 +43,9 @@ | |||
43 | * which is not an error as such. This is -ENOENT. It means that @vcn is out | 43 | * which is not an error as such. This is -ENOENT. It means that @vcn is out |
44 | * of bounds of the runlist. | 44 | * of bounds of the runlist. |
45 | * | 45 | * |
46 | * Note the runlist can be NULL after this function returns if @vcn is zero and | ||
47 | * the attribute has zero allocated size, i.e. there simply is no runlist. | ||
48 | * | ||
46 | * Locking: - The runlist must be locked for writing. | 49 | * Locking: - The runlist must be locked for writing. |
47 | * - This function modifies the runlist. | 50 | * - This function modifies the runlist. |
48 | */ | 51 | */ |
@@ -54,6 +57,7 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) | |||
54 | ATTR_RECORD *a; | 57 | ATTR_RECORD *a; |
55 | ntfs_attr_search_ctx *ctx; | 58 | ntfs_attr_search_ctx *ctx; |
56 | runlist_element *rl; | 59 | runlist_element *rl; |
60 | unsigned long flags; | ||
57 | int err = 0; | 61 | int err = 0; |
58 | 62 | ||
59 | ntfs_debug("Mapping runlist part containing vcn 0x%llx.", | 63 | ntfs_debug("Mapping runlist part containing vcn 0x%llx.", |
@@ -85,8 +89,11 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) | |||
85 | * ntfs_mapping_pairs_decompress() fails. | 89 | * ntfs_mapping_pairs_decompress() fails. |
86 | */ | 90 | */ |
87 | end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn) + 1; | 91 | end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn) + 1; |
88 | if (unlikely(!a->data.non_resident.lowest_vcn && end_vcn <= 1)) | 92 | if (unlikely(!a->data.non_resident.lowest_vcn && end_vcn <= 1)) { |
93 | read_lock_irqsave(&ni->size_lock, flags); | ||
89 | end_vcn = ni->allocated_size >> ni->vol->cluster_size_bits; | 94 | end_vcn = ni->allocated_size >> ni->vol->cluster_size_bits; |
95 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
96 | } | ||
90 | if (unlikely(vcn >= end_vcn)) { | 97 | if (unlikely(vcn >= end_vcn)) { |
91 | err = -ENOENT; | 98 | err = -ENOENT; |
92 | goto err_out; | 99 | goto err_out; |
@@ -165,6 +172,7 @@ LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn, | |||
165 | const BOOL write_locked) | 172 | const BOOL write_locked) |
166 | { | 173 | { |
167 | LCN lcn; | 174 | LCN lcn; |
175 | unsigned long flags; | ||
168 | BOOL is_retry = FALSE; | 176 | BOOL is_retry = FALSE; |
169 | 177 | ||
170 | ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.", | 178 | ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.", |
@@ -173,6 +181,14 @@ LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn, | |||
173 | BUG_ON(!ni); | 181 | BUG_ON(!ni); |
174 | BUG_ON(!NInoNonResident(ni)); | 182 | BUG_ON(!NInoNonResident(ni)); |
175 | BUG_ON(vcn < 0); | 183 | BUG_ON(vcn < 0); |
184 | if (!ni->runlist.rl) { | ||
185 | read_lock_irqsave(&ni->size_lock, flags); | ||
186 | if (!ni->allocated_size) { | ||
187 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
188 | return LCN_ENOENT; | ||
189 | } | ||
190 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
191 | } | ||
176 | retry_remap: | 192 | retry_remap: |
177 | /* Convert vcn to lcn. If that fails map the runlist and retry once. */ | 193 | /* Convert vcn to lcn. If that fails map the runlist and retry once. */ |
178 | lcn = ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn); | 194 | lcn = ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn); |
@@ -255,6 +271,7 @@ retry_remap: | |||
255 | runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, | 271 | runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, |
256 | const BOOL write_locked) | 272 | const BOOL write_locked) |
257 | { | 273 | { |
274 | unsigned long flags; | ||
258 | runlist_element *rl; | 275 | runlist_element *rl; |
259 | int err = 0; | 276 | int err = 0; |
260 | BOOL is_retry = FALSE; | 277 | BOOL is_retry = FALSE; |
@@ -265,6 +282,14 @@ runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, | |||
265 | BUG_ON(!ni); | 282 | BUG_ON(!ni); |
266 | BUG_ON(!NInoNonResident(ni)); | 283 | BUG_ON(!NInoNonResident(ni)); |
267 | BUG_ON(vcn < 0); | 284 | BUG_ON(vcn < 0); |
285 | if (!ni->runlist.rl) { | ||
286 | read_lock_irqsave(&ni->size_lock, flags); | ||
287 | if (!ni->allocated_size) { | ||
288 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
289 | return ERR_PTR(-ENOENT); | ||
290 | } | ||
291 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
292 | } | ||
268 | retry_remap: | 293 | retry_remap: |
269 | rl = ni->runlist.rl; | 294 | rl = ni->runlist.rl; |
270 | if (likely(rl && vcn >= rl[0].vcn)) { | 295 | if (likely(rl && vcn >= rl[0].vcn)) { |
@@ -528,6 +553,11 @@ int load_attribute_list(ntfs_volume *vol, runlist *runlist, u8 *al_start, | |||
528 | block_size_bits = sb->s_blocksize_bits; | 553 | block_size_bits = sb->s_blocksize_bits; |
529 | down_read(&runlist->lock); | 554 | down_read(&runlist->lock); |
530 | rl = runlist->rl; | 555 | rl = runlist->rl; |
556 | if (!rl) { | ||
557 | ntfs_error(sb, "Cannot read attribute list since runlist is " | ||
558 | "missing."); | ||
559 | goto err_out; | ||
560 | } | ||
531 | /* Read all clusters specified by the runlist one run at a time. */ | 561 | /* Read all clusters specified by the runlist one run at a time. */ |
532 | while (rl->length) { | 562 | while (rl->length) { |
533 | lcn = ntfs_rl_vcn_to_lcn(rl, rl->vcn); | 563 | lcn = ntfs_rl_vcn_to_lcn(rl, rl->vcn); |
@@ -1247,6 +1277,46 @@ int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size) | |||
1247 | } | 1277 | } |
1248 | 1278 | ||
1249 | /** | 1279 | /** |
1280 | * ntfs_resident_attr_value_resize - resize the value of a resident attribute | ||
1281 | * @m: mft record containing attribute record | ||
1282 | * @a: attribute record whose value to resize | ||
1283 | * @new_size: new size in bytes to which to resize the attribute value of @a | ||
1284 | * | ||
1285 | * Resize the value of the attribute @a in the mft record @m to @new_size bytes. | ||
1286 | * If the value is made bigger, the newly allocated space is cleared. | ||
1287 | * | ||
1288 | * Return 0 on success and -errno on error. The following error codes are | ||
1289 | * defined: | ||
1290 | * -ENOSPC - Not enough space in the mft record @m to perform the resize. | ||
1291 | * | ||
1292 | * Note: On error, no modifications have been performed whatsoever. | ||
1293 | * | ||
1294 | * Warning: If you make a record smaller without having copied all the data you | ||
1295 | * are interested in the data may be overwritten. | ||
1296 | */ | ||
1297 | int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, | ||
1298 | const u32 new_size) | ||
1299 | { | ||
1300 | u32 old_size; | ||
1301 | |||
1302 | /* Resize the resident part of the attribute record. */ | ||
1303 | if (ntfs_attr_record_resize(m, a, | ||
1304 | le16_to_cpu(a->data.resident.value_offset) + new_size)) | ||
1305 | return -ENOSPC; | ||
1306 | /* | ||
1307 | * The resize succeeded! If we made the attribute value bigger, clear | ||
1308 | * the area between the old size and @new_size. | ||
1309 | */ | ||
1310 | old_size = le32_to_cpu(a->data.resident.value_length); | ||
1311 | if (new_size > old_size) | ||
1312 | memset((u8*)a + le16_to_cpu(a->data.resident.value_offset) + | ||
1313 | old_size, 0, new_size - old_size); | ||
1314 | /* Finally update the length of the attribute value. */ | ||
1315 | a->data.resident.value_length = cpu_to_le32(new_size); | ||
1316 | return 0; | ||
1317 | } | ||
1318 | |||
1319 | /** | ||
1250 | * ntfs_attr_make_non_resident - convert a resident to a non-resident attribute | 1320 | * ntfs_attr_make_non_resident - convert a resident to a non-resident attribute |
1251 | * @ni: ntfs inode describing the attribute to convert | 1321 | * @ni: ntfs inode describing the attribute to convert |
1252 | * | 1322 | * |
@@ -1302,6 +1372,12 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) | |||
1302 | return err; | 1372 | return err; |
1303 | } | 1373 | } |
1304 | /* | 1374 | /* |
1375 | * FIXME: Compressed and encrypted attributes are not supported when | ||
1376 | * writing and we should never have gotten here for them. | ||
1377 | */ | ||
1378 | BUG_ON(NInoCompressed(ni)); | ||
1379 | BUG_ON(NInoEncrypted(ni)); | ||
1380 | /* | ||
1305 | * The size needs to be aligned to a cluster boundary for allocation | 1381 | * The size needs to be aligned to a cluster boundary for allocation |
1306 | * purposes. | 1382 | * purposes. |
1307 | */ | 1383 | */ |
@@ -1377,10 +1453,15 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) | |||
1377 | BUG_ON(a->non_resident); | 1453 | BUG_ON(a->non_resident); |
1378 | /* | 1454 | /* |
1379 | * Calculate new offsets for the name and the mapping pairs array. | 1455 | * Calculate new offsets for the name and the mapping pairs array. |
1380 | * We assume the attribute is not compressed or sparse. | ||
1381 | */ | 1456 | */ |
1382 | name_ofs = (offsetof(ATTR_REC, | 1457 | if (NInoSparse(ni) || NInoCompressed(ni)) |
1383 | data.non_resident.compressed_size) + 7) & ~7; | 1458 | name_ofs = (offsetof(ATTR_REC, |
1459 | data.non_resident.compressed_size) + | ||
1460 | sizeof(a->data.non_resident.compressed_size) + | ||
1461 | 7) & ~7; | ||
1462 | else | ||
1463 | name_ofs = (offsetof(ATTR_REC, | ||
1464 | data.non_resident.compressed_size) + 7) & ~7; | ||
1384 | mp_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7; | 1465 | mp_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7; |
1385 | /* | 1466 | /* |
1386 | * Determine the size of the resident part of the now non-resident | 1467 | * Determine the size of the resident part of the now non-resident |
@@ -1419,24 +1500,23 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) | |||
1419 | memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset), | 1500 | memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset), |
1420 | a->name_length * sizeof(ntfschar)); | 1501 | a->name_length * sizeof(ntfschar)); |
1421 | a->name_offset = cpu_to_le16(name_ofs); | 1502 | a->name_offset = cpu_to_le16(name_ofs); |
1422 | /* | ||
1423 | * FIXME: For now just clear all of these as we do not support them | ||
1424 | * when writing. | ||
1425 | */ | ||
1426 | a->flags &= cpu_to_le16(0xffff & ~le16_to_cpu(ATTR_IS_SPARSE | | ||
1427 | ATTR_IS_ENCRYPTED | ATTR_COMPRESSION_MASK)); | ||
1428 | /* Setup the fields specific to non-resident attributes. */ | 1503 | /* Setup the fields specific to non-resident attributes. */ |
1429 | a->data.non_resident.lowest_vcn = 0; | 1504 | a->data.non_resident.lowest_vcn = 0; |
1430 | a->data.non_resident.highest_vcn = cpu_to_sle64((new_size - 1) >> | 1505 | a->data.non_resident.highest_vcn = cpu_to_sle64((new_size - 1) >> |
1431 | vol->cluster_size_bits); | 1506 | vol->cluster_size_bits); |
1432 | a->data.non_resident.mapping_pairs_offset = cpu_to_le16(mp_ofs); | 1507 | a->data.non_resident.mapping_pairs_offset = cpu_to_le16(mp_ofs); |
1433 | a->data.non_resident.compression_unit = 0; | ||
1434 | memset(&a->data.non_resident.reserved, 0, | 1508 | memset(&a->data.non_resident.reserved, 0, |
1435 | sizeof(a->data.non_resident.reserved)); | 1509 | sizeof(a->data.non_resident.reserved)); |
1436 | a->data.non_resident.allocated_size = cpu_to_sle64(new_size); | 1510 | a->data.non_resident.allocated_size = cpu_to_sle64(new_size); |
1437 | a->data.non_resident.data_size = | 1511 | a->data.non_resident.data_size = |
1438 | a->data.non_resident.initialized_size = | 1512 | a->data.non_resident.initialized_size = |
1439 | cpu_to_sle64(attr_size); | 1513 | cpu_to_sle64(attr_size); |
1514 | if (NInoSparse(ni) || NInoCompressed(ni)) { | ||
1515 | a->data.non_resident.compression_unit = 4; | ||
1516 | a->data.non_resident.compressed_size = | ||
1517 | a->data.non_resident.allocated_size; | ||
1518 | } else | ||
1519 | a->data.non_resident.compression_unit = 0; | ||
1440 | /* Generate the mapping pairs array into the attribute record. */ | 1520 | /* Generate the mapping pairs array into the attribute record. */ |
1441 | err = ntfs_mapping_pairs_build(vol, (u8*)a + mp_ofs, | 1521 | err = ntfs_mapping_pairs_build(vol, (u8*)a + mp_ofs, |
1442 | arec_size - mp_ofs, rl, 0, -1, NULL); | 1522 | arec_size - mp_ofs, rl, 0, -1, NULL); |
@@ -1446,16 +1526,19 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) | |||
1446 | goto undo_err_out; | 1526 | goto undo_err_out; |
1447 | } | 1527 | } |
1448 | /* Setup the in-memory attribute structure to be non-resident. */ | 1528 | /* Setup the in-memory attribute structure to be non-resident. */ |
1449 | /* | ||
1450 | * FIXME: For now just clear all of these as we do not support them | ||
1451 | * when writing. | ||
1452 | */ | ||
1453 | NInoClearSparse(ni); | ||
1454 | NInoClearEncrypted(ni); | ||
1455 | NInoClearCompressed(ni); | ||
1456 | ni->runlist.rl = rl; | 1529 | ni->runlist.rl = rl; |
1457 | write_lock_irqsave(&ni->size_lock, flags); | 1530 | write_lock_irqsave(&ni->size_lock, flags); |
1458 | ni->allocated_size = new_size; | 1531 | ni->allocated_size = new_size; |
1532 | if (NInoSparse(ni) || NInoCompressed(ni)) { | ||
1533 | ni->itype.compressed.size = ni->allocated_size; | ||
1534 | ni->itype.compressed.block_size = 1U << | ||
1535 | (a->data.non_resident.compression_unit + | ||
1536 | vol->cluster_size_bits); | ||
1537 | ni->itype.compressed.block_size_bits = | ||
1538 | ffs(ni->itype.compressed.block_size) - 1; | ||
1539 | ni->itype.compressed.block_clusters = 1U << | ||
1540 | a->data.non_resident.compression_unit; | ||
1541 | } | ||
1459 | write_unlock_irqrestore(&ni->size_lock, flags); | 1542 | write_unlock_irqrestore(&ni->size_lock, flags); |
1460 | /* | 1543 | /* |
1461 | * This needs to be last since the address space operations ->readpage | 1544 | * This needs to be last since the address space operations ->readpage |
@@ -1603,6 +1686,12 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val) | |||
1603 | BUG_ON(cnt < 0); | 1686 | BUG_ON(cnt < 0); |
1604 | if (!cnt) | 1687 | if (!cnt) |
1605 | goto done; | 1688 | goto done; |
1689 | /* | ||
1690 | * FIXME: Compressed and encrypted attributes are not supported when | ||
1691 | * writing and we should never have gotten here for them. | ||
1692 | */ | ||
1693 | BUG_ON(NInoCompressed(ni)); | ||
1694 | BUG_ON(NInoEncrypted(ni)); | ||
1606 | mapping = VFS_I(ni)->i_mapping; | 1695 | mapping = VFS_I(ni)->i_mapping; |
1607 | /* Work out the starting index and page offset. */ | 1696 | /* Work out the starting index and page offset. */ |
1608 | idx = ofs >> PAGE_CACHE_SHIFT; | 1697 | idx = ofs >> PAGE_CACHE_SHIFT; |
diff --git a/fs/ntfs/attrib.h b/fs/ntfs/attrib.h index 0e4ac6d3c0e7..0618ed6fd7b3 100644 --- a/fs/ntfs/attrib.h +++ b/fs/ntfs/attrib.h | |||
@@ -99,6 +99,8 @@ extern int ntfs_attr_can_be_resident(const ntfs_volume *vol, | |||
99 | const ATTR_TYPE type); | 99 | const ATTR_TYPE type); |
100 | 100 | ||
101 | extern int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size); | 101 | extern int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size); |
102 | extern int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, | ||
103 | const u32 new_size); | ||
102 | 104 | ||
103 | extern int ntfs_attr_make_non_resident(ntfs_inode *ni); | 105 | extern int ntfs_attr_make_non_resident(ntfs_inode *ni); |
104 | 106 | ||
diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c index 6d265cfd49aa..25d24106f893 100644 --- a/fs/ntfs/compress.c +++ b/fs/ntfs/compress.c | |||
@@ -539,7 +539,6 @@ int ntfs_read_compressed_block(struct page *page) | |||
539 | if (unlikely(!pages || !bhs)) { | 539 | if (unlikely(!pages || !bhs)) { |
540 | kfree(bhs); | 540 | kfree(bhs); |
541 | kfree(pages); | 541 | kfree(pages); |
542 | SetPageError(page); | ||
543 | unlock_page(page); | 542 | unlock_page(page); |
544 | ntfs_error(vol->sb, "Failed to allocate internal buffers."); | 543 | ntfs_error(vol->sb, "Failed to allocate internal buffers."); |
545 | return -ENOMEM; | 544 | return -ENOMEM; |
@@ -871,9 +870,6 @@ lock_retry_remap: | |||
871 | for (; prev_cur_page < cur_page; prev_cur_page++) { | 870 | for (; prev_cur_page < cur_page; prev_cur_page++) { |
872 | page = pages[prev_cur_page]; | 871 | page = pages[prev_cur_page]; |
873 | if (page) { | 872 | if (page) { |
874 | if (prev_cur_page == xpage && | ||
875 | !xpage_done) | ||
876 | SetPageError(page); | ||
877 | flush_dcache_page(page); | 873 | flush_dcache_page(page); |
878 | kunmap(page); | 874 | kunmap(page); |
879 | unlock_page(page); | 875 | unlock_page(page); |
@@ -904,8 +900,6 @@ lock_retry_remap: | |||
904 | "Terminating them with extreme " | 900 | "Terminating them with extreme " |
905 | "prejudice. Inode 0x%lx, page index " | 901 | "prejudice. Inode 0x%lx, page index " |
906 | "0x%lx.", ni->mft_no, page->index); | 902 | "0x%lx.", ni->mft_no, page->index); |
907 | if (cur_page == xpage && !xpage_done) | ||
908 | SetPageError(page); | ||
909 | flush_dcache_page(page); | 903 | flush_dcache_page(page); |
910 | kunmap(page); | 904 | kunmap(page); |
911 | unlock_page(page); | 905 | unlock_page(page); |
@@ -953,8 +947,6 @@ err_out: | |||
953 | for (i = cur_page; i < max_page; i++) { | 947 | for (i = cur_page; i < max_page; i++) { |
954 | page = pages[i]; | 948 | page = pages[i]; |
955 | if (page) { | 949 | if (page) { |
956 | if (i == xpage && !xpage_done) | ||
957 | SetPageError(page); | ||
958 | flush_dcache_page(page); | 950 | flush_dcache_page(page); |
959 | kunmap(page); | 951 | kunmap(page); |
960 | unlock_page(page); | 952 | unlock_page(page); |
diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c index 46779471c542..795c3d1930f5 100644 --- a/fs/ntfs/dir.c +++ b/fs/ntfs/dir.c | |||
@@ -1051,7 +1051,8 @@ static inline int ntfs_filldir(ntfs_volume *vol, loff_t fpos, | |||
1051 | ie->key.file_name.file_name_length, &name, | 1051 | ie->key.file_name.file_name_length, &name, |
1052 | NTFS_MAX_NAME_LEN * NLS_MAX_CHARSET_SIZE + 1); | 1052 | NTFS_MAX_NAME_LEN * NLS_MAX_CHARSET_SIZE + 1); |
1053 | if (name_len <= 0) { | 1053 | if (name_len <= 0) { |
1054 | ntfs_debug("Skipping unrepresentable file."); | 1054 | ntfs_warning(vol->sb, "Skipping unrepresentable inode 0x%llx.", |
1055 | (long long)MREF_LE(ie->data.dir.indexed_file)); | ||
1055 | return 0; | 1056 | return 0; |
1056 | } | 1057 | } |
1057 | if (ie->key.file_name.file_attributes & | 1058 | if (ie->key.file_name.file_attributes & |
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index e0f530ce6b99..be9fd1dd423d 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * file.c - NTFS kernel file operations. Part of the Linux-NTFS project. | 2 | * file.c - NTFS kernel file operations. Part of the Linux-NTFS project. |
3 | * | 3 | * |
4 | * Copyright (c) 2001-2004 Anton Altaparmakov | 4 | * Copyright (c) 2001-2005 Anton Altaparmakov |
5 | * | 5 | * |
6 | * This program/include file is free software; you can redistribute it and/or | 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 | 7 | * modify it under the terms of the GNU General Public License as published |
@@ -94,6 +94,11 @@ static int ntfs_file_fsync(struct file *filp, struct dentry *dentry, | |||
94 | if (!datasync || !NInoNonResident(NTFS_I(vi))) | 94 | if (!datasync || !NInoNonResident(NTFS_I(vi))) |
95 | ret = ntfs_write_inode(vi, 1); | 95 | ret = ntfs_write_inode(vi, 1); |
96 | write_inode_now(vi, !datasync); | 96 | write_inode_now(vi, !datasync); |
97 | /* | ||
98 | * NOTE: If we were to use mapping->private_list (see ext2 and | ||
99 | * fs/buffer.c) for dirty blocks then we could optimize the below to be | ||
100 | * sync_mapping_buffers(vi->i_mapping). | ||
101 | */ | ||
97 | err = sync_blockdev(vi->i_sb->s_bdev); | 102 | err = sync_blockdev(vi->i_sb->s_bdev); |
98 | if (unlikely(err && !ret)) | 103 | if (unlikely(err && !ret)) |
99 | ret = err; | 104 | ret = err; |
diff --git a/fs/ntfs/index.c b/fs/ntfs/index.c index 11fd5307d780..8f2d5727546f 100644 --- a/fs/ntfs/index.c +++ b/fs/ntfs/index.c | |||
@@ -205,6 +205,7 @@ int ntfs_index_lookup(const void *key, const int key_len, | |||
205 | &ie->key, key_len)) { | 205 | &ie->key, key_len)) { |
206 | ir_done: | 206 | ir_done: |
207 | ictx->is_in_root = TRUE; | 207 | ictx->is_in_root = TRUE; |
208 | ictx->ir = ir; | ||
208 | ictx->actx = actx; | 209 | ictx->actx = actx; |
209 | ictx->base_ni = base_ni; | 210 | ictx->base_ni = base_ni; |
210 | ictx->ia = NULL; | 211 | ictx->ia = NULL; |
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 886214a77f90..dc4bbe3acf5c 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c | |||
@@ -1013,41 +1013,50 @@ skip_large_dir_stuff: | |||
1013 | } | 1013 | } |
1014 | a = ctx->attr; | 1014 | a = ctx->attr; |
1015 | /* Setup the state. */ | 1015 | /* Setup the state. */ |
1016 | if (a->non_resident) { | 1016 | if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) { |
1017 | NInoSetNonResident(ni); | 1017 | if (a->flags & ATTR_COMPRESSION_MASK) { |
1018 | if (a->flags & (ATTR_COMPRESSION_MASK | | 1018 | NInoSetCompressed(ni); |
1019 | ATTR_IS_SPARSE)) { | 1019 | if (vol->cluster_size > 4096) { |
1020 | if (a->flags & ATTR_COMPRESSION_MASK) { | 1020 | ntfs_error(vi->i_sb, "Found " |
1021 | NInoSetCompressed(ni); | ||
1022 | if (vol->cluster_size > 4096) { | ||
1023 | ntfs_error(vi->i_sb, "Found " | ||
1024 | "compressed data but " | 1021 | "compressed data but " |
1025 | "compression is " | 1022 | "compression is " |
1026 | "disabled due to " | 1023 | "disabled due to " |
1027 | "cluster size (%i) > " | 1024 | "cluster size (%i) > " |
1028 | "4kiB.", | 1025 | "4kiB.", |
1029 | vol->cluster_size); | 1026 | vol->cluster_size); |
1030 | goto unm_err_out; | 1027 | goto unm_err_out; |
1031 | } | 1028 | } |
1032 | if ((a->flags & ATTR_COMPRESSION_MASK) | 1029 | if ((a->flags & ATTR_COMPRESSION_MASK) |
1033 | != ATTR_IS_COMPRESSED) { | 1030 | != ATTR_IS_COMPRESSED) { |
1034 | ntfs_error(vi->i_sb, "Found " | 1031 | ntfs_error(vi->i_sb, "Found unknown " |
1035 | "unknown compression " | 1032 | "compression method " |
1036 | "method or corrupt " | 1033 | "or corrupt file."); |
1037 | "file."); | 1034 | goto unm_err_out; |
1038 | goto unm_err_out; | ||
1039 | } | ||
1040 | } | 1035 | } |
1041 | if (a->flags & ATTR_IS_SPARSE) | 1036 | } |
1042 | NInoSetSparse(ni); | 1037 | if (a->flags & ATTR_IS_SPARSE) |
1038 | NInoSetSparse(ni); | ||
1039 | } | ||
1040 | if (a->flags & ATTR_IS_ENCRYPTED) { | ||
1041 | if (NInoCompressed(ni)) { | ||
1042 | ntfs_error(vi->i_sb, "Found encrypted and " | ||
1043 | "compressed data."); | ||
1044 | goto unm_err_out; | ||
1045 | } | ||
1046 | NInoSetEncrypted(ni); | ||
1047 | } | ||
1048 | if (a->non_resident) { | ||
1049 | NInoSetNonResident(ni); | ||
1050 | if (NInoCompressed(ni) || NInoSparse(ni)) { | ||
1043 | if (a->data.non_resident.compression_unit != | 1051 | if (a->data.non_resident.compression_unit != |
1044 | 4) { | 1052 | 4) { |
1045 | ntfs_error(vi->i_sb, "Found " | 1053 | ntfs_error(vi->i_sb, "Found " |
1046 | "nonstandard compression unit " | 1054 | "nonstandard " |
1047 | "(%u instead of 4). Cannot " | 1055 | "compression unit (%u " |
1048 | "handle this.", | 1056 | "instead of 4). " |
1049 | a->data.non_resident. | 1057 | "Cannot handle this.", |
1050 | compression_unit); | 1058 | a->data.non_resident. |
1059 | compression_unit); | ||
1051 | err = -EOPNOTSUPP; | 1060 | err = -EOPNOTSUPP; |
1052 | goto unm_err_out; | 1061 | goto unm_err_out; |
1053 | } | 1062 | } |
@@ -1065,14 +1074,6 @@ skip_large_dir_stuff: | |||
1065 | a->data.non_resident. | 1074 | a->data.non_resident. |
1066 | compressed_size); | 1075 | compressed_size); |
1067 | } | 1076 | } |
1068 | if (a->flags & ATTR_IS_ENCRYPTED) { | ||
1069 | if (a->flags & ATTR_COMPRESSION_MASK) { | ||
1070 | ntfs_error(vi->i_sb, "Found encrypted " | ||
1071 | "and compressed data."); | ||
1072 | goto unm_err_out; | ||
1073 | } | ||
1074 | NInoSetEncrypted(ni); | ||
1075 | } | ||
1076 | if (a->data.non_resident.lowest_vcn) { | 1077 | if (a->data.non_resident.lowest_vcn) { |
1077 | ntfs_error(vi->i_sb, "First extent of $DATA " | 1078 | ntfs_error(vi->i_sb, "First extent of $DATA " |
1078 | "attribute has non zero " | 1079 | "attribute has non zero " |
@@ -1212,6 +1213,75 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) | |||
1212 | if (unlikely(err)) | 1213 | if (unlikely(err)) |
1213 | goto unm_err_out; | 1214 | goto unm_err_out; |
1214 | a = ctx->attr; | 1215 | a = ctx->attr; |
1216 | if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) { | ||
1217 | if (a->flags & ATTR_COMPRESSION_MASK) { | ||
1218 | NInoSetCompressed(ni); | ||
1219 | if ((ni->type != AT_DATA) || (ni->type == AT_DATA && | ||
1220 | ni->name_len)) { | ||
1221 | ntfs_error(vi->i_sb, "Found compressed " | ||
1222 | "non-data or named data " | ||
1223 | "attribute. Please report " | ||
1224 | "you saw this message to " | ||
1225 | "linux-ntfs-dev@lists." | ||
1226 | "sourceforge.net"); | ||
1227 | goto unm_err_out; | ||
1228 | } | ||
1229 | if (vol->cluster_size > 4096) { | ||
1230 | ntfs_error(vi->i_sb, "Found compressed " | ||
1231 | "attribute but compression is " | ||
1232 | "disabled due to cluster size " | ||
1233 | "(%i) > 4kiB.", | ||
1234 | vol->cluster_size); | ||
1235 | goto unm_err_out; | ||
1236 | } | ||
1237 | if ((a->flags & ATTR_COMPRESSION_MASK) != | ||
1238 | ATTR_IS_COMPRESSED) { | ||
1239 | ntfs_error(vi->i_sb, "Found unknown " | ||
1240 | "compression method."); | ||
1241 | goto unm_err_out; | ||
1242 | } | ||
1243 | } | ||
1244 | /* | ||
1245 | * The encryption flag set in an index root just means to | ||
1246 | * compress all files. | ||
1247 | */ | ||
1248 | if (NInoMstProtected(ni) && ni->type != AT_INDEX_ROOT) { | ||
1249 | ntfs_error(vi->i_sb, "Found mst protected attribute " | ||
1250 | "but the attribute is %s. Please " | ||
1251 | "report you saw this message to " | ||
1252 | "linux-ntfs-dev@lists.sourceforge.net", | ||
1253 | NInoCompressed(ni) ? "compressed" : | ||
1254 | "sparse"); | ||
1255 | goto unm_err_out; | ||
1256 | } | ||
1257 | if (a->flags & ATTR_IS_SPARSE) | ||
1258 | NInoSetSparse(ni); | ||
1259 | } | ||
1260 | if (a->flags & ATTR_IS_ENCRYPTED) { | ||
1261 | if (NInoCompressed(ni)) { | ||
1262 | ntfs_error(vi->i_sb, "Found encrypted and compressed " | ||
1263 | "data."); | ||
1264 | goto unm_err_out; | ||
1265 | } | ||
1266 | /* | ||
1267 | * The encryption flag set in an index root just means to | ||
1268 | * encrypt all files. | ||
1269 | */ | ||
1270 | if (NInoMstProtected(ni) && ni->type != AT_INDEX_ROOT) { | ||
1271 | ntfs_error(vi->i_sb, "Found mst protected attribute " | ||
1272 | "but the attribute is encrypted. " | ||
1273 | "Please report you saw this message " | ||
1274 | "to linux-ntfs-dev@lists.sourceforge." | ||
1275 | "net"); | ||
1276 | goto unm_err_out; | ||
1277 | } | ||
1278 | if (ni->type != AT_DATA) { | ||
1279 | ntfs_error(vi->i_sb, "Found encrypted non-data " | ||
1280 | "attribute."); | ||
1281 | goto unm_err_out; | ||
1282 | } | ||
1283 | NInoSetEncrypted(ni); | ||
1284 | } | ||
1215 | if (!a->non_resident) { | 1285 | if (!a->non_resident) { |
1216 | /* Ensure the attribute name is placed before the value. */ | 1286 | /* Ensure the attribute name is placed before the value. */ |
1217 | if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >= | 1287 | if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >= |
@@ -1220,11 +1290,10 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) | |||
1220 | "the attribute value."); | 1290 | "the attribute value."); |
1221 | goto unm_err_out; | 1291 | goto unm_err_out; |
1222 | } | 1292 | } |
1223 | if (NInoMstProtected(ni) || a->flags) { | 1293 | if (NInoMstProtected(ni)) { |
1224 | ntfs_error(vi->i_sb, "Found mst protected attribute " | 1294 | ntfs_error(vi->i_sb, "Found mst protected attribute " |
1225 | "or attribute with non-zero flags but " | 1295 | "but the attribute is resident. " |
1226 | "the attribute is resident. Please " | 1296 | "Please report you saw this message to " |
1227 | "report you saw this message to " | ||
1228 | "linux-ntfs-dev@lists.sourceforge.net"); | 1297 | "linux-ntfs-dev@lists.sourceforge.net"); |
1229 | goto unm_err_out; | 1298 | goto unm_err_out; |
1230 | } | 1299 | } |
@@ -1250,50 +1319,8 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) | |||
1250 | "the mapping pairs array."); | 1319 | "the mapping pairs array."); |
1251 | goto unm_err_out; | 1320 | goto unm_err_out; |
1252 | } | 1321 | } |
1253 | if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) { | 1322 | if ((NInoCompressed(ni) || NInoSparse(ni)) && |
1254 | if (a->flags & ATTR_COMPRESSION_MASK) { | 1323 | ni->type != AT_INDEX_ROOT) { |
1255 | NInoSetCompressed(ni); | ||
1256 | if ((ni->type != AT_DATA) || (ni->type == | ||
1257 | AT_DATA && ni->name_len)) { | ||
1258 | ntfs_error(vi->i_sb, "Found compressed " | ||
1259 | "non-data or named " | ||
1260 | "data attribute. " | ||
1261 | "Please report you " | ||
1262 | "saw this message to " | ||
1263 | "linux-ntfs-dev@lists." | ||
1264 | "sourceforge.net"); | ||
1265 | goto unm_err_out; | ||
1266 | } | ||
1267 | if (vol->cluster_size > 4096) { | ||
1268 | ntfs_error(vi->i_sb, "Found compressed " | ||
1269 | "attribute but " | ||
1270 | "compression is " | ||
1271 | "disabled due to " | ||
1272 | "cluster size (%i) > " | ||
1273 | "4kiB.", | ||
1274 | vol->cluster_size); | ||
1275 | goto unm_err_out; | ||
1276 | } | ||
1277 | if ((a->flags & ATTR_COMPRESSION_MASK) != | ||
1278 | ATTR_IS_COMPRESSED) { | ||
1279 | ntfs_error(vi->i_sb, "Found unknown " | ||
1280 | "compression method."); | ||
1281 | goto unm_err_out; | ||
1282 | } | ||
1283 | } | ||
1284 | if (NInoMstProtected(ni)) { | ||
1285 | ntfs_error(vi->i_sb, "Found mst protected " | ||
1286 | "attribute but the attribute " | ||
1287 | "is %s. Please report you " | ||
1288 | "saw this message to " | ||
1289 | "linux-ntfs-dev@lists." | ||
1290 | "sourceforge.net", | ||
1291 | NInoCompressed(ni) ? | ||
1292 | "compressed" : "sparse"); | ||
1293 | goto unm_err_out; | ||
1294 | } | ||
1295 | if (a->flags & ATTR_IS_SPARSE) | ||
1296 | NInoSetSparse(ni); | ||
1297 | if (a->data.non_resident.compression_unit != 4) { | 1324 | if (a->data.non_resident.compression_unit != 4) { |
1298 | ntfs_error(vi->i_sb, "Found nonstandard " | 1325 | ntfs_error(vi->i_sb, "Found nonstandard " |
1299 | "compression unit (%u instead " | 1326 | "compression unit (%u instead " |
@@ -1313,23 +1340,6 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) | |||
1313 | ni->itype.compressed.size = sle64_to_cpu( | 1340 | ni->itype.compressed.size = sle64_to_cpu( |
1314 | a->data.non_resident.compressed_size); | 1341 | a->data.non_resident.compressed_size); |
1315 | } | 1342 | } |
1316 | if (a->flags & ATTR_IS_ENCRYPTED) { | ||
1317 | if (a->flags & ATTR_COMPRESSION_MASK) { | ||
1318 | ntfs_error(vi->i_sb, "Found encrypted and " | ||
1319 | "compressed data."); | ||
1320 | goto unm_err_out; | ||
1321 | } | ||
1322 | if (NInoMstProtected(ni)) { | ||
1323 | ntfs_error(vi->i_sb, "Found mst protected " | ||
1324 | "attribute but the attribute " | ||
1325 | "is encrypted. Please report " | ||
1326 | "you saw this message to " | ||
1327 | "linux-ntfs-dev@lists." | ||
1328 | "sourceforge.net"); | ||
1329 | goto unm_err_out; | ||
1330 | } | ||
1331 | NInoSetEncrypted(ni); | ||
1332 | } | ||
1333 | if (a->data.non_resident.lowest_vcn) { | 1343 | if (a->data.non_resident.lowest_vcn) { |
1334 | ntfs_error(vi->i_sb, "First extent of attribute has " | 1344 | ntfs_error(vi->i_sb, "First extent of attribute has " |
1335 | "non-zero lowest_vcn."); | 1345 | "non-zero lowest_vcn."); |
@@ -1348,12 +1358,12 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) | |||
1348 | vi->i_mapping->a_ops = &ntfs_mst_aops; | 1358 | vi->i_mapping->a_ops = &ntfs_mst_aops; |
1349 | else | 1359 | else |
1350 | vi->i_mapping->a_ops = &ntfs_aops; | 1360 | vi->i_mapping->a_ops = &ntfs_aops; |
1351 | if (NInoCompressed(ni) || NInoSparse(ni)) | 1361 | if ((NInoCompressed(ni) || NInoSparse(ni)) && ni->type != AT_INDEX_ROOT) |
1352 | vi->i_blocks = ni->itype.compressed.size >> 9; | 1362 | vi->i_blocks = ni->itype.compressed.size >> 9; |
1353 | else | 1363 | else |
1354 | vi->i_blocks = ni->allocated_size >> 9; | 1364 | vi->i_blocks = ni->allocated_size >> 9; |
1355 | /* | 1365 | /* |
1356 | * Make sure the base inode doesn't go away and attach it to the | 1366 | * Make sure the base inode does not go away and attach it to the |
1357 | * attribute inode. | 1367 | * attribute inode. |
1358 | */ | 1368 | */ |
1359 | igrab(base_vi); | 1369 | igrab(base_vi); |
@@ -1480,7 +1490,10 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi) | |||
1480 | "after the attribute value."); | 1490 | "after the attribute value."); |
1481 | goto unm_err_out; | 1491 | goto unm_err_out; |
1482 | } | 1492 | } |
1483 | /* Compressed/encrypted/sparse index root is not allowed. */ | 1493 | /* |
1494 | * Compressed/encrypted/sparse index root is not allowed, except for | ||
1495 | * directories of course but those are not dealt with here. | ||
1496 | */ | ||
1484 | if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_ENCRYPTED | | 1497 | if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_ENCRYPTED | |
1485 | ATTR_IS_SPARSE)) { | 1498 | ATTR_IS_SPARSE)) { |
1486 | ntfs_error(vi->i_sb, "Found compressed/encrypted/sparse index " | 1499 | ntfs_error(vi->i_sb, "Found compressed/encrypted/sparse index " |
@@ -2430,16 +2443,18 @@ int ntfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
2430 | * We skipped the truncate but must still update | 2443 | * We skipped the truncate but must still update |
2431 | * timestamps. | 2444 | * timestamps. |
2432 | */ | 2445 | */ |
2433 | ia_valid |= ATTR_MTIME|ATTR_CTIME; | 2446 | ia_valid |= ATTR_MTIME | ATTR_CTIME; |
2434 | } | 2447 | } |
2435 | } | 2448 | } |
2436 | |||
2437 | if (ia_valid & ATTR_ATIME) | 2449 | if (ia_valid & ATTR_ATIME) |
2438 | vi->i_atime = attr->ia_atime; | 2450 | vi->i_atime = timespec_trunc(attr->ia_atime, |
2451 | vi->i_sb->s_time_gran); | ||
2439 | if (ia_valid & ATTR_MTIME) | 2452 | if (ia_valid & ATTR_MTIME) |
2440 | vi->i_mtime = attr->ia_mtime; | 2453 | vi->i_mtime = timespec_trunc(attr->ia_mtime, |
2454 | vi->i_sb->s_time_gran); | ||
2441 | if (ia_valid & ATTR_CTIME) | 2455 | if (ia_valid & ATTR_CTIME) |
2442 | vi->i_ctime = attr->ia_ctime; | 2456 | vi->i_ctime = timespec_trunc(attr->ia_ctime, |
2457 | vi->i_sb->s_time_gran); | ||
2443 | mark_inode_dirty(vi); | 2458 | mark_inode_dirty(vi); |
2444 | out: | 2459 | out: |
2445 | return err; | 2460 | return err; |
diff --git a/fs/ntfs/lcnalloc.c b/fs/ntfs/lcnalloc.c index a4bc07616e5d..7b5934290685 100644 --- a/fs/ntfs/lcnalloc.c +++ b/fs/ntfs/lcnalloc.c | |||
@@ -54,6 +54,8 @@ int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol, | |||
54 | int ret = 0; | 54 | int ret = 0; |
55 | 55 | ||
56 | ntfs_debug("Entering."); | 56 | ntfs_debug("Entering."); |
57 | if (!rl) | ||
58 | return 0; | ||
57 | for (; rl->length; rl++) { | 59 | for (; rl->length; rl++) { |
58 | int err; | 60 | int err; |
59 | 61 | ||
@@ -163,17 +165,9 @@ runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn, | |||
163 | BUG_ON(zone < FIRST_ZONE); | 165 | BUG_ON(zone < FIRST_ZONE); |
164 | BUG_ON(zone > LAST_ZONE); | 166 | BUG_ON(zone > LAST_ZONE); |
165 | 167 | ||
166 | /* Return empty runlist if @count == 0 */ | 168 | /* Return NULL if @count is zero. */ |
167 | // FIXME: Do we want to just return NULL instead? (AIA) | 169 | if (!count) |
168 | if (!count) { | 170 | return NULL; |
169 | rl = ntfs_malloc_nofs(PAGE_SIZE); | ||
170 | if (!rl) | ||
171 | return ERR_PTR(-ENOMEM); | ||
172 | rl[0].vcn = start_vcn; | ||
173 | rl[0].lcn = LCN_RL_NOT_MAPPED; | ||
174 | rl[0].length = 0; | ||
175 | return rl; | ||
176 | } | ||
177 | /* Take the lcnbmp lock for writing. */ | 171 | /* Take the lcnbmp lock for writing. */ |
178 | down_write(&vol->lcnbmp_lock); | 172 | down_write(&vol->lcnbmp_lock); |
179 | /* | 173 | /* |
@@ -788,7 +782,8 @@ out: | |||
788 | * @vi: vfs inode whose runlist describes the clusters to free | 782 | * @vi: vfs inode whose runlist describes the clusters to free |
789 | * @start_vcn: vcn in the runlist of @vi at which to start freeing clusters | 783 | * @start_vcn: vcn in the runlist of @vi at which to start freeing clusters |
790 | * @count: number of clusters to free or -1 for all clusters | 784 | * @count: number of clusters to free or -1 for all clusters |
791 | * @is_rollback: if TRUE this is a rollback operation | 785 | * @write_locked: true if the runlist is locked for writing |
786 | * @is_rollback: true if this is a rollback operation | ||
792 | * | 787 | * |
793 | * Free @count clusters starting at the cluster @start_vcn in the runlist | 788 | * Free @count clusters starting at the cluster @start_vcn in the runlist |
794 | * described by the vfs inode @vi. | 789 | * described by the vfs inode @vi. |
@@ -806,17 +801,17 @@ out: | |||
806 | * Return the number of deallocated clusters (not counting sparse ones) on | 801 | * Return the number of deallocated clusters (not counting sparse ones) on |
807 | * success and -errno on error. | 802 | * success and -errno on error. |
808 | * | 803 | * |
809 | * Locking: - The runlist described by @vi must be unlocked on entry and is | 804 | * Locking: - The runlist described by @vi must be locked on entry and is |
810 | * unlocked on return. | 805 | * locked on return. Note if the runlist is locked for reading the |
811 | * - This function takes the runlist lock of @vi for reading and | 806 | * lock may be dropped and reacquired. Note the runlist may be |
812 | * sometimes for writing and sometimes modifies the runlist. | 807 | * modified when needed runlist fragments need to be mapped. |
813 | * - The volume lcn bitmap must be unlocked on entry and is unlocked | 808 | * - The volume lcn bitmap must be unlocked on entry and is unlocked |
814 | * on return. | 809 | * on return. |
815 | * - This function takes the volume lcn bitmap lock for writing and | 810 | * - This function takes the volume lcn bitmap lock for writing and |
816 | * modifies the bitmap contents. | 811 | * modifies the bitmap contents. |
817 | */ | 812 | */ |
818 | s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count, | 813 | s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count, |
819 | const BOOL is_rollback) | 814 | const BOOL write_locked, const BOOL is_rollback) |
820 | { | 815 | { |
821 | s64 delta, to_free, total_freed, real_freed; | 816 | s64 delta, to_free, total_freed, real_freed; |
822 | ntfs_inode *ni; | 817 | ntfs_inode *ni; |
@@ -848,8 +843,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count, | |||
848 | 843 | ||
849 | total_freed = real_freed = 0; | 844 | total_freed = real_freed = 0; |
850 | 845 | ||
851 | down_read(&ni->runlist.lock); | 846 | rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, write_locked); |
852 | rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, FALSE); | ||
853 | if (IS_ERR(rl)) { | 847 | if (IS_ERR(rl)) { |
854 | if (!is_rollback) | 848 | if (!is_rollback) |
855 | ntfs_error(vol->sb, "Failed to find first runlist " | 849 | ntfs_error(vol->sb, "Failed to find first runlist " |
@@ -903,7 +897,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count, | |||
903 | 897 | ||
904 | /* Attempt to map runlist. */ | 898 | /* Attempt to map runlist. */ |
905 | vcn = rl->vcn; | 899 | vcn = rl->vcn; |
906 | rl = ntfs_attr_find_vcn_nolock(ni, vcn, FALSE); | 900 | rl = ntfs_attr_find_vcn_nolock(ni, vcn, write_locked); |
907 | if (IS_ERR(rl)) { | 901 | if (IS_ERR(rl)) { |
908 | err = PTR_ERR(rl); | 902 | err = PTR_ERR(rl); |
909 | if (!is_rollback) | 903 | if (!is_rollback) |
@@ -950,7 +944,6 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count, | |||
950 | /* Update the total done clusters. */ | 944 | /* Update the total done clusters. */ |
951 | total_freed += to_free; | 945 | total_freed += to_free; |
952 | } | 946 | } |
953 | up_read(&ni->runlist.lock); | ||
954 | if (likely(!is_rollback)) | 947 | if (likely(!is_rollback)) |
955 | up_write(&vol->lcnbmp_lock); | 948 | up_write(&vol->lcnbmp_lock); |
956 | 949 | ||
@@ -960,7 +953,6 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count, | |||
960 | ntfs_debug("Done."); | 953 | ntfs_debug("Done."); |
961 | return real_freed; | 954 | return real_freed; |
962 | err_out: | 955 | err_out: |
963 | up_read(&ni->runlist.lock); | ||
964 | if (is_rollback) | 956 | if (is_rollback) |
965 | return err; | 957 | return err; |
966 | /* If no real clusters were freed, no need to rollback. */ | 958 | /* If no real clusters were freed, no need to rollback. */ |
@@ -973,7 +965,8 @@ err_out: | |||
973 | * If rollback fails, set the volume errors flag, emit an error | 965 | * If rollback fails, set the volume errors flag, emit an error |
974 | * message, and return the error code. | 966 | * message, and return the error code. |
975 | */ | 967 | */ |
976 | delta = __ntfs_cluster_free(vi, start_vcn, total_freed, TRUE); | 968 | delta = __ntfs_cluster_free(vi, start_vcn, total_freed, write_locked, |
969 | TRUE); | ||
977 | if (delta < 0) { | 970 | if (delta < 0) { |
978 | ntfs_error(vol->sb, "Failed to rollback (error %i). Leaving " | 971 | ntfs_error(vol->sb, "Failed to rollback (error %i). Leaving " |
979 | "inconsistent metadata! Unmount and run " | 972 | "inconsistent metadata! Unmount and run " |
diff --git a/fs/ntfs/lcnalloc.h b/fs/ntfs/lcnalloc.h index 4cac1c024af6..e4d7fb98d685 100644 --- a/fs/ntfs/lcnalloc.h +++ b/fs/ntfs/lcnalloc.h | |||
@@ -43,13 +43,14 @@ extern runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, | |||
43 | const NTFS_CLUSTER_ALLOCATION_ZONES zone); | 43 | const NTFS_CLUSTER_ALLOCATION_ZONES zone); |
44 | 44 | ||
45 | extern s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, | 45 | extern s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, |
46 | s64 count, const BOOL is_rollback); | 46 | s64 count, const BOOL write_locked, const BOOL is_rollback); |
47 | 47 | ||
48 | /** | 48 | /** |
49 | * ntfs_cluster_free - free clusters on an ntfs volume | 49 | * ntfs_cluster_free - free clusters on an ntfs volume |
50 | * @vi: vfs inode whose runlist describes the clusters to free | 50 | * @vi: vfs inode whose runlist describes the clusters to free |
51 | * @start_vcn: vcn in the runlist of @vi at which to start freeing clusters | 51 | * @start_vcn: vcn in the runlist of @vi at which to start freeing clusters |
52 | * @count: number of clusters to free or -1 for all clusters | 52 | * @count: number of clusters to free or -1 for all clusters |
53 | * @write_locked: true if the runlist is locked for writing | ||
53 | * | 54 | * |
54 | * Free @count clusters starting at the cluster @start_vcn in the runlist | 55 | * Free @count clusters starting at the cluster @start_vcn in the runlist |
55 | * described by the vfs inode @vi. | 56 | * described by the vfs inode @vi. |
@@ -64,19 +65,19 @@ extern s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, | |||
64 | * Return the number of deallocated clusters (not counting sparse ones) on | 65 | * Return the number of deallocated clusters (not counting sparse ones) on |
65 | * success and -errno on error. | 66 | * success and -errno on error. |
66 | * | 67 | * |
67 | * Locking: - The runlist described by @vi must be unlocked on entry and is | 68 | * Locking: - The runlist described by @vi must be locked on entry and is |
68 | * unlocked on return. | 69 | * locked on return. Note if the runlist is locked for reading the |
69 | * - This function takes the runlist lock of @vi for reading and | 70 | * lock may be dropped and reacquired. Note the runlist may be |
70 | * sometimes for writing and sometimes modifies the runlist. | 71 | * modified when needed runlist fragments need to be mapped. |
71 | * - The volume lcn bitmap must be unlocked on entry and is unlocked | 72 | * - The volume lcn bitmap must be unlocked on entry and is unlocked |
72 | * on return. | 73 | * on return. |
73 | * - This function takes the volume lcn bitmap lock for writing and | 74 | * - This function takes the volume lcn bitmap lock for writing and |
74 | * modifies the bitmap contents. | 75 | * modifies the bitmap contents. |
75 | */ | 76 | */ |
76 | static inline s64 ntfs_cluster_free(struct inode *vi, const VCN start_vcn, | 77 | static inline s64 ntfs_cluster_free(struct inode *vi, const VCN start_vcn, |
77 | s64 count) | 78 | s64 count, const BOOL write_locked) |
78 | { | 79 | { |
79 | return __ntfs_cluster_free(vi, start_vcn, count, FALSE); | 80 | return __ntfs_cluster_free(vi, start_vcn, count, write_locked, FALSE); |
80 | } | 81 | } |
81 | 82 | ||
82 | extern int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol, | 83 | extern int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol, |
@@ -93,8 +94,10 @@ extern int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol, | |||
93 | * | 94 | * |
94 | * Return 0 on success and -errno on error. | 95 | * Return 0 on success and -errno on error. |
95 | * | 96 | * |
96 | * Locking: This function takes the volume lcn bitmap lock for writing and | 97 | * Locking: - This function takes the volume lcn bitmap lock for writing and |
97 | * modifies the bitmap contents. | 98 | * modifies the bitmap contents. |
99 | * - The caller must have locked the runlist @rl for reading or | ||
100 | * writing. | ||
98 | */ | 101 | */ |
99 | static inline int ntfs_cluster_free_from_rl(ntfs_volume *vol, | 102 | static inline int ntfs_cluster_free_from_rl(ntfs_volume *vol, |
100 | const runlist_element *rl) | 103 | const runlist_element *rl) |
diff --git a/fs/ntfs/logfile.c b/fs/ntfs/logfile.c index 8edb8e20fb08..0173e95500d9 100644 --- a/fs/ntfs/logfile.c +++ b/fs/ntfs/logfile.c | |||
@@ -121,7 +121,7 @@ static BOOL ntfs_check_restart_page_header(struct inode *vi, | |||
121 | */ | 121 | */ |
122 | if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) { | 122 | if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) { |
123 | ntfs_error(vi->i_sb, "$LogFile restart page is not modified " | 123 | ntfs_error(vi->i_sb, "$LogFile restart page is not modified " |
124 | "chkdsk but a chkdsk LSN is specified."); | 124 | "by chkdsk but a chkdsk LSN is specified."); |
125 | return FALSE; | 125 | return FALSE; |
126 | } | 126 | } |
127 | ntfs_debug("Done."); | 127 | ntfs_debug("Done."); |
@@ -312,10 +312,12 @@ err_out: | |||
312 | * @vi: $LogFile inode to which the restart page belongs | 312 | * @vi: $LogFile inode to which the restart page belongs |
313 | * @rp: restart page to check | 313 | * @rp: restart page to check |
314 | * @pos: position in @vi at which the restart page resides | 314 | * @pos: position in @vi at which the restart page resides |
315 | * @wrp: copy of the multi sector transfer deprotected restart page | 315 | * @wrp: [OUT] copy of the multi sector transfer deprotected restart page |
316 | * @lsn: [OUT] set to the current logfile lsn on success | ||
316 | * | 317 | * |
317 | * Check the restart page @rp for consistency and return TRUE if it is | 318 | * Check the restart page @rp for consistency and return 0 if it is consistent |
318 | * consistent and FALSE otherwise. | 319 | * and -errno otherwise. The restart page may have been modified by chkdsk in |
320 | * which case its magic is CHKD instead of RSTR. | ||
319 | * | 321 | * |
320 | * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not | 322 | * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not |
321 | * require the full restart page. | 323 | * require the full restart page. |
@@ -323,25 +325,33 @@ err_out: | |||
323 | * If @wrp is not NULL, on success, *@wrp will point to a buffer containing a | 325 | * If @wrp is not NULL, on success, *@wrp will point to a buffer containing a |
324 | * copy of the complete multi sector transfer deprotected page. On failure, | 326 | * copy of the complete multi sector transfer deprotected page. On failure, |
325 | * *@wrp is undefined. | 327 | * *@wrp is undefined. |
328 | * | ||
329 | * Simillarly, if @lsn is not NULL, on succes *@lsn will be set to the current | ||
330 | * logfile lsn according to this restart page. On failure, *@lsn is undefined. | ||
331 | * | ||
332 | * The following error codes are defined: | ||
333 | * -EINVAL - The restart page is inconsistent. | ||
334 | * -ENOMEM - Not enough memory to load the restart page. | ||
335 | * -EIO - Failed to reading from $LogFile. | ||
326 | */ | 336 | */ |
327 | static BOOL ntfs_check_and_load_restart_page(struct inode *vi, | 337 | static int ntfs_check_and_load_restart_page(struct inode *vi, |
328 | RESTART_PAGE_HEADER *rp, s64 pos, RESTART_PAGE_HEADER **wrp) | 338 | RESTART_PAGE_HEADER *rp, s64 pos, RESTART_PAGE_HEADER **wrp, |
339 | LSN *lsn) | ||
329 | { | 340 | { |
330 | RESTART_AREA *ra; | 341 | RESTART_AREA *ra; |
331 | RESTART_PAGE_HEADER *trp; | 342 | RESTART_PAGE_HEADER *trp; |
332 | int size; | 343 | int size, err; |
333 | BOOL ret; | ||
334 | 344 | ||
335 | ntfs_debug("Entering."); | 345 | ntfs_debug("Entering."); |
336 | /* Check the restart page header for consistency. */ | 346 | /* Check the restart page header for consistency. */ |
337 | if (!ntfs_check_restart_page_header(vi, rp, pos)) { | 347 | if (!ntfs_check_restart_page_header(vi, rp, pos)) { |
338 | /* Error output already done inside the function. */ | 348 | /* Error output already done inside the function. */ |
339 | return FALSE; | 349 | return -EINVAL; |
340 | } | 350 | } |
341 | /* Check the restart area for consistency. */ | 351 | /* Check the restart area for consistency. */ |
342 | if (!ntfs_check_restart_area(vi, rp)) { | 352 | if (!ntfs_check_restart_area(vi, rp)) { |
343 | /* Error output already done inside the function. */ | 353 | /* Error output already done inside the function. */ |
344 | return FALSE; | 354 | return -EINVAL; |
345 | } | 355 | } |
346 | ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset)); | 356 | ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset)); |
347 | /* | 357 | /* |
@@ -352,7 +362,7 @@ static BOOL ntfs_check_and_load_restart_page(struct inode *vi, | |||
352 | if (!trp) { | 362 | if (!trp) { |
353 | ntfs_error(vi->i_sb, "Failed to allocate memory for $LogFile " | 363 | ntfs_error(vi->i_sb, "Failed to allocate memory for $LogFile " |
354 | "restart page buffer."); | 364 | "restart page buffer."); |
355 | return FALSE; | 365 | return -ENOMEM; |
356 | } | 366 | } |
357 | /* | 367 | /* |
358 | * Read the whole of the restart page into the buffer. If it fits | 368 | * Read the whole of the restart page into the buffer. If it fits |
@@ -379,6 +389,9 @@ static BOOL ntfs_check_and_load_restart_page(struct inode *vi, | |||
379 | if (IS_ERR(page)) { | 389 | if (IS_ERR(page)) { |
380 | ntfs_error(vi->i_sb, "Error mapping $LogFile " | 390 | ntfs_error(vi->i_sb, "Error mapping $LogFile " |
381 | "page (index %lu).", idx); | 391 | "page (index %lu).", idx); |
392 | err = PTR_ERR(page); | ||
393 | if (err != -EIO && err != -ENOMEM) | ||
394 | err = -EIO; | ||
382 | goto err_out; | 395 | goto err_out; |
383 | } | 396 | } |
384 | size = min_t(int, to_read, PAGE_CACHE_SIZE); | 397 | size = min_t(int, to_read, PAGE_CACHE_SIZE); |
@@ -392,29 +405,57 @@ static BOOL ntfs_check_and_load_restart_page(struct inode *vi, | |||
392 | /* Perform the multi sector transfer deprotection on the buffer. */ | 405 | /* Perform the multi sector transfer deprotection on the buffer. */ |
393 | if (post_read_mst_fixup((NTFS_RECORD*)trp, | 406 | if (post_read_mst_fixup((NTFS_RECORD*)trp, |
394 | le32_to_cpu(rp->system_page_size))) { | 407 | le32_to_cpu(rp->system_page_size))) { |
395 | ntfs_error(vi->i_sb, "Multi sector transfer error detected in " | 408 | /* |
396 | "$LogFile restart page."); | 409 | * A multi sector tranfer error was detected. We only need to |
397 | goto err_out; | 410 | * abort if the restart page contents exceed the multi sector |
411 | * transfer fixup of the first sector. | ||
412 | */ | ||
413 | if (le16_to_cpu(rp->restart_area_offset) + | ||
414 | le16_to_cpu(ra->restart_area_length) > | ||
415 | NTFS_BLOCK_SIZE - sizeof(u16)) { | ||
416 | ntfs_error(vi->i_sb, "Multi sector transfer error " | ||
417 | "detected in $LogFile restart page."); | ||
418 | err = -EINVAL; | ||
419 | goto err_out; | ||
420 | } | ||
421 | } | ||
422 | /* | ||
423 | * If the restart page is modified by chkdsk or there are no active | ||
424 | * logfile clients, the logfile is consistent. Otherwise, need to | ||
425 | * check the log client records for consistency, too. | ||
426 | */ | ||
427 | err = 0; | ||
428 | if (ntfs_is_rstr_record(rp->magic) && | ||
429 | ra->client_in_use_list != LOGFILE_NO_CLIENT) { | ||
430 | if (!ntfs_check_log_client_array(vi, trp)) { | ||
431 | err = -EINVAL; | ||
432 | goto err_out; | ||
433 | } | ||
434 | } | ||
435 | if (lsn) { | ||
436 | if (ntfs_is_rstr_record(rp->magic)) | ||
437 | *lsn = sle64_to_cpu(ra->current_lsn); | ||
438 | else /* if (ntfs_is_chkd_record(rp->magic)) */ | ||
439 | *lsn = sle64_to_cpu(rp->chkdsk_lsn); | ||
398 | } | 440 | } |
399 | /* Check the log client records for consistency. */ | ||
400 | ret = ntfs_check_log_client_array(vi, trp); | ||
401 | if (ret && wrp) | ||
402 | *wrp = trp; | ||
403 | else | ||
404 | ntfs_free(trp); | ||
405 | ntfs_debug("Done."); | 441 | ntfs_debug("Done."); |
406 | return ret; | 442 | if (wrp) |
443 | *wrp = trp; | ||
444 | else { | ||
407 | err_out: | 445 | err_out: |
408 | ntfs_free(trp); | 446 | ntfs_free(trp); |
409 | return FALSE; | 447 | } |
448 | return err; | ||
410 | } | 449 | } |
411 | 450 | ||
412 | /** | 451 | /** |
413 | * ntfs_check_logfile - check the journal for consistency | 452 | * ntfs_check_logfile - check the journal for consistency |
414 | * @log_vi: struct inode of loaded journal $LogFile to check | 453 | * @log_vi: struct inode of loaded journal $LogFile to check |
454 | * @rp: [OUT] on success this is a copy of the current restart page | ||
415 | * | 455 | * |
416 | * Check the $LogFile journal for consistency and return TRUE if it is | 456 | * Check the $LogFile journal for consistency and return TRUE if it is |
417 | * consistent and FALSE if not. | 457 | * consistent and FALSE if not. On success, the current restart page is |
458 | * returned in *@rp. Caller must call ntfs_free(*@rp) when finished with it. | ||
418 | * | 459 | * |
419 | * At present we only check the two restart pages and ignore the log record | 460 | * At present we only check the two restart pages and ignore the log record |
420 | * pages. | 461 | * pages. |
@@ -424,19 +465,18 @@ err_out: | |||
424 | * if the $LogFile was created on a system with a different page size to ours | 465 | * if the $LogFile was created on a system with a different page size to ours |
425 | * yet and mst deprotection would fail if our page size is smaller. | 466 | * yet and mst deprotection would fail if our page size is smaller. |
426 | */ | 467 | */ |
427 | BOOL ntfs_check_logfile(struct inode *log_vi) | 468 | BOOL ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp) |
428 | { | 469 | { |
429 | s64 size, pos, rstr1_pos, rstr2_pos; | 470 | s64 size, pos; |
471 | LSN rstr1_lsn, rstr2_lsn; | ||
430 | ntfs_volume *vol = NTFS_SB(log_vi->i_sb); | 472 | ntfs_volume *vol = NTFS_SB(log_vi->i_sb); |
431 | struct address_space *mapping = log_vi->i_mapping; | 473 | struct address_space *mapping = log_vi->i_mapping; |
432 | struct page *page = NULL; | 474 | struct page *page = NULL; |
433 | u8 *kaddr = NULL; | 475 | u8 *kaddr = NULL; |
434 | RESTART_PAGE_HEADER *rstr1_ph = NULL; | 476 | RESTART_PAGE_HEADER *rstr1_ph = NULL; |
435 | RESTART_PAGE_HEADER *rstr2_ph = NULL; | 477 | RESTART_PAGE_HEADER *rstr2_ph = NULL; |
436 | int log_page_size, log_page_mask, ofs; | 478 | int log_page_size, log_page_mask, err; |
437 | BOOL logfile_is_empty = TRUE; | 479 | BOOL logfile_is_empty = TRUE; |
438 | BOOL rstr1_found = FALSE; | ||
439 | BOOL rstr2_found = FALSE; | ||
440 | u8 log_page_bits; | 480 | u8 log_page_bits; |
441 | 481 | ||
442 | ntfs_debug("Entering."); | 482 | ntfs_debug("Entering."); |
@@ -491,7 +531,7 @@ BOOL ntfs_check_logfile(struct inode *log_vi) | |||
491 | if (IS_ERR(page)) { | 531 | if (IS_ERR(page)) { |
492 | ntfs_error(vol->sb, "Error mapping $LogFile " | 532 | ntfs_error(vol->sb, "Error mapping $LogFile " |
493 | "page (index %lu).", idx); | 533 | "page (index %lu).", idx); |
494 | return FALSE; | 534 | goto err_out; |
495 | } | 535 | } |
496 | } | 536 | } |
497 | kaddr = (u8*)page_address(page) + (pos & ~PAGE_CACHE_MASK); | 537 | kaddr = (u8*)page_address(page) + (pos & ~PAGE_CACHE_MASK); |
@@ -510,99 +550,95 @@ BOOL ntfs_check_logfile(struct inode *log_vi) | |||
510 | */ | 550 | */ |
511 | if (ntfs_is_rcrd_recordp((le32*)kaddr)) | 551 | if (ntfs_is_rcrd_recordp((le32*)kaddr)) |
512 | break; | 552 | break; |
513 | /* | 553 | /* If not a (modified by chkdsk) restart page, continue. */ |
514 | * A modified by chkdsk restart page means we cannot handle | 554 | if (!ntfs_is_rstr_recordp((le32*)kaddr) && |
515 | * this log file. | 555 | !ntfs_is_chkd_recordp((le32*)kaddr)) { |
516 | */ | ||
517 | if (ntfs_is_chkd_recordp((le32*)kaddr)) { | ||
518 | ntfs_error(vol->sb, "$LogFile has been modified by " | ||
519 | "chkdsk. Mount this volume in " | ||
520 | "Windows."); | ||
521 | goto err_out; | ||
522 | } | ||
523 | /* If not a restart page, continue. */ | ||
524 | if (!ntfs_is_rstr_recordp((le32*)kaddr)) { | ||
525 | /* Skip to the minimum page size for the next one. */ | ||
526 | if (!pos) | 556 | if (!pos) |
527 | pos = NTFS_BLOCK_SIZE >> 1; | 557 | pos = NTFS_BLOCK_SIZE >> 1; |
528 | continue; | 558 | continue; |
529 | } | 559 | } |
530 | /* We now know we have a restart page. */ | ||
531 | if (!pos) { | ||
532 | rstr1_found = TRUE; | ||
533 | rstr1_pos = pos; | ||
534 | } else { | ||
535 | if (rstr2_found) { | ||
536 | ntfs_error(vol->sb, "Found more than two " | ||
537 | "restart pages in $LogFile."); | ||
538 | goto err_out; | ||
539 | } | ||
540 | rstr2_found = TRUE; | ||
541 | rstr2_pos = pos; | ||
542 | } | ||
543 | /* | 560 | /* |
544 | * Check the restart page for consistency and get a copy of the | 561 | * Check the (modified by chkdsk) restart page for consistency |
545 | * complete multi sector transfer deprotected restart page. | 562 | * and get a copy of the complete multi sector transfer |
563 | * deprotected restart page. | ||
546 | */ | 564 | */ |
547 | if (!ntfs_check_and_load_restart_page(log_vi, | 565 | err = ntfs_check_and_load_restart_page(log_vi, |
548 | (RESTART_PAGE_HEADER*)kaddr, pos, | 566 | (RESTART_PAGE_HEADER*)kaddr, pos, |
549 | !pos ? &rstr1_ph : &rstr2_ph)) { | 567 | !rstr1_ph ? &rstr1_ph : &rstr2_ph, |
550 | /* Error output already done inside the function. */ | 568 | !rstr1_ph ? &rstr1_lsn : &rstr2_lsn); |
551 | goto err_out; | 569 | if (!err) { |
570 | /* | ||
571 | * If we have now found the first (modified by chkdsk) | ||
572 | * restart page, continue looking for the second one. | ||
573 | */ | ||
574 | if (!pos) { | ||
575 | pos = NTFS_BLOCK_SIZE >> 1; | ||
576 | continue; | ||
577 | } | ||
578 | /* | ||
579 | * We have now found the second (modified by chkdsk) | ||
580 | * restart page, so we can stop looking. | ||
581 | */ | ||
582 | break; | ||
552 | } | 583 | } |
553 | /* | 584 | /* |
554 | * We have a valid restart page. The next one must be after | 585 | * Error output already done inside the function. Note, we do |
555 | * a whole system page size as specified by the valid restart | 586 | * not abort if the restart page was invalid as we might still |
556 | * page. | 587 | * find a valid one further in the file. |
557 | */ | 588 | */ |
589 | if (err != -EINVAL) { | ||
590 | ntfs_unmap_page(page); | ||
591 | goto err_out; | ||
592 | } | ||
593 | /* Continue looking. */ | ||
558 | if (!pos) | 594 | if (!pos) |
559 | pos = le32_to_cpu(rstr1_ph->system_page_size) >> 1; | 595 | pos = NTFS_BLOCK_SIZE >> 1; |
560 | } | 596 | } |
561 | if (page) { | 597 | if (page) |
562 | ntfs_unmap_page(page); | 598 | ntfs_unmap_page(page); |
563 | page = NULL; | ||
564 | } | ||
565 | if (logfile_is_empty) { | 599 | if (logfile_is_empty) { |
566 | NVolSetLogFileEmpty(vol); | 600 | NVolSetLogFileEmpty(vol); |
567 | is_empty: | 601 | is_empty: |
568 | ntfs_debug("Done. ($LogFile is empty.)"); | 602 | ntfs_debug("Done. ($LogFile is empty.)"); |
569 | return TRUE; | 603 | return TRUE; |
570 | } | 604 | } |
571 | if (!rstr1_found || !rstr2_found) { | 605 | if (!rstr1_ph) { |
572 | ntfs_error(vol->sb, "Did not find two restart pages in " | 606 | BUG_ON(rstr2_ph); |
573 | "$LogFile."); | 607 | ntfs_error(vol->sb, "Did not find any restart pages in " |
574 | goto err_out; | 608 | "$LogFile and it was not empty."); |
609 | return FALSE; | ||
610 | } | ||
611 | /* If both restart pages were found, use the more recent one. */ | ||
612 | if (rstr2_ph) { | ||
613 | /* | ||
614 | * If the second restart area is more recent, switch to it. | ||
615 | * Otherwise just throw it away. | ||
616 | */ | ||
617 | if (rstr2_lsn > rstr1_lsn) { | ||
618 | ntfs_free(rstr1_ph); | ||
619 | rstr1_ph = rstr2_ph; | ||
620 | /* rstr1_lsn = rstr2_lsn; */ | ||
621 | } else | ||
622 | ntfs_free(rstr2_ph); | ||
623 | rstr2_ph = NULL; | ||
575 | } | 624 | } |
576 | /* | ||
577 | * The two restart areas must be identical except for the update | ||
578 | * sequence number. | ||
579 | */ | ||
580 | ofs = le16_to_cpu(rstr1_ph->usa_ofs); | ||
581 | if (memcmp(rstr1_ph, rstr2_ph, ofs) || (ofs += sizeof(u16), | ||
582 | memcmp((u8*)rstr1_ph + ofs, (u8*)rstr2_ph + ofs, | ||
583 | le32_to_cpu(rstr1_ph->system_page_size) - ofs))) { | ||
584 | ntfs_error(vol->sb, "The two restart pages in $LogFile do not " | ||
585 | "match."); | ||
586 | goto err_out; | ||
587 | } | ||
588 | ntfs_free(rstr1_ph); | ||
589 | ntfs_free(rstr2_ph); | ||
590 | /* All consistency checks passed. */ | 625 | /* All consistency checks passed. */ |
626 | if (rp) | ||
627 | *rp = rstr1_ph; | ||
628 | else | ||
629 | ntfs_free(rstr1_ph); | ||
591 | ntfs_debug("Done."); | 630 | ntfs_debug("Done."); |
592 | return TRUE; | 631 | return TRUE; |
593 | err_out: | 632 | err_out: |
594 | if (page) | ||
595 | ntfs_unmap_page(page); | ||
596 | if (rstr1_ph) | 633 | if (rstr1_ph) |
597 | ntfs_free(rstr1_ph); | 634 | ntfs_free(rstr1_ph); |
598 | if (rstr2_ph) | ||
599 | ntfs_free(rstr2_ph); | ||
600 | return FALSE; | 635 | return FALSE; |
601 | } | 636 | } |
602 | 637 | ||
603 | /** | 638 | /** |
604 | * ntfs_is_logfile_clean - check in the journal if the volume is clean | 639 | * ntfs_is_logfile_clean - check in the journal if the volume is clean |
605 | * @log_vi: struct inode of loaded journal $LogFile to check | 640 | * @log_vi: struct inode of loaded journal $LogFile to check |
641 | * @rp: copy of the current restart page | ||
606 | * | 642 | * |
607 | * Analyze the $LogFile journal and return TRUE if it indicates the volume was | 643 | * Analyze the $LogFile journal and return TRUE if it indicates the volume was |
608 | * shutdown cleanly and FALSE if not. | 644 | * shutdown cleanly and FALSE if not. |
@@ -619,11 +655,9 @@ err_out: | |||
619 | * is empty this function requires that NVolLogFileEmpty() is true otherwise an | 655 | * is empty this function requires that NVolLogFileEmpty() is true otherwise an |
620 | * empty volume will be reported as dirty. | 656 | * empty volume will be reported as dirty. |
621 | */ | 657 | */ |
622 | BOOL ntfs_is_logfile_clean(struct inode *log_vi) | 658 | BOOL ntfs_is_logfile_clean(struct inode *log_vi, const RESTART_PAGE_HEADER *rp) |
623 | { | 659 | { |
624 | ntfs_volume *vol = NTFS_SB(log_vi->i_sb); | 660 | ntfs_volume *vol = NTFS_SB(log_vi->i_sb); |
625 | struct page *page; | ||
626 | RESTART_PAGE_HEADER *rp; | ||
627 | RESTART_AREA *ra; | 661 | RESTART_AREA *ra; |
628 | 662 | ||
629 | ntfs_debug("Entering."); | 663 | ntfs_debug("Entering."); |
@@ -632,24 +666,15 @@ BOOL ntfs_is_logfile_clean(struct inode *log_vi) | |||
632 | ntfs_debug("Done. ($LogFile is empty.)"); | 666 | ntfs_debug("Done. ($LogFile is empty.)"); |
633 | return TRUE; | 667 | return TRUE; |
634 | } | 668 | } |
635 | /* | 669 | BUG_ON(!rp); |
636 | * Read the first restart page. It will be possibly incomplete and | 670 | if (!ntfs_is_rstr_record(rp->magic) && |
637 | * will not be multi sector transfer deprotected but we only need the | 671 | !ntfs_is_chkd_record(rp->magic)) { |
638 | * first NTFS_BLOCK_SIZE bytes so it does not matter. | 672 | ntfs_error(vol->sb, "Restart page buffer is invalid. This is " |
639 | */ | 673 | "probably a bug in that the $LogFile should " |
640 | page = ntfs_map_page(log_vi->i_mapping, 0); | 674 | "have been consistency checked before calling " |
641 | if (IS_ERR(page)) { | 675 | "this function."); |
642 | ntfs_error(vol->sb, "Error mapping $LogFile page (index 0)."); | ||
643 | return FALSE; | 676 | return FALSE; |
644 | } | 677 | } |
645 | rp = (RESTART_PAGE_HEADER*)page_address(page); | ||
646 | if (!ntfs_is_rstr_record(rp->magic)) { | ||
647 | ntfs_error(vol->sb, "No restart page found at offset zero in " | ||
648 | "$LogFile. This is probably a bug in that " | ||
649 | "the $LogFile should have been consistency " | ||
650 | "checked before calling this function."); | ||
651 | goto err_out; | ||
652 | } | ||
653 | ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset)); | 678 | ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset)); |
654 | /* | 679 | /* |
655 | * If the $LogFile has active clients, i.e. it is open, and we do not | 680 | * If the $LogFile has active clients, i.e. it is open, and we do not |
@@ -659,15 +684,11 @@ BOOL ntfs_is_logfile_clean(struct inode *log_vi) | |||
659 | if (ra->client_in_use_list != LOGFILE_NO_CLIENT && | 684 | if (ra->client_in_use_list != LOGFILE_NO_CLIENT && |
660 | !(ra->flags & RESTART_VOLUME_IS_CLEAN)) { | 685 | !(ra->flags & RESTART_VOLUME_IS_CLEAN)) { |
661 | ntfs_debug("Done. $LogFile indicates a dirty shutdown."); | 686 | ntfs_debug("Done. $LogFile indicates a dirty shutdown."); |
662 | goto err_out; | 687 | return FALSE; |
663 | } | 688 | } |
664 | ntfs_unmap_page(page); | ||
665 | /* $LogFile indicates a clean shutdown. */ | 689 | /* $LogFile indicates a clean shutdown. */ |
666 | ntfs_debug("Done. $LogFile indicates a clean shutdown."); | 690 | ntfs_debug("Done. $LogFile indicates a clean shutdown."); |
667 | return TRUE; | 691 | return TRUE; |
668 | err_out: | ||
669 | ntfs_unmap_page(page); | ||
670 | return FALSE; | ||
671 | } | 692 | } |
672 | 693 | ||
673 | /** | 694 | /** |
diff --git a/fs/ntfs/logfile.h b/fs/ntfs/logfile.h index 4ee4378de061..42388f95ea6d 100644 --- a/fs/ntfs/logfile.h +++ b/fs/ntfs/logfile.h | |||
@@ -2,7 +2,7 @@ | |||
2 | * logfile.h - Defines for NTFS kernel journal ($LogFile) handling. Part of | 2 | * logfile.h - Defines for NTFS kernel journal ($LogFile) handling. Part of |
3 | * the Linux-NTFS project. | 3 | * the Linux-NTFS project. |
4 | * | 4 | * |
5 | * Copyright (c) 2000-2004 Anton Altaparmakov | 5 | * Copyright (c) 2000-2005 Anton Altaparmakov |
6 | * | 6 | * |
7 | * This program/include file is free software; you can redistribute it and/or | 7 | * This program/include file is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License as published | 8 | * modify it under the terms of the GNU General Public License as published |
@@ -296,9 +296,11 @@ typedef struct { | |||
296 | /* sizeof() = 160 (0xa0) bytes */ | 296 | /* sizeof() = 160 (0xa0) bytes */ |
297 | } __attribute__ ((__packed__)) LOG_CLIENT_RECORD; | 297 | } __attribute__ ((__packed__)) LOG_CLIENT_RECORD; |
298 | 298 | ||
299 | extern BOOL ntfs_check_logfile(struct inode *log_vi); | 299 | extern BOOL ntfs_check_logfile(struct inode *log_vi, |
300 | RESTART_PAGE_HEADER **rp); | ||
300 | 301 | ||
301 | extern BOOL ntfs_is_logfile_clean(struct inode *log_vi); | 302 | extern BOOL ntfs_is_logfile_clean(struct inode *log_vi, |
303 | const RESTART_PAGE_HEADER *rp); | ||
302 | 304 | ||
303 | extern BOOL ntfs_empty_logfile(struct inode *log_vi); | 305 | extern BOOL ntfs_empty_logfile(struct inode *log_vi); |
304 | 306 | ||
diff --git a/fs/ntfs/malloc.h b/fs/ntfs/malloc.h index fac5944df6d8..9994e019a3cf 100644 --- a/fs/ntfs/malloc.h +++ b/fs/ntfs/malloc.h | |||
@@ -27,27 +27,63 @@ | |||
27 | #include <linux/highmem.h> | 27 | #include <linux/highmem.h> |
28 | 28 | ||
29 | /** | 29 | /** |
30 | * ntfs_malloc_nofs - allocate memory in multiples of pages | 30 | * __ntfs_malloc - allocate memory in multiples of pages |
31 | * @size number of bytes to allocate | 31 | * @size: number of bytes to allocate |
32 | * @gfp_mask: extra flags for the allocator | ||
33 | * | ||
34 | * Internal function. You probably want ntfs_malloc_nofs()... | ||
32 | * | 35 | * |
33 | * Allocates @size bytes of memory, rounded up to multiples of PAGE_SIZE and | 36 | * Allocates @size bytes of memory, rounded up to multiples of PAGE_SIZE and |
34 | * returns a pointer to the allocated memory. | 37 | * returns a pointer to the allocated memory. |
35 | * | 38 | * |
36 | * If there was insufficient memory to complete the request, return NULL. | 39 | * If there was insufficient memory to complete the request, return NULL. |
40 | * Depending on @gfp_mask the allocation may be guaranteed to succeed. | ||
37 | */ | 41 | */ |
38 | static inline void *ntfs_malloc_nofs(unsigned long size) | 42 | static inline void *__ntfs_malloc(unsigned long size, |
43 | unsigned int __nocast gfp_mask) | ||
39 | { | 44 | { |
40 | if (likely(size <= PAGE_SIZE)) { | 45 | if (likely(size <= PAGE_SIZE)) { |
41 | BUG_ON(!size); | 46 | BUG_ON(!size); |
42 | /* kmalloc() has per-CPU caches so is faster for now. */ | 47 | /* kmalloc() has per-CPU caches so is faster for now. */ |
43 | return kmalloc(PAGE_SIZE, GFP_NOFS); | 48 | return kmalloc(PAGE_SIZE, gfp_mask); |
44 | /* return (void *)__get_free_page(GFP_NOFS | __GFP_HIGHMEM); */ | 49 | /* return (void *)__get_free_page(gfp_mask); */ |
45 | } | 50 | } |
46 | if (likely(size >> PAGE_SHIFT < num_physpages)) | 51 | if (likely(size >> PAGE_SHIFT < num_physpages)) |
47 | return __vmalloc(size, GFP_NOFS | __GFP_HIGHMEM, PAGE_KERNEL); | 52 | return __vmalloc(size, gfp_mask, PAGE_KERNEL); |
48 | return NULL; | 53 | return NULL; |
49 | } | 54 | } |
50 | 55 | ||
56 | /** | ||
57 | * ntfs_malloc_nofs - allocate memory in multiples of pages | ||
58 | * @size: number of bytes to allocate | ||
59 | * | ||
60 | * Allocates @size bytes of memory, rounded up to multiples of PAGE_SIZE and | ||
61 | * returns a pointer to the allocated memory. | ||
62 | * | ||
63 | * If there was insufficient memory to complete the request, return NULL. | ||
64 | */ | ||
65 | static inline void *ntfs_malloc_nofs(unsigned long size) | ||
66 | { | ||
67 | return __ntfs_malloc(size, GFP_NOFS | __GFP_HIGHMEM); | ||
68 | } | ||
69 | |||
70 | /** | ||
71 | * ntfs_malloc_nofs_nofail - allocate memory in multiples of pages | ||
72 | * @size: number of bytes to allocate | ||
73 | * | ||
74 | * Allocates @size bytes of memory, rounded up to multiples of PAGE_SIZE and | ||
75 | * returns a pointer to the allocated memory. | ||
76 | * | ||
77 | * This function guarantees that the allocation will succeed. It will sleep | ||
78 | * for as long as it takes to complete the allocation. | ||
79 | * | ||
80 | * If there was insufficient memory to complete the request, return NULL. | ||
81 | */ | ||
82 | static inline void *ntfs_malloc_nofs_nofail(unsigned long size) | ||
83 | { | ||
84 | return __ntfs_malloc(size, GFP_NOFS | __GFP_HIGHMEM | __GFP_NOFAIL); | ||
85 | } | ||
86 | |||
51 | static inline void ntfs_free(void *addr) | 87 | static inline void ntfs_free(void *addr) |
52 | { | 88 | { |
53 | if (likely(((unsigned long)addr < VMALLOC_START) || | 89 | if (likely(((unsigned long)addr < VMALLOC_START) || |
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index 317f7c679fd3..2c32b84385a8 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c | |||
@@ -511,7 +511,6 @@ int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no, | |||
511 | } while (bh); | 511 | } while (bh); |
512 | tail->b_this_page = head; | 512 | tail->b_this_page = head; |
513 | attach_page_buffers(page, head); | 513 | attach_page_buffers(page, head); |
514 | BUG_ON(!page_has_buffers(page)); | ||
515 | } | 514 | } |
516 | bh = head = page_buffers(page); | 515 | bh = head = page_buffers(page); |
517 | BUG_ON(!bh); | 516 | BUG_ON(!bh); |
@@ -692,7 +691,6 @@ int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync) | |||
692 | */ | 691 | */ |
693 | if (!NInoTestClearDirty(ni)) | 692 | if (!NInoTestClearDirty(ni)) |
694 | goto done; | 693 | goto done; |
695 | BUG_ON(!page_has_buffers(page)); | ||
696 | bh = head = page_buffers(page); | 694 | bh = head = page_buffers(page); |
697 | BUG_ON(!bh); | 695 | BUG_ON(!bh); |
698 | rl = NULL; | 696 | rl = NULL; |
@@ -1955,7 +1953,7 @@ restore_undo_alloc: | |||
1955 | a = ctx->attr; | 1953 | a = ctx->attr; |
1956 | a->data.non_resident.highest_vcn = cpu_to_sle64(old_last_vcn - 1); | 1954 | a->data.non_resident.highest_vcn = cpu_to_sle64(old_last_vcn - 1); |
1957 | undo_alloc: | 1955 | undo_alloc: |
1958 | if (ntfs_cluster_free(vol->mft_ino, old_last_vcn, -1) < 0) { | 1956 | if (ntfs_cluster_free(vol->mft_ino, old_last_vcn, -1, TRUE) < 0) { |
1959 | ntfs_error(vol->sb, "Failed to free clusters from mft data " | 1957 | ntfs_error(vol->sb, "Failed to free clusters from mft data " |
1960 | "attribute.%s", es); | 1958 | "attribute.%s", es); |
1961 | NVolSetErrors(vol); | 1959 | NVolSetErrors(vol); |
diff --git a/fs/ntfs/runlist.c b/fs/ntfs/runlist.c index 758855b0414e..f5b2ac929081 100644 --- a/fs/ntfs/runlist.c +++ b/fs/ntfs/runlist.c | |||
@@ -35,7 +35,7 @@ static inline void ntfs_rl_mm(runlist_element *base, int dst, int src, | |||
35 | int size) | 35 | int size) |
36 | { | 36 | { |
37 | if (likely((dst != src) && (size > 0))) | 37 | if (likely((dst != src) && (size > 0))) |
38 | memmove(base + dst, base + src, size * sizeof (*base)); | 38 | memmove(base + dst, base + src, size * sizeof(*base)); |
39 | } | 39 | } |
40 | 40 | ||
41 | /** | 41 | /** |
@@ -95,6 +95,51 @@ static inline runlist_element *ntfs_rl_realloc(runlist_element *rl, | |||
95 | } | 95 | } |
96 | 96 | ||
97 | /** | 97 | /** |
98 | * ntfs_rl_realloc_nofail - Reallocate memory for runlists | ||
99 | * @rl: original runlist | ||
100 | * @old_size: number of runlist elements in the original runlist @rl | ||
101 | * @new_size: number of runlist elements we need space for | ||
102 | * | ||
103 | * As the runlists grow, more memory will be required. To prevent the | ||
104 | * kernel having to allocate and reallocate large numbers of small bits of | ||
105 | * memory, this function returns an entire page of memory. | ||
106 | * | ||
107 | * This function guarantees that the allocation will succeed. It will sleep | ||
108 | * for as long as it takes to complete the allocation. | ||
109 | * | ||
110 | * It is up to the caller to serialize access to the runlist @rl. | ||
111 | * | ||
112 | * N.B. If the new allocation doesn't require a different number of pages in | ||
113 | * memory, the function will return the original pointer. | ||
114 | * | ||
115 | * On success, return a pointer to the newly allocated, or recycled, memory. | ||
116 | * On error, return -errno. The following error codes are defined: | ||
117 | * -ENOMEM - Not enough memory to allocate runlist array. | ||
118 | * -EINVAL - Invalid parameters were passed in. | ||
119 | */ | ||
120 | static inline runlist_element *ntfs_rl_realloc_nofail(runlist_element *rl, | ||
121 | int old_size, int new_size) | ||
122 | { | ||
123 | runlist_element *new_rl; | ||
124 | |||
125 | old_size = PAGE_ALIGN(old_size * sizeof(*rl)); | ||
126 | new_size = PAGE_ALIGN(new_size * sizeof(*rl)); | ||
127 | if (old_size == new_size) | ||
128 | return rl; | ||
129 | |||
130 | new_rl = ntfs_malloc_nofs_nofail(new_size); | ||
131 | BUG_ON(!new_rl); | ||
132 | |||
133 | if (likely(rl != NULL)) { | ||
134 | if (unlikely(old_size > new_size)) | ||
135 | old_size = new_size; | ||
136 | memcpy(new_rl, rl, old_size); | ||
137 | ntfs_free(rl); | ||
138 | } | ||
139 | return new_rl; | ||
140 | } | ||
141 | |||
142 | /** | ||
98 | * ntfs_are_rl_mergeable - test if two runlists can be joined together | 143 | * ntfs_are_rl_mergeable - test if two runlists can be joined together |
99 | * @dst: original runlist | 144 | * @dst: original runlist |
100 | * @src: new runlist to test for mergeability with @dst | 145 | * @src: new runlist to test for mergeability with @dst |
@@ -497,6 +542,7 @@ runlist_element *ntfs_runlists_merge(runlist_element *drl, | |||
497 | /* Scan to the end of the source runlist. */ | 542 | /* Scan to the end of the source runlist. */ |
498 | for (dend = 0; likely(drl[dend].length); dend++) | 543 | for (dend = 0; likely(drl[dend].length); dend++) |
499 | ; | 544 | ; |
545 | dend++; | ||
500 | drl = ntfs_rl_realloc(drl, dend, dend + 1); | 546 | drl = ntfs_rl_realloc(drl, dend, dend + 1); |
501 | if (IS_ERR(drl)) | 547 | if (IS_ERR(drl)) |
502 | return drl; | 548 | return drl; |
@@ -566,8 +612,8 @@ runlist_element *ntfs_runlists_merge(runlist_element *drl, | |||
566 | ((drl[dins].vcn + drl[dins].length) <= /* End of hole */ | 612 | ((drl[dins].vcn + drl[dins].length) <= /* End of hole */ |
567 | (srl[send - 1].vcn + srl[send - 1].length))); | 613 | (srl[send - 1].vcn + srl[send - 1].length))); |
568 | 614 | ||
569 | /* Or we'll lose an end marker */ | 615 | /* Or we will lose an end marker. */ |
570 | if (start && finish && (drl[dins].length == 0)) | 616 | if (finish && !drl[dins].length) |
571 | ss++; | 617 | ss++; |
572 | if (marker && (drl[dins].vcn + drl[dins].length > srl[send - 1].vcn)) | 618 | if (marker && (drl[dins].vcn + drl[dins].length > srl[send - 1].vcn)) |
573 | finish = FALSE; | 619 | finish = FALSE; |
@@ -621,11 +667,8 @@ runlist_element *ntfs_runlists_merge(runlist_element *drl, | |||
621 | if (drl[ds].lcn != LCN_RL_NOT_MAPPED) { | 667 | if (drl[ds].lcn != LCN_RL_NOT_MAPPED) { |
622 | /* Add an unmapped runlist element. */ | 668 | /* Add an unmapped runlist element. */ |
623 | if (!slots) { | 669 | if (!slots) { |
624 | /* FIXME/TODO: We need to have the | 670 | drl = ntfs_rl_realloc_nofail(drl, ds, |
625 | * extra memory already! (AIA) */ | 671 | ds + 2); |
626 | drl = ntfs_rl_realloc(drl, ds, ds + 2); | ||
627 | if (!drl) | ||
628 | goto critical_error; | ||
629 | slots = 2; | 672 | slots = 2; |
630 | } | 673 | } |
631 | ds++; | 674 | ds++; |
@@ -640,13 +683,8 @@ runlist_element *ntfs_runlists_merge(runlist_element *drl, | |||
640 | drl[ds].length = marker_vcn - drl[ds].vcn; | 683 | drl[ds].length = marker_vcn - drl[ds].vcn; |
641 | /* Finally add the ENOENT terminator. */ | 684 | /* Finally add the ENOENT terminator. */ |
642 | ds++; | 685 | ds++; |
643 | if (!slots) { | 686 | if (!slots) |
644 | /* FIXME/TODO: We need to have the extra | 687 | drl = ntfs_rl_realloc_nofail(drl, ds, ds + 1); |
645 | * memory already! (AIA) */ | ||
646 | drl = ntfs_rl_realloc(drl, ds, ds + 1); | ||
647 | if (!drl) | ||
648 | goto critical_error; | ||
649 | } | ||
650 | drl[ds].vcn = marker_vcn; | 688 | drl[ds].vcn = marker_vcn; |
651 | drl[ds].lcn = LCN_ENOENT; | 689 | drl[ds].lcn = LCN_ENOENT; |
652 | drl[ds].length = (s64)0; | 690 | drl[ds].length = (s64)0; |
@@ -659,11 +697,6 @@ finished: | |||
659 | ntfs_debug("Merged runlist:"); | 697 | ntfs_debug("Merged runlist:"); |
660 | ntfs_debug_dump_runlist(drl); | 698 | ntfs_debug_dump_runlist(drl); |
661 | return drl; | 699 | return drl; |
662 | |||
663 | critical_error: | ||
664 | /* Critical error! We cannot afford to fail here. */ | ||
665 | ntfs_error(NULL, "Critical error! Not enough memory."); | ||
666 | panic("NTFS: Cannot continue."); | ||
667 | } | 700 | } |
668 | 701 | ||
669 | /** | 702 | /** |
@@ -727,6 +760,9 @@ runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol, | |||
727 | ntfs_error(vol->sb, "Corrupt attribute."); | 760 | ntfs_error(vol->sb, "Corrupt attribute."); |
728 | return ERR_PTR(-EIO); | 761 | return ERR_PTR(-EIO); |
729 | } | 762 | } |
763 | /* If the mapping pairs array is valid but empty, nothing to do. */ | ||
764 | if (!vcn && !*buf) | ||
765 | return old_rl; | ||
730 | /* Current position in runlist array. */ | 766 | /* Current position in runlist array. */ |
731 | rlpos = 0; | 767 | rlpos = 0; |
732 | /* Allocate first page and set current runlist size to one page. */ | 768 | /* Allocate first page and set current runlist size to one page. */ |
@@ -1419,6 +1455,7 @@ err_out: | |||
1419 | 1455 | ||
1420 | /** | 1456 | /** |
1421 | * ntfs_rl_truncate_nolock - truncate a runlist starting at a specified vcn | 1457 | * ntfs_rl_truncate_nolock - truncate a runlist starting at a specified vcn |
1458 | * @vol: ntfs volume (needed for error output) | ||
1422 | * @runlist: runlist to truncate | 1459 | * @runlist: runlist to truncate |
1423 | * @new_length: the new length of the runlist in VCNs | 1460 | * @new_length: the new length of the runlist in VCNs |
1424 | * | 1461 | * |
@@ -1426,12 +1463,16 @@ err_out: | |||
1426 | * holding the runlist elements to a length of @new_length VCNs. | 1463 | * holding the runlist elements to a length of @new_length VCNs. |
1427 | * | 1464 | * |
1428 | * If @new_length lies within the runlist, the runlist elements with VCNs of | 1465 | * If @new_length lies within the runlist, the runlist elements with VCNs of |
1429 | * @new_length and above are discarded. | 1466 | * @new_length and above are discarded. As a special case if @new_length is |
1467 | * zero, the runlist is discarded and set to NULL. | ||
1430 | * | 1468 | * |
1431 | * If @new_length lies beyond the runlist, a sparse runlist element is added to | 1469 | * If @new_length lies beyond the runlist, a sparse runlist element is added to |
1432 | * the end of the runlist @runlist or if the last runlist element is a sparse | 1470 | * the end of the runlist @runlist or if the last runlist element is a sparse |
1433 | * one already, this is extended. | 1471 | * one already, this is extended. |
1434 | * | 1472 | * |
1473 | * Note, no checking is done for unmapped runlist elements. It is assumed that | ||
1474 | * the caller has mapped any elements that need to be mapped already. | ||
1475 | * | ||
1435 | * Return 0 on success and -errno on error. | 1476 | * Return 0 on success and -errno on error. |
1436 | * | 1477 | * |
1437 | * Locking: The caller must hold @runlist->lock for writing. | 1478 | * Locking: The caller must hold @runlist->lock for writing. |
@@ -1446,6 +1487,13 @@ int ntfs_rl_truncate_nolock(const ntfs_volume *vol, runlist *const runlist, | |||
1446 | BUG_ON(!runlist); | 1487 | BUG_ON(!runlist); |
1447 | BUG_ON(new_length < 0); | 1488 | BUG_ON(new_length < 0); |
1448 | rl = runlist->rl; | 1489 | rl = runlist->rl; |
1490 | if (!new_length) { | ||
1491 | ntfs_debug("Freeing runlist."); | ||
1492 | runlist->rl = NULL; | ||
1493 | if (rl) | ||
1494 | ntfs_free(rl); | ||
1495 | return 0; | ||
1496 | } | ||
1449 | if (unlikely(!rl)) { | 1497 | if (unlikely(!rl)) { |
1450 | /* | 1498 | /* |
1451 | * Create a runlist consisting of a sparse runlist element of | 1499 | * Create a runlist consisting of a sparse runlist element of |
@@ -1553,4 +1601,288 @@ int ntfs_rl_truncate_nolock(const ntfs_volume *vol, runlist *const runlist, | |||
1553 | return 0; | 1601 | return 0; |
1554 | } | 1602 | } |
1555 | 1603 | ||
1604 | /** | ||
1605 | * ntfs_rl_punch_nolock - punch a hole into a runlist | ||
1606 | * @vol: ntfs volume (needed for error output) | ||
1607 | * @runlist: runlist to punch a hole into | ||
1608 | * @start: starting VCN of the hole to be created | ||
1609 | * @length: size of the hole to be created in units of clusters | ||
1610 | * | ||
1611 | * Punch a hole into the runlist @runlist starting at VCN @start and of size | ||
1612 | * @length clusters. | ||
1613 | * | ||
1614 | * Return 0 on success and -errno on error, in which case @runlist has not been | ||
1615 | * modified. | ||
1616 | * | ||
1617 | * If @start and/or @start + @length are outside the runlist return error code | ||
1618 | * -ENOENT. | ||
1619 | * | ||
1620 | * If the runlist contains unmapped or error elements between @start and @start | ||
1621 | * + @length return error code -EINVAL. | ||
1622 | * | ||
1623 | * Locking: The caller must hold @runlist->lock for writing. | ||
1624 | */ | ||
1625 | int ntfs_rl_punch_nolock(const ntfs_volume *vol, runlist *const runlist, | ||
1626 | const VCN start, const s64 length) | ||
1627 | { | ||
1628 | const VCN end = start + length; | ||
1629 | s64 delta; | ||
1630 | runlist_element *rl, *rl_end, *rl_real_end, *trl; | ||
1631 | int old_size; | ||
1632 | BOOL lcn_fixup = FALSE; | ||
1633 | |||
1634 | ntfs_debug("Entering for start 0x%llx, length 0x%llx.", | ||
1635 | (long long)start, (long long)length); | ||
1636 | BUG_ON(!runlist); | ||
1637 | BUG_ON(start < 0); | ||
1638 | BUG_ON(length < 0); | ||
1639 | BUG_ON(end < 0); | ||
1640 | rl = runlist->rl; | ||
1641 | if (unlikely(!rl)) { | ||
1642 | if (likely(!start && !length)) | ||
1643 | return 0; | ||
1644 | return -ENOENT; | ||
1645 | } | ||
1646 | /* Find @start in the runlist. */ | ||
1647 | while (likely(rl->length && start >= rl[1].vcn)) | ||
1648 | rl++; | ||
1649 | rl_end = rl; | ||
1650 | /* Find @end in the runlist. */ | ||
1651 | while (likely(rl_end->length && end >= rl_end[1].vcn)) { | ||
1652 | /* Verify there are no unmapped or error elements. */ | ||
1653 | if (unlikely(rl_end->lcn < LCN_HOLE)) | ||
1654 | return -EINVAL; | ||
1655 | rl_end++; | ||
1656 | } | ||
1657 | /* Check the last element. */ | ||
1658 | if (unlikely(rl_end->length && rl_end->lcn < LCN_HOLE)) | ||
1659 | return -EINVAL; | ||
1660 | /* This covers @start being out of bounds, too. */ | ||
1661 | if (!rl_end->length && end > rl_end->vcn) | ||
1662 | return -ENOENT; | ||
1663 | if (!length) | ||
1664 | return 0; | ||
1665 | if (!rl->length) | ||
1666 | return -ENOENT; | ||
1667 | rl_real_end = rl_end; | ||
1668 | /* Determine the runlist size. */ | ||
1669 | while (likely(rl_real_end->length)) | ||
1670 | rl_real_end++; | ||
1671 | old_size = rl_real_end - runlist->rl + 1; | ||
1672 | /* If @start is in a hole simply extend the hole. */ | ||
1673 | if (rl->lcn == LCN_HOLE) { | ||
1674 | /* | ||
1675 | * If both @start and @end are in the same sparse run, we are | ||
1676 | * done. | ||
1677 | */ | ||
1678 | if (end <= rl[1].vcn) { | ||
1679 | ntfs_debug("Done (requested hole is already sparse)."); | ||
1680 | return 0; | ||
1681 | } | ||
1682 | extend_hole: | ||
1683 | /* Extend the hole. */ | ||
1684 | rl->length = end - rl->vcn; | ||
1685 | /* If @end is in a hole, merge it with the current one. */ | ||
1686 | if (rl_end->lcn == LCN_HOLE) { | ||
1687 | rl_end++; | ||
1688 | rl->length = rl_end->vcn - rl->vcn; | ||
1689 | } | ||
1690 | /* We have done the hole. Now deal with the remaining tail. */ | ||
1691 | rl++; | ||
1692 | /* Cut out all runlist elements up to @end. */ | ||
1693 | if (rl < rl_end) | ||
1694 | memmove(rl, rl_end, (rl_real_end - rl_end + 1) * | ||
1695 | sizeof(*rl)); | ||
1696 | /* Adjust the beginning of the tail if necessary. */ | ||
1697 | if (end > rl->vcn) { | ||
1698 | s64 delta = end - rl->vcn; | ||
1699 | rl->vcn = end; | ||
1700 | rl->length -= delta; | ||
1701 | /* Only adjust the lcn if it is real. */ | ||
1702 | if (rl->lcn >= 0) | ||
1703 | rl->lcn += delta; | ||
1704 | } | ||
1705 | shrink_allocation: | ||
1706 | /* Reallocate memory if the allocation changed. */ | ||
1707 | if (rl < rl_end) { | ||
1708 | rl = ntfs_rl_realloc(runlist->rl, old_size, | ||
1709 | old_size - (rl_end - rl)); | ||
1710 | if (IS_ERR(rl)) | ||
1711 | ntfs_warning(vol->sb, "Failed to shrink " | ||
1712 | "runlist buffer. This just " | ||
1713 | "wastes a bit of memory " | ||
1714 | "temporarily so we ignore it " | ||
1715 | "and return success."); | ||
1716 | else | ||
1717 | runlist->rl = rl; | ||
1718 | } | ||
1719 | ntfs_debug("Done (extend hole)."); | ||
1720 | return 0; | ||
1721 | } | ||
1722 | /* | ||
1723 | * If @start is at the beginning of a run things are easier as there is | ||
1724 | * no need to split the first run. | ||
1725 | */ | ||
1726 | if (start == rl->vcn) { | ||
1727 | /* | ||
1728 | * @start is at the beginning of a run. | ||
1729 | * | ||
1730 | * If the previous run is sparse, extend its hole. | ||
1731 | * | ||
1732 | * If @end is not in the same run, switch the run to be sparse | ||
1733 | * and extend the newly created hole. | ||
1734 | * | ||
1735 | * Thus both of these cases reduce the problem to the above | ||
1736 | * case of "@start is in a hole". | ||
1737 | */ | ||
1738 | if (rl > runlist->rl && (rl - 1)->lcn == LCN_HOLE) { | ||
1739 | rl--; | ||
1740 | goto extend_hole; | ||
1741 | } | ||
1742 | if (end >= rl[1].vcn) { | ||
1743 | rl->lcn = LCN_HOLE; | ||
1744 | goto extend_hole; | ||
1745 | } | ||
1746 | /* | ||
1747 | * The final case is when @end is in the same run as @start. | ||
1748 | * For this need to split the run into two. One run for the | ||
1749 | * sparse region between the beginning of the old run, i.e. | ||
1750 | * @start, and @end and one for the remaining non-sparse | ||
1751 | * region, i.e. between @end and the end of the old run. | ||
1752 | */ | ||
1753 | trl = ntfs_rl_realloc(runlist->rl, old_size, old_size + 1); | ||
1754 | if (IS_ERR(trl)) | ||
1755 | goto enomem_out; | ||
1756 | old_size++; | ||
1757 | if (runlist->rl != trl) { | ||
1758 | rl = trl + (rl - runlist->rl); | ||
1759 | rl_end = trl + (rl_end - runlist->rl); | ||
1760 | rl_real_end = trl + (rl_real_end - runlist->rl); | ||
1761 | runlist->rl = trl; | ||
1762 | } | ||
1763 | split_end: | ||
1764 | /* Shift all the runs up by one. */ | ||
1765 | memmove(rl + 1, rl, (rl_real_end - rl + 1) * sizeof(*rl)); | ||
1766 | /* Finally, setup the two split runs. */ | ||
1767 | rl->lcn = LCN_HOLE; | ||
1768 | rl->length = length; | ||
1769 | rl++; | ||
1770 | rl->vcn += length; | ||
1771 | /* Only adjust the lcn if it is real. */ | ||
1772 | if (rl->lcn >= 0 || lcn_fixup) | ||
1773 | rl->lcn += length; | ||
1774 | rl->length -= length; | ||
1775 | ntfs_debug("Done (split one)."); | ||
1776 | return 0; | ||
1777 | } | ||
1778 | /* | ||
1779 | * @start is neither in a hole nor at the beginning of a run. | ||
1780 | * | ||
1781 | * If @end is in a hole, things are easier as simply truncating the run | ||
1782 | * @start is in to end at @start - 1, deleting all runs after that up | ||
1783 | * to @end, and finally extending the beginning of the run @end is in | ||
1784 | * to be @start is all that is needed. | ||
1785 | */ | ||
1786 | if (rl_end->lcn == LCN_HOLE) { | ||
1787 | /* Truncate the run containing @start. */ | ||
1788 | rl->length = start - rl->vcn; | ||
1789 | rl++; | ||
1790 | /* Cut out all runlist elements up to @end. */ | ||
1791 | if (rl < rl_end) | ||
1792 | memmove(rl, rl_end, (rl_real_end - rl_end + 1) * | ||
1793 | sizeof(*rl)); | ||
1794 | /* Extend the beginning of the run @end is in to be @start. */ | ||
1795 | rl->vcn = start; | ||
1796 | rl->length = rl[1].vcn - start; | ||
1797 | goto shrink_allocation; | ||
1798 | } | ||
1799 | /* | ||
1800 | * If @end is not in a hole there are still two cases to distinguish. | ||
1801 | * Either @end is or is not in the same run as @start. | ||
1802 | * | ||
1803 | * The second case is easier as it can be reduced to an already solved | ||
1804 | * problem by truncating the run @start is in to end at @start - 1. | ||
1805 | * Then, if @end is in the next run need to split the run into a sparse | ||
1806 | * run followed by a non-sparse run (already covered above) and if @end | ||
1807 | * is not in the next run switching it to be sparse, again reduces the | ||
1808 | * problem to the already covered case of "@start is in a hole". | ||
1809 | */ | ||
1810 | if (end >= rl[1].vcn) { | ||
1811 | /* | ||
1812 | * If @end is not in the next run, reduce the problem to the | ||
1813 | * case of "@start is in a hole". | ||
1814 | */ | ||
1815 | if (rl[1].length && end >= rl[2].vcn) { | ||
1816 | /* Truncate the run containing @start. */ | ||
1817 | rl->length = start - rl->vcn; | ||
1818 | rl++; | ||
1819 | rl->vcn = start; | ||
1820 | rl->lcn = LCN_HOLE; | ||
1821 | goto extend_hole; | ||
1822 | } | ||
1823 | trl = ntfs_rl_realloc(runlist->rl, old_size, old_size + 1); | ||
1824 | if (IS_ERR(trl)) | ||
1825 | goto enomem_out; | ||
1826 | old_size++; | ||
1827 | if (runlist->rl != trl) { | ||
1828 | rl = trl + (rl - runlist->rl); | ||
1829 | rl_end = trl + (rl_end - runlist->rl); | ||
1830 | rl_real_end = trl + (rl_real_end - runlist->rl); | ||
1831 | runlist->rl = trl; | ||
1832 | } | ||
1833 | /* Truncate the run containing @start. */ | ||
1834 | rl->length = start - rl->vcn; | ||
1835 | rl++; | ||
1836 | /* | ||
1837 | * @end is in the next run, reduce the problem to the case | ||
1838 | * where "@start is at the beginning of a run and @end is in | ||
1839 | * the same run as @start". | ||
1840 | */ | ||
1841 | delta = rl->vcn - start; | ||
1842 | rl->vcn = start; | ||
1843 | if (rl->lcn >= 0) { | ||
1844 | rl->lcn -= delta; | ||
1845 | /* Need this in case the lcn just became negative. */ | ||
1846 | lcn_fixup = TRUE; | ||
1847 | } | ||
1848 | rl->length += delta; | ||
1849 | goto split_end; | ||
1850 | } | ||
1851 | /* | ||
1852 | * The first case from above, i.e. @end is in the same run as @start. | ||
1853 | * We need to split the run into three. One run for the non-sparse | ||
1854 | * region between the beginning of the old run and @start, one for the | ||
1855 | * sparse region between @start and @end, and one for the remaining | ||
1856 | * non-sparse region, i.e. between @end and the end of the old run. | ||
1857 | */ | ||
1858 | trl = ntfs_rl_realloc(runlist->rl, old_size, old_size + 2); | ||
1859 | if (IS_ERR(trl)) | ||
1860 | goto enomem_out; | ||
1861 | old_size += 2; | ||
1862 | if (runlist->rl != trl) { | ||
1863 | rl = trl + (rl - runlist->rl); | ||
1864 | rl_end = trl + (rl_end - runlist->rl); | ||
1865 | rl_real_end = trl + (rl_real_end - runlist->rl); | ||
1866 | runlist->rl = trl; | ||
1867 | } | ||
1868 | /* Shift all the runs up by two. */ | ||
1869 | memmove(rl + 2, rl, (rl_real_end - rl + 1) * sizeof(*rl)); | ||
1870 | /* Finally, setup the three split runs. */ | ||
1871 | rl->length = start - rl->vcn; | ||
1872 | rl++; | ||
1873 | rl->vcn = start; | ||
1874 | rl->lcn = LCN_HOLE; | ||
1875 | rl->length = length; | ||
1876 | rl++; | ||
1877 | delta = end - rl->vcn; | ||
1878 | rl->vcn = end; | ||
1879 | rl->lcn += delta; | ||
1880 | rl->length -= delta; | ||
1881 | ntfs_debug("Done (split both)."); | ||
1882 | return 0; | ||
1883 | enomem_out: | ||
1884 | ntfs_error(vol->sb, "Not enough memory to extend runlist buffer."); | ||
1885 | return -ENOMEM; | ||
1886 | } | ||
1887 | |||
1556 | #endif /* NTFS_RW */ | 1888 | #endif /* NTFS_RW */ |
diff --git a/fs/ntfs/runlist.h b/fs/ntfs/runlist.h index aa0ee6540e7c..47728fbb610b 100644 --- a/fs/ntfs/runlist.h +++ b/fs/ntfs/runlist.h | |||
@@ -94,6 +94,9 @@ extern int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst, | |||
94 | extern int ntfs_rl_truncate_nolock(const ntfs_volume *vol, | 94 | extern int ntfs_rl_truncate_nolock(const ntfs_volume *vol, |
95 | runlist *const runlist, const s64 new_length); | 95 | runlist *const runlist, const s64 new_length); |
96 | 96 | ||
97 | int ntfs_rl_punch_nolock(const ntfs_volume *vol, runlist *const runlist, | ||
98 | const VCN start, const s64 length); | ||
99 | |||
97 | #endif /* NTFS_RW */ | 100 | #endif /* NTFS_RW */ |
98 | 101 | ||
99 | #endif /* _LINUX_NTFS_RUNLIST_H */ | 102 | #endif /* _LINUX_NTFS_RUNLIST_H */ |
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 41aa8eb6755b..b2b392961268 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c | |||
@@ -1133,7 +1133,8 @@ mft_unmap_out: | |||
1133 | * | 1133 | * |
1134 | * Return TRUE on success or FALSE on error. | 1134 | * Return TRUE on success or FALSE on error. |
1135 | */ | 1135 | */ |
1136 | static BOOL load_and_check_logfile(ntfs_volume *vol) | 1136 | static BOOL load_and_check_logfile(ntfs_volume *vol, |
1137 | RESTART_PAGE_HEADER **rp) | ||
1137 | { | 1138 | { |
1138 | struct inode *tmp_ino; | 1139 | struct inode *tmp_ino; |
1139 | 1140 | ||
@@ -1145,7 +1146,7 @@ static BOOL load_and_check_logfile(ntfs_volume *vol) | |||
1145 | /* Caller will display error message. */ | 1146 | /* Caller will display error message. */ |
1146 | return FALSE; | 1147 | return FALSE; |
1147 | } | 1148 | } |
1148 | if (!ntfs_check_logfile(tmp_ino)) { | 1149 | if (!ntfs_check_logfile(tmp_ino, rp)) { |
1149 | iput(tmp_ino); | 1150 | iput(tmp_ino); |
1150 | /* ntfs_check_logfile() will have displayed error output. */ | 1151 | /* ntfs_check_logfile() will have displayed error output. */ |
1151 | return FALSE; | 1152 | return FALSE; |
@@ -1689,6 +1690,7 @@ static BOOL load_system_files(ntfs_volume *vol) | |||
1689 | VOLUME_INFORMATION *vi; | 1690 | VOLUME_INFORMATION *vi; |
1690 | ntfs_attr_search_ctx *ctx; | 1691 | ntfs_attr_search_ctx *ctx; |
1691 | #ifdef NTFS_RW | 1692 | #ifdef NTFS_RW |
1693 | RESTART_PAGE_HEADER *rp; | ||
1692 | int err; | 1694 | int err; |
1693 | #endif /* NTFS_RW */ | 1695 | #endif /* NTFS_RW */ |
1694 | 1696 | ||
@@ -1841,8 +1843,9 @@ get_ctx_vol_failed: | |||
1841 | * Get the inode for the logfile, check it and determine if the volume | 1843 | * Get the inode for the logfile, check it and determine if the volume |
1842 | * was shutdown cleanly. | 1844 | * was shutdown cleanly. |
1843 | */ | 1845 | */ |
1844 | if (!load_and_check_logfile(vol) || | 1846 | rp = NULL; |
1845 | !ntfs_is_logfile_clean(vol->logfile_ino)) { | 1847 | if (!load_and_check_logfile(vol, &rp) || |
1848 | !ntfs_is_logfile_clean(vol->logfile_ino, rp)) { | ||
1846 | static const char *es1a = "Failed to load $LogFile"; | 1849 | static const char *es1a = "Failed to load $LogFile"; |
1847 | static const char *es1b = "$LogFile is not clean"; | 1850 | static const char *es1b = "$LogFile is not clean"; |
1848 | static const char *es2 = ". Mount in Windows."; | 1851 | static const char *es2 = ". Mount in Windows."; |
@@ -1857,6 +1860,10 @@ get_ctx_vol_failed: | |||
1857 | "continue nor on_errors=" | 1860 | "continue nor on_errors=" |
1858 | "remount-ro was specified%s", | 1861 | "remount-ro was specified%s", |
1859 | es1, es2); | 1862 | es1, es2); |
1863 | if (vol->logfile_ino) { | ||
1864 | BUG_ON(!rp); | ||
1865 | ntfs_free(rp); | ||
1866 | } | ||
1860 | goto iput_logfile_err_out; | 1867 | goto iput_logfile_err_out; |
1861 | } | 1868 | } |
1862 | sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; | 1869 | sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; |
@@ -1867,6 +1874,7 @@ get_ctx_vol_failed: | |||
1867 | /* This will prevent a read-write remount. */ | 1874 | /* This will prevent a read-write remount. */ |
1868 | NVolSetErrors(vol); | 1875 | NVolSetErrors(vol); |
1869 | } | 1876 | } |
1877 | ntfs_free(rp); | ||
1870 | #endif /* NTFS_RW */ | 1878 | #endif /* NTFS_RW */ |
1871 | /* Get the root directory inode so we can do path lookups. */ | 1879 | /* Get the root directory inode so we can do path lookups. */ |
1872 | vol->root_ino = ntfs_iget(sb, FILE_root); | 1880 | vol->root_ino = ntfs_iget(sb, FILE_root); |
diff --git a/fs/ntfs/unistr.c b/fs/ntfs/unistr.c index 19c42e231b44..a389a5a16c84 100644 --- a/fs/ntfs/unistr.c +++ b/fs/ntfs/unistr.c | |||
@@ -372,7 +372,8 @@ retry: wc = nls->uni2char(le16_to_cpu(ins[i]), ns + o, | |||
372 | return -EINVAL; | 372 | return -EINVAL; |
373 | conversion_err: | 373 | conversion_err: |
374 | ntfs_error(vol->sb, "Unicode name contains characters that cannot be " | 374 | ntfs_error(vol->sb, "Unicode name contains characters that cannot be " |
375 | "converted to character set %s.", nls->charset); | 375 | "converted to character set %s. You might want to " |
376 | "try to use the mount option nls=utf8.", nls->charset); | ||
376 | if (ns != *outs) | 377 | if (ns != *outs) |
377 | kfree(ns); | 378 | kfree(ns); |
378 | if (wc != -ENAMETOOLONG) | 379 | if (wc != -ENAMETOOLONG) |