aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fat
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fat')
-rw-r--r--fs/fat/dir.c56
-rw-r--r--fs/fat/file.c13
-rw-r--r--fs/fat/inode.c59
3 files changed, 126 insertions, 2 deletions
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 698b85bb1dd4..3e50a4166283 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -20,6 +20,7 @@
20#include <linux/dirent.h> 20#include <linux/dirent.h>
21#include <linux/smp_lock.h> 21#include <linux/smp_lock.h>
22#include <linux/buffer_head.h> 22#include <linux/buffer_head.h>
23#include <linux/compat.h>
23#include <asm/uaccess.h> 24#include <asm/uaccess.h>
24 25
25static inline loff_t fat_make_i_pos(struct super_block *sb, 26static inline loff_t fat_make_i_pos(struct super_block *sb,
@@ -741,10 +742,65 @@ static int fat_dir_ioctl(struct inode * inode, struct file * filp,
741 return ret; 742 return ret;
742} 743}
743 744
745#ifdef CONFIG_COMPAT
746#define VFAT_IOCTL_READDIR_BOTH32 _IOR('r', 1, struct compat_dirent[2])
747#define VFAT_IOCTL_READDIR_SHORT32 _IOR('r', 2, struct compat_dirent[2])
748
749static long fat_compat_put_dirent32(struct dirent *d,
750 struct compat_dirent __user *d32)
751{
752 if (!access_ok(VERIFY_WRITE, d32, sizeof(struct compat_dirent)))
753 return -EFAULT;
754
755 __put_user(d->d_ino, &d32->d_ino);
756 __put_user(d->d_off, &d32->d_off);
757 __put_user(d->d_reclen, &d32->d_reclen);
758 if (__copy_to_user(d32->d_name, d->d_name, d->d_reclen))
759 return -EFAULT;
760
761 return 0;
762}
763
764static long fat_compat_dir_ioctl(struct file *file, unsigned cmd,
765 unsigned long arg)
766{
767 struct compat_dirent __user *p = compat_ptr(arg);
768 int ret;
769 mm_segment_t oldfs = get_fs();
770 struct dirent d[2];
771
772 switch (cmd) {
773 case VFAT_IOCTL_READDIR_BOTH32:
774 cmd = VFAT_IOCTL_READDIR_BOTH;
775 break;
776 case VFAT_IOCTL_READDIR_SHORT32:
777 cmd = VFAT_IOCTL_READDIR_SHORT;
778 break;
779 default:
780 return -ENOIOCTLCMD;
781 }
782
783 set_fs(KERNEL_DS);
784 lock_kernel();
785 ret = fat_dir_ioctl(file->f_dentry->d_inode, file,
786 cmd, (unsigned long) &d);
787 unlock_kernel();
788 set_fs(oldfs);
789 if (ret >= 0) {
790 ret |= fat_compat_put_dirent32(&d[0], p);
791 ret |= fat_compat_put_dirent32(&d[1], p + 1);
792 }
793 return ret;
794}
795#endif /* CONFIG_COMPAT */
796
744const struct file_operations fat_dir_operations = { 797const struct file_operations fat_dir_operations = {
745 .read = generic_read_dir, 798 .read = generic_read_dir,
746 .readdir = fat_readdir, 799 .readdir = fat_readdir,
747 .ioctl = fat_dir_ioctl, 800 .ioctl = fat_dir_ioctl,
801#ifdef CONFIG_COMPAT
802 .compat_ioctl = fat_compat_dir_ioctl,
803#endif
748 .fsync = file_fsync, 804 .fsync = file_fsync,
749}; 805};
750 806
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 1ee25232e6af..d50fc47169c1 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -13,6 +13,7 @@
13#include <linux/smp_lock.h> 13#include <linux/smp_lock.h>
14#include <linux/buffer_head.h> 14#include <linux/buffer_head.h>
15#include <linux/writeback.h> 15#include <linux/writeback.h>
16#include <linux/blkdev.h>
16 17
17int fat_generic_ioctl(struct inode *inode, struct file *filp, 18int fat_generic_ioctl(struct inode *inode, struct file *filp,
18 unsigned int cmd, unsigned long arg) 19 unsigned int cmd, unsigned long arg)
@@ -112,6 +113,16 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp,
112 } 113 }
113} 114}
114 115
116static int fat_file_release(struct inode *inode, struct file *filp)
117{
118 if ((filp->f_mode & FMODE_WRITE) &&
119 MSDOS_SB(inode->i_sb)->options.flush) {
120 fat_flush_inodes(inode->i_sb, inode, NULL);
121 blk_congestion_wait(WRITE, HZ/10);
122 }
123 return 0;
124}
125
115const struct file_operations fat_file_operations = { 126const struct file_operations fat_file_operations = {
116 .llseek = generic_file_llseek, 127 .llseek = generic_file_llseek,
117 .read = do_sync_read, 128 .read = do_sync_read,
@@ -121,6 +132,7 @@ const struct file_operations fat_file_operations = {
121 .aio_read = generic_file_aio_read, 132 .aio_read = generic_file_aio_read,
122 .aio_write = generic_file_aio_write, 133 .aio_write = generic_file_aio_write,
123 .mmap = generic_file_mmap, 134 .mmap = generic_file_mmap,
135 .release = fat_file_release,
124 .ioctl = fat_generic_ioctl, 136 .ioctl = fat_generic_ioctl,
125 .fsync = file_fsync, 137 .fsync = file_fsync,
126 .sendfile = generic_file_sendfile, 138 .sendfile = generic_file_sendfile,
@@ -289,6 +301,7 @@ void fat_truncate(struct inode *inode)
289 lock_kernel(); 301 lock_kernel();
290 fat_free(inode, nr_clusters); 302 fat_free(inode, nr_clusters);
291 unlock_kernel(); 303 unlock_kernel();
304 fat_flush_inodes(inode->i_sb, inode, NULL);
292} 305}
293 306
294struct inode_operations fat_file_inode_operations = { 307struct inode_operations fat_file_inode_operations = {
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index ab96ae823753..045738032a83 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -24,6 +24,7 @@
24#include <linux/vfs.h> 24#include <linux/vfs.h>
25#include <linux/parser.h> 25#include <linux/parser.h>
26#include <linux/uio.h> 26#include <linux/uio.h>
27#include <linux/writeback.h>
27#include <asm/unaligned.h> 28#include <asm/unaligned.h>
28 29
29#ifndef CONFIG_FAT_DEFAULT_IOCHARSET 30#ifndef CONFIG_FAT_DEFAULT_IOCHARSET
@@ -853,7 +854,7 @@ enum {
853 Opt_charset, Opt_shortname_lower, Opt_shortname_win95, 854 Opt_charset, Opt_shortname_lower, Opt_shortname_win95,
854 Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, 855 Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes,
855 Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, 856 Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
856 Opt_obsolate, Opt_err, 857 Opt_obsolate, Opt_flush, Opt_err,
857}; 858};
858 859
859static match_table_t fat_tokens = { 860static match_table_t fat_tokens = {
@@ -885,7 +886,8 @@ static match_table_t fat_tokens = {
885 {Opt_obsolate, "cvf_format=%20s"}, 886 {Opt_obsolate, "cvf_format=%20s"},
886 {Opt_obsolate, "cvf_options=%100s"}, 887 {Opt_obsolate, "cvf_options=%100s"},
887 {Opt_obsolate, "posix"}, 888 {Opt_obsolate, "posix"},
888 {Opt_err, NULL} 889 {Opt_flush, "flush"},
890 {Opt_err, NULL},
889}; 891};
890static match_table_t msdos_tokens = { 892static match_table_t msdos_tokens = {
891 {Opt_nodots, "nodots"}, 893 {Opt_nodots, "nodots"},
@@ -1026,6 +1028,9 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
1026 return 0; 1028 return 0;
1027 opts->codepage = option; 1029 opts->codepage = option;
1028 break; 1030 break;
1031 case Opt_flush:
1032 opts->flush = 1;
1033 break;
1029 1034
1030 /* msdos specific */ 1035 /* msdos specific */
1031 case Opt_dots: 1036 case Opt_dots:
@@ -1425,6 +1430,56 @@ out_fail:
1425 1430
1426EXPORT_SYMBOL_GPL(fat_fill_super); 1431EXPORT_SYMBOL_GPL(fat_fill_super);
1427 1432
1433/*
1434 * helper function for fat_flush_inodes. This writes both the inode
1435 * and the file data blocks, waiting for in flight data blocks before
1436 * the start of the call. It does not wait for any io started
1437 * during the call
1438 */
1439static int writeback_inode(struct inode *inode)
1440{
1441
1442 int ret;
1443 struct address_space *mapping = inode->i_mapping;
1444 struct writeback_control wbc = {
1445 .sync_mode = WB_SYNC_NONE,
1446 .nr_to_write = 0,
1447 };
1448 /* if we used WB_SYNC_ALL, sync_inode waits for the io for the
1449 * inode to finish. So WB_SYNC_NONE is sent down to sync_inode
1450 * and filemap_fdatawrite is used for the data blocks
1451 */
1452 ret = sync_inode(inode, &wbc);
1453 if (!ret)
1454 ret = filemap_fdatawrite(mapping);
1455 return ret;
1456}
1457
1458/*
1459 * write data and metadata corresponding to i1 and i2. The io is
1460 * started but we do not wait for any of it to finish.
1461 *
1462 * filemap_flush is used for the block device, so if there is a dirty
1463 * page for a block already in flight, we will not wait and start the
1464 * io over again
1465 */
1466int fat_flush_inodes(struct super_block *sb, struct inode *i1, struct inode *i2)
1467{
1468 int ret = 0;
1469 if (!MSDOS_SB(sb)->options.flush)
1470 return 0;
1471 if (i1)
1472 ret = writeback_inode(i1);
1473 if (!ret && i2)
1474 ret = writeback_inode(i2);
1475 if (!ret && sb) {
1476 struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping;
1477 ret = filemap_flush(mapping);
1478 }
1479 return ret;
1480}
1481EXPORT_SYMBOL_GPL(fat_flush_inodes);
1482
1428static int __init init_fat_fs(void) 1483static int __init init_fat_fs(void)
1429{ 1484{
1430 int err; 1485 int err;