diff options
-rw-r--r-- | fs/hfsplus/catalog.c | 10 | ||||
-rw-r--r-- | fs/hfsplus/extents.c | 30 | ||||
-rw-r--r-- | fs/hfsplus/hfsplus_fs.h | 37 | ||||
-rw-r--r-- | fs/hfsplus/inode.c | 27 | ||||
-rw-r--r-- | fs/hfsplus/ioctl.c | 4 | ||||
-rw-r--r-- | fs/hfsplus/super.c | 2 |
6 files changed, 78 insertions, 32 deletions
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c index 8af45fc5b051..0aa40b36a9e7 100644 --- a/fs/hfsplus/catalog.c +++ b/fs/hfsplus/catalog.c | |||
@@ -227,7 +227,8 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct ino | |||
227 | 227 | ||
228 | dir->i_size++; | 228 | dir->i_size++; |
229 | dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; | 229 | dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; |
230 | mark_inode_dirty(dir); | 230 | hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY); |
231 | |||
231 | hfs_find_exit(&fd); | 232 | hfs_find_exit(&fd); |
232 | return 0; | 233 | return 0; |
233 | 234 | ||
@@ -308,7 +309,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) | |||
308 | 309 | ||
309 | dir->i_size--; | 310 | dir->i_size--; |
310 | dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; | 311 | dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; |
311 | mark_inode_dirty(dir); | 312 | hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY); |
312 | out: | 313 | out: |
313 | hfs_find_exit(&fd); | 314 | hfs_find_exit(&fd); |
314 | 315 | ||
@@ -353,7 +354,6 @@ int hfsplus_rename_cat(u32 cnid, | |||
353 | goto out; | 354 | goto out; |
354 | dst_dir->i_size++; | 355 | dst_dir->i_size++; |
355 | dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC; | 356 | dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC; |
356 | mark_inode_dirty(dst_dir); | ||
357 | 357 | ||
358 | /* finally remove the old entry */ | 358 | /* finally remove the old entry */ |
359 | hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); | 359 | hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); |
@@ -365,7 +365,6 @@ int hfsplus_rename_cat(u32 cnid, | |||
365 | goto out; | 365 | goto out; |
366 | src_dir->i_size--; | 366 | src_dir->i_size--; |
367 | src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC; | 367 | src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC; |
368 | mark_inode_dirty(src_dir); | ||
369 | 368 | ||
370 | /* remove old thread entry */ | 369 | /* remove old thread entry */ |
371 | hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL); | 370 | hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL); |
@@ -387,6 +386,9 @@ int hfsplus_rename_cat(u32 cnid, | |||
387 | goto out; | 386 | goto out; |
388 | } | 387 | } |
389 | err = hfs_brec_insert(&dst_fd, &entry, entry_size); | 388 | err = hfs_brec_insert(&dst_fd, &entry, entry_size); |
389 | |||
390 | hfsplus_mark_inode_dirty(dst_dir, HFSPLUS_I_CAT_DIRTY); | ||
391 | hfsplus_mark_inode_dirty(src_dir, HFSPLUS_I_CAT_DIRTY); | ||
390 | out: | 392 | out: |
391 | hfs_bnode_put(dst_fd.bnode); | 393 | hfs_bnode_put(dst_fd.bnode); |
392 | hfs_find_exit(&src_fd); | 394 | hfs_find_exit(&src_fd); |
diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c index 06b4fc3151a3..b1127ef26750 100644 --- a/fs/hfsplus/extents.c +++ b/fs/hfsplus/extents.c | |||
@@ -108,6 +108,14 @@ static void __hfsplus_ext_write_extent(struct inode *inode, struct hfs_find_data | |||
108 | fd->entryoffset, fd->entrylength); | 108 | fd->entryoffset, fd->entrylength); |
109 | hip->extent_state &= ~HFSPLUS_EXT_DIRTY; | 109 | hip->extent_state &= ~HFSPLUS_EXT_DIRTY; |
110 | } | 110 | } |
111 | |||
112 | /* | ||
113 | * We can't just use hfsplus_mark_inode_dirty here, because we | ||
114 | * also get called from hfsplus_write_inode, which should not | ||
115 | * redirty the inode. Instead the callers have to be careful | ||
116 | * to explicily mark the inode dirty, too. | ||
117 | */ | ||
118 | set_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags); | ||
111 | } | 119 | } |
112 | 120 | ||
113 | static void hfsplus_ext_write_extent_locked(struct inode *inode) | 121 | static void hfsplus_ext_write_extent_locked(struct inode *inode) |
@@ -197,6 +205,7 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock, | |||
197 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); | 205 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
198 | int res = -EIO; | 206 | int res = -EIO; |
199 | u32 ablock, dblock, mask; | 207 | u32 ablock, dblock, mask; |
208 | int was_dirty = 0; | ||
200 | int shift; | 209 | int shift; |
201 | 210 | ||
202 | /* Convert inode block to disk allocation block */ | 211 | /* Convert inode block to disk allocation block */ |
@@ -223,14 +232,20 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock, | |||
223 | return -EIO; | 232 | return -EIO; |
224 | 233 | ||
225 | mutex_lock(&hip->extents_lock); | 234 | mutex_lock(&hip->extents_lock); |
235 | |||
236 | /* | ||
237 | * hfsplus_ext_read_extent will write out a cached extent into | ||
238 | * the extents btree. In that case we may have to mark the inode | ||
239 | * dirty even for a pure read of an extent here. | ||
240 | */ | ||
241 | was_dirty = (hip->extent_state & HFSPLUS_EXT_DIRTY); | ||
226 | res = hfsplus_ext_read_extent(inode, ablock); | 242 | res = hfsplus_ext_read_extent(inode, ablock); |
227 | if (!res) { | 243 | if (res) { |
228 | dblock = hfsplus_ext_find_block(hip->cached_extents, | ||
229 | ablock - hip->cached_start); | ||
230 | } else { | ||
231 | mutex_unlock(&hip->extents_lock); | 244 | mutex_unlock(&hip->extents_lock); |
232 | return -EIO; | 245 | return -EIO; |
233 | } | 246 | } |
247 | dblock = hfsplus_ext_find_block(hip->cached_extents, | ||
248 | ablock - hip->cached_start); | ||
234 | mutex_unlock(&hip->extents_lock); | 249 | mutex_unlock(&hip->extents_lock); |
235 | 250 | ||
236 | done: | 251 | done: |
@@ -242,8 +257,9 @@ done: | |||
242 | hip->phys_size += sb->s_blocksize; | 257 | hip->phys_size += sb->s_blocksize; |
243 | hip->fs_blocks++; | 258 | hip->fs_blocks++; |
244 | inode_add_bytes(inode, sb->s_blocksize); | 259 | inode_add_bytes(inode, sb->s_blocksize); |
245 | mark_inode_dirty(inode); | ||
246 | } | 260 | } |
261 | if (create || was_dirty) | ||
262 | mark_inode_dirty(inode); | ||
247 | return 0; | 263 | return 0; |
248 | } | 264 | } |
249 | 265 | ||
@@ -438,7 +454,7 @@ out: | |||
438 | mutex_unlock(&hip->extents_lock); | 454 | mutex_unlock(&hip->extents_lock); |
439 | if (!res) { | 455 | if (!res) { |
440 | hip->alloc_blocks += len; | 456 | hip->alloc_blocks += len; |
441 | mark_inode_dirty(inode); | 457 | hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY); |
442 | } | 458 | } |
443 | return res; | 459 | return res; |
444 | 460 | ||
@@ -529,5 +545,5 @@ out: | |||
529 | hip->phys_size = inode->i_size; | 545 | hip->phys_size = inode->i_size; |
530 | hip->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; | 546 | hip->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; |
531 | inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits); | 547 | inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits); |
532 | mark_inode_dirty(inode); | 548 | hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY); |
533 | } | 549 | } |
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 9889d0033b8f..65c698f78ef7 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h | |||
@@ -157,6 +157,11 @@ struct hfsplus_sb_info { | |||
157 | #define HFSPLUS_SB_HFSX 3 | 157 | #define HFSPLUS_SB_HFSX 3 |
158 | #define HFSPLUS_SB_CASEFOLD 4 | 158 | #define HFSPLUS_SB_CASEFOLD 4 |
159 | 159 | ||
160 | static inline struct hfsplus_sb_info *HFSPLUS_SB(struct super_block *sb) | ||
161 | { | ||
162 | return sb->s_fs_info; | ||
163 | } | ||
164 | |||
160 | 165 | ||
161 | struct hfsplus_inode_info { | 166 | struct hfsplus_inode_info { |
162 | atomic_t opencnt; | 167 | atomic_t opencnt; |
@@ -205,10 +210,31 @@ struct hfsplus_inode_info { | |||
205 | #define HFSPLUS_EXT_NEW 0x0002 | 210 | #define HFSPLUS_EXT_NEW 0x0002 |
206 | 211 | ||
207 | #define HFSPLUS_I_RSRC 0 /* represents a resource fork */ | 212 | #define HFSPLUS_I_RSRC 0 /* represents a resource fork */ |
213 | #define HFSPLUS_I_CAT_DIRTY 1 /* has changes in the catalog tree */ | ||
214 | #define HFSPLUS_I_EXT_DIRTY 2 /* has changes in the extent tree */ | ||
215 | #define HFSPLUS_I_ALLOC_DIRTY 3 /* has changes in the allocation file */ | ||
208 | 216 | ||
209 | #define HFSPLUS_IS_RSRC(inode) \ | 217 | #define HFSPLUS_IS_RSRC(inode) \ |
210 | test_bit(HFSPLUS_I_RSRC, &HFSPLUS_I(inode)->flags) | 218 | test_bit(HFSPLUS_I_RSRC, &HFSPLUS_I(inode)->flags) |
211 | 219 | ||
220 | static inline struct hfsplus_inode_info *HFSPLUS_I(struct inode *inode) | ||
221 | { | ||
222 | return list_entry(inode, struct hfsplus_inode_info, vfs_inode); | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | * Mark an inode dirty, and also mark the btree in which the | ||
227 | * specific type of metadata is stored. | ||
228 | * For data or metadata that gets written back by into the catalog btree | ||
229 | * by hfsplus_write_inode a plain mark_inode_dirty call is enough. | ||
230 | */ | ||
231 | static inline void hfsplus_mark_inode_dirty(struct inode *inode, | ||
232 | unsigned int flag) | ||
233 | { | ||
234 | set_bit(flag, &HFSPLUS_I(inode)->flags); | ||
235 | mark_inode_dirty(inode); | ||
236 | } | ||
237 | |||
212 | struct hfs_find_data { | 238 | struct hfs_find_data { |
213 | /* filled by caller */ | 239 | /* filled by caller */ |
214 | hfsplus_btree_key *search_key; | 240 | hfsplus_btree_key *search_key; |
@@ -397,17 +423,6 @@ int hfs_part_find(struct super_block *, sector_t *, sector_t *); | |||
397 | int hfsplus_submit_bio(struct block_device *bdev, sector_t sector, | 423 | int hfsplus_submit_bio(struct block_device *bdev, sector_t sector, |
398 | void *data, int rw); | 424 | void *data, int rw); |
399 | 425 | ||
400 | /* access macros */ | ||
401 | static inline struct hfsplus_sb_info *HFSPLUS_SB(struct super_block *sb) | ||
402 | { | ||
403 | return sb->s_fs_info; | ||
404 | } | ||
405 | |||
406 | static inline struct hfsplus_inode_info *HFSPLUS_I(struct inode *inode) | ||
407 | { | ||
408 | return list_entry(inode, struct hfsplus_inode_info, vfs_inode); | ||
409 | } | ||
410 | |||
411 | /* time macros */ | 426 | /* time macros */ |
412 | #define __hfsp_mt2ut(t) (be32_to_cpu(t) - 2082844800U) | 427 | #define __hfsp_mt2ut(t) (be32_to_cpu(t) - 2082844800U) |
413 | #define __hfsp_ut2mt(t) (cpu_to_be32(t + 2082844800U)) | 428 | #define __hfsp_ut2mt(t) (cpu_to_be32(t + 2082844800U)) |
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 0946e2cdca5e..bf6535b73261 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c | |||
@@ -307,8 +307,9 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) | |||
307 | int hfsplus_file_fsync(struct file *file, int datasync) | 307 | int hfsplus_file_fsync(struct file *file, int datasync) |
308 | { | 308 | { |
309 | struct inode *inode = file->f_mapping->host; | 309 | struct inode *inode = file->f_mapping->host; |
310 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); | ||
310 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); | 311 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); |
311 | int error, error2; | 312 | int error = 0, error2; |
312 | 313 | ||
313 | /* | 314 | /* |
314 | * Sync inode metadata into the catalog and extent trees. | 315 | * Sync inode metadata into the catalog and extent trees. |
@@ -318,13 +319,21 @@ int hfsplus_file_fsync(struct file *file, int datasync) | |||
318 | /* | 319 | /* |
319 | * And explicitly write out the btrees. | 320 | * And explicitly write out the btrees. |
320 | */ | 321 | */ |
321 | error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping); | 322 | if (test_and_clear_bit(HFSPLUS_I_CAT_DIRTY, &hip->flags)) |
322 | error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping); | 323 | error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping); |
323 | if (!error) | 324 | |
324 | error = error2; | 325 | if (test_and_clear_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags)) { |
325 | error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); | 326 | error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping); |
326 | if (!error) | 327 | if (!error) |
327 | error = error2; | 328 | error = error2; |
329 | } | ||
330 | |||
331 | if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) { | ||
332 | error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); | ||
333 | if (!error) | ||
334 | error = error2; | ||
335 | } | ||
336 | |||
328 | return error; | 337 | return error; |
329 | } | 338 | } |
330 | 339 | ||
@@ -590,6 +599,8 @@ int hfsplus_cat_write_inode(struct inode *inode) | |||
590 | hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, | 599 | hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, |
591 | sizeof(struct hfsplus_cat_file)); | 600 | sizeof(struct hfsplus_cat_file)); |
592 | } | 601 | } |
602 | |||
603 | set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags); | ||
593 | out: | 604 | out: |
594 | hfs_find_exit(&fd); | 605 | hfs_find_exit(&fd); |
595 | return 0; | 606 | return 0; |
diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c index 40a85a3ded6e..f5a7224f4cbb 100644 --- a/fs/hfsplus/ioctl.c +++ b/fs/hfsplus/ioctl.c | |||
@@ -147,9 +147,11 @@ int hfsplus_setxattr(struct dentry *dentry, const char *name, | |||
147 | res = -ERANGE; | 147 | res = -ERANGE; |
148 | } else | 148 | } else |
149 | res = -EOPNOTSUPP; | 149 | res = -EOPNOTSUPP; |
150 | if (!res) | 150 | if (!res) { |
151 | hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, | 151 | hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, |
152 | sizeof(struct hfsplus_cat_file)); | 152 | sizeof(struct hfsplus_cat_file)); |
153 | hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); | ||
154 | } | ||
153 | out: | 155 | out: |
154 | hfs_find_exit(&fd); | 156 | hfs_find_exit(&fd); |
155 | return res; | 157 | return res; |
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 985423728e1d..036650123c4c 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c | |||
@@ -472,7 +472,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
472 | &str, sbi->hidden_dir); | 472 | &str, sbi->hidden_dir); |
473 | mutex_unlock(&sbi->vh_mutex); | 473 | mutex_unlock(&sbi->vh_mutex); |
474 | 474 | ||
475 | mark_inode_dirty(sbi->hidden_dir); | 475 | hfsplus_mark_inode_dirty(sbi->hidden_dir, HFSPLUS_I_CAT_DIRTY); |
476 | } | 476 | } |
477 | out: | 477 | out: |
478 | unload_nls(sbi->nls); | 478 | unload_nls(sbi->nls); |