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 | }; |