diff options
Diffstat (limited to 'fs/hfsplus/inode.c')
| -rw-r--r-- | fs/hfsplus/inode.c | 77 |
1 files changed, 74 insertions, 3 deletions
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 9bbb82924a22..c5a979d62c65 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c | |||
| @@ -31,10 +31,19 @@ static int hfsplus_write_begin(struct file *file, struct address_space *mapping, | |||
| 31 | loff_t pos, unsigned len, unsigned flags, | 31 | loff_t pos, unsigned len, unsigned flags, |
| 32 | struct page **pagep, void **fsdata) | 32 | struct page **pagep, void **fsdata) |
| 33 | { | 33 | { |
| 34 | int ret; | ||
| 35 | |||
| 34 | *pagep = NULL; | 36 | *pagep = NULL; |
| 35 | return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 37 | ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, |
| 36 | hfsplus_get_block, | 38 | hfsplus_get_block, |
| 37 | &HFSPLUS_I(mapping->host).phys_size); | 39 | &HFSPLUS_I(mapping->host).phys_size); |
| 40 | if (unlikely(ret)) { | ||
| 41 | loff_t isize = mapping->host->i_size; | ||
| 42 | if (pos + len > isize) | ||
| 43 | vmtruncate(mapping->host, isize); | ||
| 44 | } | ||
| 45 | |||
| 46 | return ret; | ||
| 38 | } | 47 | } |
| 39 | 48 | ||
| 40 | static sector_t hfsplus_bmap(struct address_space *mapping, sector_t block) | 49 | static sector_t hfsplus_bmap(struct address_space *mapping, sector_t block) |
| @@ -105,9 +114,24 @@ static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb, | |||
| 105 | { | 114 | { |
| 106 | struct file *file = iocb->ki_filp; | 115 | struct file *file = iocb->ki_filp; |
| 107 | struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host; | 116 | struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host; |
| 117 | ssize_t ret; | ||
| 108 | 118 | ||
| 109 | return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, | 119 | ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, |
| 110 | offset, nr_segs, hfsplus_get_block, NULL); | 120 | offset, nr_segs, hfsplus_get_block, NULL); |
| 121 | |||
| 122 | /* | ||
| 123 | * In case of error extending write may have instantiated a few | ||
| 124 | * blocks outside i_size. Trim these off again. | ||
| 125 | */ | ||
| 126 | if (unlikely((rw & WRITE) && ret < 0)) { | ||
| 127 | loff_t isize = i_size_read(inode); | ||
| 128 | loff_t end = offset + iov_length(iov, nr_segs); | ||
| 129 | |||
| 130 | if (end > isize) | ||
| 131 | vmtruncate(inode, isize); | ||
| 132 | } | ||
| 133 | |||
| 134 | return ret; | ||
| 111 | } | 135 | } |
| 112 | 136 | ||
| 113 | static int hfsplus_writepages(struct address_space *mapping, | 137 | static int hfsplus_writepages(struct address_space *mapping, |
| @@ -266,9 +290,56 @@ static int hfsplus_file_release(struct inode *inode, struct file *file) | |||
| 266 | return 0; | 290 | return 0; |
| 267 | } | 291 | } |
| 268 | 292 | ||
| 293 | static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) | ||
| 294 | { | ||
| 295 | struct inode *inode = dentry->d_inode; | ||
| 296 | int error; | ||
| 297 | |||
| 298 | error = inode_change_ok(inode, attr); | ||
| 299 | if (error) | ||
| 300 | return error; | ||
| 301 | |||
| 302 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 303 | attr->ia_size != i_size_read(inode)) { | ||
| 304 | error = vmtruncate(inode, attr->ia_size); | ||
| 305 | if (error) | ||
| 306 | return error; | ||
| 307 | } | ||
| 308 | |||
| 309 | setattr_copy(inode, attr); | ||
| 310 | mark_inode_dirty(inode); | ||
| 311 | return 0; | ||
| 312 | } | ||
| 313 | |||
| 314 | static int hfsplus_file_fsync(struct file *filp, int datasync) | ||
| 315 | { | ||
| 316 | struct inode *inode = filp->f_mapping->host; | ||
| 317 | struct super_block * sb; | ||
| 318 | int ret, err; | ||
| 319 | |||
| 320 | /* sync the inode to buffers */ | ||
| 321 | ret = write_inode_now(inode, 0); | ||
| 322 | |||
| 323 | /* sync the superblock to buffers */ | ||
| 324 | sb = inode->i_sb; | ||
| 325 | if (sb->s_dirt) { | ||
| 326 | if (!(sb->s_flags & MS_RDONLY)) | ||
| 327 | hfsplus_sync_fs(sb, 1); | ||
| 328 | else | ||
| 329 | sb->s_dirt = 0; | ||
| 330 | } | ||
| 331 | |||
| 332 | /* .. finally sync the buffers to disk */ | ||
| 333 | err = sync_blockdev(sb->s_bdev); | ||
| 334 | if (!ret) | ||
| 335 | ret = err; | ||
| 336 | return ret; | ||
| 337 | } | ||
| 338 | |||
| 269 | static const struct inode_operations hfsplus_file_inode_operations = { | 339 | static const struct inode_operations hfsplus_file_inode_operations = { |
| 270 | .lookup = hfsplus_file_lookup, | 340 | .lookup = hfsplus_file_lookup, |
| 271 | .truncate = hfsplus_file_truncate, | 341 | .truncate = hfsplus_file_truncate, |
| 342 | .setattr = hfsplus_setattr, | ||
| 272 | .setxattr = hfsplus_setxattr, | 343 | .setxattr = hfsplus_setxattr, |
| 273 | .getxattr = hfsplus_getxattr, | 344 | .getxattr = hfsplus_getxattr, |
| 274 | .listxattr = hfsplus_listxattr, | 345 | .listxattr = hfsplus_listxattr, |
| @@ -282,7 +353,7 @@ static const struct file_operations hfsplus_file_operations = { | |||
| 282 | .aio_write = generic_file_aio_write, | 353 | .aio_write = generic_file_aio_write, |
| 283 | .mmap = generic_file_mmap, | 354 | .mmap = generic_file_mmap, |
| 284 | .splice_read = generic_file_splice_read, | 355 | .splice_read = generic_file_splice_read, |
| 285 | .fsync = file_fsync, | 356 | .fsync = hfsplus_file_fsync, |
| 286 | .open = hfsplus_file_open, | 357 | .open = hfsplus_file_open, |
| 287 | .release = hfsplus_file_release, | 358 | .release = hfsplus_file_release, |
| 288 | .unlocked_ioctl = hfsplus_ioctl, | 359 | .unlocked_ioctl = hfsplus_ioctl, |
