Loading fs/fat/fat.h +2 −1 Original line number Diff line number Diff line Loading @@ -306,7 +306,8 @@ extern long fat_generic_ioctl(struct file *filp, unsigned int cmd, extern const struct file_operations fat_file_operations; extern const struct inode_operations fat_file_inode_operations; extern int fat_setattr(struct dentry * dentry, struct iattr * attr); extern void fat_truncate(struct inode *inode); extern int fat_setsize(struct inode *inode, loff_t offset); extern void fat_truncate_blocks(struct inode *inode, loff_t offset); extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); extern int fat_file_fsync(struct file *file, int datasync); Loading fs/fat/file.c +26 −8 Original line number Diff line number Diff line Loading @@ -283,7 +283,7 @@ static int fat_free(struct inode *inode, int skip) return fat_free_clusters(inode, free_start); } void fat_truncate(struct inode *inode) void fat_truncate_blocks(struct inode *inode, loff_t offset) { struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); const unsigned int cluster_size = sbi->cluster_size; Loading @@ -293,10 +293,10 @@ void fat_truncate(struct inode *inode) * This protects against truncating a file bigger than it was then * trying to write into the hole. */ if (MSDOS_I(inode)->mmu_private > inode->i_size) MSDOS_I(inode)->mmu_private = inode->i_size; if (MSDOS_I(inode)->mmu_private > offset) MSDOS_I(inode)->mmu_private = offset; nr_clusters = (inode->i_size + (cluster_size - 1)) >> sbi->cluster_bits; nr_clusters = (offset + (cluster_size - 1)) >> sbi->cluster_bits; fat_free(inode, nr_clusters); fat_flush_inodes(inode->i_sb, inode, NULL); Loading Loading @@ -364,6 +364,18 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode) return 0; } int fat_setsize(struct inode *inode, loff_t offset) { int error; error = simple_setsize(inode, offset); if (error) return error; fat_truncate_blocks(inode, offset); return error; } #define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET) /* valid file mode bits */ #define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO) Loading @@ -378,7 +390,8 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) /* * Expand the file. Since inode_setattr() updates ->i_size * before calling the ->truncate(), but FAT needs to fill the * hole before it. * hole before it. XXX: this is no longer true with new truncate * sequence. */ if (attr->ia_valid & ATTR_SIZE) { if (attr->ia_size > inode->i_size) { Loading Loading @@ -427,15 +440,20 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) attr->ia_valid &= ~ATTR_MODE; } if (attr->ia_valid) error = inode_setattr(inode, attr); if (attr->ia_valid & ATTR_SIZE) { error = fat_setsize(inode, attr->ia_size); if (error) goto out; } generic_setattr(inode, attr); mark_inode_dirty(inode); out: return error; } EXPORT_SYMBOL_GPL(fat_setattr); const struct inode_operations fat_file_inode_operations = { .truncate = fat_truncate, .setattr = fat_setattr, .getattr = fat_getattr, }; fs/fat/inode.c +29 −6 Original line number Diff line number Diff line Loading @@ -142,14 +142,29 @@ static int fat_readpages(struct file *file, struct address_space *mapping, return mpage_readpages(mapping, pages, nr_pages, fat_get_block); } static void fat_write_failed(struct address_space *mapping, loff_t to) { struct inode *inode = mapping->host; if (to > inode->i_size) { truncate_pagecache(inode, to, inode->i_size); fat_truncate_blocks(inode, inode->i_size); } } static int fat_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) { int err; *pagep = NULL; return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, fat_get_block, err = cont_write_begin_newtrunc(file, mapping, pos, len, flags, pagep, fsdata, fat_get_block, &MSDOS_I(mapping->host)->mmu_private); if (err < 0) fat_write_failed(mapping, pos + len); return err; } static int fat_write_end(struct file *file, struct address_space *mapping, Loading @@ -159,6 +174,8 @@ static int fat_write_end(struct file *file, struct address_space *mapping, struct inode *inode = mapping->host; int err; err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); if (err < len) fat_write_failed(mapping, pos + len); if (!(err < 0) && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) { inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; MSDOS_I(inode)->i_attrs |= ATTR_ARCH; Loading @@ -172,7 +189,9 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, loff_t offset, unsigned long nr_segs) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; struct address_space *mapping = file->f_mapping; struct inode *inode = mapping->host; ssize_t ret; if (rw == WRITE) { /* Loading @@ -193,8 +212,12 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, * FAT need to use the DIO_LOCKING for avoiding the race * condition of fat_get_block() and ->truncate(). */ return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, fat_get_block, NULL); ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, fat_get_block, NULL); if (ret < 0 && (rw & WRITE)) fat_write_failed(mapping, offset + iov_length(iov, nr_segs)); return ret; } static sector_t _fat_bmap(struct address_space *mapping, sector_t block) Loading Loading @@ -429,7 +452,7 @@ static void fat_delete_inode(struct inode *inode) { truncate_inode_pages(&inode->i_data, 0); inode->i_size = 0; fat_truncate(inode); fat_truncate_blocks(inode, 0); clear_inode(inode); } Loading Loading
fs/fat/fat.h +2 −1 Original line number Diff line number Diff line Loading @@ -306,7 +306,8 @@ extern long fat_generic_ioctl(struct file *filp, unsigned int cmd, extern const struct file_operations fat_file_operations; extern const struct inode_operations fat_file_inode_operations; extern int fat_setattr(struct dentry * dentry, struct iattr * attr); extern void fat_truncate(struct inode *inode); extern int fat_setsize(struct inode *inode, loff_t offset); extern void fat_truncate_blocks(struct inode *inode, loff_t offset); extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); extern int fat_file_fsync(struct file *file, int datasync); Loading
fs/fat/file.c +26 −8 Original line number Diff line number Diff line Loading @@ -283,7 +283,7 @@ static int fat_free(struct inode *inode, int skip) return fat_free_clusters(inode, free_start); } void fat_truncate(struct inode *inode) void fat_truncate_blocks(struct inode *inode, loff_t offset) { struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); const unsigned int cluster_size = sbi->cluster_size; Loading @@ -293,10 +293,10 @@ void fat_truncate(struct inode *inode) * This protects against truncating a file bigger than it was then * trying to write into the hole. */ if (MSDOS_I(inode)->mmu_private > inode->i_size) MSDOS_I(inode)->mmu_private = inode->i_size; if (MSDOS_I(inode)->mmu_private > offset) MSDOS_I(inode)->mmu_private = offset; nr_clusters = (inode->i_size + (cluster_size - 1)) >> sbi->cluster_bits; nr_clusters = (offset + (cluster_size - 1)) >> sbi->cluster_bits; fat_free(inode, nr_clusters); fat_flush_inodes(inode->i_sb, inode, NULL); Loading Loading @@ -364,6 +364,18 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode) return 0; } int fat_setsize(struct inode *inode, loff_t offset) { int error; error = simple_setsize(inode, offset); if (error) return error; fat_truncate_blocks(inode, offset); return error; } #define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET) /* valid file mode bits */ #define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO) Loading @@ -378,7 +390,8 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) /* * Expand the file. Since inode_setattr() updates ->i_size * before calling the ->truncate(), but FAT needs to fill the * hole before it. * hole before it. XXX: this is no longer true with new truncate * sequence. */ if (attr->ia_valid & ATTR_SIZE) { if (attr->ia_size > inode->i_size) { Loading Loading @@ -427,15 +440,20 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) attr->ia_valid &= ~ATTR_MODE; } if (attr->ia_valid) error = inode_setattr(inode, attr); if (attr->ia_valid & ATTR_SIZE) { error = fat_setsize(inode, attr->ia_size); if (error) goto out; } generic_setattr(inode, attr); mark_inode_dirty(inode); out: return error; } EXPORT_SYMBOL_GPL(fat_setattr); const struct inode_operations fat_file_inode_operations = { .truncate = fat_truncate, .setattr = fat_setattr, .getattr = fat_getattr, };
fs/fat/inode.c +29 −6 Original line number Diff line number Diff line Loading @@ -142,14 +142,29 @@ static int fat_readpages(struct file *file, struct address_space *mapping, return mpage_readpages(mapping, pages, nr_pages, fat_get_block); } static void fat_write_failed(struct address_space *mapping, loff_t to) { struct inode *inode = mapping->host; if (to > inode->i_size) { truncate_pagecache(inode, to, inode->i_size); fat_truncate_blocks(inode, inode->i_size); } } static int fat_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) { int err; *pagep = NULL; return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, fat_get_block, err = cont_write_begin_newtrunc(file, mapping, pos, len, flags, pagep, fsdata, fat_get_block, &MSDOS_I(mapping->host)->mmu_private); if (err < 0) fat_write_failed(mapping, pos + len); return err; } static int fat_write_end(struct file *file, struct address_space *mapping, Loading @@ -159,6 +174,8 @@ static int fat_write_end(struct file *file, struct address_space *mapping, struct inode *inode = mapping->host; int err; err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); if (err < len) fat_write_failed(mapping, pos + len); if (!(err < 0) && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) { inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; MSDOS_I(inode)->i_attrs |= ATTR_ARCH; Loading @@ -172,7 +189,9 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, loff_t offset, unsigned long nr_segs) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; struct address_space *mapping = file->f_mapping; struct inode *inode = mapping->host; ssize_t ret; if (rw == WRITE) { /* Loading @@ -193,8 +212,12 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, * FAT need to use the DIO_LOCKING for avoiding the race * condition of fat_get_block() and ->truncate(). */ return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, fat_get_block, NULL); ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, fat_get_block, NULL); if (ret < 0 && (rw & WRITE)) fat_write_failed(mapping, offset + iov_length(iov, nr_segs)); return ret; } static sector_t _fat_bmap(struct address_space *mapping, sector_t block) Loading Loading @@ -429,7 +452,7 @@ static void fat_delete_inode(struct inode *inode) { truncate_inode_pages(&inode->i_data, 0); inode->i_size = 0; fat_truncate(inode); fat_truncate_blocks(inode, 0); clear_inode(inode); } Loading