diff options
Diffstat (limited to 'fs/fat/file.c')
-rw-r--r-- | fs/fat/file.c | 59 |
1 files changed, 45 insertions, 14 deletions
diff --git a/fs/fat/file.c b/fs/fat/file.c index e8c159de236b..990dfae022e5 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
@@ -8,6 +8,7 @@ | |||
8 | 8 | ||
9 | #include <linux/capability.h> | 9 | #include <linux/capability.h> |
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/compat.h> | ||
11 | #include <linux/mount.h> | 12 | #include <linux/mount.h> |
12 | #include <linux/time.h> | 13 | #include <linux/time.h> |
13 | #include <linux/buffer_head.h> | 14 | #include <linux/buffer_head.h> |
@@ -114,9 +115,9 @@ out: | |||
114 | return err; | 115 | return err; |
115 | } | 116 | } |
116 | 117 | ||
117 | int fat_generic_ioctl(struct inode *inode, struct file *filp, | 118 | long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
118 | unsigned int cmd, unsigned long arg) | ||
119 | { | 119 | { |
120 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
120 | u32 __user *user_attr = (u32 __user *)arg; | 121 | u32 __user *user_attr = (u32 __user *)arg; |
121 | 122 | ||
122 | switch (cmd) { | 123 | switch (cmd) { |
@@ -129,6 +130,15 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp, | |||
129 | } | 130 | } |
130 | } | 131 | } |
131 | 132 | ||
133 | #ifdef CONFIG_COMPAT | ||
134 | static long fat_generic_compat_ioctl(struct file *filp, unsigned int cmd, | ||
135 | unsigned long arg) | ||
136 | |||
137 | { | ||
138 | return fat_generic_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); | ||
139 | } | ||
140 | #endif | ||
141 | |||
132 | static int fat_file_release(struct inode *inode, struct file *filp) | 142 | static int fat_file_release(struct inode *inode, struct file *filp) |
133 | { | 143 | { |
134 | if ((filp->f_mode & FMODE_WRITE) && | 144 | if ((filp->f_mode & FMODE_WRITE) && |
@@ -139,12 +149,12 @@ static int fat_file_release(struct inode *inode, struct file *filp) | |||
139 | return 0; | 149 | return 0; |
140 | } | 150 | } |
141 | 151 | ||
142 | int fat_file_fsync(struct file *filp, struct dentry *dentry, int datasync) | 152 | int fat_file_fsync(struct file *filp, int datasync) |
143 | { | 153 | { |
144 | struct inode *inode = dentry->d_inode; | 154 | struct inode *inode = filp->f_mapping->host; |
145 | int res, err; | 155 | int res, err; |
146 | 156 | ||
147 | res = simple_fsync(filp, dentry, datasync); | 157 | res = generic_file_fsync(filp, datasync); |
148 | err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping); | 158 | err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping); |
149 | 159 | ||
150 | return res ? res : err; | 160 | return res ? res : err; |
@@ -159,7 +169,10 @@ const struct file_operations fat_file_operations = { | |||
159 | .aio_write = generic_file_aio_write, | 169 | .aio_write = generic_file_aio_write, |
160 | .mmap = generic_file_mmap, | 170 | .mmap = generic_file_mmap, |
161 | .release = fat_file_release, | 171 | .release = fat_file_release, |
162 | .ioctl = fat_generic_ioctl, | 172 | .unlocked_ioctl = fat_generic_ioctl, |
173 | #ifdef CONFIG_COMPAT | ||
174 | .compat_ioctl = fat_generic_compat_ioctl, | ||
175 | #endif | ||
163 | .fsync = fat_file_fsync, | 176 | .fsync = fat_file_fsync, |
164 | .splice_read = generic_file_splice_read, | 177 | .splice_read = generic_file_splice_read, |
165 | }; | 178 | }; |
@@ -270,7 +283,7 @@ static int fat_free(struct inode *inode, int skip) | |||
270 | return fat_free_clusters(inode, free_start); | 283 | return fat_free_clusters(inode, free_start); |
271 | } | 284 | } |
272 | 285 | ||
273 | void fat_truncate(struct inode *inode) | 286 | void fat_truncate_blocks(struct inode *inode, loff_t offset) |
274 | { | 287 | { |
275 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | 288 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); |
276 | const unsigned int cluster_size = sbi->cluster_size; | 289 | const unsigned int cluster_size = sbi->cluster_size; |
@@ -280,10 +293,10 @@ void fat_truncate(struct inode *inode) | |||
280 | * This protects against truncating a file bigger than it was then | 293 | * This protects against truncating a file bigger than it was then |
281 | * trying to write into the hole. | 294 | * trying to write into the hole. |
282 | */ | 295 | */ |
283 | if (MSDOS_I(inode)->mmu_private > inode->i_size) | 296 | if (MSDOS_I(inode)->mmu_private > offset) |
284 | MSDOS_I(inode)->mmu_private = inode->i_size; | 297 | MSDOS_I(inode)->mmu_private = offset; |
285 | 298 | ||
286 | nr_clusters = (inode->i_size + (cluster_size - 1)) >> sbi->cluster_bits; | 299 | nr_clusters = (offset + (cluster_size - 1)) >> sbi->cluster_bits; |
287 | 300 | ||
288 | fat_free(inode, nr_clusters); | 301 | fat_free(inode, nr_clusters); |
289 | fat_flush_inodes(inode->i_sb, inode, NULL); | 302 | fat_flush_inodes(inode->i_sb, inode, NULL); |
@@ -351,6 +364,18 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode) | |||
351 | return 0; | 364 | return 0; |
352 | } | 365 | } |
353 | 366 | ||
367 | int fat_setsize(struct inode *inode, loff_t offset) | ||
368 | { | ||
369 | int error; | ||
370 | |||
371 | error = simple_setsize(inode, offset); | ||
372 | if (error) | ||
373 | return error; | ||
374 | fat_truncate_blocks(inode, offset); | ||
375 | |||
376 | return error; | ||
377 | } | ||
378 | |||
354 | #define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET) | 379 | #define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET) |
355 | /* valid file mode bits */ | 380 | /* valid file mode bits */ |
356 | #define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO) | 381 | #define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO) |
@@ -365,7 +390,8 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) | |||
365 | /* | 390 | /* |
366 | * Expand the file. Since inode_setattr() updates ->i_size | 391 | * Expand the file. Since inode_setattr() updates ->i_size |
367 | * before calling the ->truncate(), but FAT needs to fill the | 392 | * before calling the ->truncate(), but FAT needs to fill the |
368 | * hole before it. | 393 | * hole before it. XXX: this is no longer true with new truncate |
394 | * sequence. | ||
369 | */ | 395 | */ |
370 | if (attr->ia_valid & ATTR_SIZE) { | 396 | if (attr->ia_valid & ATTR_SIZE) { |
371 | if (attr->ia_size > inode->i_size) { | 397 | if (attr->ia_size > inode->i_size) { |
@@ -414,15 +440,20 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) | |||
414 | attr->ia_valid &= ~ATTR_MODE; | 440 | attr->ia_valid &= ~ATTR_MODE; |
415 | } | 441 | } |
416 | 442 | ||
417 | if (attr->ia_valid) | 443 | if (attr->ia_valid & ATTR_SIZE) { |
418 | error = inode_setattr(inode, attr); | 444 | error = fat_setsize(inode, attr->ia_size); |
445 | if (error) | ||
446 | goto out; | ||
447 | } | ||
448 | |||
449 | generic_setattr(inode, attr); | ||
450 | mark_inode_dirty(inode); | ||
419 | out: | 451 | out: |
420 | return error; | 452 | return error; |
421 | } | 453 | } |
422 | EXPORT_SYMBOL_GPL(fat_setattr); | 454 | EXPORT_SYMBOL_GPL(fat_setattr); |
423 | 455 | ||
424 | const struct inode_operations fat_file_inode_operations = { | 456 | const struct inode_operations fat_file_inode_operations = { |
425 | .truncate = fat_truncate, | ||
426 | .setattr = fat_setattr, | 457 | .setattr = fat_setattr, |
427 | .getattr = fat_getattr, | 458 | .getattr = fat_getattr, |
428 | }; | 459 | }; |