ocfs2: set i_mode on disk during acl operations

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>

authored by Mark Fasheh and committed by Joel Becker fcefd25a 6527f8f8

+72 -5
+72 -5
fs/ocfs2/acl.c
··· 30 30 #include "alloc.h" 31 31 #include "dlmglue.h" 32 32 #include "file.h" 33 + #include "inode.h" 34 + #include "journal.h" 33 35 #include "ocfs2_fs.h" 34 36 35 37 #include "xattr.h" ··· 168 166 } 169 167 170 168 /* 169 + * Helper function to set i_mode in memory and disk. Some call paths 170 + * will not have di_bh or a journal handle to pass, in which case it 171 + * will create it's own. 172 + */ 173 + static int ocfs2_acl_set_mode(struct inode *inode, struct buffer_head *di_bh, 174 + handle_t *handle, umode_t new_mode) 175 + { 176 + int ret, commit_handle = 0; 177 + struct ocfs2_dinode *di; 178 + 179 + if (di_bh == NULL) { 180 + ret = ocfs2_read_inode_block(inode, &di_bh); 181 + if (ret) { 182 + mlog_errno(ret); 183 + goto out; 184 + } 185 + } else 186 + get_bh(di_bh); 187 + 188 + if (handle == NULL) { 189 + handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb), 190 + OCFS2_INODE_UPDATE_CREDITS); 191 + if (IS_ERR(handle)) { 192 + ret = PTR_ERR(handle); 193 + mlog_errno(ret); 194 + goto out_brelse; 195 + } 196 + 197 + commit_handle = 1; 198 + } 199 + 200 + di = (struct ocfs2_dinode *)di_bh->b_data; 201 + ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh, 202 + OCFS2_JOURNAL_ACCESS_WRITE); 203 + if (ret) { 204 + mlog_errno(ret); 205 + goto out_commit; 206 + } 207 + 208 + inode->i_mode = new_mode; 209 + di->i_mode = cpu_to_le16(inode->i_mode); 210 + 211 + ocfs2_journal_dirty(handle, di_bh); 212 + 213 + out_commit: 214 + if (commit_handle) 215 + ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); 216 + out_brelse: 217 + brelse(di_bh); 218 + out: 219 + return ret; 220 + } 221 + 222 + /* 171 223 * Set the access or default ACL of an inode. 172 224 */ 173 225 static int ocfs2_set_acl(handle_t *handle, ··· 249 193 if (ret < 0) 250 194 return ret; 251 195 else { 252 - inode->i_mode = mode; 253 196 if (ret == 0) 254 197 acl = NULL; 198 + 199 + ret = ocfs2_acl_set_mode(inode, di_bh, 200 + handle, mode); 201 + if (ret) 202 + return ret; 203 + 255 204 } 256 205 } 257 206 break; ··· 344 283 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 345 284 struct posix_acl *acl = NULL; 346 285 int ret = 0; 286 + mode_t mode; 347 287 348 288 if (!S_ISLNK(inode->i_mode)) { 349 289 if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { ··· 353 291 if (IS_ERR(acl)) 354 292 return PTR_ERR(acl); 355 293 } 356 - if (!acl) 357 - inode->i_mode &= ~current_umask(); 294 + if (!acl) { 295 + mode = inode->i_mode & ~current_umask(); 296 + ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode); 297 + if (ret) { 298 + mlog_errno(ret); 299 + goto cleanup; 300 + } 301 + } 358 302 } 359 303 if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) { 360 304 struct posix_acl *clone; 361 - mode_t mode; 362 305 363 306 if (S_ISDIR(inode->i_mode)) { 364 307 ret = ocfs2_set_acl(handle, inode, di_bh, ··· 380 313 mode = inode->i_mode; 381 314 ret = posix_acl_create_masq(clone, &mode); 382 315 if (ret >= 0) { 383 - inode->i_mode = mode; 316 + ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode); 384 317 if (ret > 0) { 385 318 ret = ocfs2_set_acl(handle, inode, 386 319 di_bh, ACL_TYPE_ACCESS,