diff options
Diffstat (limited to 'fs/ceph/acl.c')
-rw-r--r-- | fs/ceph/acl.c | 30 |
1 files changed, 22 insertions, 8 deletions
diff --git a/fs/ceph/acl.c b/fs/ceph/acl.c index 59cb307b15fb..027408d55aee 100644 --- a/fs/ceph/acl.c +++ b/fs/ceph/acl.c @@ -45,6 +45,7 @@ static inline void ceph_set_cached_acl(struct inode *inode, struct posix_acl *ceph_get_acl(struct inode *inode, int type) { int size; + unsigned int retry_cnt = 0; const char *name; char *value = NULL; struct posix_acl *acl; @@ -60,6 +61,7 @@ struct posix_acl *ceph_get_acl(struct inode *inode, int type) BUG(); } +retry: size = __ceph_getxattr(inode, name, "", 0); if (size > 0) { value = kzalloc(size, GFP_NOFS); @@ -68,12 +70,22 @@ struct posix_acl *ceph_get_acl(struct inode *inode, int type) size = __ceph_getxattr(inode, name, value, size); } - if (size > 0) + if (size == -ERANGE && retry_cnt < 10) { + retry_cnt++; + kfree(value); + value = NULL; + goto retry; + } + + if (size > 0) { acl = posix_acl_from_xattr(&init_user_ns, value, size); - else if (size == -ERANGE || size == -ENODATA || size == 0) + } else if (size == -ENODATA || size == 0) { acl = NULL; - else + } else { + pr_err_ratelimited("get acl %llx.%llx failed, err=%d\n", + ceph_vinop(inode), size); acl = ERR_PTR(-EIO); + } kfree(value); @@ -89,6 +101,7 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type) const char *name = NULL; char *value = NULL; struct iattr newattrs; + struct timespec64 old_ctime = inode->i_ctime; umode_t new_mode = inode->i_mode, old_mode = inode->i_mode; switch (type) { @@ -133,7 +146,7 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type) if (new_mode != old_mode) { newattrs.ia_ctime = current_time(inode); newattrs.ia_mode = new_mode; - newattrs.ia_valid = ATTR_MODE; + newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; ret = __ceph_setattr(inode, &newattrs); if (ret) goto out_free; @@ -142,8 +155,9 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type) ret = __ceph_setxattr(inode, name, value, size, 0); if (ret) { if (new_mode != old_mode) { + newattrs.ia_ctime = old_ctime; newattrs.ia_mode = old_mode; - newattrs.ia_valid = ATTR_MODE; + newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; __ceph_setattr(inode, &newattrs); } goto out_free; @@ -171,10 +185,10 @@ int ceph_pre_init_acls(struct inode *dir, umode_t *mode, return err; if (acl) { - int ret = posix_acl_equiv_mode(acl, mode); - if (ret < 0) + err = posix_acl_equiv_mode(acl, mode); + if (err < 0) goto out_err; - if (ret == 0) { + if (err == 0) { posix_acl_release(acl); acl = NULL; } |