diff options
| -rw-r--r-- | fs/fat/fat.h | 3 | ||||
| -rw-r--r-- | fs/fat/file.c | 34 | ||||
| -rw-r--r-- | fs/fat/inode.c | 35 |
3 files changed, 57 insertions, 15 deletions
diff --git a/fs/fat/fat.h b/fs/fat/fat.h index a1c8c4b44fdb..27ac25725954 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h | |||
| @@ -306,7 +306,8 @@ extern long fat_generic_ioctl(struct file *filp, unsigned int cmd, | |||
| 306 | extern const struct file_operations fat_file_operations; | 306 | extern const struct file_operations fat_file_operations; |
| 307 | extern const struct inode_operations fat_file_inode_operations; | 307 | extern const struct inode_operations fat_file_inode_operations; |
| 308 | extern int fat_setattr(struct dentry * dentry, struct iattr * attr); | 308 | extern int fat_setattr(struct dentry * dentry, struct iattr * attr); |
| 309 | extern void fat_truncate(struct inode *inode); | 309 | extern int fat_setsize(struct inode *inode, loff_t offset); |
| 310 | extern void fat_truncate_blocks(struct inode *inode, loff_t offset); | ||
| 310 | extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, | 311 | extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, |
| 311 | struct kstat *stat); | 312 | struct kstat *stat); |
| 312 | extern int fat_file_fsync(struct file *file, int datasync); | 313 | extern int fat_file_fsync(struct file *file, int datasync); |
diff --git a/fs/fat/file.c b/fs/fat/file.c index 8c13b8acfd2f..990dfae022e5 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
| @@ -283,7 +283,7 @@ static int fat_free(struct inode *inode, int skip) | |||
| 283 | return fat_free_clusters(inode, free_start); | 283 | return fat_free_clusters(inode, free_start); |
| 284 | } | 284 | } |
| 285 | 285 | ||
| 286 | void fat_truncate(struct inode *inode) | 286 | void fat_truncate_blocks(struct inode *inode, loff_t offset) |
| 287 | { | 287 | { |
| 288 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | 288 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); |
| 289 | const unsigned int cluster_size = sbi->cluster_size; | 289 | const unsigned int cluster_size = sbi->cluster_size; |
| @@ -293,10 +293,10 @@ void fat_truncate(struct inode *inode) | |||
| 293 | * This protects against truncating a file bigger than it was then | 293 | * This protects against truncating a file bigger than it was then |
| 294 | * trying to write into the hole. | 294 | * trying to write into the hole. |
| 295 | */ | 295 | */ |
| 296 | if (MSDOS_I(inode)->mmu_private > inode->i_size) | 296 | if (MSDOS_I(inode)->mmu_private > offset) |
| 297 | MSDOS_I(inode)->mmu_private = inode->i_size; | 297 | MSDOS_I(inode)->mmu_private = offset; |
| 298 | 298 | ||
| 299 | nr_clusters = (inode->i_size + (cluster_size - 1)) >> sbi->cluster_bits; | 299 | nr_clusters = (offset + (cluster_size - 1)) >> sbi->cluster_bits; |
| 300 | 300 | ||
| 301 | fat_free(inode, nr_clusters); | 301 | fat_free(inode, nr_clusters); |
| 302 | fat_flush_inodes(inode->i_sb, inode, NULL); | 302 | fat_flush_inodes(inode->i_sb, inode, NULL); |
| @@ -364,6 +364,18 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode) | |||
| 364 | return 0; | 364 | return 0; |
| 365 | } | 365 | } |
| 366 | 366 | ||
| 367 | int fat_setsize(struct inode *inode, loff_t offset) | ||
| 368 | { | ||
| 369 | int error; | ||
| 370 | |||
| 371 | error = simple_setsize(inode, offset); | ||
| 372 | if (error) | ||
| 373 | return error; | ||
| 374 | fat_truncate_blocks(inode, offset); | ||
| 375 | |||
| 376 | return error; | ||
| 377 | } | ||
| 378 | |||
| 367 | #define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET) | 379 | #define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET) |
| 368 | /* valid file mode bits */ | 380 | /* valid file mode bits */ |
| 369 | #define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO) | 381 | #define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO) |
| @@ -378,7 +390,8 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 378 | /* | 390 | /* |
| 379 | * Expand the file. Since inode_setattr() updates ->i_size | 391 | * Expand the file. Since inode_setattr() updates ->i_size |
| 380 | * before calling the ->truncate(), but FAT needs to fill the | 392 | * before calling the ->truncate(), but FAT needs to fill the |
| 381 | * hole before it. | 393 | * hole before it. XXX: this is no longer true with new truncate |
| 394 | * sequence. | ||
| 382 | */ | 395 | */ |
| 383 | if (attr->ia_valid & ATTR_SIZE) { | 396 | if (attr->ia_valid & ATTR_SIZE) { |
| 384 | if (attr->ia_size > inode->i_size) { | 397 | if (attr->ia_size > inode->i_size) { |
| @@ -427,15 +440,20 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 427 | attr->ia_valid &= ~ATTR_MODE; | 440 | attr->ia_valid &= ~ATTR_MODE; |
| 428 | } | 441 | } |
| 429 | 442 | ||
| 430 | if (attr->ia_valid) | 443 | if (attr->ia_valid & ATTR_SIZE) { |
| 431 | error = inode_setattr(inode, attr); | 444 | error = fat_setsize(inode, attr->ia_size); |
| 445 | if (error) | ||
| 446 | goto out; | ||
| 447 | } | ||
| 448 | |||
| 449 | generic_setattr(inode, attr); | ||
| 450 | mark_inode_dirty(inode); | ||
| 432 | out: | 451 | out: |
| 433 | return error; | 452 | return error; |
| 434 | } | 453 | } |
| 435 | EXPORT_SYMBOL_GPL(fat_setattr); | 454 | EXPORT_SYMBOL_GPL(fat_setattr); |
| 436 | 455 | ||
| 437 | const struct inode_operations fat_file_inode_operations = { | 456 | const struct inode_operations fat_file_inode_operations = { |
| 438 | .truncate = fat_truncate, | ||
| 439 | .setattr = fat_setattr, | 457 | .setattr = fat_setattr, |
| 440 | .getattr = fat_getattr, | 458 | .getattr = fat_getattr, |
| 441 | }; | 459 | }; |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index ed33904926ee..7bf45aee56d7 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
| @@ -142,14 +142,29 @@ static int fat_readpages(struct file *file, struct address_space *mapping, | |||
| 142 | return mpage_readpages(mapping, pages, nr_pages, fat_get_block); | 142 | return mpage_readpages(mapping, pages, nr_pages, fat_get_block); |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | static void fat_write_failed(struct address_space *mapping, loff_t to) | ||
| 146 | { | ||
| 147 | struct inode *inode = mapping->host; | ||
| 148 | |||
| 149 | if (to > inode->i_size) { | ||
| 150 | truncate_pagecache(inode, to, inode->i_size); | ||
| 151 | fat_truncate_blocks(inode, inode->i_size); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 145 | static int fat_write_begin(struct file *file, struct address_space *mapping, | 155 | static int fat_write_begin(struct file *file, struct address_space *mapping, |
| 146 | loff_t pos, unsigned len, unsigned flags, | 156 | loff_t pos, unsigned len, unsigned flags, |
| 147 | struct page **pagep, void **fsdata) | 157 | struct page **pagep, void **fsdata) |
| 148 | { | 158 | { |
| 159 | int err; | ||
| 160 | |||
| 149 | *pagep = NULL; | 161 | *pagep = NULL; |
| 150 | return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 162 | err = cont_write_begin_newtrunc(file, mapping, pos, len, flags, |
| 151 | fat_get_block, | 163 | pagep, fsdata, fat_get_block, |
| 152 | &MSDOS_I(mapping->host)->mmu_private); | 164 | &MSDOS_I(mapping->host)->mmu_private); |
| 165 | if (err < 0) | ||
| 166 | fat_write_failed(mapping, pos + len); | ||
| 167 | return err; | ||
| 153 | } | 168 | } |
| 154 | 169 | ||
| 155 | static int fat_write_end(struct file *file, struct address_space *mapping, | 170 | static int fat_write_end(struct file *file, struct address_space *mapping, |
| @@ -159,6 +174,8 @@ static int fat_write_end(struct file *file, struct address_space *mapping, | |||
| 159 | struct inode *inode = mapping->host; | 174 | struct inode *inode = mapping->host; |
| 160 | int err; | 175 | int err; |
| 161 | err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); | 176 | err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); |
| 177 | if (err < len) | ||
| 178 | fat_write_failed(mapping, pos + len); | ||
| 162 | if (!(err < 0) && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) { | 179 | if (!(err < 0) && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) { |
| 163 | inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; | 180 | inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; |
| 164 | MSDOS_I(inode)->i_attrs |= ATTR_ARCH; | 181 | MSDOS_I(inode)->i_attrs |= ATTR_ARCH; |
| @@ -172,7 +189,9 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, | |||
| 172 | loff_t offset, unsigned long nr_segs) | 189 | loff_t offset, unsigned long nr_segs) |
| 173 | { | 190 | { |
| 174 | struct file *file = iocb->ki_filp; | 191 | struct file *file = iocb->ki_filp; |
| 175 | struct inode *inode = file->f_mapping->host; | 192 | struct address_space *mapping = file->f_mapping; |
| 193 | struct inode *inode = mapping->host; | ||
| 194 | ssize_t ret; | ||
| 176 | 195 | ||
| 177 | if (rw == WRITE) { | 196 | if (rw == WRITE) { |
| 178 | /* | 197 | /* |
| @@ -193,8 +212,12 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, | |||
| 193 | * FAT need to use the DIO_LOCKING for avoiding the race | 212 | * FAT need to use the DIO_LOCKING for avoiding the race |
| 194 | * condition of fat_get_block() and ->truncate(). | 213 | * condition of fat_get_block() and ->truncate(). |
| 195 | */ | 214 | */ |
| 196 | return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, | 215 | ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev, |
| 197 | offset, nr_segs, fat_get_block, NULL); | 216 | iov, offset, nr_segs, fat_get_block, NULL); |
| 217 | if (ret < 0 && (rw & WRITE)) | ||
| 218 | fat_write_failed(mapping, offset + iov_length(iov, nr_segs)); | ||
| 219 | |||
| 220 | return ret; | ||
| 198 | } | 221 | } |
| 199 | 222 | ||
| 200 | static sector_t _fat_bmap(struct address_space *mapping, sector_t block) | 223 | static sector_t _fat_bmap(struct address_space *mapping, sector_t block) |
| @@ -429,7 +452,7 @@ static void fat_delete_inode(struct inode *inode) | |||
| 429 | { | 452 | { |
| 430 | truncate_inode_pages(&inode->i_data, 0); | 453 | truncate_inode_pages(&inode->i_data, 0); |
| 431 | inode->i_size = 0; | 454 | inode->i_size = 0; |
| 432 | fat_truncate(inode); | 455 | fat_truncate_blocks(inode, 0); |
| 433 | clear_inode(inode); | 456 | clear_inode(inode); |
| 434 | } | 457 | } |
| 435 | 458 | ||
