diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-30 12:07:01 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-30 12:07:01 -0700 |
commit | 56f29d7fe452890eeeb7f2b0138b2d95b9745fb6 (patch) | |
tree | 01b6b70297c53c9beb8d11eb186fbad9c166b1a2 /fs/sync.c | |
parent | e823aff2d6eb43083abcc75a32ddfb167c324089 (diff) | |
parent | 059af497c23492cb1ddcbba11c09dad385960bc0 (diff) |
Merge branch 'block' of git://brick.kernel.dk/data/git/linux-2.6-block
* 'block' of git://brick.kernel.dk/data/git/linux-2.6-block: (67 commits)
[PATCH] blk_queue_start_tag() shared map race fix
[PATCH] Update axboe@suse.de email address
[PATCH] fix creating zero sized bio mempools in low memory system
[PATCH] CONFIG_BLOCK: blk_congestion_wait() fix
[PATCH] CONFIG_BLOCK internal.h cleanups
[PATCH] BLOCK: Make USB storage depend on SCSI rather than selecting it [try #6]
[PATCH] BLOCK: Make it possible to disable the block layer [try #6]
[PATCH] BLOCK: Remove no-longer necessary linux/buffer_head.h inclusions [try #6]
[PATCH] BLOCK: Remove no-longer necessary linux/mpage.h inclusions [try #6]
[PATCH] BLOCK: Move the msdos device ioctl compat stuff to the msdos driver [try #6]
[PATCH] BLOCK: Move the Ext3 device ioctl compat stuff to the Ext3 driver [try #6]
[PATCH] BLOCK: Move the Ext2 device ioctl compat stuff to the Ext2 driver [try #6]
[PATCH] BLOCK: Move the ReiserFS device ioctl compat stuff to the ReiserFS driver [try #6]
[PATCH] BLOCK: Move common FS-specific ioctls to linux/fs.h [try #6]
[PATCH] BLOCK: Move the loop device ioctl compat stuff to the loop driver [try #6]
[PATCH] BLOCK: Move __invalidate_device() to block_dev.c [try #6]
[PATCH] BLOCK: Dissociate generic_writepages() from mpage stuff [try #6]
[PATCH] BLOCK: Remove dependence on existence of blockdev_superblock [try #6]
[PATCH] BLOCK: Move extern declarations out of fs/*.c into header files [try #6]
[PATCH] BLOCK: Don't call block_sync_page() from AFS [try #6]
...
Diffstat (limited to 'fs/sync.c')
-rw-r--r-- | fs/sync.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/fs/sync.c b/fs/sync.c index 955aef04da28..1de747b5ddb9 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -10,11 +10,124 @@ #include <linux/syscalls.h> #include <linux/linkage.h> #include <linux/pagemap.h> +#include <linux/quotaops.h> +#include <linux/buffer_head.h> #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ SYNC_FILE_RANGE_WAIT_AFTER) /* + * sync everything. Start out by waking pdflush, because that writes back + * all queues in parallel. + */ +static void do_sync(unsigned long wait) +{ + wakeup_pdflush(0); + sync_inodes(0); /* All mappings, inodes and their blockdevs */ + DQUOT_SYNC(NULL); + sync_supers(); /* Write the superblocks */ + sync_filesystems(0); /* Start syncing the filesystems */ + sync_filesystems(wait); /* Waitingly sync the filesystems */ + sync_inodes(wait); /* Mappings, inodes and blockdevs, again. */ + if (!wait) + printk("Emergency Sync complete\n"); + if (unlikely(laptop_mode)) + laptop_sync_completion(); +} + +asmlinkage long sys_sync(void) +{ + do_sync(1); + return 0; +} + +void emergency_sync(void) +{ + pdflush_operation(do_sync, 0); +} + +/* + * Generic function to fsync a file. + * + * filp may be NULL if called via the msync of a vma. + */ +int file_fsync(struct file *filp, struct dentry *dentry, int datasync) +{ + struct inode * inode = dentry->d_inode; + struct super_block * sb; + int ret, err; + + /* sync the inode to buffers */ + ret = write_inode_now(inode, 0); + + /* sync the superblock to buffers */ + sb = inode->i_sb; + lock_super(sb); + if (sb->s_op->write_super) + sb->s_op->write_super(sb); + unlock_super(sb); + + /* .. finally sync the buffers to disk */ + err = sync_blockdev(sb->s_bdev); + if (!ret) + ret = err; + return ret; +} + +long do_fsync(struct file *file, int datasync) +{ + int ret; + int err; + struct address_space *mapping = file->f_mapping; + + if (!file->f_op || !file->f_op->fsync) { + /* Why? We can still call filemap_fdatawrite */ + ret = -EINVAL; + goto out; + } + + ret = filemap_fdatawrite(mapping); + + /* + * We need to protect against concurrent writers, which could cause + * livelocks in fsync_buffers_list(). + */ + mutex_lock(&mapping->host->i_mutex); + err = file->f_op->fsync(file, file->f_dentry, datasync); + if (!ret) + ret = err; + mutex_unlock(&mapping->host->i_mutex); + err = filemap_fdatawait(mapping); + if (!ret) + ret = err; +out: + return ret; +} + +static long __do_fsync(unsigned int fd, int datasync) +{ + struct file *file; + int ret = -EBADF; + + file = fget(fd); + if (file) { + ret = do_fsync(file, datasync); + fput(file); + } + return ret; +} + +asmlinkage long sys_fsync(unsigned int fd) +{ + return __do_fsync(fd, 0); +} + +asmlinkage long sys_fdatasync(unsigned int fd) +{ + return __do_fsync(fd, 1); +} + +/* * sys_sync_file_range() permits finely controlled syncing over a segment of * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is * zero then sys_sync_file_range() will operate from offset out to EOF. |