static bool ovl_is_private_xattr(const char *name)
 {
-       return strncmp(name, OVL_XATTR_PRE_NAME, OVL_XATTR_PRE_LEN) == 0;
+#define OVL_XATTR_PRE_NAME OVL_XATTR_PREFIX "."
+       return strncmp(name, OVL_XATTR_PRE_NAME,
+                      sizeof(OVL_XATTR_PRE_NAME) - 1) == 0;
 }
 
 int ovl_setxattr(struct dentry *dentry, struct inode *inode,
        if (err)
                goto out;
 
-       err = -EPERM;
-       if (ovl_is_private_xattr(name))
-               goto out_drop_write;
-
        err = ovl_copy_up(dentry);
        if (err)
                goto out_drop_write;
        .setattr        = ovl_setattr,
        .permission     = ovl_permission,
        .getattr        = ovl_getattr,
-       .setxattr       = ovl_setxattr,
+       .setxattr       = generic_setxattr,
        .getxattr       = ovl_getxattr,
        .listxattr      = ovl_listxattr,
        .removexattr    = ovl_removexattr,
        .get_link       = ovl_get_link,
        .readlink       = ovl_readlink,
        .getattr        = ovl_getattr,
-       .setxattr       = ovl_setxattr,
+       .setxattr       = generic_setxattr,
        .getxattr       = ovl_getxattr,
        .listxattr      = ovl_listxattr,
        .removexattr    = ovl_removexattr,
 
 #include <linux/sched.h>
 #include <linux/statfs.h>
 #include <linux/seq_file.h>
+#include <linux/posix_acl_xattr.h>
 #include "overlayfs.h"
 
 MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
        return ctr;
 }
 
+static int ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
+                                  struct dentry *dentry, struct inode *inode,
+                                  const char *name, const void *value,
+                                  size_t size, int flags)
+{
+       struct dentry *workdir = ovl_workdir(dentry);
+       struct inode *realinode = ovl_inode_real(inode, NULL);
+       struct posix_acl *acl = NULL;
+       int err;
+
+       /* Check that everything is OK before copy-up */
+       if (value) {
+               acl = posix_acl_from_xattr(&init_user_ns, value, size);
+               if (IS_ERR(acl))
+                       return PTR_ERR(acl);
+       }
+       err = -EOPNOTSUPP;
+       if (!IS_POSIXACL(d_inode(workdir)))
+               goto out_acl_release;
+       if (!realinode->i_op->set_acl)
+               goto out_acl_release;
+       if (handler->flags == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) {
+               err = acl ? -EACCES : 0;
+               goto out_acl_release;
+       }
+       err = -EPERM;
+       if (!inode_owner_or_capable(inode))
+               goto out_acl_release;
+
+       posix_acl_release(acl);
+
+       return ovl_setxattr(dentry, inode, handler->name, value, size, flags);
+
+out_acl_release:
+       posix_acl_release(acl);
+       return err;
+}
+
+static int ovl_other_xattr_set(const struct xattr_handler *handler,
+                              struct dentry *dentry, struct inode *inode,
+                              const char *name, const void *value,
+                              size_t size, int flags)
+{
+       return ovl_setxattr(dentry, inode, name, value, size, flags);
+}
+
+static int ovl_own_xattr_set(const struct xattr_handler *handler,
+                            struct dentry *dentry, struct inode *inode,
+                            const char *name, const void *value,
+                            size_t size, int flags)
+{
+       return -EPERM;
+}
+
+static const struct xattr_handler ovl_posix_acl_access_xattr_handler = {
+       .name = XATTR_NAME_POSIX_ACL_ACCESS,
+       .flags = ACL_TYPE_ACCESS,
+       .set = ovl_posix_acl_xattr_set,
+};
+
+static const struct xattr_handler ovl_posix_acl_default_xattr_handler = {
+       .name = XATTR_NAME_POSIX_ACL_DEFAULT,
+       .flags = ACL_TYPE_DEFAULT,
+       .set = ovl_posix_acl_xattr_set,
+};
+
+static const struct xattr_handler ovl_own_xattr_handler = {
+       .prefix = OVL_XATTR_PREFIX,
+       .set = ovl_own_xattr_set,
+};
+
+static const struct xattr_handler ovl_other_xattr_handler = {
+       .prefix = "", /* catch all */
+       .set = ovl_other_xattr_set,
+};
+
+static const struct xattr_handler *ovl_xattr_handlers[] = {
+       &ovl_posix_acl_access_xattr_handler,
+       &ovl_posix_acl_default_xattr_handler,
+       &ovl_own_xattr_handler,
+       &ovl_other_xattr_handler,
+       NULL
+};
+
+static const struct xattr_handler *ovl_xattr_noacl_handlers[] = {
+       &ovl_own_xattr_handler,
+       &ovl_other_xattr_handler,
+       NULL,
+};
+
 static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct path upperpath = { NULL, NULL };
 
        sb->s_magic = OVERLAYFS_SUPER_MAGIC;
        sb->s_op = &ovl_super_operations;
+       if (IS_ENABLED(CONFIG_FS_POSIX_ACL))
+               sb->s_xattr = ovl_xattr_handlers;
+       else
+               sb->s_xattr = ovl_xattr_noacl_handlers;
        sb->s_root = root_dentry;
        sb->s_fs_info = ufs;
        sb->s_flags |= MS_POSIXACL;