Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fat: convert to use the new truncate convention.

Cc: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nick Piggin <npiggin@suse.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

authored by

npiggin@suse.de and committed by
Al Viro
459f6ed3 737f2e93

+57 -15
+2 -1
fs/fat/fat.h
··· 306 306 extern const struct file_operations fat_file_operations; 307 307 extern const struct inode_operations fat_file_inode_operations; 308 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 311 extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, 311 312 struct kstat *stat); 312 313 extern int fat_file_fsync(struct file *file, int datasync);
+26 -8
fs/fat/file.c
··· 283 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 288 struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); 289 289 const unsigned int cluster_size = sbi->cluster_size; ··· 293 293 * This protects against truncating a file bigger than it was then 294 294 * trying to write into the hole. 295 295 */ 296 - if (MSDOS_I(inode)->mmu_private > inode->i_size) 297 - MSDOS_I(inode)->mmu_private = inode->i_size; 296 + if (MSDOS_I(inode)->mmu_private > offset) 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 301 fat_free(inode, nr_clusters); 302 302 fat_flush_inodes(inode->i_sb, inode, NULL); ··· 364 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 379 #define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET) 368 380 /* valid file mode bits */ 369 381 #define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO) ··· 390 378 /* 391 379 * Expand the file. Since inode_setattr() updates ->i_size 392 380 * before calling the ->truncate(), but FAT needs to fill the 393 - * hole before it. 381 + * hole before it. XXX: this is no longer true with new truncate 382 + * sequence. 394 383 */ 395 384 if (attr->ia_valid & ATTR_SIZE) { 396 385 if (attr->ia_size > inode->i_size) { ··· 440 427 attr->ia_valid &= ~ATTR_MODE; 441 428 } 442 429 443 - if (attr->ia_valid) 444 - error = inode_setattr(inode, attr); 430 + if (attr->ia_valid & ATTR_SIZE) { 431 + error = fat_setsize(inode, attr->ia_size); 432 + if (error) 433 + goto out; 434 + } 435 + 436 + generic_setattr(inode, attr); 437 + mark_inode_dirty(inode); 445 438 out: 446 439 return error; 447 440 } 448 441 EXPORT_SYMBOL_GPL(fat_setattr); 449 442 450 443 const struct inode_operations fat_file_inode_operations = { 451 - .truncate = fat_truncate, 452 444 .setattr = fat_setattr, 453 445 .getattr = fat_getattr, 454 446 };
+29 -6
fs/fat/inode.c
··· 142 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 155 static int fat_write_begin(struct file *file, struct address_space *mapping, 146 156 loff_t pos, unsigned len, unsigned flags, 147 157 struct page **pagep, void **fsdata) 148 158 { 159 + int err; 160 + 149 161 *pagep = NULL; 150 - return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, 151 - fat_get_block, 162 + err = cont_write_begin_newtrunc(file, mapping, pos, len, flags, 163 + pagep, fsdata, fat_get_block, 152 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 170 static int fat_write_end(struct file *file, struct address_space *mapping, ··· 174 159 struct inode *inode = mapping->host; 175 160 int err; 176 161 err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); 162 + if (err < len) 163 + fat_write_failed(mapping, pos + len); 177 164 if (!(err < 0) && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) { 178 165 inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; 179 166 MSDOS_I(inode)->i_attrs |= ATTR_ARCH; ··· 189 172 loff_t offset, unsigned long nr_segs) 190 173 { 191 174 struct file *file = iocb->ki_filp; 192 - struct inode *inode = file->f_mapping->host; 175 + struct address_space *mapping = file->f_mapping; 176 + struct inode *inode = mapping->host; 177 + ssize_t ret; 193 178 194 179 if (rw == WRITE) { 195 180 /* ··· 212 193 * FAT need to use the DIO_LOCKING for avoiding the race 213 194 * condition of fat_get_block() and ->truncate(). 214 195 */ 215 - return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, 216 - offset, nr_segs, fat_get_block, NULL); 196 + ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev, 197 + iov, offset, nr_segs, fat_get_block, NULL); 198 + if (ret < 0 && (rw & WRITE)) 199 + fat_write_failed(mapping, offset + iov_length(iov, nr_segs)); 200 + 201 + return ret; 217 202 } 218 203 219 204 static sector_t _fat_bmap(struct address_space *mapping, sector_t block) ··· 452 429 { 453 430 truncate_inode_pages(&inode->i_data, 0); 454 431 inode->i_size = 0; 455 - fat_truncate(inode); 432 + fat_truncate_blocks(inode, 0); 456 433 clear_inode(inode); 457 434 } 458 435