diff options
Diffstat (limited to 'fs/fat/file.c')
-rw-r--r-- | fs/fat/file.c | 38 |
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 | ||
15 | int fat_generic_ioctl(struct inode *inode, struct file *filp, | 17 | int 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 | ||
129 | static 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); | ||
143 | out: | ||
144 | return err; | ||
145 | } | ||
146 | |||
127 | int fat_notify_change(struct dentry *dentry, struct iattr *attr) | 147 | int 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 | ||
176 | EXPORT_SYMBOL(fat_notify_change); | 202 | EXPORT_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. */ |
179 | static int fat_free(struct inode *inode, int skip) | 205 | static int fat_free(struct inode *inode, int skip) |