diff options
Diffstat (limited to 'fs/hfsplus/inode.c')
-rw-r--r-- | fs/hfsplus/inode.c | 89 |
1 files changed, 57 insertions, 32 deletions
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 8afd7e84f98d..a8df651747f0 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * Inode handling routines | 8 | * Inode handling routines |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/blkdev.h> | ||
11 | #include <linux/mm.h> | 12 | #include <linux/mm.h> |
12 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
13 | #include <linux/pagemap.h> | 14 | #include <linux/pagemap.h> |
@@ -77,7 +78,8 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask) | |||
77 | if (!tree) | 78 | if (!tree) |
78 | return 0; | 79 | return 0; |
79 | if (tree->node_size >= PAGE_CACHE_SIZE) { | 80 | if (tree->node_size >= PAGE_CACHE_SIZE) { |
80 | nidx = page->index >> (tree->node_size_shift - PAGE_CACHE_SHIFT); | 81 | nidx = page->index >> |
82 | (tree->node_size_shift - PAGE_CACHE_SHIFT); | ||
81 | spin_lock(&tree->hash_lock); | 83 | spin_lock(&tree->hash_lock); |
82 | node = hfs_bnode_findhash(tree, nidx); | 84 | node = hfs_bnode_findhash(tree, nidx); |
83 | if (!node) | 85 | if (!node) |
@@ -90,7 +92,8 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask) | |||
90 | } | 92 | } |
91 | spin_unlock(&tree->hash_lock); | 93 | spin_unlock(&tree->hash_lock); |
92 | } else { | 94 | } else { |
93 | nidx = page->index << (PAGE_CACHE_SHIFT - tree->node_size_shift); | 95 | nidx = page->index << |
96 | (PAGE_CACHE_SHIFT - tree->node_size_shift); | ||
94 | i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift); | 97 | i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift); |
95 | spin_lock(&tree->hash_lock); | 98 | spin_lock(&tree->hash_lock); |
96 | do { | 99 | do { |
@@ -166,8 +169,8 @@ const struct dentry_operations hfsplus_dentry_operations = { | |||
166 | .d_compare = hfsplus_compare_dentry, | 169 | .d_compare = hfsplus_compare_dentry, |
167 | }; | 170 | }; |
168 | 171 | ||
169 | static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dentry, | 172 | static struct dentry *hfsplus_file_lookup(struct inode *dir, |
170 | struct nameidata *nd) | 173 | struct dentry *dentry, struct nameidata *nd) |
171 | { | 174 | { |
172 | struct hfs_find_data fd; | 175 | struct hfs_find_data fd; |
173 | struct super_block *sb = dir->i_sb; | 176 | struct super_block *sb = dir->i_sb; |
@@ -190,7 +193,9 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dent | |||
190 | inode->i_ino = dir->i_ino; | 193 | inode->i_ino = dir->i_ino; |
191 | INIT_LIST_HEAD(&hip->open_dir_list); | 194 | INIT_LIST_HEAD(&hip->open_dir_list); |
192 | mutex_init(&hip->extents_lock); | 195 | mutex_init(&hip->extents_lock); |
193 | hip->flags = HFSPLUS_FLG_RSRC; | 196 | hip->extent_state = 0; |
197 | hip->flags = 0; | ||
198 | set_bit(HFSPLUS_I_RSRC, &hip->flags); | ||
194 | 199 | ||
195 | hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); | 200 | hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); |
196 | err = hfsplus_find_cat(sb, dir->i_ino, &fd); | 201 | err = hfsplus_find_cat(sb, dir->i_ino, &fd); |
@@ -219,7 +224,8 @@ out: | |||
219 | return NULL; | 224 | return NULL; |
220 | } | 225 | } |
221 | 226 | ||
222 | static void hfsplus_get_perms(struct inode *inode, struct hfsplus_perm *perms, int dir) | 227 | static void hfsplus_get_perms(struct inode *inode, |
228 | struct hfsplus_perm *perms, int dir) | ||
223 | { | 229 | { |
224 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); | 230 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); |
225 | u16 mode; | 231 | u16 mode; |
@@ -302,29 +308,41 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) | |||
302 | return 0; | 308 | return 0; |
303 | } | 309 | } |
304 | 310 | ||
305 | static int hfsplus_file_fsync(struct file *filp, int datasync) | 311 | int hfsplus_file_fsync(struct file *file, int datasync) |
306 | { | 312 | { |
307 | struct inode *inode = filp->f_mapping->host; | 313 | struct inode *inode = file->f_mapping->host; |
308 | struct super_block * sb; | 314 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
309 | int ret, err; | 315 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); |
310 | 316 | int error = 0, error2; | |
311 | /* sync the inode to buffers */ | 317 | |
312 | ret = write_inode_now(inode, 0); | 318 | /* |
313 | 319 | * Sync inode metadata into the catalog and extent trees. | |
314 | /* sync the superblock to buffers */ | 320 | */ |
315 | sb = inode->i_sb; | 321 | sync_inode_metadata(inode, 1); |
316 | if (sb->s_dirt) { | 322 | |
317 | if (!(sb->s_flags & MS_RDONLY)) | 323 | /* |
318 | hfsplus_sync_fs(sb, 1); | 324 | * And explicitly write out the btrees. |
319 | else | 325 | */ |
320 | sb->s_dirt = 0; | 326 | if (test_and_clear_bit(HFSPLUS_I_CAT_DIRTY, &hip->flags)) |
327 | error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping); | ||
328 | |||
329 | if (test_and_clear_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags)) { | ||
330 | error2 = | ||
331 | filemap_write_and_wait(sbi->ext_tree->inode->i_mapping); | ||
332 | if (!error) | ||
333 | error = error2; | ||
321 | } | 334 | } |
322 | 335 | ||
323 | /* .. finally sync the buffers to disk */ | 336 | if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) { |
324 | err = sync_blockdev(sb->s_bdev); | 337 | error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); |
325 | if (!ret) | 338 | if (!error) |
326 | ret = err; | 339 | error = error2; |
327 | return ret; | 340 | } |
341 | |||
342 | if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) | ||
343 | blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); | ||
344 | |||
345 | return error; | ||
328 | } | 346 | } |
329 | 347 | ||
330 | static const struct inode_operations hfsplus_file_inode_operations = { | 348 | static const struct inode_operations hfsplus_file_inode_operations = { |
@@ -337,7 +355,7 @@ static const struct inode_operations hfsplus_file_inode_operations = { | |||
337 | }; | 355 | }; |
338 | 356 | ||
339 | static const struct file_operations hfsplus_file_operations = { | 357 | static const struct file_operations hfsplus_file_operations = { |
340 | .llseek = generic_file_llseek, | 358 | .llseek = generic_file_llseek, |
341 | .read = do_sync_read, | 359 | .read = do_sync_read, |
342 | .aio_read = generic_file_aio_read, | 360 | .aio_read = generic_file_aio_read, |
343 | .write = do_sync_write, | 361 | .write = do_sync_write, |
@@ -370,6 +388,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, int mode) | |||
370 | INIT_LIST_HEAD(&hip->open_dir_list); | 388 | INIT_LIST_HEAD(&hip->open_dir_list); |
371 | mutex_init(&hip->extents_lock); | 389 | mutex_init(&hip->extents_lock); |
372 | atomic_set(&hip->opencnt, 0); | 390 | atomic_set(&hip->opencnt, 0); |
391 | hip->extent_state = 0; | ||
373 | hip->flags = 0; | 392 | hip->flags = 0; |
374 | memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec)); | 393 | memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec)); |
375 | memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); | 394 | memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); |
@@ -457,7 +476,8 @@ void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork) | |||
457 | } | 476 | } |
458 | } | 477 | } |
459 | 478 | ||
460 | void hfsplus_inode_write_fork(struct inode *inode, struct hfsplus_fork_raw *fork) | 479 | void hfsplus_inode_write_fork(struct inode *inode, |
480 | struct hfsplus_fork_raw *fork) | ||
461 | { | 481 | { |
462 | memcpy(&fork->extents, &HFSPLUS_I(inode)->first_extents, | 482 | memcpy(&fork->extents, &HFSPLUS_I(inode)->first_extents, |
463 | sizeof(hfsplus_extent_rec)); | 483 | sizeof(hfsplus_extent_rec)); |
@@ -499,13 +519,14 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd) | |||
499 | hfs_bnode_read(fd->bnode, &entry, fd->entryoffset, | 519 | hfs_bnode_read(fd->bnode, &entry, fd->entryoffset, |
500 | sizeof(struct hfsplus_cat_file)); | 520 | sizeof(struct hfsplus_cat_file)); |
501 | 521 | ||
502 | hfsplus_inode_read_fork(inode, HFSPLUS_IS_DATA(inode) ? | 522 | hfsplus_inode_read_fork(inode, HFSPLUS_IS_RSRC(inode) ? |
503 | &file->data_fork : &file->rsrc_fork); | 523 | &file->rsrc_fork : &file->data_fork); |
504 | hfsplus_get_perms(inode, &file->permissions, 0); | 524 | hfsplus_get_perms(inode, &file->permissions, 0); |
505 | inode->i_nlink = 1; | 525 | inode->i_nlink = 1; |
506 | if (S_ISREG(inode->i_mode)) { | 526 | if (S_ISREG(inode->i_mode)) { |
507 | if (file->permissions.dev) | 527 | if (file->permissions.dev) |
508 | inode->i_nlink = be32_to_cpu(file->permissions.dev); | 528 | inode->i_nlink = |
529 | be32_to_cpu(file->permissions.dev); | ||
509 | inode->i_op = &hfsplus_file_inode_operations; | 530 | inode->i_op = &hfsplus_file_inode_operations; |
510 | inode->i_fop = &hfsplus_file_operations; | 531 | inode->i_fop = &hfsplus_file_operations; |
511 | inode->i_mapping->a_ops = &hfsplus_aops; | 532 | inode->i_mapping->a_ops = &hfsplus_aops; |
@@ -578,7 +599,9 @@ int hfsplus_cat_write_inode(struct inode *inode) | |||
578 | sizeof(struct hfsplus_cat_file)); | 599 | sizeof(struct hfsplus_cat_file)); |
579 | hfsplus_inode_write_fork(inode, &file->data_fork); | 600 | hfsplus_inode_write_fork(inode, &file->data_fork); |
580 | hfsplus_cat_set_perms(inode, &file->permissions); | 601 | hfsplus_cat_set_perms(inode, &file->permissions); |
581 | if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE) | 602 | if (HFSPLUS_FLG_IMMUTABLE & |
603 | (file->permissions.rootflags | | ||
604 | file->permissions.userflags)) | ||
582 | file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED); | 605 | file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED); |
583 | else | 606 | else |
584 | file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED); | 607 | file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED); |
@@ -588,6 +611,8 @@ int hfsplus_cat_write_inode(struct inode *inode) | |||
588 | hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, | 611 | hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, |
589 | sizeof(struct hfsplus_cat_file)); | 612 | sizeof(struct hfsplus_cat_file)); |
590 | } | 613 | } |
614 | |||
615 | set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags); | ||
591 | out: | 616 | out: |
592 | hfs_find_exit(&fd); | 617 | hfs_find_exit(&fd); |
593 | return 0; | 618 | return 0; |