179 lines
5.7 KiB
Plaintext
179 lines
5.7 KiB
Plaintext
From 48b8926b6b02382bc774efee2ed2cd6be8770ac0 Mon Sep 17 00:00:00 2001
|
|
From: Michal Marek <mmarek@suse.cz>
|
|
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 <mmarek@suse.cz>
|
|
|
|
---
|
|
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
|
|
*
|