Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/borntraeger...
[cascardo/linux.git] / fs / ceph / acl.c
index cebf2eb..5bd853b 100644 (file)
@@ -169,36 +169,109 @@ out:
        return ret;
 }
 
-int ceph_init_acl(struct dentry *dentry, struct inode *inode, struct inode *dir)
+int ceph_pre_init_acls(struct inode *dir, umode_t *mode,
+                      struct ceph_acls_info *info)
 {
-       struct posix_acl *default_acl, *acl;
-       umode_t new_mode = inode->i_mode;
-       int error;
-
-       error = posix_acl_create(dir, &new_mode, &default_acl, &acl);
-       if (error)
-               return error;
-
-       if (!default_acl && !acl) {
-               cache_no_acl(inode);
-               if (new_mode != inode->i_mode) {
-                       struct iattr newattrs = {
-                               .ia_mode = new_mode,
-                               .ia_valid = ATTR_MODE,
-                       };
-                       error = ceph_setattr(dentry, &newattrs);
+       struct posix_acl *acl, *default_acl;
+       size_t val_size1 = 0, val_size2 = 0;
+       struct ceph_pagelist *pagelist = NULL;
+       void *tmp_buf = NULL;
+       int err;
+
+       err = posix_acl_create(dir, mode, &default_acl, &acl);
+       if (err)
+               return err;
+
+       if (acl) {
+               int ret = posix_acl_equiv_mode(acl, mode);
+               if (ret < 0)
+                       goto out_err;
+               if (ret == 0) {
+                       posix_acl_release(acl);
+                       acl = NULL;
                }
-               return error;
        }
 
-       if (default_acl) {
-               error = ceph_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
-               posix_acl_release(default_acl);
-       }
+       if (!default_acl && !acl)
+               return 0;
+
+       if (acl)
+               val_size1 = posix_acl_xattr_size(acl->a_count);
+       if (default_acl)
+               val_size2 = posix_acl_xattr_size(default_acl->a_count);
+
+       err = -ENOMEM;
+       tmp_buf = kmalloc(max(val_size1, val_size2), GFP_NOFS);
+       if (!tmp_buf)
+               goto out_err;
+       pagelist = kmalloc(sizeof(struct ceph_pagelist), GFP_NOFS);
+       if (!pagelist)
+               goto out_err;
+       ceph_pagelist_init(pagelist);
+
+       err = ceph_pagelist_reserve(pagelist, PAGE_SIZE);
+       if (err)
+               goto out_err;
+
+       ceph_pagelist_encode_32(pagelist, acl && default_acl ? 2 : 1);
+
        if (acl) {
-               if (!error)
-                       error = ceph_set_acl(inode, acl, ACL_TYPE_ACCESS);
-               posix_acl_release(acl);
+               size_t len = strlen(POSIX_ACL_XATTR_ACCESS);
+               err = ceph_pagelist_reserve(pagelist, len + val_size1 + 8);
+               if (err)
+                       goto out_err;
+               ceph_pagelist_encode_string(pagelist, POSIX_ACL_XATTR_ACCESS,
+                                           len);
+               err = posix_acl_to_xattr(&init_user_ns, acl,
+                                        tmp_buf, val_size1);
+               if (err < 0)
+                       goto out_err;
+               ceph_pagelist_encode_32(pagelist, val_size1);
+               ceph_pagelist_append(pagelist, tmp_buf, val_size1);
        }
-       return error;
+       if (default_acl) {
+               size_t len = strlen(POSIX_ACL_XATTR_DEFAULT);
+               err = ceph_pagelist_reserve(pagelist, len + val_size2 + 8);
+               if (err)
+                       goto out_err;
+               err = ceph_pagelist_encode_string(pagelist,
+                                                 POSIX_ACL_XATTR_DEFAULT, len);
+               err = posix_acl_to_xattr(&init_user_ns, default_acl,
+                                        tmp_buf, val_size2);
+               if (err < 0)
+                       goto out_err;
+               ceph_pagelist_encode_32(pagelist, val_size2);
+               ceph_pagelist_append(pagelist, tmp_buf, val_size2);
+       }
+
+       kfree(tmp_buf);
+
+       info->acl = acl;
+       info->default_acl = default_acl;
+       info->pagelist = pagelist;
+       return 0;
+
+out_err:
+       posix_acl_release(acl);
+       posix_acl_release(default_acl);
+       kfree(tmp_buf);
+       if (pagelist)
+               ceph_pagelist_release(pagelist);
+       return err;
+}
+
+void ceph_init_inode_acls(struct inode* inode, struct ceph_acls_info *info)
+{
+       if (!inode)
+               return;
+       ceph_set_cached_acl(inode, ACL_TYPE_ACCESS, info->acl);
+       ceph_set_cached_acl(inode, ACL_TYPE_DEFAULT, info->default_acl);
+}
+
+void ceph_release_acls_info(struct ceph_acls_info *info)
+{
+       posix_acl_release(info->acl);
+       posix_acl_release(info->default_acl);
+       if (info->pagelist)
+               ceph_pagelist_release(info->pagelist);
 }