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) |
