|
@@ -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,
|