diff options
Diffstat (limited to 'fs/ntfs')
-rw-r--r-- | fs/ntfs/ChangeLog | 9 | ||||
-rw-r--r-- | fs/ntfs/aops.c | 34 | ||||
-rw-r--r-- | fs/ntfs/attrib.c | 107 | ||||
-rw-r--r-- | fs/ntfs/attrib.h | 5 | ||||
-rw-r--r-- | fs/ntfs/lcnalloc.c | 39 | ||||
-rw-r--r-- | fs/ntfs/mft.c | 38 |
6 files changed, 119 insertions, 113 deletions
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index b40c334e616f..9d42393c16c0 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog | |||
@@ -63,6 +63,15 @@ ToDo/Notes: | |||
63 | - Fix a bug in fs/ntfs/runlist.c::ntfs_mapping_pairs_decompress() in | 63 | - Fix a bug in fs/ntfs/runlist.c::ntfs_mapping_pairs_decompress() in |
64 | the creation of the unmapped runlist element for the base attribute | 64 | the creation of the unmapped runlist element for the base attribute |
65 | extent. | 65 | extent. |
66 | - Split ntfs_map_runlist() into ntfs_map_runlist() and a non-locking | ||
67 | helper ntfs_map_runlist_nolock() which is used by ntfs_map_runlist(). | ||
68 | This allows us to map runlist fragments with the runlist lock already | ||
69 | held without having to drop and reacquire it around the call. Adapt | ||
70 | all callers. | ||
71 | - Change ntfs_find_vcn() to ntfs_find_vcn_nolock() which takes a locked | ||
72 | runlist. This allows us to find runlist elements with the runlist | ||
73 | lock already held without having to drop and reacquire it around the | ||
74 | call. Adapt all callers. | ||
66 | 75 | ||
67 | 2.1.22 - Many bug and race fixes and error handling improvements. | 76 | 2.1.22 - Many bug and race fixes and error handling improvements. |
68 | 77 | ||
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 812d53e93354..2b4b8b9e8796 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * aops.c - NTFS kernel address space operations and page cache handling. | 2 | * aops.c - NTFS kernel address space operations and page cache handling. |
3 | * Part of the Linux-NTFS project. | 3 | * Part of the Linux-NTFS project. |
4 | * | 4 | * |
5 | * Copyright (c) 2001-2004 Anton Altaparmakov | 5 | * Copyright (c) 2001-2005 Anton Altaparmakov |
6 | * Copyright (c) 2002 Richard Russon | 6 | * Copyright (c) 2002 Richard Russon |
7 | * | 7 | * |
8 | * This program/include file is free software; you can redistribute it and/or | 8 | * This program/include file is free software; you can redistribute it and/or |
@@ -135,7 +135,7 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) | |||
135 | i * rec_size), rec_size); | 135 | i * rec_size), rec_size); |
136 | flush_dcache_page(page); | 136 | flush_dcache_page(page); |
137 | kunmap_atomic(addr, KM_BIO_SRC_IRQ); | 137 | kunmap_atomic(addr, KM_BIO_SRC_IRQ); |
138 | if (likely(!PageError(page) && page_uptodate)) | 138 | if (likely(page_uptodate && !PageError(page))) |
139 | SetPageUptodate(page); | 139 | SetPageUptodate(page); |
140 | } | 140 | } |
141 | unlock_page(page); | 141 | unlock_page(page); |
@@ -347,11 +347,11 @@ handle_zblock: | |||
347 | */ | 347 | */ |
348 | static int ntfs_readpage(struct file *file, struct page *page) | 348 | static int ntfs_readpage(struct file *file, struct page *page) |
349 | { | 349 | { |
350 | loff_t i_size; | ||
351 | ntfs_inode *ni, *base_ni; | 350 | ntfs_inode *ni, *base_ni; |
352 | u8 *kaddr; | 351 | u8 *kaddr; |
353 | ntfs_attr_search_ctx *ctx; | 352 | ntfs_attr_search_ctx *ctx; |
354 | MFT_RECORD *mrec; | 353 | MFT_RECORD *mrec; |
354 | unsigned long flags; | ||
355 | u32 attr_len; | 355 | u32 attr_len; |
356 | int err = 0; | 356 | int err = 0; |
357 | 357 | ||
@@ -389,9 +389,9 @@ static int ntfs_readpage(struct file *file, struct page *page) | |||
389 | * Attribute is resident, implying it is not compressed or encrypted. | 389 | * Attribute is resident, implying it is not compressed or encrypted. |
390 | * This also means the attribute is smaller than an mft record and | 390 | * This also means the attribute is smaller than an mft record and |
391 | * hence smaller than a page, so can simply zero out any pages with | 391 | * hence smaller than a page, so can simply zero out any pages with |
392 | * index above 0. We can also do this if the file size is 0. | 392 | * index above 0. |
393 | */ | 393 | */ |
394 | if (unlikely(page->index > 0 || !i_size_read(VFS_I(ni)))) { | 394 | if (unlikely(page->index > 0)) { |
395 | kaddr = kmap_atomic(page, KM_USER0); | 395 | kaddr = kmap_atomic(page, KM_USER0); |
396 | memset(kaddr, 0, PAGE_CACHE_SIZE); | 396 | memset(kaddr, 0, PAGE_CACHE_SIZE); |
397 | flush_dcache_page(page); | 397 | flush_dcache_page(page); |
@@ -418,9 +418,10 @@ static int ntfs_readpage(struct file *file, struct page *page) | |||
418 | if (unlikely(err)) | 418 | if (unlikely(err)) |
419 | goto put_unm_err_out; | 419 | goto put_unm_err_out; |
420 | attr_len = le32_to_cpu(ctx->attr->data.resident.value_length); | 420 | attr_len = le32_to_cpu(ctx->attr->data.resident.value_length); |
421 | i_size = i_size_read(VFS_I(ni)); | 421 | read_lock_irqsave(&ni->size_lock, flags); |
422 | if (unlikely(attr_len > i_size)) | 422 | if (unlikely(attr_len > ni->initialized_size)) |
423 | attr_len = i_size; | 423 | attr_len = ni->initialized_size; |
424 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
424 | kaddr = kmap_atomic(page, KM_USER0); | 425 | kaddr = kmap_atomic(page, KM_USER0); |
425 | /* Copy the data to the page. */ | 426 | /* Copy the data to the page. */ |
426 | memcpy(kaddr, (u8*)ctx->attr + | 427 | memcpy(kaddr, (u8*)ctx->attr + |
@@ -1247,20 +1248,6 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc) | |||
1247 | int err; | 1248 | int err; |
1248 | 1249 | ||
1249 | BUG_ON(!PageLocked(page)); | 1250 | BUG_ON(!PageLocked(page)); |
1250 | /* | ||
1251 | * If a previous ntfs_truncate() failed, repeat it and abort if it | ||
1252 | * fails again. | ||
1253 | */ | ||
1254 | if (unlikely(NInoTruncateFailed(ni))) { | ||
1255 | down_write(&vi->i_alloc_sem); | ||
1256 | err = ntfs_truncate(vi); | ||
1257 | up_write(&vi->i_alloc_sem); | ||
1258 | if (err || NInoTruncateFailed(ni)) { | ||
1259 | if (!err) | ||
1260 | err = -EIO; | ||
1261 | goto err_out; | ||
1262 | } | ||
1263 | } | ||
1264 | i_size = i_size_read(vi); | 1251 | i_size = i_size_read(vi); |
1265 | /* Is the page fully outside i_size? (truncate in progress) */ | 1252 | /* Is the page fully outside i_size? (truncate in progress) */ |
1266 | if (unlikely(page->index >= (i_size + PAGE_CACHE_SIZE - 1) >> | 1253 | if (unlikely(page->index >= (i_size + PAGE_CACHE_SIZE - 1) >> |
@@ -1490,13 +1477,12 @@ static int ntfs_prepare_nonresident_write(struct page *page, | |||
1490 | 1477 | ||
1491 | read_lock_irqsave(&ni->size_lock, flags); | 1478 | read_lock_irqsave(&ni->size_lock, flags); |
1492 | /* | 1479 | /* |
1493 | * The first out of bounds block for the allocated size. No need to | 1480 | * The first out of bounds block for the allocated size. No need to |
1494 | * round up as allocated_size is in multiples of cluster size and the | 1481 | * round up as allocated_size is in multiples of cluster size and the |
1495 | * minimum cluster size is 512 bytes, which is equal to the smallest | 1482 | * minimum cluster size is 512 bytes, which is equal to the smallest |
1496 | * blocksize. | 1483 | * blocksize. |
1497 | */ | 1484 | */ |
1498 | ablock = ni->allocated_size >> blocksize_bits; | 1485 | ablock = ni->allocated_size >> blocksize_bits; |
1499 | |||
1500 | i_size = i_size_read(vi); | 1486 | i_size = i_size_read(vi); |
1501 | initialized_size = ni->initialized_size; | 1487 | initialized_size = ni->initialized_size; |
1502 | read_unlock_irqrestore(&ni->size_lock, flags); | 1488 | read_unlock_irqrestore(&ni->size_lock, flags); |
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 7d668466dcd7..7a16f7ca76d8 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /** | 1 | /** |
2 | * attrib.c - NTFS attribute operations. Part of the Linux-NTFS project. | 2 | * attrib.c - NTFS attribute operations. Part of the Linux-NTFS project. |
3 | * | 3 | * |
4 | * Copyright (c) 2001-2004 Anton Altaparmakov | 4 | * Copyright (c) 2001-2005 Anton Altaparmakov |
5 | * Copyright (c) 2002 Richard Russon | 5 | * Copyright (c) 2002 Richard Russon |
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 |
@@ -30,7 +30,7 @@ | |||
30 | #include "types.h" | 30 | #include "types.h" |
31 | 31 | ||
32 | /** | 32 | /** |
33 | * ntfs_map_runlist - map (a part of) a runlist of an ntfs inode | 33 | * ntfs_map_runlist_nolock - map (a part of) a runlist of an ntfs inode |
34 | * @ni: ntfs inode for which to map (part of) a runlist | 34 | * @ni: ntfs inode for which to map (part of) a runlist |
35 | * @vcn: map runlist part containing this vcn | 35 | * @vcn: map runlist part containing this vcn |
36 | * | 36 | * |
@@ -38,24 +38,23 @@ | |||
38 | * | 38 | * |
39 | * Return 0 on success and -errno on error. | 39 | * Return 0 on success and -errno on error. |
40 | * | 40 | * |
41 | * Locking: - The runlist must be unlocked on entry and is unlocked on return. | 41 | * Locking: - The runlist must be locked for writing. |
42 | * - This function takes the lock for writing and modifies the runlist. | 42 | * - This function modifies the runlist. |
43 | */ | 43 | */ |
44 | int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) | 44 | int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) |
45 | { | 45 | { |
46 | ntfs_inode *base_ni; | 46 | ntfs_inode *base_ni; |
47 | ntfs_attr_search_ctx *ctx; | ||
48 | MFT_RECORD *mrec; | 47 | MFT_RECORD *mrec; |
48 | ntfs_attr_search_ctx *ctx; | ||
49 | runlist_element *rl; | ||
49 | int err = 0; | 50 | int err = 0; |
50 | 51 | ||
51 | ntfs_debug("Mapping runlist part containing vcn 0x%llx.", | 52 | ntfs_debug("Mapping runlist part containing vcn 0x%llx.", |
52 | (unsigned long long)vcn); | 53 | (unsigned long long)vcn); |
53 | |||
54 | if (!NInoAttr(ni)) | 54 | if (!NInoAttr(ni)) |
55 | base_ni = ni; | 55 | base_ni = ni; |
56 | else | 56 | else |
57 | base_ni = ni->ext.base_ntfs_ino; | 57 | base_ni = ni->ext.base_ntfs_ino; |
58 | |||
59 | mrec = map_mft_record(base_ni); | 58 | mrec = map_mft_record(base_ni); |
60 | if (IS_ERR(mrec)) | 59 | if (IS_ERR(mrec)) |
61 | return PTR_ERR(mrec); | 60 | return PTR_ERR(mrec); |
@@ -66,15 +65,7 @@ int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) | |||
66 | } | 65 | } |
67 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, | 66 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, |
68 | CASE_SENSITIVE, vcn, NULL, 0, ctx); | 67 | CASE_SENSITIVE, vcn, NULL, 0, ctx); |
69 | if (unlikely(err)) | 68 | if (likely(!err)) { |
70 | goto put_err_out; | ||
71 | |||
72 | down_write(&ni->runlist.lock); | ||
73 | /* Make sure someone else didn't do the work while we were sleeping. */ | ||
74 | if (likely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) <= | ||
75 | LCN_RL_NOT_MAPPED)) { | ||
76 | runlist_element *rl; | ||
77 | |||
78 | rl = ntfs_mapping_pairs_decompress(ni->vol, ctx->attr, | 69 | rl = ntfs_mapping_pairs_decompress(ni->vol, ctx->attr, |
79 | ni->runlist.rl); | 70 | ni->runlist.rl); |
80 | if (IS_ERR(rl)) | 71 | if (IS_ERR(rl)) |
@@ -82,9 +73,6 @@ int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) | |||
82 | else | 73 | else |
83 | ni->runlist.rl = rl; | 74 | ni->runlist.rl = rl; |
84 | } | 75 | } |
85 | up_write(&ni->runlist.lock); | ||
86 | |||
87 | put_err_out: | ||
88 | ntfs_attr_put_search_ctx(ctx); | 76 | ntfs_attr_put_search_ctx(ctx); |
89 | err_out: | 77 | err_out: |
90 | unmap_mft_record(base_ni); | 78 | unmap_mft_record(base_ni); |
@@ -92,17 +80,45 @@ err_out: | |||
92 | } | 80 | } |
93 | 81 | ||
94 | /** | 82 | /** |
95 | * ntfs_find_vcn - find a vcn in the runlist described by an ntfs inode | 83 | * ntfs_map_runlist - map (a part of) a runlist of an ntfs inode |
96 | * @ni: ntfs inode describing the runlist to search | 84 | * @ni: ntfs inode for which to map (part of) a runlist |
97 | * @vcn: vcn to find | 85 | * @vcn: map runlist part containing this vcn |
98 | * @need_write: if false, lock for reading and if true, lock for writing | 86 | * |
87 | * Map the part of a runlist containing the @vcn of the ntfs inode @ni. | ||
88 | * | ||
89 | * Return 0 on success and -errno on error. | ||
90 | * | ||
91 | * Locking: - The runlist must be unlocked on entry and is unlocked on return. | ||
92 | * - This function takes the runlist lock for writing and modifies the | ||
93 | * runlist. | ||
94 | */ | ||
95 | int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) | ||
96 | { | ||
97 | int err = 0; | ||
98 | |||
99 | down_write(&ni->runlist.lock); | ||
100 | /* Make sure someone else didn't do the work while we were sleeping. */ | ||
101 | if (likely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) <= | ||
102 | LCN_RL_NOT_MAPPED)) | ||
103 | err = ntfs_map_runlist_nolock(ni, vcn); | ||
104 | up_write(&ni->runlist.lock); | ||
105 | return err; | ||
106 | } | ||
107 | |||
108 | /** | ||
109 | * ntfs_find_vcn_nolock - find a vcn in the runlist described by an ntfs inode | ||
110 | * @ni: ntfs inode describing the runlist to search | ||
111 | * @vcn: vcn to find | ||
112 | * @write_locked: true if the runlist is locked for writing | ||
99 | * | 113 | * |
100 | * Find the virtual cluster number @vcn in the runlist described by the ntfs | 114 | * Find the virtual cluster number @vcn in the runlist described by the ntfs |
101 | * inode @ni and return the address of the runlist element containing the @vcn. | 115 | * inode @ni and return the address of the runlist element containing the @vcn. |
102 | * The runlist is left locked and the caller has to unlock it. If @need_write | 116 | * The runlist is left locked and the caller has to unlock it. In the error |
103 | * is true, the runlist is locked for writing and if @need_write is false, the | 117 | * case, the runlist is left in the same locking state as on entry. |
104 | * runlist is locked for reading. In the error case, the runlist is not left | 118 | * |
105 | * locked. | 119 | * Note if @write_locked is FALSE the lock may be dropped inside the function |
120 | * so you cannot rely on the runlist still being the same when this function | ||
121 | * returns. | ||
106 | * | 122 | * |
107 | * Note you need to distinguish between the lcn of the returned runlist element | 123 | * Note you need to distinguish between the lcn of the returned runlist element |
108 | * being >= 0 and LCN_HOLE. In the later case you have to return zeroes on | 124 | * being >= 0 and LCN_HOLE. In the later case you have to return zeroes on |
@@ -124,28 +140,24 @@ err_out: | |||
124 | * true, it is locked for writing. Otherwise is is locked for | 140 | * true, it is locked for writing. Otherwise is is locked for |
125 | * reading. | 141 | * reading. |
126 | */ | 142 | */ |
127 | runlist_element *ntfs_find_vcn(ntfs_inode *ni, const VCN vcn, | 143 | runlist_element *ntfs_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, |
128 | const BOOL need_write) | 144 | const BOOL write_locked) |
129 | { | 145 | { |
130 | runlist_element *rl; | 146 | runlist_element *rl; |
131 | int err = 0; | 147 | int err = 0; |
132 | BOOL is_retry = FALSE; | 148 | BOOL is_retry = FALSE; |
133 | 149 | ||
134 | ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, lock for %sing.", | 150 | ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.", |
135 | ni->mft_no, (unsigned long long)vcn, | 151 | ni->mft_no, (unsigned long long)vcn, |
136 | !need_write ? "read" : "writ"); | 152 | write_locked ? "write" : "read"); |
137 | BUG_ON(!ni); | 153 | BUG_ON(!ni); |
138 | BUG_ON(!NInoNonResident(ni)); | 154 | BUG_ON(!NInoNonResident(ni)); |
139 | BUG_ON(vcn < 0); | 155 | BUG_ON(vcn < 0); |
140 | lock_retry_remap: | 156 | retry_remap: |
141 | if (!need_write) | ||
142 | down_read(&ni->runlist.lock); | ||
143 | else | ||
144 | down_write(&ni->runlist.lock); | ||
145 | rl = ni->runlist.rl; | 157 | rl = ni->runlist.rl; |
146 | if (likely(rl && vcn >= rl[0].vcn)) { | 158 | if (likely(rl && vcn >= rl[0].vcn)) { |
147 | while (likely(rl->length)) { | 159 | while (likely(rl->length)) { |
148 | if (likely(vcn < rl[1].vcn)) { | 160 | if (unlikely(vcn < rl[1].vcn)) { |
149 | if (likely(rl->lcn >= LCN_HOLE)) { | 161 | if (likely(rl->lcn >= LCN_HOLE)) { |
150 | ntfs_debug("Done."); | 162 | ntfs_debug("Done."); |
151 | return rl; | 163 | return rl; |
@@ -161,19 +173,23 @@ lock_retry_remap: | |||
161 | err = -EIO; | 173 | err = -EIO; |
162 | } | 174 | } |
163 | } | 175 | } |
164 | if (!need_write) | ||
165 | up_read(&ni->runlist.lock); | ||
166 | else | ||
167 | up_write(&ni->runlist.lock); | ||
168 | if (!err && !is_retry) { | 176 | if (!err && !is_retry) { |
169 | /* | 177 | /* |
170 | * The @vcn is in an unmapped region, map the runlist and | 178 | * The @vcn is in an unmapped region, map the runlist and |
171 | * retry. | 179 | * retry. |
172 | */ | 180 | */ |
173 | err = ntfs_map_runlist(ni, vcn); | 181 | if (!write_locked) { |
182 | up_read(&ni->runlist.lock); | ||
183 | down_write(&ni->runlist.lock); | ||
184 | } | ||
185 | err = ntfs_map_runlist_nolock(ni, vcn); | ||
186 | if (!write_locked) { | ||
187 | up_write(&ni->runlist.lock); | ||
188 | down_read(&ni->runlist.lock); | ||
189 | } | ||
174 | if (likely(!err)) { | 190 | if (likely(!err)) { |
175 | is_retry = TRUE; | 191 | is_retry = TRUE; |
176 | goto lock_retry_remap; | 192 | goto retry_remap; |
177 | } | 193 | } |
178 | /* | 194 | /* |
179 | * -EINVAL and -ENOENT coming from a failed mapping attempt are | 195 | * -EINVAL and -ENOENT coming from a failed mapping attempt are |
@@ -184,7 +200,8 @@ lock_retry_remap: | |||
184 | err = -EIO; | 200 | err = -EIO; |
185 | } else if (!err) | 201 | } else if (!err) |
186 | err = -EIO; | 202 | err = -EIO; |
187 | ntfs_error(ni->vol->sb, "Failed with error code %i.", err); | 203 | if (err != -ENOENT) |
204 | ntfs_error(ni->vol->sb, "Failed with error code %i.", err); | ||
188 | return ERR_PTR(err); | 205 | return ERR_PTR(err); |
189 | } | 206 | } |
190 | 207 | ||
diff --git a/fs/ntfs/attrib.h b/fs/ntfs/attrib.h index e0c2c6c81bc0..3eb451657025 100644 --- a/fs/ntfs/attrib.h +++ b/fs/ntfs/attrib.h | |||
@@ -60,10 +60,11 @@ typedef struct { | |||
60 | ATTR_RECORD *base_attr; | 60 | ATTR_RECORD *base_attr; |
61 | } ntfs_attr_search_ctx; | 61 | } ntfs_attr_search_ctx; |
62 | 62 | ||
63 | extern int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn); | ||
63 | extern int ntfs_map_runlist(ntfs_inode *ni, VCN vcn); | 64 | extern int ntfs_map_runlist(ntfs_inode *ni, VCN vcn); |
64 | 65 | ||
65 | extern runlist_element *ntfs_find_vcn(ntfs_inode *ni, const VCN vcn, | 66 | extern runlist_element *ntfs_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, |
66 | const BOOL need_write); | 67 | const BOOL write_locked); |
67 | 68 | ||
68 | int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name, | 69 | int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name, |
69 | const u32 name_len, const IGNORE_CASE_BOOL ic, | 70 | const u32 name_len, const IGNORE_CASE_BOOL ic, |
diff --git a/fs/ntfs/lcnalloc.c b/fs/ntfs/lcnalloc.c index 5346596fa871..8db4492b139c 100644 --- a/fs/ntfs/lcnalloc.c +++ b/fs/ntfs/lcnalloc.c | |||
@@ -849,7 +849,8 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count, | |||
849 | total_freed = real_freed = 0; | 849 | total_freed = real_freed = 0; |
850 | 850 | ||
851 | /* This returns with ni->runlist locked for reading on success. */ | 851 | /* This returns with ni->runlist locked for reading on success. */ |
852 | rl = ntfs_find_vcn(ni, start_vcn, FALSE); | 852 | down_read(&ni->runlist.lock); |
853 | rl = ntfs_find_vcn_nolock(ni, start_vcn, FALSE); | ||
853 | if (IS_ERR(rl)) { | 854 | if (IS_ERR(rl)) { |
854 | if (!is_rollback) | 855 | if (!is_rollback) |
855 | ntfs_error(vol->sb, "Failed to find first runlist " | 856 | ntfs_error(vol->sb, "Failed to find first runlist " |
@@ -863,7 +864,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count, | |||
863 | ntfs_error(vol->sb, "First runlist element has " | 864 | ntfs_error(vol->sb, "First runlist element has " |
864 | "invalid lcn, aborting."); | 865 | "invalid lcn, aborting."); |
865 | err = -EIO; | 866 | err = -EIO; |
866 | goto unl_err_out; | 867 | goto err_out; |
867 | } | 868 | } |
868 | /* Find the starting cluster inside the run that needs freeing. */ | 869 | /* Find the starting cluster inside the run that needs freeing. */ |
869 | delta = start_vcn - rl->vcn; | 870 | delta = start_vcn - rl->vcn; |
@@ -881,7 +882,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count, | |||
881 | if (!is_rollback) | 882 | if (!is_rollback) |
882 | ntfs_error(vol->sb, "Failed to clear first run " | 883 | ntfs_error(vol->sb, "Failed to clear first run " |
883 | "(error %i), aborting.", err); | 884 | "(error %i), aborting.", err); |
884 | goto unl_err_out; | 885 | goto err_out; |
885 | } | 886 | } |
886 | /* We have freed @to_free real clusters. */ | 887 | /* We have freed @to_free real clusters. */ |
887 | real_freed = to_free; | 888 | real_freed = to_free; |
@@ -901,30 +902,15 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count, | |||
901 | if (unlikely(rl->lcn < LCN_HOLE)) { | 902 | if (unlikely(rl->lcn < LCN_HOLE)) { |
902 | VCN vcn; | 903 | VCN vcn; |
903 | 904 | ||
904 | /* | 905 | /* Attempt to map runlist. */ |
905 | * Attempt to map runlist, dropping runlist lock for | ||
906 | * the duration. | ||
907 | */ | ||
908 | vcn = rl->vcn; | 906 | vcn = rl->vcn; |
909 | up_read(&ni->runlist.lock); | 907 | rl = ntfs_find_vcn_nolock(ni, vcn, FALSE); |
910 | err = ntfs_map_runlist(ni, vcn); | ||
911 | if (err) { | ||
912 | if (!is_rollback) | ||
913 | ntfs_error(vol->sb, "Failed to map " | ||
914 | "runlist fragment."); | ||
915 | if (err == -EINVAL || err == -ENOENT) | ||
916 | err = -EIO; | ||
917 | goto err_out; | ||
918 | } | ||
919 | /* | ||
920 | * This returns with ni->runlist locked for reading on | ||
921 | * success. | ||
922 | */ | ||
923 | rl = ntfs_find_vcn(ni, vcn, FALSE); | ||
924 | if (IS_ERR(rl)) { | 908 | if (IS_ERR(rl)) { |
925 | err = PTR_ERR(rl); | 909 | err = PTR_ERR(rl); |
926 | if (!is_rollback) | 910 | if (!is_rollback) |
927 | ntfs_error(vol->sb, "Failed to find " | 911 | ntfs_error(vol->sb, "Failed to map " |
912 | "runlist fragment or " | ||
913 | "failed to find " | ||
928 | "subsequent runlist " | 914 | "subsequent runlist " |
929 | "element."); | 915 | "element."); |
930 | goto err_out; | 916 | goto err_out; |
@@ -937,7 +923,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count, | |||
937 | (unsigned long long) | 923 | (unsigned long long) |
938 | rl->lcn); | 924 | rl->lcn); |
939 | err = -EIO; | 925 | err = -EIO; |
940 | goto unl_err_out; | 926 | goto err_out; |
941 | } | 927 | } |
942 | } | 928 | } |
943 | /* The number of clusters in this run that need freeing. */ | 929 | /* The number of clusters in this run that need freeing. */ |
@@ -953,7 +939,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count, | |||
953 | if (!is_rollback) | 939 | if (!is_rollback) |
954 | ntfs_error(vol->sb, "Failed to clear " | 940 | ntfs_error(vol->sb, "Failed to clear " |
955 | "subsequent run."); | 941 | "subsequent run."); |
956 | goto unl_err_out; | 942 | goto err_out; |
957 | } | 943 | } |
958 | /* We have freed @to_free real clusters. */ | 944 | /* We have freed @to_free real clusters. */ |
959 | real_freed += to_free; | 945 | real_freed += to_free; |
@@ -974,9 +960,8 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count, | |||
974 | /* We are done. Return the number of actually freed clusters. */ | 960 | /* We are done. Return the number of actually freed clusters. */ |
975 | ntfs_debug("Done."); | 961 | ntfs_debug("Done."); |
976 | return real_freed; | 962 | return real_freed; |
977 | unl_err_out: | ||
978 | up_read(&ni->runlist.lock); | ||
979 | err_out: | 963 | err_out: |
964 | up_read(&ni->runlist.lock); | ||
980 | if (is_rollback) | 965 | if (is_rollback) |
981 | return err; | 966 | return err; |
982 | /* If no real clusters were freed, no need to rollback. */ | 967 | /* If no real clusters were freed, no need to rollback. */ |
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index 4e0bf39426cf..0975d738834c 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /** | 1 | /** |
2 | * mft.c - NTFS kernel mft record operations. Part of the Linux-NTFS project. | 2 | * mft.c - NTFS kernel mft record operations. Part of the Linux-NTFS project. |
3 | * | 3 | * |
4 | * Copyright (c) 2001-2004 Anton Altaparmakov | 4 | * Copyright (c) 2001-2005 Anton Altaparmakov |
5 | * Copyright (c) 2002 Richard Russon | 5 | * Copyright (c) 2002 Richard Russon |
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 |
@@ -287,7 +287,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref, | |||
287 | } | 287 | } |
288 | unmap_mft_record(ni); | 288 | unmap_mft_record(ni); |
289 | ntfs_error(base_ni->vol->sb, "Found stale extent mft " | 289 | ntfs_error(base_ni->vol->sb, "Found stale extent mft " |
290 | "reference! Corrupt file system. " | 290 | "reference! Corrupt filesystem. " |
291 | "Run chkdsk."); | 291 | "Run chkdsk."); |
292 | return ERR_PTR(-EIO); | 292 | return ERR_PTR(-EIO); |
293 | } | 293 | } |
@@ -318,7 +318,7 @@ map_err_out: | |||
318 | /* Verify the sequence number if it is present. */ | 318 | /* Verify the sequence number if it is present. */ |
319 | if (seq_no && (le16_to_cpu(m->sequence_number) != seq_no)) { | 319 | if (seq_no && (le16_to_cpu(m->sequence_number) != seq_no)) { |
320 | ntfs_error(base_ni->vol->sb, "Found stale extent mft " | 320 | ntfs_error(base_ni->vol->sb, "Found stale extent mft " |
321 | "reference! Corrupt file system. Run chkdsk."); | 321 | "reference! Corrupt filesystem. Run chkdsk."); |
322 | destroy_ni = TRUE; | 322 | destroy_ni = TRUE; |
323 | m = ERR_PTR(-EIO); | 323 | m = ERR_PTR(-EIO); |
324 | goto unm_err_out; | 324 | goto unm_err_out; |
@@ -1292,19 +1292,20 @@ static int ntfs_mft_bitmap_extend_allocation_nolock(ntfs_volume *vol) | |||
1292 | /* | 1292 | /* |
1293 | * Determine the last lcn of the mft bitmap. The allocated size of the | 1293 | * Determine the last lcn of the mft bitmap. The allocated size of the |
1294 | * mft bitmap cannot be zero so we are ok to do this. | 1294 | * mft bitmap cannot be zero so we are ok to do this. |
1295 | * ntfs_find_vcn() returns the runlist locked on success. | ||
1296 | */ | 1295 | */ |
1296 | down_write(&mftbmp_ni->runlist.lock); | ||
1297 | read_lock_irqsave(&mftbmp_ni->size_lock, flags); | 1297 | read_lock_irqsave(&mftbmp_ni->size_lock, flags); |
1298 | ll = mftbmp_ni->allocated_size; | 1298 | ll = mftbmp_ni->allocated_size; |
1299 | read_unlock_irqrestore(&mftbmp_ni->size_lock, flags); | 1299 | read_unlock_irqrestore(&mftbmp_ni->size_lock, flags); |
1300 | rl = ntfs_find_vcn(mftbmp_ni, (ll - 1) >> vol->cluster_size_bits, TRUE); | 1300 | rl = ntfs_find_vcn_nolock(mftbmp_ni, |
1301 | (ll - 1) >> vol->cluster_size_bits, TRUE); | ||
1301 | if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) { | 1302 | if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) { |
1303 | up_write(&mftbmp_ni->runlist.lock); | ||
1302 | ntfs_error(vol->sb, "Failed to determine last allocated " | 1304 | ntfs_error(vol->sb, "Failed to determine last allocated " |
1303 | "cluster of mft bitmap attribute."); | 1305 | "cluster of mft bitmap attribute."); |
1304 | if (!IS_ERR(rl)) { | 1306 | if (!IS_ERR(rl)) |
1305 | up_write(&mftbmp_ni->runlist.lock); | ||
1306 | ret = -EIO; | 1307 | ret = -EIO; |
1307 | } else | 1308 | else |
1308 | ret = PTR_ERR(rl); | 1309 | ret = PTR_ERR(rl); |
1309 | return ret; | 1310 | return ret; |
1310 | } | 1311 | } |
@@ -1428,6 +1429,8 @@ static int ntfs_mft_bitmap_extend_allocation_nolock(ntfs_volume *vol) | |||
1428 | // TODO: Deal with this by moving this extent to a new mft | 1429 | // TODO: Deal with this by moving this extent to a new mft |
1429 | // record or by starting a new extent in a new mft record or by | 1430 | // record or by starting a new extent in a new mft record or by |
1430 | // moving other attributes out of this mft record. | 1431 | // moving other attributes out of this mft record. |
1432 | // Note: It will need to be a special mft record and if none of | ||
1433 | // those are available it gets rather complicated... | ||
1431 | ntfs_error(vol->sb, "Not enough space in this mft record to " | 1434 | ntfs_error(vol->sb, "Not enough space in this mft record to " |
1432 | "accomodate extended mft bitmap attribute " | 1435 | "accomodate extended mft bitmap attribute " |
1433 | "extent. Cannot handle this yet."); | 1436 | "extent. Cannot handle this yet."); |
@@ -1719,19 +1722,20 @@ static int ntfs_mft_data_extend_allocation_nolock(ntfs_volume *vol) | |||
1719 | * Determine the preferred allocation location, i.e. the last lcn of | 1722 | * Determine the preferred allocation location, i.e. the last lcn of |
1720 | * the mft data attribute. The allocated size of the mft data | 1723 | * the mft data attribute. The allocated size of the mft data |
1721 | * attribute cannot be zero so we are ok to do this. | 1724 | * attribute cannot be zero so we are ok to do this. |
1722 | * ntfs_find_vcn() returns the runlist locked on success. | ||
1723 | */ | 1725 | */ |
1726 | down_write(&mft_ni->runlist.lock); | ||
1724 | read_lock_irqsave(&mft_ni->size_lock, flags); | 1727 | read_lock_irqsave(&mft_ni->size_lock, flags); |
1725 | ll = mft_ni->allocated_size; | 1728 | ll = mft_ni->allocated_size; |
1726 | read_unlock_irqrestore(&mft_ni->size_lock, flags); | 1729 | read_unlock_irqrestore(&mft_ni->size_lock, flags); |
1727 | rl = ntfs_find_vcn(mft_ni, (ll - 1) >> vol->cluster_size_bits, TRUE); | 1730 | rl = ntfs_find_vcn_nolock(mft_ni, (ll - 1) >> vol->cluster_size_bits, |
1731 | TRUE); | ||
1728 | if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) { | 1732 | if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) { |
1733 | up_write(&mft_ni->runlist.lock); | ||
1729 | ntfs_error(vol->sb, "Failed to determine last allocated " | 1734 | ntfs_error(vol->sb, "Failed to determine last allocated " |
1730 | "cluster of mft data attribute."); | 1735 | "cluster of mft data attribute."); |
1731 | if (!IS_ERR(rl)) { | 1736 | if (!IS_ERR(rl)) |
1732 | up_write(&mft_ni->runlist.lock); | ||
1733 | ret = -EIO; | 1737 | ret = -EIO; |
1734 | } else | 1738 | else |
1735 | ret = PTR_ERR(rl); | 1739 | ret = PTR_ERR(rl); |
1736 | return ret; | 1740 | return ret; |
1737 | } | 1741 | } |
@@ -1858,7 +1862,11 @@ static int ntfs_mft_data_extend_allocation_nolock(ntfs_volume *vol) | |||
1858 | // moving other attributes out of this mft record. | 1862 | // moving other attributes out of this mft record. |
1859 | // Note: Use the special reserved mft records and ensure that | 1863 | // Note: Use the special reserved mft records and ensure that |
1860 | // this extent is not required to find the mft record in | 1864 | // this extent is not required to find the mft record in |
1861 | // question. | 1865 | // question. If no free special records left we would need to |
1866 | // move an existing record away, insert ours in its place, and | ||
1867 | // then place the moved record into the newly allocated space | ||
1868 | // and we would then need to update all references to this mft | ||
1869 | // record appropriately. This is rather complicated... | ||
1862 | ntfs_error(vol->sb, "Not enough space in this mft record to " | 1870 | ntfs_error(vol->sb, "Not enough space in this mft record to " |
1863 | "accomodate extended mft data attribute " | 1871 | "accomodate extended mft data attribute " |
1864 | "extent. Cannot handle this yet."); | 1872 | "extent. Cannot handle this yet."); |
@@ -2021,7 +2029,7 @@ static int ntfs_mft_record_layout(const ntfs_volume *vol, const s64 mft_no, | |||
2021 | "reports this as corruption, please email " | 2029 | "reports this as corruption, please email " |
2022 | "linux-ntfs-dev@lists.sourceforge.net stating " | 2030 | "linux-ntfs-dev@lists.sourceforge.net stating " |
2023 | "that you saw this message and that the " | 2031 | "that you saw this message and that the " |
2024 | "modified file system created was corrupt. " | 2032 | "modified filesystem created was corrupt. " |
2025 | "Thank you."); | 2033 | "Thank you."); |
2026 | } | 2034 | } |
2027 | /* Set the update sequence number to 1. */ | 2035 | /* Set the update sequence number to 1. */ |