forked from Minki/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>
This commit is contained in:
parent
737f2e93b9
commit
459f6ed3b8
@ -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);
|
||||
|
@ -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;
|
||||
@ -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);
|
||||
@ -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)
|
||||
@ -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) {
|
||||
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
@ -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;
|
||||
@ -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) {
|
||||
/*
|
||||
@ -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)
|
||||
@ -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…
Reference in New Issue
Block a user