Commit 3475ea42 authored by Nick Piggin's avatar Nick Piggin Committed by James Toy

Signed-off-by: Nick Piggin <npiggin@suse.de>

Cc: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Jan Kara <jack@suse.cz>
Cc: Dave Kleikamp <shaggy@linux.vnet.ibm.com>
Cc: Chris Mason <chris.mason@oracle.com>
Cc: Hugh Dickins <hugh.dickins@tiscali.co.uk>
Cc: Miklos Szeredi <miklos@szeredi.hu>
Cc: Trond Myklebust <trond.myklebust@fys.uio.no>
Cc: Steven French <sfrench@us.ibm.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 85a3602b
...@@ -302,7 +302,7 @@ extern int fat_generic_ioctl(struct inode *inode, struct file *filp, ...@@ -302,7 +302,7 @@ extern int fat_generic_ioctl(struct inode *inode, struct file *filp,
extern const struct file_operations fat_file_operations; extern const struct file_operations fat_file_operations;
extern const struct inode_operations fat_file_inode_operations; extern const struct inode_operations fat_file_inode_operations;
extern int fat_setattr(struct dentry * dentry, struct iattr * attr); extern int fat_setattr(struct dentry * dentry, struct iattr * attr);
extern void fat_truncate(struct inode *inode); extern void fat_truncate_blocks(struct inode *inode, loff_t offset);
extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat); struct kstat *stat);
extern int fat_file_fsync(struct file *file, struct dentry *dentry, extern int fat_file_fsync(struct file *file, struct dentry *dentry,
......
...@@ -270,7 +270,7 @@ static int fat_free(struct inode *inode, int skip) ...@@ -270,7 +270,7 @@ static int fat_free(struct inode *inode, int skip)
return fat_free_clusters(inode, free_start); 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); struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
const unsigned int cluster_size = sbi->cluster_size; const unsigned int cluster_size = sbi->cluster_size;
...@@ -280,10 +280,10 @@ void fat_truncate(struct inode *inode) ...@@ -280,10 +280,10 @@ void fat_truncate(struct inode *inode)
* This protects against truncating a file bigger than it was then * This protects against truncating a file bigger than it was then
* trying to write into the hole. * trying to write into the hole.
*/ */
if (MSDOS_I(inode)->mmu_private > inode->i_size) if (MSDOS_I(inode)->mmu_private > offset)
MSDOS_I(inode)->mmu_private = inode->i_size; 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_free(inode, nr_clusters);
fat_flush_inodes(inode->i_sb, inode, NULL); fat_flush_inodes(inode->i_sb, inode, NULL);
...@@ -351,6 +351,18 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode) ...@@ -351,6 +351,18 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode)
return 0; return 0;
} }
static 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) #define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)
/* valid file mode bits */ /* valid file mode bits */
#define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO) #define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO)
...@@ -365,7 +377,8 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -365,7 +377,8 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
/* /*
* Expand the file. Since inode_setattr() updates ->i_size * Expand the file. Since inode_setattr() updates ->i_size
* before calling the ->truncate(), but FAT needs to fill the * 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_valid & ATTR_SIZE) {
if (attr->ia_size > inode->i_size) { if (attr->ia_size > inode->i_size) {
...@@ -414,15 +427,21 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -414,15 +427,21 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
attr->ia_valid &= ~ATTR_MODE; attr->ia_valid &= ~ATTR_MODE;
} }
if (attr->ia_valid) if (attr->ia_valid & ATTR_SIZE) {
error = inode_setattr(inode, attr); error = fat_setsize(inode, attr->ia_size);
if (error)
goto out;
}
generic_setattr(inode, attr);
mark_inode_dirty(inode);
out: out:
return error; return error;
} }
EXPORT_SYMBOL_GPL(fat_setattr); EXPORT_SYMBOL_GPL(fat_setattr);
const struct inode_operations fat_file_inode_operations = { const struct inode_operations fat_file_inode_operations = {
.truncate = fat_truncate, .new_truncate = 1,
.setattr = fat_setattr, .setattr = fat_setattr,
.getattr = fat_getattr, .getattr = fat_getattr,
}; };
...@@ -146,10 +146,19 @@ static int fat_write_begin(struct file *file, struct address_space *mapping, ...@@ -146,10 +146,19 @@ static int fat_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags, loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata) struct page **pagep, void **fsdata)
{ {
int err;
*pagep = NULL; *pagep = NULL;
return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, err = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
fat_get_block, fat_get_block,
&MSDOS_I(mapping->host)->mmu_private); &MSDOS_I(mapping->host)->mmu_private);
if (err < 0) {
struct inode *inode = mapping->host;
loff_t isize = inode->i_size;
if (pos + len > isize)
fat_truncate_blocks(inode, isize);
}
return err;
} }
static int fat_write_end(struct file *file, struct address_space *mapping, static int fat_write_end(struct file *file, struct address_space *mapping,
...@@ -159,6 +168,11 @@ static int fat_write_end(struct file *file, struct address_space *mapping, ...@@ -159,6 +168,11 @@ static int fat_write_end(struct file *file, struct address_space *mapping,
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
int err; int err;
err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata);
if (err < len) {
loff_t isize = inode->i_size;
if (pos + len > isize)
fat_truncate_blocks(inode, isize);
}
if (!(err < 0) && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) { if (!(err < 0) && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) {
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
MSDOS_I(inode)->i_attrs |= ATTR_ARCH; MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
...@@ -173,6 +187,7 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, ...@@ -173,6 +187,7 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
{ {
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host; struct inode *inode = file->f_mapping->host;
ssize_t ret;
if (rw == WRITE) { if (rw == WRITE) {
/* /*
...@@ -193,8 +208,12 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, ...@@ -193,8 +208,12 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
* FAT need to use the DIO_LOCKING for avoiding the race * FAT need to use the DIO_LOCKING for avoiding the race
* condition of fat_get_block() and ->truncate(). * condition of fat_get_block() and ->truncate().
*/ */
return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs, fat_get_block, NULL); offset, nr_segs, fat_get_block, NULL);
if (ret < 0 && (rw & WRITE))
fat_truncate_blocks(inode, inode->i_size);
return ret;
} }
static sector_t _fat_bmap(struct address_space *mapping, sector_t block) static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
...@@ -429,7 +448,7 @@ static void fat_delete_inode(struct inode *inode) ...@@ -429,7 +448,7 @@ static void fat_delete_inode(struct inode *inode)
{ {
truncate_inode_pages(&inode->i_data, 0); truncate_inode_pages(&inode->i_data, 0);
inode->i_size = 0; inode->i_size = 0;
fat_truncate(inode); fat_truncate_blocks(inode, 0);
clear_inode(inode); clear_inode(inode);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment