aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/hfsplus/catalog.c10
-rw-r--r--fs/hfsplus/extents.c30
-rw-r--r--fs/hfsplus/hfsplus_fs.h37
-rw-r--r--fs/hfsplus/inode.c27
-rw-r--r--fs/hfsplus/ioctl.c4
-rw-r--r--fs/hfsplus/super.c2
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);
312out: 313out:
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);
390out: 392out:
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
113static void hfsplus_ext_write_extent_locked(struct inode *inode) 121static 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
236done: 251done:
@@ -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
160static inline struct hfsplus_sb_info *HFSPLUS_SB(struct super_block *sb)
161{
162 return sb->s_fs_info;
163}
164
160 165
161struct hfsplus_inode_info { 166struct 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
220static 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 */
231static 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
212struct hfs_find_data { 238struct 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 *);
397int hfsplus_submit_bio(struct block_device *bdev, sector_t sector, 423int 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 */
401static inline struct hfsplus_sb_info *HFSPLUS_SB(struct super_block *sb)
402{
403 return sb->s_fs_info;
404}
405
406static 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)
307int hfsplus_file_fsync(struct file *file, int datasync) 307int 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);
593out: 604out:
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 }
153out: 155out:
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 }
477out: 477out:
478 unload_nls(sbi->nls); 478 unload_nls(sbi->nls);