Merge master.kernel.org:/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw
[pandora-kernel.git] / fs / gfs2 / ops_file.c
index 359965c..b3f1e03 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/ext2_fs.h>
 #include <linux/crc32.h>
 #include <linux/lm_interface.h>
+#include <linux/writeback.h>
 #include <asm/uaccess.h>
 
 #include "gfs2.h"
@@ -71,7 +72,7 @@ static int gfs2_read_actor(read_descriptor_t *desc, struct page *page,
                size = count;
 
        kaddr = kmap(page);
-       memcpy(desc->arg.buf, kaddr + offset, size);
+       memcpy(desc->arg.data, kaddr + offset, size);
        kunmap(page);
 
        desc->count = count - size;
@@ -86,7 +87,7 @@ int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state,
        struct inode *inode = &ip->i_inode;
        read_descriptor_t desc;
        desc.written = 0;
-       desc.arg.buf = buf;
+       desc.arg.data = buf;
        desc.count = size;
        desc.error = 0;
        do_generic_mapping_read(inode->i_mapping, ra_state,
@@ -253,7 +254,7 @@ static int gfs2_get_flags(struct file *filp, u32 __user *ptr)
        u32 fsflags;
 
        gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
-       error = gfs2_glock_nq_m_atime(1, &gh);
+       error = gfs2_glock_nq_atime(&gh);
        if (error)
                return error;
 
@@ -266,6 +267,24 @@ static int gfs2_get_flags(struct file *filp, u32 __user *ptr)
        return error;
 }
 
+void gfs2_set_inode_flags(struct inode *inode)
+{
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct gfs2_dinode_host *di = &ip->i_di;
+       unsigned int flags = inode->i_flags;
+
+       flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
+       if (di->di_flags & GFS2_DIF_IMMUTABLE)
+               flags |= S_IMMUTABLE;
+       if (di->di_flags & GFS2_DIF_APPENDONLY)
+               flags |= S_APPEND;
+       if (di->di_flags & GFS2_DIF_NOATIME)
+               flags |= S_NOATIME;
+       if (di->di_flags & GFS2_DIF_SYNC)
+               flags |= S_SYNC;
+       inode->i_flags = flags;
+}
+
 /* Flags that can be set by user space */
 #define GFS2_FLAGS_USER_SET (GFS2_DIF_JDATA|                   \
                             GFS2_DIF_DIRECTIO|                 \
@@ -336,8 +355,9 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
                goto out_trans_end;
        gfs2_trans_add_bh(ip->i_gl, bh, 1);
        ip->i_di.di_flags = new_flags;
-       gfs2_dinode_out(&ip->i_di, bh->b_data);
+       gfs2_dinode_out(ip, bh->b_data);
        brelse(bh);
+       gfs2_set_inode_flags(inode);
 out_trans_end:
        gfs2_trans_end(sdp);
 out:
@@ -425,7 +445,7 @@ static int gfs2_open(struct inode *inode, struct file *file)
        gfs2_assert_warn(GFS2_SB(inode), !file->private_data);
        file->private_data = fp;
 
-       if (S_ISREG(ip->i_di.di_mode)) {
+       if (S_ISREG(ip->i_inode.i_mode)) {
                error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY,
                                           &i_gh);
                if (error)
@@ -484,16 +504,40 @@ static int gfs2_close(struct inode *inode, struct file *file)
  * @file: the file that points to the dentry (we ignore this)
  * @dentry: the dentry that points to the inode to sync
  *
+ * The VFS will flush "normal" data for us. We only need to worry
+ * about metadata here. For journaled data, we just do a log flush
+ * as we can't avoid it. Otherwise we can just bale out if datasync
+ * is set. For stuffed inodes we must flush the log in order to
+ * ensure that all data is on disk.
+ *
+ * The call to write_inode_now() is there to write back metadata and
+ * the inode itself. It does also try and write the data, but thats
+ * (hopefully) a no-op due to the VFS having already called filemap_fdatawrite()
+ * for us.
+ *
  * Returns: errno
  */
 
 static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync)
 {
-       struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
+       struct inode *inode = dentry->d_inode;
+       int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC);
+       int ret = 0;
 
-       gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl);
+       if (gfs2_is_jdata(GFS2_I(inode))) {
+               gfs2_log_flush(GFS2_SB(inode), GFS2_I(inode)->i_gl);
+               return 0;
+       }
 
-       return 0;
+       if (sync_state != 0) {
+               if (!datasync)
+                       ret = write_inode_now(inode, 0);
+
+               if (gfs2_is_stuffed(GFS2_I(inode)))
+                       gfs2_log_flush(GFS2_SB(inode), GFS2_I(inode)->i_gl);
+       }
+
+       return ret;
 }
 
 /**
@@ -515,7 +559,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
 
        if (!(fl->fl_flags & FL_POSIX))
                return -ENOLCK;
-       if ((ip->i_di.di_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+       if ((ip->i_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
                return -ENOLCK;
 
        if (sdp->sd_args.ar_localflocks) {
@@ -617,7 +661,7 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl)
 
        if (!(fl->fl_flags & FL_FLOCK))
                return -ENOLCK;
-       if ((ip->i_di.di_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+       if ((ip->i_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
                return -ENOLCK;
 
        if (sdp->sd_args.ar_localflocks)