ocfs2: set i_mode on disk during acl operations
authorMark Fasheh <mfasheh@suse.com>
Mon, 15 Mar 2010 22:39:00 +0000 (15:39 -0700)
committerJoel Becker <joel.becker@oracle.com>
Wed, 17 Mar 2010 19:28:22 +0000 (12:28 -0700)
ocfs2_set_acl() and ocfs2_init_acl() were setting i_mode on the in-memory
inode, but never setting it on the disk copy. Thus, acls were some times not
getting propagated between nodes. This patch fixes the issue by adding a
helper function ocfs2_acl_set_mode() which does this the right way.
ocfs2_set_acl() and ocfs2_init_acl() are then updated to call
ocfs2_acl_set_mode().

Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Signed-off-by: Joel Becker <joel.becker@oracle.com>
fs/ocfs2/acl.c

index 0501974..8ccf0f8 100644 (file)
@@ -30,6 +30,8 @@
 #include "alloc.h"
 #include "dlmglue.h"
 #include "file.h"
+#include "inode.h"
+#include "journal.h"
 #include "ocfs2_fs.h"
 
 #include "xattr.h"
@@ -165,6 +167,60 @@ static struct posix_acl *ocfs2_get_acl(struct inode *inode, int type)
        return acl;
 }
 
+/*
+ * Helper function to set i_mode in memory and disk. Some call paths
+ * will not have di_bh or a journal handle to pass, in which case it
+ * will create it's own.
+ */
+static int ocfs2_acl_set_mode(struct inode *inode, struct buffer_head *di_bh,
+                             handle_t *handle, umode_t new_mode)
+{
+       int ret, commit_handle = 0;
+       struct ocfs2_dinode *di;
+
+       if (di_bh == NULL) {
+               ret = ocfs2_read_inode_block(inode, &di_bh);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       } else
+               get_bh(di_bh);
+
+       if (handle == NULL) {
+               handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb),
+                                          OCFS2_INODE_UPDATE_CREDITS);
+               if (IS_ERR(handle)) {
+                       ret = PTR_ERR(handle);
+                       mlog_errno(ret);
+                       goto out_brelse;
+               }
+
+               commit_handle = 1;
+       }
+
+       di = (struct ocfs2_dinode *)di_bh->b_data;
+       ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
+                                     OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       inode->i_mode = new_mode;
+       di->i_mode = cpu_to_le16(inode->i_mode);
+
+       ocfs2_journal_dirty(handle, di_bh);
+
+out_commit:
+       if (commit_handle)
+               ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+out_brelse:
+       brelse(di_bh);
+out:
+       return ret;
+}
+
 /*
  * Set the access or default ACL of an inode.
  */
@@ -193,9 +249,14 @@ static int ocfs2_set_acl(handle_t *handle,
                        if (ret < 0)
                                return ret;
                        else {
-                               inode->i_mode = mode;
                                if (ret == 0)
                                        acl = NULL;
+
+                               ret = ocfs2_acl_set_mode(inode, di_bh,
+                                                        handle, mode);
+                               if (ret)
+                                       return ret;
+
                        }
                }
                break;
@@ -283,6 +344,7 @@ int ocfs2_init_acl(handle_t *handle,
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        struct posix_acl *acl = NULL;
        int ret = 0;
+       mode_t mode;
 
        if (!S_ISLNK(inode->i_mode)) {
                if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) {
@@ -291,12 +353,17 @@ int ocfs2_init_acl(handle_t *handle,
                        if (IS_ERR(acl))
                                return PTR_ERR(acl);
                }
-               if (!acl)
-                       inode->i_mode &= ~current_umask();
+               if (!acl) {
+                       mode = inode->i_mode & ~current_umask();
+                       ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
+                       if (ret) {
+                               mlog_errno(ret);
+                               goto cleanup;
+                       }
+               }
        }
        if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) {
                struct posix_acl *clone;
-               mode_t mode;
 
                if (S_ISDIR(inode->i_mode)) {
                        ret = ocfs2_set_acl(handle, inode, di_bh,
@@ -313,7 +380,7 @@ int ocfs2_init_acl(handle_t *handle,
                mode = inode->i_mode;
                ret = posix_acl_create_masq(clone, &mode);
                if (ret >= 0) {
-                       inode->i_mode = mode;
+                       ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
                        if (ret > 0) {
                                ret = ocfs2_set_acl(handle, inode,
                                                    di_bh, ACL_TYPE_ACCESS,