From 48b8926b6b02382bc774efee2ed2cd6be8770ac0 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Fri, 20 Nov 2009 17:25:21 +0100 Subject: [PATCH] Revert "vfs: Remove generic_osync_inode() and sync_page_range{_nolock}()" References: bnc#557231 Commit 18f2ee705d98034b0f229a3202d827468d4bffd9 broke iscsitarget, revert it temporarily. The exports are marged _GPL though. Signed-off-by: Michal Marek --- fs/fs-writeback.c | 54 ++++++++++++++++++++++++++++++++++++++ include/linux/fs.h | 5 +++ include/linux/writeback.h | 4 ++ mm/filemap.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+) --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -1280,3 +1280,57 @@ int sync_inode(struct inode *inode, stru return ret; } EXPORT_SYMBOL(sync_inode); + +/** + * generic_osync_inode - flush all dirty data for a given inode to disk + * @inode: inode to write + * @mapping: the address_space that should be flushed + * @what: what to write and wait upon + * + * This can be called by file_write functions for files which have the + * O_SYNC flag set, to flush dirty writes to disk. + * + * @what is a bitmask, specifying which part of the inode's data should be + * written and waited upon. + * + * OSYNC_DATA: i_mapping's dirty data + * OSYNC_METADATA: the buffers at i_mapping->private_list + * OSYNC_INODE: the inode itself + */ + +int generic_osync_inode(struct inode *inode, struct address_space *mapping, int what) +{ + int err = 0; + int need_write_inode_now = 0; + int err2; + + if (what & OSYNC_DATA) + err = filemap_fdatawrite(mapping); + if (what & (OSYNC_METADATA|OSYNC_DATA)) { + err2 = sync_mapping_buffers(mapping); + if (!err) + err = err2; + } + if (what & OSYNC_DATA) { + err2 = filemap_fdatawait(mapping); + if (!err) + err = err2; + } + + spin_lock(&inode_lock); + if ((inode->i_state & I_DIRTY) && + ((what & OSYNC_INODE) || (inode->i_state & I_DIRTY_DATASYNC))) + need_write_inode_now = 1; + spin_unlock(&inode_lock); + + if (need_write_inode_now) { + err2 = write_inode_now(inode, 1); + if (!err) + err = err2; + } + else + inode_sync_wait(inode); + + return err; +} +EXPORT_SYMBOL_GPL(generic_osync_inode); --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1459,6 +1459,11 @@ int fiemap_check_flags(struct fiemap_ext #define DT_SOCK 12 #define DT_WHT 14 +#define OSYNC_METADATA (1<<0) +#define OSYNC_DATA (1<<1) +#define OSYNC_INODE (1<<2) +int generic_osync_inode(struct inode *, struct address_space *, int); + /* * This is the "filldir" function type, used by readdir() to let * the kernel specify what kind of dirent layout it wants to have. --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -148,6 +148,10 @@ int write_cache_pages(struct address_spa struct writeback_control *wbc, writepage_t writepage, void *data); int do_writepages(struct address_space *mapping, struct writeback_control *wbc); +int sync_page_range(struct inode *inode, struct address_space *mapping, + loff_t pos, loff_t count); +int sync_page_range_nolock(struct inode *inode, struct address_space *mapping, + loff_t pos, loff_t count); void set_page_dirty_balance(struct page *page, int page_mkwrite); void writeback_set_ratelimit(void); --- a/mm/filemap.c +++ b/mm/filemap.c @@ -334,6 +334,70 @@ int filemap_fdatawait_range(struct addre EXPORT_SYMBOL(filemap_fdatawait_range); /** + * sync_page_range - write and wait on all pages in the passed range + * @inode: target inode + * @mapping: target address_space + * @pos: beginning offset in pages to write + * @count: number of bytes to write + * + * Write and wait upon all the pages in the passed range. This is a "data + * integrity" operation. It waits upon in-flight writeout before starting and + * waiting upon new writeout. If there was an IO error, return it. + * + * We need to re-take i_mutex during the generic_osync_inode list walk because + * it is otherwise livelockable. + */ +int sync_page_range(struct inode *inode, struct address_space *mapping, + loff_t pos, loff_t count) +{ + pgoff_t start = pos >> PAGE_CACHE_SHIFT; + pgoff_t end = (pos + count - 1) >> PAGE_CACHE_SHIFT; + int ret; + + if (!mapping_cap_writeback_dirty(mapping) || !count) + return 0; + ret = filemap_fdatawrite_range(mapping, pos, pos + count - 1); + if (ret == 0) { + mutex_lock(&inode->i_mutex); + ret = generic_osync_inode(inode, mapping, OSYNC_METADATA); + mutex_unlock(&inode->i_mutex); + } + if (ret == 0) + ret = wait_on_page_writeback_range(mapping, start, end); + return ret; +} +EXPORT_SYMBOL_GPL(sync_page_range); + +/** + * sync_page_range_nolock - write & wait on all pages in the passed range without locking + * @inode: target inode + * @mapping: target address_space + * @pos: beginning offset in pages to write + * @count: number of bytes to write + * + * Note: Holding i_mutex across sync_page_range_nolock() is not a good idea + * as it forces O_SYNC writers to different parts of the same file + * to be serialised right until io completion. + */ +int sync_page_range_nolock(struct inode *inode, struct address_space *mapping, + loff_t pos, loff_t count) +{ + pgoff_t start = pos >> PAGE_CACHE_SHIFT; + pgoff_t end = (pos + count - 1) >> PAGE_CACHE_SHIFT; + int ret; + + if (!mapping_cap_writeback_dirty(mapping) || !count) + return 0; + ret = filemap_fdatawrite_range(mapping, pos, pos + count - 1); + if (ret == 0) + ret = generic_osync_inode(inode, mapping, OSYNC_METADATA); + if (ret == 0) + ret = wait_on_page_writeback_range(mapping, start, end); + return ret; +} +EXPORT_SYMBOL_GPL(sync_page_range_nolock); + +/** * filemap_fdatawait - wait for all under-writeback pages to complete * @mapping: address space structure to wait for *