From: Chris Mason <mason@xxxxxxxx> Subject: 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@xxxxxxxx> --- a/fs/fat/file.c Fri Aug 04 14:02:26 2006 -0400 +++ b/fs/fat/file.c Fri Aug 04 15:25:09 2006 -0400 @@ -13,6 +13,7 @@ #include <linux/smp_lock.h> #include <linux/buffer_head.h> #include <linux/writeback.h> +#include <linux/blkdev.h> int fat_generic_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) @@ -112,6 +113,17 @@ int fat_generic_ioctl(struct inode *inod } } +static int fat_file_release(struct inode *inode, struct file *filp) +{ + if ((filp->f_mode & FMODE_WRITE) && + MSDOS_SB(inode->i_sb)->options.flush) { + writeback_inode(inode); + writeback_bdev(inode->i_sb); + blk_congestion_wait(WRITE, HZ/10); + } + return 0; +} + const struct file_operations fat_file_operations = { .llseek = generic_file_llseek, .read = do_sync_read, @@ -121,6 +133,7 @@ const struct file_operations fat_file_op .aio_read = generic_file_aio_read, .aio_write = generic_file_aio_write, .mmap = generic_file_mmap, + .release = fat_file_release, .ioctl = fat_generic_ioctl, .fsync = file_fsync, .sendfile = generic_file_sendfile, @@ -289,6 +302,10 @@ void fat_truncate(struct inode *inode) lock_kernel(); fat_free(inode, nr_clusters); unlock_kernel(); + if (MSDOS_SB(inode->i_sb)->options.flush) { + writeback_inode(inode); + writeback_bdev(inode->i_sb); + } } struct inode_operations fat_file_inode_operations = { --- a/fs/fat/inode.c Fri Aug 04 14:02:26 2006 -0400 +++ b/fs/fat/inode.c Fri Aug 04 14:02:26 2006 -0400 @@ -24,6 +24,7 @@ #include <linux/vfs.h> #include <linux/parser.h> #include <linux/uio.h> +#include <linux/writeback.h> #include <asm/unaligned.h> #ifndef CONFIG_FAT_DEFAULT_IOCHARSET @@ -861,7 +862,7 @@ enum { Opt_charset, Opt_shortname_lower, Opt_shortname_win95, Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, - Opt_obsolate, Opt_err, + Opt_obsolate, Opt_flush, Opt_err, }; static match_table_t fat_tokens = { @@ -893,7 +894,8 @@ static match_table_t fat_tokens = { {Opt_obsolate, "cvf_format=%20s"}, {Opt_obsolate, "cvf_options=%100s"}, {Opt_obsolate, "posix"}, - {Opt_err, NULL} + {Opt_flush, "flush"}, + {Opt_err, NULL}, }; static match_table_t msdos_tokens = { {Opt_nodots, "nodots"}, @@ -1034,6 +1036,9 @@ static int parse_options(char *options, return 0; opts->codepage = option; break; + case Opt_flush: + opts->flush = 1; + break; /* msdos specific */ case Opt_dots: --- a/fs/fs-writeback.c Fri Aug 04 14:02:26 2006 -0400 +++ b/fs/fs-writeback.c Fri Aug 04 14:41:46 2006 -0400 @@ -391,6 +391,41 @@ sync_sb_inodes(struct super_block *sb, s } /* + * starts IO on any dirty blocks in the block device. This uses + * filemap_flush, and so it does not wait for the io to finish, and does + * not wait on any IO currently in flight. + */ +void writeback_bdev(struct super_block *sb) +{ + struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; + filemap_flush(mapping); +} +EXPORT_SYMBOL_GPL(writeback_bdev); + +/* + * start writeback on both the inode and the data blocks. + * filemap_fdatawrite is used, so it waits for any IO that was in + * flight for dirty blocks at the start of this call. This will not + * wait for any IO it starts. + */ +void writeback_inode(struct inode *inode) +{ + + struct address_space *mapping = inode->i_mapping; + struct writeback_control wbc = { + .sync_mode = WB_SYNC_NONE, + .nr_to_write = 0, + }; + /* if we used WB_SYNC_ALL, sync_inode waits for the io for the + * inode to finish. So WB_SYNC_NONE is sent down to sync_inode + * and filemap_fdatawrite is used for the data blocks + */ + sync_inode(inode, &wbc); + filemap_fdatawrite(mapping); +} +EXPORT_SYMBOL_GPL(writeback_inode); + +/* * Start writeback of dirty pagecache data against all unlocked inodes. * * Note: --- a/fs/msdos/namei.c Fri Aug 04 14:02:26 2006 -0400 +++ b/fs/msdos/namei.c Fri Aug 04 14:02:26 2006 -0400 @@ -11,6 +11,7 @@ #include <linux/buffer_head.h> #include <linux/msdos_fs.h> #include <linux/smp_lock.h> +#include <linux/writeback.h> /* Characters that are undesirable in an MS-DOS file name */ static unsigned char bad_chars[] = "*?<>|\""; @@ -280,7 +281,7 @@ static int msdos_create(struct inode *di struct nameidata *nd) { struct super_block *sb = dir->i_sb; - struct inode *inode; + struct inode *inode = NULL; struct fat_slot_info sinfo; struct timespec ts; unsigned char msdos_name[MSDOS_NAME]; @@ -316,6 +317,11 @@ static int msdos_create(struct inode *di d_instantiate(dentry, inode); out: unlock_kernel(); + if (!err && MSDOS_SB(sb)->options.flush) { + writeback_inode(dir); + writeback_inode(inode); + writeback_bdev(sb); + } return err; } @@ -348,6 +354,11 @@ static int msdos_rmdir(struct inode *dir fat_detach(inode); out: unlock_kernel(); + if (!err && MSDOS_SB(inode->i_sb)->options.flush) { + writeback_inode(dir); + writeback_inode(inode); + writeback_bdev(inode->i_sb); + } return err; } @@ -401,6 +412,11 @@ static int msdos_mkdir(struct inode *dir d_instantiate(dentry, inode); unlock_kernel(); + if (MSDOS_SB(sb)->options.flush) { + writeback_inode(dir); + writeback_inode(inode); + writeback_bdev(sb); + } return 0; out_free: @@ -430,6 +446,11 @@ static int msdos_unlink(struct inode *di fat_detach(inode); out: unlock_kernel(); + if (!err && MSDOS_SB(inode->i_sb)->options.flush) { + writeback_inode(dir); + writeback_inode(inode); + writeback_bdev(inode->i_sb); + } return err; } @@ -635,6 +656,11 @@ static int msdos_rename(struct inode *ol new_dir, new_msdos_name, new_dentry, is_hid); out: unlock_kernel(); + if (!err && MSDOS_SB(old_dir->i_sb)->options.flush) { + writeback_inode(old_dir); + writeback_inode(new_dir); + writeback_bdev(old_dir->i_sb); + } return err; } --- a/include/linux/msdos_fs.h Fri Aug 04 14:02:26 2006 -0400 +++ b/include/linux/msdos_fs.h Fri Aug 04 14:02:26 2006 -0400 @@ -204,6 +204,7 @@ struct fat_mount_options { unicode_xlate:1, /* create escape sequences for unhandled Unicode */ numtail:1, /* Does first alias have a numeric '~1' type tail? */ atari:1, /* Use Atari GEMDOS variation of MS-DOS fs */ + flush:1, /* write things quickly */ nocase:1; /* Does this need case conversion? 0=need case conversion*/ }; --- a/include/linux/writeback.h Fri Aug 04 14:02:26 2006 -0400 +++ b/include/linux/writeback.h Fri Aug 04 14:02:26 2006 -0400 @@ -69,6 +69,8 @@ int inode_wait(void *); int inode_wait(void *); void sync_inodes_sb(struct super_block *, int wait); void sync_inodes(int wait); +void writeback_bdev(struct super_block *); +void writeback_inode(struct inode *); /* writeback.h requires fs.h; it, too, is not included from here. */ static inline void wait_on_inode(struct inode *inode) - To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html