diff options
Diffstat (limited to 'fs/hfs/inode.c')
| -rw-r--r-- | fs/hfs/inode.c | 70 |
1 files changed, 63 insertions, 7 deletions
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 14f5cb1b9fdc..397b7adc7ce6 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c | |||
| @@ -39,10 +39,19 @@ static int hfs_write_begin(struct file *file, struct address_space *mapping, | |||
| 39 | loff_t pos, unsigned len, unsigned flags, | 39 | loff_t pos, unsigned len, unsigned flags, |
| 40 | struct page **pagep, void **fsdata) | 40 | struct page **pagep, void **fsdata) |
| 41 | { | 41 | { |
| 42 | int ret; | ||
| 43 | |||
| 42 | *pagep = NULL; | 44 | *pagep = NULL; |
| 43 | return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 45 | ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, |
| 44 | hfs_get_block, | 46 | hfs_get_block, |
| 45 | &HFS_I(mapping->host)->phys_size); | 47 | &HFS_I(mapping->host)->phys_size); |
| 48 | if (unlikely(ret)) { | ||
| 49 | loff_t isize = mapping->host->i_size; | ||
| 50 | if (pos + len > isize) | ||
| 51 | vmtruncate(mapping->host, isize); | ||
| 52 | } | ||
| 53 | |||
| 54 | return ret; | ||
| 46 | } | 55 | } |
| 47 | 56 | ||
| 48 | static sector_t hfs_bmap(struct address_space *mapping, sector_t block) | 57 | static sector_t hfs_bmap(struct address_space *mapping, sector_t block) |
| @@ -112,9 +121,24 @@ static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb, | |||
| 112 | { | 121 | { |
| 113 | struct file *file = iocb->ki_filp; | 122 | struct file *file = iocb->ki_filp; |
| 114 | struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host; | 123 | struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host; |
| 124 | ssize_t ret; | ||
| 115 | 125 | ||
| 116 | return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, | 126 | ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, |
| 117 | offset, nr_segs, hfs_get_block, NULL); | 127 | offset, nr_segs, hfs_get_block, NULL); |
| 128 | |||
| 129 | /* | ||
| 130 | * In case of error extending write may have instantiated a few | ||
| 131 | * blocks outside i_size. Trim these off again. | ||
| 132 | */ | ||
| 133 | if (unlikely((rw & WRITE) && ret < 0)) { | ||
| 134 | loff_t isize = i_size_read(inode); | ||
| 135 | loff_t end = offset + iov_length(iov, nr_segs); | ||
| 136 | |||
| 137 | if (end > isize) | ||
| 138 | vmtruncate(inode, isize); | ||
| 139 | } | ||
| 140 | |||
| 141 | return ret; | ||
| 118 | } | 142 | } |
| 119 | 143 | ||
| 120 | static int hfs_writepages(struct address_space *mapping, | 144 | static int hfs_writepages(struct address_space *mapping, |
| @@ -507,8 +531,10 @@ out: | |||
| 507 | return NULL; | 531 | return NULL; |
| 508 | } | 532 | } |
| 509 | 533 | ||
| 510 | void hfs_clear_inode(struct inode *inode) | 534 | void hfs_evict_inode(struct inode *inode) |
| 511 | { | 535 | { |
| 536 | truncate_inode_pages(&inode->i_data, 0); | ||
| 537 | end_writeback(inode); | ||
| 512 | if (HFS_IS_RSRC(inode) && HFS_I(inode)->rsrc_inode) { | 538 | if (HFS_IS_RSRC(inode) && HFS_I(inode)->rsrc_inode) { |
| 513 | HFS_I(HFS_I(inode)->rsrc_inode)->rsrc_inode = NULL; | 539 | HFS_I(HFS_I(inode)->rsrc_inode)->rsrc_inode = NULL; |
| 514 | iput(HFS_I(inode)->rsrc_inode); | 540 | iput(HFS_I(inode)->rsrc_inode); |
| @@ -588,13 +614,43 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr) | |||
| 588 | attr->ia_mode = inode->i_mode & ~S_IWUGO; | 614 | attr->ia_mode = inode->i_mode & ~S_IWUGO; |
| 589 | attr->ia_mode &= S_ISDIR(inode->i_mode) ? ~hsb->s_dir_umask: ~hsb->s_file_umask; | 615 | attr->ia_mode &= S_ISDIR(inode->i_mode) ? ~hsb->s_dir_umask: ~hsb->s_file_umask; |
| 590 | } | 616 | } |
| 591 | error = inode_setattr(inode, attr); | ||
| 592 | if (error) | ||
| 593 | return error; | ||
| 594 | 617 | ||
| 618 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 619 | attr->ia_size != i_size_read(inode)) { | ||
| 620 | error = vmtruncate(inode, attr->ia_size); | ||
| 621 | if (error) | ||
| 622 | return error; | ||
| 623 | } | ||
| 624 | |||
| 625 | setattr_copy(inode, attr); | ||
| 626 | mark_inode_dirty(inode); | ||
| 595 | return 0; | 627 | return 0; |
| 596 | } | 628 | } |
| 597 | 629 | ||
| 630 | static int hfs_file_fsync(struct file *filp, int datasync) | ||
| 631 | { | ||
| 632 | struct inode *inode = filp->f_mapping->host; | ||
| 633 | struct super_block * sb; | ||
| 634 | int ret, err; | ||
| 635 | |||
| 636 | /* sync the inode to buffers */ | ||
| 637 | ret = write_inode_now(inode, 0); | ||
| 638 | |||
| 639 | /* sync the superblock to buffers */ | ||
| 640 | sb = inode->i_sb; | ||
| 641 | if (sb->s_dirt) { | ||
| 642 | lock_super(sb); | ||
| 643 | sb->s_dirt = 0; | ||
| 644 | if (!(sb->s_flags & MS_RDONLY)) | ||
| 645 | hfs_mdb_commit(sb); | ||
| 646 | unlock_super(sb); | ||
| 647 | } | ||
| 648 | /* .. finally sync the buffers to disk */ | ||
| 649 | err = sync_blockdev(sb->s_bdev); | ||
| 650 | if (!ret) | ||
| 651 | ret = err; | ||
| 652 | return ret; | ||
| 653 | } | ||
| 598 | 654 | ||
| 599 | static const struct file_operations hfs_file_operations = { | 655 | static const struct file_operations hfs_file_operations = { |
| 600 | .llseek = generic_file_llseek, | 656 | .llseek = generic_file_llseek, |
| @@ -604,7 +660,7 @@ static const struct file_operations hfs_file_operations = { | |||
| 604 | .aio_write = generic_file_aio_write, | 660 | .aio_write = generic_file_aio_write, |
| 605 | .mmap = generic_file_mmap, | 661 | .mmap = generic_file_mmap, |
| 606 | .splice_read = generic_file_splice_read, | 662 | .splice_read = generic_file_splice_read, |
| 607 | .fsync = file_fsync, | 663 | .fsync = hfs_file_fsync, |
| 608 | .open = hfs_file_open, | 664 | .open = hfs_file_open, |
| 609 | .release = hfs_file_release, | 665 | .release = hfs_file_release, |
| 610 | }; | 666 | }; |
