aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <mason@suse.com>2006-09-29 05:00:03 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-29 12:18:12 -0400
commitae78bf9c4f5fde3c67e2829505f195d7347ce3e4 (patch)
treeb9376237e596ed7e95db35b9ccf1ad3177b10460
parent6b77df08a36d989f7dd00ccb6a026a0e96170d16 (diff)
[PATCH] add -o flush for fat
Fat is commonly used on removable media. Mounting with -o flush tells the FS to write things to disk as quickly as possible. It is like -o sync, but much faster (and not as safe). Signed-off-by: Chris Mason <mason@suse.com> Cc: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/fat/file.c13
-rw-r--r--fs/fat/inode.c59
-rw-r--r--fs/msdos/namei.c11
-rw-r--r--include/linux/msdos_fs.h3
4 files changed, 83 insertions, 3 deletions
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;
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 9e44158a7540..d220165d4918 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -280,7 +280,7 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, int mode,
280 struct nameidata *nd) 280 struct nameidata *nd)
281{ 281{
282 struct super_block *sb = dir->i_sb; 282 struct super_block *sb = dir->i_sb;
283 struct inode *inode; 283 struct inode *inode = NULL;
284 struct fat_slot_info sinfo; 284 struct fat_slot_info sinfo;
285 struct timespec ts; 285 struct timespec ts;
286 unsigned char msdos_name[MSDOS_NAME]; 286 unsigned char msdos_name[MSDOS_NAME];
@@ -316,6 +316,8 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, int mode,
316 d_instantiate(dentry, inode); 316 d_instantiate(dentry, inode);
317out: 317out:
318 unlock_kernel(); 318 unlock_kernel();
319 if (!err)
320 err = fat_flush_inodes(sb, dir, inode);
319 return err; 321 return err;
320} 322}
321 323
@@ -348,6 +350,8 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
348 fat_detach(inode); 350 fat_detach(inode);
349out: 351out:
350 unlock_kernel(); 352 unlock_kernel();
353 if (!err)
354 err = fat_flush_inodes(inode->i_sb, dir, inode);
351 355
352 return err; 356 return err;
353} 357}
@@ -401,6 +405,7 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode)
401 d_instantiate(dentry, inode); 405 d_instantiate(dentry, inode);
402 406
403 unlock_kernel(); 407 unlock_kernel();
408 fat_flush_inodes(sb, dir, inode);
404 return 0; 409 return 0;
405 410
406out_free: 411out_free:
@@ -430,6 +435,8 @@ static int msdos_unlink(struct inode *dir, struct dentry *dentry)
430 fat_detach(inode); 435 fat_detach(inode);
431out: 436out:
432 unlock_kernel(); 437 unlock_kernel();
438 if (!err)
439 err = fat_flush_inodes(inode->i_sb, dir, inode);
433 440
434 return err; 441 return err;
435} 442}
@@ -635,6 +642,8 @@ static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,
635 new_dir, new_msdos_name, new_dentry, is_hid); 642 new_dir, new_msdos_name, new_dentry, is_hid);
636out: 643out:
637 unlock_kernel(); 644 unlock_kernel();
645 if (!err)
646 err = fat_flush_inodes(old_dir->i_sb, old_dir, new_dir);
638 return err; 647 return err;
639} 648}
640 649
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index bae62d62dc3e..ce6c85815cbd 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -204,6 +204,7 @@ struct fat_mount_options {
204 unicode_xlate:1, /* create escape sequences for unhandled Unicode */ 204 unicode_xlate:1, /* create escape sequences for unhandled Unicode */
205 numtail:1, /* Does first alias have a numeric '~1' type tail? */ 205 numtail:1, /* Does first alias have a numeric '~1' type tail? */
206 atari:1, /* Use Atari GEMDOS variation of MS-DOS fs */ 206 atari:1, /* Use Atari GEMDOS variation of MS-DOS fs */
207 flush:1, /* write things quickly */
207 nocase:1; /* Does this need case conversion? 0=need case conversion*/ 208 nocase:1; /* Does this need case conversion? 0=need case conversion*/
208}; 209};
209 210
@@ -412,6 +413,8 @@ extern int fat_sync_inode(struct inode *inode);
412extern int fat_fill_super(struct super_block *sb, void *data, int silent, 413extern int fat_fill_super(struct super_block *sb, void *data, int silent,
413 struct inode_operations *fs_dir_inode_ops, int isvfat); 414 struct inode_operations *fs_dir_inode_ops, int isvfat);
414 415
416extern int fat_flush_inodes(struct super_block *sb, struct inode *i1,
417 struct inode *i2);
415/* fat/misc.c */ 418/* fat/misc.c */
416extern void fat_fs_panic(struct super_block *s, const char *fmt, ...); 419extern void fat_fs_panic(struct super_block *s, const char *fmt, ...);
417extern void fat_clusters_flush(struct super_block *sb); 420extern void fat_clusters_flush(struct super_block *sb);