mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	[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>
This commit is contained in:
		
							parent
							
								
									6b77df08a3
								
							
						
					
					
						commit
						ae78bf9c4f
					
				
					 4 changed files with 83 additions and 3 deletions
				
			
		| 
						 | 
				
			
			@ -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,16 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp,
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int fat_file_release(struct inode *inode, struct file *filp)
 | 
			
		||||
{
 | 
			
		||||
	if ((filp->f_mode & FMODE_WRITE) &&
 | 
			
		||||
	     MSDOS_SB(inode->i_sb)->options.flush) {
 | 
			
		||||
		fat_flush_inodes(inode->i_sb, inode, NULL);
 | 
			
		||||
		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 +132,7 @@ const struct file_operations fat_file_operations = {
 | 
			
		|||
	.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 +301,7 @@ void fat_truncate(struct inode *inode)
 | 
			
		|||
	lock_kernel();
 | 
			
		||||
	fat_free(inode, nr_clusters);
 | 
			
		||||
	unlock_kernel();
 | 
			
		||||
	fat_flush_inodes(inode->i_sb, inode, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct inode_operations fat_file_inode_operations = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -853,7 +854,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 = {
 | 
			
		||||
| 
						 | 
				
			
			@ -885,7 +886,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"},
 | 
			
		||||
| 
						 | 
				
			
			@ -1026,6 +1028,9 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
 | 
			
		|||
				return 0;
 | 
			
		||||
			opts->codepage = option;
 | 
			
		||||
			break;
 | 
			
		||||
		case Opt_flush:
 | 
			
		||||
			opts->flush = 1;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		/* msdos specific */
 | 
			
		||||
		case Opt_dots:
 | 
			
		||||
| 
						 | 
				
			
			@ -1425,6 +1430,56 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
 | 
			
		|||
 | 
			
		||||
EXPORT_SYMBOL_GPL(fat_fill_super);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * helper function for fat_flush_inodes.  This writes both the inode
 | 
			
		||||
 * and the file data blocks, waiting for in flight data blocks before
 | 
			
		||||
 * the start of the call.  It does not wait for any io started
 | 
			
		||||
 * during the call
 | 
			
		||||
 */
 | 
			
		||||
static int writeback_inode(struct inode *inode)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	int ret;
 | 
			
		||||
	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
 | 
			
		||||
	*/
 | 
			
		||||
	ret = sync_inode(inode, &wbc);
 | 
			
		||||
	if (!ret)
 | 
			
		||||
	       ret = filemap_fdatawrite(mapping);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * write data and metadata corresponding to i1 and i2.  The io is
 | 
			
		||||
 * started but we do not wait for any of it to finish.
 | 
			
		||||
 *
 | 
			
		||||
 * filemap_flush is used for the block device, so if there is a dirty
 | 
			
		||||
 * page for a block already in flight, we will not wait and start the
 | 
			
		||||
 * io over again
 | 
			
		||||
 */
 | 
			
		||||
int fat_flush_inodes(struct super_block *sb, struct inode *i1, struct inode *i2)
 | 
			
		||||
{
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
	if (!MSDOS_SB(sb)->options.flush)
 | 
			
		||||
		return 0;
 | 
			
		||||
	if (i1)
 | 
			
		||||
		ret = writeback_inode(i1);
 | 
			
		||||
	if (!ret && i2)
 | 
			
		||||
		ret = writeback_inode(i2);
 | 
			
		||||
	if (!ret && sb) {
 | 
			
		||||
		struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping;
 | 
			
		||||
		ret = filemap_flush(mapping);
 | 
			
		||||
	}
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(fat_flush_inodes);
 | 
			
		||||
 | 
			
		||||
static int __init init_fat_fs(void)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -280,7 +280,7 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, int mode,
 | 
			
		|||
			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 +316,8 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, int mode,
 | 
			
		|||
	d_instantiate(dentry, inode);
 | 
			
		||||
out:
 | 
			
		||||
	unlock_kernel();
 | 
			
		||||
	if (!err)
 | 
			
		||||
		err = fat_flush_inodes(sb, dir, inode);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -348,6 +350,8 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
 | 
			
		|||
	fat_detach(inode);
 | 
			
		||||
out:
 | 
			
		||||
	unlock_kernel();
 | 
			
		||||
	if (!err)
 | 
			
		||||
		err = fat_flush_inodes(inode->i_sb, dir, inode);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -401,6 +405,7 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 | 
			
		|||
	d_instantiate(dentry, inode);
 | 
			
		||||
 | 
			
		||||
	unlock_kernel();
 | 
			
		||||
	fat_flush_inodes(sb, dir, inode);
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
out_free:
 | 
			
		||||
| 
						 | 
				
			
			@ -430,6 +435,8 @@ static int msdos_unlink(struct inode *dir, struct dentry *dentry)
 | 
			
		|||
	fat_detach(inode);
 | 
			
		||||
out:
 | 
			
		||||
	unlock_kernel();
 | 
			
		||||
	if (!err)
 | 
			
		||||
		err = fat_flush_inodes(inode->i_sb, dir, inode);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -635,6 +642,8 @@ static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,
 | 
			
		|||
			      new_dir, new_msdos_name, new_dentry, is_hid);
 | 
			
		||||
out:
 | 
			
		||||
	unlock_kernel();
 | 
			
		||||
	if (!err)
 | 
			
		||||
		err = fat_flush_inodes(old_dir->i_sb, old_dir, new_dir);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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*/
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -412,6 +413,8 @@ extern int fat_sync_inode(struct inode *inode);
 | 
			
		|||
extern int fat_fill_super(struct super_block *sb, void *data, int silent,
 | 
			
		||||
			struct inode_operations *fs_dir_inode_ops, int isvfat);
 | 
			
		||||
 | 
			
		||||
extern int fat_flush_inodes(struct super_block *sb, struct inode *i1,
 | 
			
		||||
		            struct inode *i2);
 | 
			
		||||
/* fat/misc.c */
 | 
			
		||||
extern void fat_fs_panic(struct super_block *s, const char *fmt, ...);
 | 
			
		||||
extern void fat_clusters_flush(struct super_block *sb);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue