aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fat/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fat/file.c')
-rw-r--r--fs/fat/file.c38
1 files changed, 32 insertions, 6 deletions
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 7134403d5be2..e99c5a73b39e 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -6,11 +6,13 @@
6 * regular file handling primitives for fat-based filesystems 6 * regular file handling primitives for fat-based filesystems
7 */ 7 */
8 8
9#include <linux/capability.h>
9#include <linux/module.h> 10#include <linux/module.h>
10#include <linux/time.h> 11#include <linux/time.h>
11#include <linux/msdos_fs.h> 12#include <linux/msdos_fs.h>
12#include <linux/smp_lock.h> 13#include <linux/smp_lock.h>
13#include <linux/buffer_head.h> 14#include <linux/buffer_head.h>
15#include <linux/writeback.h>
14 16
15int fat_generic_ioctl(struct inode *inode, struct file *filp, 17int fat_generic_ioctl(struct inode *inode, struct file *filp,
16 unsigned int cmd, unsigned long arg) 18 unsigned int cmd, unsigned long arg)
@@ -40,7 +42,7 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp,
40 if (err) 42 if (err)
41 return err; 43 return err;
42 44
43 down(&inode->i_sem); 45 mutex_lock(&inode->i_mutex);
44 46
45 if (IS_RDONLY(inode)) { 47 if (IS_RDONLY(inode)) {
46 err = -EROFS; 48 err = -EROFS;
@@ -102,7 +104,7 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp,
102 MSDOS_I(inode)->i_attrs = attr & ATTR_UNUSED; 104 MSDOS_I(inode)->i_attrs = attr & ATTR_UNUSED;
103 mark_inode_dirty(inode); 105 mark_inode_dirty(inode);
104 up: 106 up:
105 up(&inode->i_sem); 107 mutex_unlock(&inode->i_mutex);
106 return err; 108 return err;
107 } 109 }
108 default: 110 default:
@@ -124,6 +126,24 @@ struct file_operations fat_file_operations = {
124 .sendfile = generic_file_sendfile, 126 .sendfile = generic_file_sendfile,
125}; 127};
126 128
129static int fat_cont_expand(struct inode *inode, loff_t size)
130{
131 struct address_space *mapping = inode->i_mapping;
132 loff_t start = inode->i_size, count = size - inode->i_size;
133 int err;
134
135 err = generic_cont_expand_simple(inode, size);
136 if (err)
137 goto out;
138
139 inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
140 mark_inode_dirty(inode);
141 if (IS_SYNC(inode))
142 err = sync_page_range_nolock(inode, mapping, start, count);
143out:
144 return err;
145}
146
127int fat_notify_change(struct dentry *dentry, struct iattr *attr) 147int fat_notify_change(struct dentry *dentry, struct iattr *attr)
128{ 148{
129 struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); 149 struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
@@ -132,11 +152,17 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr)
132 152
133 lock_kernel(); 153 lock_kernel();
134 154
135 /* FAT cannot truncate to a longer file */ 155 /*
156 * Expand the file. Since inode_setattr() updates ->i_size
157 * before calling the ->truncate(), but FAT needs to fill the
158 * hole before it.
159 */
136 if (attr->ia_valid & ATTR_SIZE) { 160 if (attr->ia_valid & ATTR_SIZE) {
137 if (attr->ia_size > inode->i_size) { 161 if (attr->ia_size > inode->i_size) {
138 error = -EPERM; 162 error = fat_cont_expand(inode, attr->ia_size);
139 goto out; 163 if (error || attr->ia_valid == ATTR_SIZE)
164 goto out;
165 attr->ia_valid &= ~ATTR_SIZE;
140 } 166 }
141 } 167 }
142 168
@@ -173,7 +199,7 @@ out:
173 return error; 199 return error;
174} 200}
175 201
176EXPORT_SYMBOL(fat_notify_change); 202EXPORT_SYMBOL_GPL(fat_notify_change);
177 203
178/* Free all clusters after the skip'th cluster. */ 204/* Free all clusters after the skip'th cluster. */
179static int fat_free(struct inode *inode, int skip) 205static int fat_free(struct inode *inode, int skip)