summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/gfs2/inode.c4
-rw-r--r--fs/gfs2/inode.h6
-rw-r--r--fs/gfs2/ops_address.c78
-rw-r--r--fs/gfs2/ops_address.h2
-rw-r--r--fs/gfs2/ops_file.c13
5 files changed, 72 insertions, 31 deletions
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index af493fc6c8c..532784eb5ba 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -136,7 +136,6 @@ void gfs2_set_iop(struct inode *inode)
if (S_ISREG(mode)) {
inode->i_op = &gfs2_file_iops;
inode->i_fop = &gfs2_file_fops;
- inode->i_mapping->a_ops = &gfs2_file_aops;
} else if (S_ISDIR(mode)) {
inode->i_op = &gfs2_dir_iops;
inode->i_fop = &gfs2_dir_fops;
@@ -290,6 +289,9 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
di->di_entries = be32_to_cpu(str->di_entries);
di->di_eattr = be64_to_cpu(str->di_eattr);
+ if (S_ISREG(ip->i_inode.i_mode))
+ gfs2_set_aops(&ip->i_inode);
+
return 0;
}
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h
index bed3dc212a1..d4465066261 100644
--- a/fs/gfs2/inode.h
+++ b/fs/gfs2/inode.h
@@ -26,6 +26,12 @@ static inline int gfs2_is_writeback(const struct gfs2_inode *ip)
return (sdp->sd_args.ar_data == GFS2_DATA_WRITEBACK) && !gfs2_is_jdata(ip);
}
+static inline int gfs2_is_ordered(const struct gfs2_inode *ip)
+{
+ const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ return (sdp->sd_args.ar_data == GFS2_DATA_ORDERED) && !gfs2_is_jdata(ip);
+}
+
static inline int gfs2_is_dir(const struct gfs2_inode *ip)
{
return S_ISDIR(ip->i_inode.i_mode);
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index ed154af8617..207014f363d 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -162,28 +162,18 @@ out_ignore:
}
/**
- * gfs2_writepages - Write a bunch of dirty pages back to disk
+ * gfs2_writeback_writepages - Write a bunch of dirty pages back to disk
* @mapping: The mapping to write
* @wbc: Write-back control
*
- * For journaled files and/or ordered writes this just falls back to the
- * kernel's default writepages path for now. We will probably want to change
- * that eventually (i.e. when we look at allocate on flush).
- *
- * For the data=writeback case though we can already ignore buffer heads
+ * For the data=writeback case we can already ignore buffer heads
* and write whole extents at once. This is a big reduction in the
* number of I/O requests we send and the bmap calls we make in this case.
*/
-static int gfs2_writepages(struct address_space *mapping,
- struct writeback_control *wbc)
+static int gfs2_writeback_writepages(struct address_space *mapping,
+ struct writeback_control *wbc)
{
- struct inode *inode = mapping->host;
- struct gfs2_inode *ip = GFS2_I(inode);
-
- if (gfs2_is_writeback(ip))
- return mpage_writepages(mapping, wbc, gfs2_get_block_noalloc);
-
- return generic_writepages(mapping, wbc);
+ return mpage_writepages(mapping, wbc, gfs2_get_block_noalloc);
}
/**
@@ -644,11 +634,7 @@ failed:
static int gfs2_set_page_dirty(struct page *page)
{
- struct gfs2_inode *ip = GFS2_I(page->mapping->host);
- struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
-
- if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
- SetPageChecked(page);
+ SetPageChecked(page);
return __set_page_dirty_buffers(page);
}
@@ -738,13 +724,9 @@ static int gfs2_ok_for_dio(struct gfs2_inode *ip, int rw, loff_t offset)
{
/*
* Should we return an error here? I can't see that O_DIRECT for
- * a journaled file makes any sense. For now we'll silently fall
- * back to buffered I/O, likewise we do the same for stuffed
- * files since they are (a) small and (b) unaligned.
+ * a stuffed file makes any sense. For now we'll silently fall
+ * back to buffered I/O
*/
- if (gfs2_is_jdata(ip))
- return 0;
-
if (gfs2_is_stuffed(ip))
return 0;
@@ -855,9 +837,22 @@ cannot_release:
return 0;
}
-const struct address_space_operations gfs2_file_aops = {
+static const struct address_space_operations gfs2_writeback_aops = {
+ .writepage = gfs2_writepage,
+ .writepages = gfs2_writeback_writepages,
+ .readpage = gfs2_readpage,
+ .readpages = gfs2_readpages,
+ .sync_page = block_sync_page,
+ .write_begin = gfs2_write_begin,
+ .write_end = gfs2_write_end,
+ .bmap = gfs2_bmap,
+ .invalidatepage = gfs2_invalidatepage,
+ .releasepage = gfs2_releasepage,
+ .direct_IO = gfs2_direct_IO,
+};
+
+static const struct address_space_operations gfs2_ordered_aops = {
.writepage = gfs2_writepage,
- .writepages = gfs2_writepages,
.readpage = gfs2_readpage,
.readpages = gfs2_readpages,
.sync_page = block_sync_page,
@@ -870,3 +865,30 @@ const struct address_space_operations gfs2_file_aops = {
.direct_IO = gfs2_direct_IO,
};
+static const struct address_space_operations gfs2_jdata_aops = {
+ .writepage = gfs2_writepage,
+ .readpage = gfs2_readpage,
+ .readpages = gfs2_readpages,
+ .sync_page = block_sync_page,
+ .write_begin = gfs2_write_begin,
+ .write_end = gfs2_write_end,
+ .set_page_dirty = gfs2_set_page_dirty,
+ .bmap = gfs2_bmap,
+ .invalidatepage = gfs2_invalidatepage,
+ .releasepage = gfs2_releasepage,
+};
+
+void gfs2_set_aops(struct inode *inode)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+
+ if (gfs2_is_writeback(ip))
+ inode->i_mapping->a_ops = &gfs2_writeback_aops;
+ else if (gfs2_is_ordered(ip))
+ inode->i_mapping->a_ops = &gfs2_ordered_aops;
+ else if (gfs2_is_jdata(ip))
+ inode->i_mapping->a_ops = &gfs2_jdata_aops;
+ else
+ BUG();
+}
+
diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h
index e8fe83fcd58..d3b76d0cdc8 100644
--- a/fs/gfs2/ops_address.h
+++ b/fs/gfs2/ops_address.h
@@ -14,12 +14,12 @@
#include <linux/buffer_head.h>
#include <linux/mm.h>
-extern const struct address_space_operations gfs2_file_aops;
extern int gfs2_get_block(struct inode *inode, sector_t lblock,
struct buffer_head *bh_result, int create);
extern int gfs2_releasepage(struct page *page, gfp_t gfp_mask);
extern int gfs2_internal_read(struct gfs2_inode *ip,
struct file_ra_state *ra_state,
char *buf, loff_t *pos, unsigned size);
+extern void gfs2_set_aops(struct inode *inode);
#endif /* __OPS_ADDRESS_DOT_H__ */
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
index 6f3aeb059c6..ad5daaa6bab 100644
--- a/fs/gfs2/ops_file.c
+++ b/fs/gfs2/ops_file.c
@@ -38,6 +38,7 @@
#include "trans.h"
#include "util.h"
#include "eaops.h"
+#include "ops_address.h"
/**
* gfs2_llseek - seek to a location in a file
@@ -245,7 +246,16 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
if (error)
goto out;
}
-
+ if ((flags ^ new_flags) & GFS2_DIF_JDATA) {
+ if (flags & GFS2_DIF_JDATA)
+ gfs2_log_flush(sdp, ip->i_gl);
+ error = filemap_fdatawrite(inode->i_mapping);
+ if (error)
+ goto out;
+ error = filemap_fdatawait(inode->i_mapping);
+ if (error)
+ goto out;
+ }
error = gfs2_trans_begin(sdp, RES_DINODE, 0);
if (error)
goto out;
@@ -257,6 +267,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
gfs2_dinode_out(ip, bh->b_data);
brelse(bh);
gfs2_set_inode_flags(inode);
+ gfs2_set_aops(inode);
out_trans_end:
gfs2_trans_end(sdp);
out: