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 | 294 | ||||
| -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, 1063 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..b6cc8cf24626 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/swap.h> | 27 | #include <linux/swap.h> |
| 28 | #include <linux/buffer_head.h> | 28 | #include <linux/buffer_head.h> |
| 29 | #include <linux/writeback.h> | 29 | #include <linux/writeback.h> |
| 30 | #include <linux/bit_spinlock.h> | ||
| 30 | 31 | ||
| 31 | #include "aops.h" | 32 | #include "aops.h" |
| 32 | #include "attrib.h" | 33 | #include "attrib.h" |
| @@ -55,9 +56,8 @@ | |||
| 55 | */ | 56 | */ |
| 56 | static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) | 57 | static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) |
| 57 | { | 58 | { |
| 58 | static DEFINE_SPINLOCK(page_uptodate_lock); | ||
| 59 | unsigned long flags; | 59 | unsigned long flags; |
| 60 | struct buffer_head *tmp; | 60 | struct buffer_head *first, *tmp; |
| 61 | struct page *page; | 61 | struct page *page; |
| 62 | ntfs_inode *ni; | 62 | ntfs_inode *ni; |
| 63 | int page_uptodate = 1; | 63 | int page_uptodate = 1; |
| @@ -89,11 +89,13 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) | |||
| 89 | } | 89 | } |
| 90 | } else { | 90 | } else { |
| 91 | clear_buffer_uptodate(bh); | 91 | clear_buffer_uptodate(bh); |
| 92 | SetPageError(page); | ||
| 92 | ntfs_error(ni->vol->sb, "Buffer I/O error, logical block %llu.", | 93 | ntfs_error(ni->vol->sb, "Buffer I/O error, logical block %llu.", |
| 93 | (unsigned long long)bh->b_blocknr); | 94 | (unsigned long long)bh->b_blocknr); |
| 94 | SetPageError(page); | ||
| 95 | } | 95 | } |
| 96 | spin_lock_irqsave(&page_uptodate_lock, flags); | 96 | first = page_buffers(page); |
| 97 | local_irq_save(flags); | ||
| 98 | bit_spin_lock(BH_Uptodate_Lock, &first->b_state); | ||
| 97 | clear_buffer_async_read(bh); | 99 | clear_buffer_async_read(bh); |
| 98 | unlock_buffer(bh); | 100 | unlock_buffer(bh); |
| 99 | tmp = bh; | 101 | tmp = bh; |
| @@ -108,7 +110,8 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) | |||
| 108 | } | 110 | } |
| 109 | tmp = tmp->b_this_page; | 111 | tmp = tmp->b_this_page; |
| 110 | } while (tmp != bh); | 112 | } while (tmp != bh); |
| 111 | spin_unlock_irqrestore(&page_uptodate_lock, flags); | 113 | bit_spin_unlock(BH_Uptodate_Lock, &first->b_state); |
| 114 | local_irq_restore(flags); | ||
| 112 | /* | 115 | /* |
| 113 | * If none of the buffers had errors then we can set the page uptodate, | 116 | * 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 | 117 | * but we first have to perform the post read mst fixups, if the |
| @@ -141,7 +144,8 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) | |||
| 141 | unlock_page(page); | 144 | unlock_page(page); |
| 142 | return; | 145 | return; |
| 143 | still_busy: | 146 | still_busy: |
| 144 | spin_unlock_irqrestore(&page_uptodate_lock, flags); | 147 | bit_spin_unlock(BH_Uptodate_Lock, &first->b_state); |
| 148 | local_irq_restore(flags); | ||
| 145 | return; | 149 | return; |
| 146 | } | 150 | } |
| 147 | 151 | ||
| @@ -185,13 +189,15 @@ static int ntfs_read_block(struct page *page) | |||
| 185 | blocksize_bits = VFS_I(ni)->i_blkbits; | 189 | blocksize_bits = VFS_I(ni)->i_blkbits; |
| 186 | blocksize = 1 << blocksize_bits; | 190 | blocksize = 1 << blocksize_bits; |
| 187 | 191 | ||
| 188 | if (!page_has_buffers(page)) | 192 | if (!page_has_buffers(page)) { |
| 189 | create_empty_buffers(page, blocksize, 0); | 193 | create_empty_buffers(page, blocksize, 0); |
| 190 | bh = head = page_buffers(page); | 194 | if (unlikely(!page_has_buffers(page))) { |
| 191 | if (unlikely(!bh)) { | 195 | unlock_page(page); |
| 192 | unlock_page(page); | 196 | return -ENOMEM; |
| 193 | return -ENOMEM; | 197 | } |
| 194 | } | 198 | } |
| 199 | bh = head = page_buffers(page); | ||
| 200 | BUG_ON(!bh); | ||
| 195 | 201 | ||
| 196 | iblock = (s64)page->index << (PAGE_CACHE_SHIFT - blocksize_bits); | 202 | iblock = (s64)page->index << (PAGE_CACHE_SHIFT - blocksize_bits); |
| 197 | read_lock_irqsave(&ni->size_lock, flags); | 203 | read_lock_irqsave(&ni->size_lock, flags); |
| @@ -204,6 +210,7 @@ static int ntfs_read_block(struct page *page) | |||
| 204 | nr = i = 0; | 210 | nr = i = 0; |
| 205 | do { | 211 | do { |
| 206 | u8 *kaddr; | 212 | u8 *kaddr; |
| 213 | int err; | ||
| 207 | 214 | ||
| 208 | if (unlikely(buffer_uptodate(bh))) | 215 | if (unlikely(buffer_uptodate(bh))) |
| 209 | continue; | 216 | continue; |
| @@ -211,6 +218,7 @@ static int ntfs_read_block(struct page *page) | |||
| 211 | arr[nr++] = bh; | 218 | arr[nr++] = bh; |
| 212 | continue; | 219 | continue; |
| 213 | } | 220 | } |
| 221 | err = 0; | ||
| 214 | bh->b_bdev = vol->sb->s_bdev; | 222 | bh->b_bdev = vol->sb->s_bdev; |
| 215 | /* Is the block within the allowed limits? */ | 223 | /* Is the block within the allowed limits? */ |
| 216 | if (iblock < lblock) { | 224 | if (iblock < lblock) { |
| @@ -252,7 +260,6 @@ lock_retry_remap: | |||
| 252 | goto handle_hole; | 260 | goto handle_hole; |
| 253 | /* If first try and runlist unmapped, map and retry. */ | 261 | /* If first try and runlist unmapped, map and retry. */ |
| 254 | if (!is_retry && lcn == LCN_RL_NOT_MAPPED) { | 262 | if (!is_retry && lcn == LCN_RL_NOT_MAPPED) { |
| 255 | int err; | ||
| 256 | is_retry = TRUE; | 263 | is_retry = TRUE; |
| 257 | /* | 264 | /* |
| 258 | * Attempt to map runlist, dropping lock for | 265 | * Attempt to map runlist, dropping lock for |
| @@ -263,20 +270,30 @@ lock_retry_remap: | |||
| 263 | if (likely(!err)) | 270 | if (likely(!err)) |
| 264 | goto lock_retry_remap; | 271 | goto lock_retry_remap; |
| 265 | rl = NULL; | 272 | rl = NULL; |
| 266 | lcn = err; | ||
| 267 | } else if (!rl) | 273 | } else if (!rl) |
| 268 | up_read(&ni->runlist.lock); | 274 | up_read(&ni->runlist.lock); |
| 275 | /* | ||
| 276 | * If buffer is outside the runlist, treat it as a | ||
| 277 | * hole. This can happen due to concurrent truncate | ||
| 278 | * for example. | ||
| 279 | */ | ||
| 280 | if (err == -ENOENT || lcn == LCN_ENOENT) { | ||
| 281 | err = 0; | ||
| 282 | goto handle_hole; | ||
| 283 | } | ||
| 269 | /* Hard error, zero out region. */ | 284 | /* Hard error, zero out region. */ |
| 285 | if (!err) | ||
| 286 | err = -EIO; | ||
| 270 | bh->b_blocknr = -1; | 287 | bh->b_blocknr = -1; |
| 271 | SetPageError(page); | 288 | SetPageError(page); |
| 272 | ntfs_error(vol->sb, "Failed to read from inode 0x%lx, " | 289 | ntfs_error(vol->sb, "Failed to read from inode 0x%lx, " |
| 273 | "attribute type 0x%x, vcn 0x%llx, " | 290 | "attribute type 0x%x, vcn 0x%llx, " |
| 274 | "offset 0x%x because its location on " | 291 | "offset 0x%x because its location on " |
| 275 | "disk could not be determined%s " | 292 | "disk could not be determined%s " |
| 276 | "(error code %lli).", ni->mft_no, | 293 | "(error code %i).", ni->mft_no, |
| 277 | ni->type, (unsigned long long)vcn, | 294 | ni->type, (unsigned long long)vcn, |
| 278 | vcn_ofs, is_retry ? " even after " | 295 | vcn_ofs, is_retry ? " even after " |
| 279 | "retrying" : "", (long long)lcn); | 296 | "retrying" : "", err); |
| 280 | } | 297 | } |
| 281 | /* | 298 | /* |
| 282 | * Either iblock was outside lblock limits or | 299 | * Either iblock was outside lblock limits or |
| @@ -289,9 +306,10 @@ handle_hole: | |||
| 289 | handle_zblock: | 306 | handle_zblock: |
| 290 | kaddr = kmap_atomic(page, KM_USER0); | 307 | kaddr = kmap_atomic(page, KM_USER0); |
| 291 | memset(kaddr + i * blocksize, 0, blocksize); | 308 | memset(kaddr + i * blocksize, 0, blocksize); |
| 292 | flush_dcache_page(page); | ||
| 293 | kunmap_atomic(kaddr, KM_USER0); | 309 | kunmap_atomic(kaddr, KM_USER0); |
| 294 | set_buffer_uptodate(bh); | 310 | flush_dcache_page(page); |
| 311 | if (likely(!err)) | ||
| 312 | set_buffer_uptodate(bh); | ||
| 295 | } while (i++, iblock++, (bh = bh->b_this_page) != head); | 313 | } while (i++, iblock++, (bh = bh->b_this_page) != head); |
| 296 | 314 | ||
| 297 | /* Release the lock if we took it. */ | 315 | /* Release the lock if we took it. */ |
| @@ -367,31 +385,38 @@ retry_readpage: | |||
| 367 | return 0; | 385 | return 0; |
| 368 | } | 386 | } |
| 369 | ni = NTFS_I(page->mapping->host); | 387 | ni = NTFS_I(page->mapping->host); |
| 370 | 388 | /* | |
| 389 | * Only $DATA attributes can be encrypted and only unnamed $DATA | ||
| 390 | * attributes can be compressed. Index root can have the flags set but | ||
| 391 | * this means to create compressed/encrypted files, not that the | ||
| 392 | * attribute is compressed/encrypted. | ||
| 393 | */ | ||
| 394 | if (ni->type != AT_INDEX_ROOT) { | ||
| 395 | /* If attribute is encrypted, deny access, just like NT4. */ | ||
| 396 | if (NInoEncrypted(ni)) { | ||
| 397 | BUG_ON(ni->type != AT_DATA); | ||
| 398 | err = -EACCES; | ||
| 399 | goto err_out; | ||
| 400 | } | ||
| 401 | /* Compressed data streams are handled in compress.c. */ | ||
| 402 | if (NInoNonResident(ni) && NInoCompressed(ni)) { | ||
| 403 | BUG_ON(ni->type != AT_DATA); | ||
| 404 | BUG_ON(ni->name_len); | ||
| 405 | return ntfs_read_compressed_block(page); | ||
| 406 | } | ||
| 407 | } | ||
| 371 | /* NInoNonResident() == NInoIndexAllocPresent() */ | 408 | /* NInoNonResident() == NInoIndexAllocPresent() */ |
| 372 | if (NInoNonResident(ni)) { | 409 | if (NInoNonResident(ni)) { |
| 373 | /* | 410 | /* 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); | 411 | return ntfs_read_block(page); |
| 389 | } | 412 | } |
| 390 | /* | 413 | /* |
| 391 | * Attribute is resident, implying it is not compressed or encrypted. | 414 | * Attribute is resident, implying it is not compressed or encrypted. |
| 392 | * This also means the attribute is smaller than an mft record and | 415 | * 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 | 416 | * hence smaller than a page, so can simply zero out any pages with |
| 394 | * index above 0. | 417 | * index above 0. Note the attribute can actually be marked compressed |
| 418 | * but if it is resident the actual data is not compressed so we are | ||
| 419 | * ok to ignore the compressed flag here. | ||
| 395 | */ | 420 | */ |
| 396 | if (unlikely(page->index > 0)) { | 421 | if (unlikely(page->index > 0)) { |
| 397 | kaddr = kmap_atomic(page, KM_USER0); | 422 | kaddr = kmap_atomic(page, KM_USER0); |
| @@ -511,19 +536,21 @@ static int ntfs_write_block(struct page *page, struct writeback_control *wbc) | |||
| 511 | BUG_ON(!PageUptodate(page)); | 536 | BUG_ON(!PageUptodate(page)); |
| 512 | create_empty_buffers(page, blocksize, | 537 | create_empty_buffers(page, blocksize, |
| 513 | (1 << BH_Uptodate) | (1 << BH_Dirty)); | 538 | (1 << BH_Uptodate) | (1 << BH_Dirty)); |
| 539 | if (unlikely(!page_has_buffers(page))) { | ||
| 540 | ntfs_warning(vol->sb, "Error allocating page " | ||
| 541 | "buffers. Redirtying page so we try " | ||
| 542 | "again later."); | ||
| 543 | /* | ||
| 544 | * Put the page back on mapping->dirty_pages, but leave | ||
| 545 | * its buffers' dirty state as-is. | ||
| 546 | */ | ||
| 547 | redirty_page_for_writepage(wbc, page); | ||
| 548 | unlock_page(page); | ||
| 549 | return 0; | ||
| 550 | } | ||
| 514 | } | 551 | } |
| 515 | bh = head = page_buffers(page); | 552 | bh = head = page_buffers(page); |
| 516 | if (unlikely(!bh)) { | 553 | 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 | 554 | ||
| 528 | /* NOTE: Different naming scheme to ntfs_read_block()! */ | 555 | /* NOTE: Different naming scheme to ntfs_read_block()! */ |
| 529 | 556 | ||
| @@ -670,6 +697,27 @@ lock_retry_remap: | |||
| 670 | } | 697 | } |
| 671 | /* It is a hole, need to instantiate it. */ | 698 | /* It is a hole, need to instantiate it. */ |
| 672 | if (lcn == LCN_HOLE) { | 699 | if (lcn == LCN_HOLE) { |
| 700 | u8 *kaddr; | ||
| 701 | unsigned long *bpos, *bend; | ||
| 702 | |||
| 703 | /* Check if the buffer is zero. */ | ||
| 704 | kaddr = kmap_atomic(page, KM_USER0); | ||
| 705 | bpos = (unsigned long *)(kaddr + bh_offset(bh)); | ||
| 706 | bend = (unsigned long *)((u8*)bpos + blocksize); | ||
| 707 | do { | ||
| 708 | if (unlikely(*bpos)) | ||
| 709 | break; | ||
| 710 | } while (likely(++bpos < bend)); | ||
| 711 | kunmap_atomic(kaddr, KM_USER0); | ||
| 712 | if (bpos == bend) { | ||
| 713 | /* | ||
| 714 | * Buffer is zero and sparse, no need to write | ||
| 715 | * it. | ||
| 716 | */ | ||
| 717 | bh->b_blocknr = -1; | ||
| 718 | clear_buffer_dirty(bh); | ||
| 719 | continue; | ||
| 720 | } | ||
| 673 | // TODO: Instantiate the hole. | 721 | // TODO: Instantiate the hole. |
| 674 | // clear_buffer_new(bh); | 722 | // clear_buffer_new(bh); |
| 675 | // unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); | 723 | // unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); |
| @@ -690,20 +738,37 @@ lock_retry_remap: | |||
| 690 | if (likely(!err)) | 738 | if (likely(!err)) |
| 691 | goto lock_retry_remap; | 739 | goto lock_retry_remap; |
| 692 | rl = NULL; | 740 | rl = NULL; |
| 693 | lcn = err; | ||
| 694 | } else if (!rl) | 741 | } else if (!rl) |
| 695 | up_read(&ni->runlist.lock); | 742 | up_read(&ni->runlist.lock); |
| 743 | /* | ||
| 744 | * If buffer is outside the runlist, truncate has cut it out | ||
| 745 | * of the runlist. Just clean and clear the buffer and set it | ||
| 746 | * uptodate so it can get discarded by the VM. | ||
| 747 | */ | ||
| 748 | if (err == -ENOENT || lcn == LCN_ENOENT) { | ||
| 749 | u8 *kaddr; | ||
| 750 | |||
| 751 | bh->b_blocknr = -1; | ||
| 752 | clear_buffer_dirty(bh); | ||
| 753 | kaddr = kmap_atomic(page, KM_USER0); | ||
| 754 | memset(kaddr + bh_offset(bh), 0, blocksize); | ||
| 755 | kunmap_atomic(kaddr, KM_USER0); | ||
| 756 | flush_dcache_page(page); | ||
| 757 | set_buffer_uptodate(bh); | ||
| 758 | err = 0; | ||
| 759 | continue; | ||
| 760 | } | ||
| 696 | /* Failed to map the buffer, even after retrying. */ | 761 | /* Failed to map the buffer, even after retrying. */ |
| 762 | if (!err) | ||
| 763 | err = -EIO; | ||
| 697 | bh->b_blocknr = -1; | 764 | bh->b_blocknr = -1; |
| 698 | ntfs_error(vol->sb, "Failed to write to inode 0x%lx, " | 765 | ntfs_error(vol->sb, "Failed to write to inode 0x%lx, " |
| 699 | "attribute type 0x%x, vcn 0x%llx, offset 0x%x " | 766 | "attribute type 0x%x, vcn 0x%llx, offset 0x%x " |
| 700 | "because its location on disk could not be " | 767 | "because its location on disk could not be " |
| 701 | "determined%s (error code %lli).", ni->mft_no, | 768 | "determined%s (error code %i).", ni->mft_no, |
| 702 | ni->type, (unsigned long long)vcn, | 769 | ni->type, (unsigned long long)vcn, |
| 703 | vcn_ofs, is_retry ? " even after " | 770 | vcn_ofs, is_retry ? " even after " |
| 704 | "retrying" : "", (long long)lcn); | 771 | "retrying" : "", err); |
| 705 | if (!err) | ||
| 706 | err = -EIO; | ||
| 707 | break; | 772 | break; |
| 708 | } while (block++, (bh = bh->b_this_page) != head); | 773 | } while (block++, (bh = bh->b_this_page) != head); |
| 709 | 774 | ||
| @@ -714,7 +779,7 @@ lock_retry_remap: | |||
| 714 | /* For the error case, need to reset bh to the beginning. */ | 779 | /* For the error case, need to reset bh to the beginning. */ |
| 715 | bh = head; | 780 | bh = head; |
| 716 | 781 | ||
| 717 | /* Just an optimization, so ->readpage() isn't called later. */ | 782 | /* Just an optimization, so ->readpage() is not called later. */ |
| 718 | if (unlikely(!PageUptodate(page))) { | 783 | if (unlikely(!PageUptodate(page))) { |
| 719 | int uptodate = 1; | 784 | int uptodate = 1; |
| 720 | do { | 785 | do { |
| @@ -730,7 +795,6 @@ lock_retry_remap: | |||
| 730 | 795 | ||
| 731 | /* Setup all mapped, dirty buffers for async write i/o. */ | 796 | /* Setup all mapped, dirty buffers for async write i/o. */ |
| 732 | do { | 797 | do { |
| 733 | get_bh(bh); | ||
| 734 | if (buffer_mapped(bh) && buffer_dirty(bh)) { | 798 | if (buffer_mapped(bh) && buffer_dirty(bh)) { |
| 735 | lock_buffer(bh); | 799 | lock_buffer(bh); |
| 736 | if (test_clear_buffer_dirty(bh)) { | 800 | if (test_clear_buffer_dirty(bh)) { |
| @@ -768,14 +832,8 @@ lock_retry_remap: | |||
| 768 | 832 | ||
| 769 | BUG_ON(PageWriteback(page)); | 833 | BUG_ON(PageWriteback(page)); |
| 770 | set_page_writeback(page); /* Keeps try_to_free_buffers() away. */ | 834 | set_page_writeback(page); /* Keeps try_to_free_buffers() away. */ |
| 771 | unlock_page(page); | ||
| 772 | 835 | ||
| 773 | /* | 836 | /* 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; | 837 | need_end_writeback = TRUE; |
| 780 | do { | 838 | do { |
| 781 | struct buffer_head *next = bh->b_this_page; | 839 | struct buffer_head *next = bh->b_this_page; |
| @@ -783,9 +841,9 @@ lock_retry_remap: | |||
| 783 | submit_bh(WRITE, bh); | 841 | submit_bh(WRITE, bh); |
| 784 | need_end_writeback = FALSE; | 842 | need_end_writeback = FALSE; |
| 785 | } | 843 | } |
| 786 | put_bh(bh); | ||
| 787 | bh = next; | 844 | bh = next; |
| 788 | } while (bh != head); | 845 | } while (bh != head); |
| 846 | unlock_page(page); | ||
| 789 | 847 | ||
| 790 | /* If no i/o was started, need to end_page_writeback(). */ | 848 | /* If no i/o was started, need to end_page_writeback(). */ |
| 791 | if (unlikely(need_end_writeback)) | 849 | if (unlikely(need_end_writeback)) |
| @@ -860,7 +918,6 @@ static int ntfs_write_mst_block(struct page *page, | |||
| 860 | sync = (wbc->sync_mode == WB_SYNC_ALL); | 918 | sync = (wbc->sync_mode == WB_SYNC_ALL); |
| 861 | 919 | ||
| 862 | /* Make sure we have mapped buffers. */ | 920 | /* Make sure we have mapped buffers. */ |
| 863 | BUG_ON(!page_has_buffers(page)); | ||
| 864 | bh = head = page_buffers(page); | 921 | bh = head = page_buffers(page); |
| 865 | BUG_ON(!bh); | 922 | BUG_ON(!bh); |
| 866 | 923 | ||
| @@ -1280,38 +1337,42 @@ retry_writepage: | |||
| 1280 | ntfs_debug("Write outside i_size - truncated?"); | 1337 | ntfs_debug("Write outside i_size - truncated?"); |
| 1281 | return 0; | 1338 | return 0; |
| 1282 | } | 1339 | } |
| 1340 | /* | ||
| 1341 | * Only $DATA attributes can be encrypted and only unnamed $DATA | ||
| 1342 | * attributes can be compressed. Index root can have the flags set but | ||
| 1343 | * this means to create compressed/encrypted files, not that the | ||
| 1344 | * attribute is compressed/encrypted. | ||
| 1345 | */ | ||
| 1346 | if (ni->type != AT_INDEX_ROOT) { | ||
| 1347 | /* If file is encrypted, deny access, just like NT4. */ | ||
| 1348 | if (NInoEncrypted(ni)) { | ||
| 1349 | unlock_page(page); | ||
| 1350 | BUG_ON(ni->type != AT_DATA); | ||
| 1351 | ntfs_debug("Denying write access to encrypted " | ||
| 1352 | "file."); | ||
| 1353 | return -EACCES; | ||
| 1354 | } | ||
| 1355 | /* Compressed data streams are handled in compress.c. */ | ||
| 1356 | if (NInoNonResident(ni) && NInoCompressed(ni)) { | ||
| 1357 | BUG_ON(ni->type != AT_DATA); | ||
| 1358 | BUG_ON(ni->name_len); | ||
| 1359 | // TODO: Implement and replace this with | ||
| 1360 | // return ntfs_write_compressed_block(page); | ||
| 1361 | unlock_page(page); | ||
| 1362 | ntfs_error(vi->i_sb, "Writing to compressed files is " | ||
| 1363 | "not supported yet. Sorry."); | ||
| 1364 | return -EOPNOTSUPP; | ||
| 1365 | } | ||
| 1366 | // TODO: Implement and remove this check. | ||
| 1367 | if (NInoNonResident(ni) && NInoSparse(ni)) { | ||
| 1368 | unlock_page(page); | ||
| 1369 | ntfs_error(vi->i_sb, "Writing to sparse files is not " | ||
| 1370 | "supported yet. Sorry."); | ||
| 1371 | return -EOPNOTSUPP; | ||
| 1372 | } | ||
| 1373 | } | ||
| 1283 | /* NInoNonResident() == NInoIndexAllocPresent() */ | 1374 | /* NInoNonResident() == NInoIndexAllocPresent() */ |
| 1284 | if (NInoNonResident(ni)) { | 1375 | 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. */ | 1376 | /* We have to zero every time due to mmap-at-end-of-file. */ |
| 1316 | if (page->index >= (i_size >> PAGE_CACHE_SHIFT)) { | 1377 | if (page->index >= (i_size >> PAGE_CACHE_SHIFT)) { |
| 1317 | /* The page straddles i_size. */ | 1378 | /* The page straddles i_size. */ |
| @@ -1324,14 +1385,16 @@ retry_writepage: | |||
| 1324 | /* Handle mst protected attributes. */ | 1385 | /* Handle mst protected attributes. */ |
| 1325 | if (NInoMstProtected(ni)) | 1386 | if (NInoMstProtected(ni)) |
| 1326 | return ntfs_write_mst_block(page, wbc); | 1387 | return ntfs_write_mst_block(page, wbc); |
| 1327 | /* Normal data stream. */ | 1388 | /* Normal, non-resident data stream. */ |
| 1328 | return ntfs_write_block(page, wbc); | 1389 | return ntfs_write_block(page, wbc); |
| 1329 | } | 1390 | } |
| 1330 | /* | 1391 | /* |
| 1331 | * Attribute is resident, implying it is not compressed, encrypted, | 1392 | * Attribute is resident, implying it is not compressed, encrypted, or |
| 1332 | * sparse, or mst protected. This also means the attribute is smaller | 1393 | * 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 | 1394 | * record and hence smaller than a page, so can simply return error on |
| 1334 | * return error on any pages with index above 0. | 1395 | * any pages with index above 0. Note the attribute can actually be |
| 1396 | * marked compressed but if it is resident the actual data is not | ||
| 1397 | * compressed so we are ok to ignore the compressed flag here. | ||
| 1335 | */ | 1398 | */ |
| 1336 | BUG_ON(page_has_buffers(page)); | 1399 | BUG_ON(page_has_buffers(page)); |
| 1337 | BUG_ON(!PageUptodate(page)); | 1400 | BUG_ON(!PageUptodate(page)); |
| @@ -1380,30 +1443,14 @@ retry_writepage: | |||
| 1380 | BUG_ON(PageWriteback(page)); | 1443 | BUG_ON(PageWriteback(page)); |
| 1381 | set_page_writeback(page); | 1444 | set_page_writeback(page); |
| 1382 | unlock_page(page); | 1445 | unlock_page(page); |
| 1383 | |||
| 1384 | /* | 1446 | /* |
| 1385 | * Here, we don't need to zero the out of bounds area everytime because | 1447 | * 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 | 1448 | * because the below memcpy() already takes care of the |
| 1387 | * requirements. If the file is converted to a non-resident one, then | 1449 | * 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 | 1450 | * non-resident one, then the code path use is switched to the |
| 1389 | * zeroing happens on each ntfs_writepage() invocation. | 1451 | * non-resident one where the zeroing happens on each ntfs_writepage() |
| 1390 | * | 1452 | * 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 | */ | 1453 | */ |
| 1406 | |||
| 1407 | attr_len = le32_to_cpu(ctx->attr->data.resident.value_length); | 1454 | attr_len = le32_to_cpu(ctx->attr->data.resident.value_length); |
| 1408 | i_size = i_size_read(vi); | 1455 | i_size = i_size_read(vi); |
| 1409 | if (unlikely(attr_len > i_size)) { | 1456 | if (unlikely(attr_len > i_size)) { |
| @@ -1681,27 +1728,25 @@ lock_retry_remap: | |||
| 1681 | if (likely(!err)) | 1728 | if (likely(!err)) |
| 1682 | goto lock_retry_remap; | 1729 | goto lock_retry_remap; |
| 1683 | rl = NULL; | 1730 | rl = NULL; |
| 1684 | lcn = err; | ||
| 1685 | } else if (!rl) | 1731 | } else if (!rl) |
| 1686 | up_read(&ni->runlist.lock); | 1732 | up_read(&ni->runlist.lock); |
| 1687 | /* | 1733 | /* |
| 1688 | * Failed to map the buffer, even after | 1734 | * Failed to map the buffer, even after |
| 1689 | * retrying. | 1735 | * retrying. |
| 1690 | */ | 1736 | */ |
| 1737 | if (!err) | ||
| 1738 | err = -EIO; | ||
| 1691 | bh->b_blocknr = -1; | 1739 | bh->b_blocknr = -1; |
| 1692 | ntfs_error(vol->sb, "Failed to write to inode " | 1740 | ntfs_error(vol->sb, "Failed to write to inode " |
| 1693 | "0x%lx, attribute type 0x%x, " | 1741 | "0x%lx, attribute type 0x%x, " |
| 1694 | "vcn 0x%llx, offset 0x%x " | 1742 | "vcn 0x%llx, offset 0x%x " |
| 1695 | "because its location on disk " | 1743 | "because its location on disk " |
| 1696 | "could not be determined%s " | 1744 | "could not be determined%s " |
| 1697 | "(error code %lli).", | 1745 | "(error code %i).", |
| 1698 | ni->mft_no, ni->type, | 1746 | ni->mft_no, ni->type, |
| 1699 | (unsigned long long)vcn, | 1747 | (unsigned long long)vcn, |
| 1700 | vcn_ofs, is_retry ? " even " | 1748 | vcn_ofs, is_retry ? " even " |
| 1701 | "after retrying" : "", | 1749 | "after retrying" : "", err); |
| 1702 | (long long)lcn); | ||
| 1703 | if (!err) | ||
| 1704 | err = -EIO; | ||
| 1705 | goto err_out; | 1750 | goto err_out; |
| 1706 | } | 1751 | } |
| 1707 | /* We now have a successful remap, i.e. lcn >= 0. */ | 1752 | /* We now have a successful remap, i.e. lcn >= 0. */ |
| @@ -2357,6 +2402,7 @@ void mark_ntfs_record_dirty(struct page *page, const unsigned int ofs) { | |||
| 2357 | buffers_to_free = bh; | 2402 | buffers_to_free = bh; |
| 2358 | } | 2403 | } |
| 2359 | bh = head = page_buffers(page); | 2404 | bh = head = page_buffers(page); |
| 2405 | BUG_ON(!bh); | ||
| 2360 | do { | 2406 | do { |
| 2361 | bh_ofs = bh_offset(bh); | 2407 | bh_ofs = bh_offset(bh); |
| 2362 | if (bh_ofs + bh_size <= ofs) | 2408 | 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) |
