aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fat
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fat')
-rw-r--r--fs/fat/file.c31
1 files changed, 28 insertions, 3 deletions
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 15229fe569c3..9b07c328a6fc 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -11,6 +11,7 @@
11#include <linux/msdos_fs.h> 11#include <linux/msdos_fs.h>
12#include <linux/smp_lock.h> 12#include <linux/smp_lock.h>
13#include <linux/buffer_head.h> 13#include <linux/buffer_head.h>
14#include <linux/writeback.h>
14 15
15int fat_generic_ioctl(struct inode *inode, struct file *filp, 16int fat_generic_ioctl(struct inode *inode, struct file *filp,
16 unsigned int cmd, unsigned long arg) 17 unsigned int cmd, unsigned long arg)
@@ -124,6 +125,24 @@ struct file_operations fat_file_operations = {
124 .sendfile = generic_file_sendfile, 125 .sendfile = generic_file_sendfile,
125}; 126};
126 127
128static int fat_cont_expand(struct inode *inode, loff_t size)
129{
130 struct address_space *mapping = inode->i_mapping;
131 loff_t start = inode->i_size, count = size - inode->i_size;
132 int err;
133
134 err = generic_cont_expand_simple(inode, size);
135 if (err)
136 goto out;
137
138 inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
139 mark_inode_dirty(inode);
140 if (IS_SYNC(inode))
141 err = sync_page_range_nolock(inode, mapping, start, count);
142out:
143 return err;
144}
145
127int fat_notify_change(struct dentry *dentry, struct iattr *attr) 146int fat_notify_change(struct dentry *dentry, struct iattr *attr)
128{ 147{
129 struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); 148 struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
@@ -132,11 +151,17 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr)
132 151
133 lock_kernel(); 152 lock_kernel();
134 153
135 /* FAT cannot truncate to a longer file */ 154 /*
155 * Expand the file. Since inode_setattr() updates ->i_size
156 * before calling the ->truncate(), but FAT needs to fill the
157 * hole before it.
158 */
136 if (attr->ia_valid & ATTR_SIZE) { 159 if (attr->ia_valid & ATTR_SIZE) {
137 if (attr->ia_size > inode->i_size) { 160 if (attr->ia_size > inode->i_size) {
138 error = -EPERM; 161 error = fat_cont_expand(inode, attr->ia_size);
139 goto out; 162 if (error || attr->ia_valid == ATTR_SIZE)
163 goto out;
164 attr->ia_valid &= ~ATTR_SIZE;
140 } 165 }
141 } 166 }
142 167