aboutsummaryrefslogtreecommitdiffstats
path: root/fs/hfsplus
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@tuxera.com>2010-11-23 08:38:15 -0500
committerChristoph Hellwig <hch@lst.de>2010-11-23 08:38:15 -0500
commite34947056076ca5467ee8256d2d9cbc594a79b37 (patch)
treec1b70f51c1e4bc38e0b0389224862afe26c5720f /fs/hfsplus
parentb33b7921db14abcd10c30d0ccfc68e364f5ef7fe (diff)
hfsplus: optimize fsync
Avoid doing unessecary work in fsync. Do nothing unless the inode was marked dirty, and only write the various metadata inodes out if they contain any dirty state from this inode. This is archived by adding three new dirty bits to the hfsplus-specific inode which are set in the correct places. Signed-off-by: Christoph Hellwig <hch@tuxera.com>
Diffstat (limited to 'fs/hfsplus')
-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);