+int mdd_acl_set(const struct lu_env *env, struct mdd_object *obj,
+ const struct lu_buf *buf, int fl)
+{
+ struct mdd_device *mdd = mdd_obj2mdd_dev(obj);
+ struct lu_attr *la = &mdd_env_info(env)->mti_la;
+ struct thandle *handle;
+ posix_acl_xattr_header *head;
+ posix_acl_xattr_entry *entry;
+ int rc, entry_count;
+ bool not_equiv, mode_change;
+ mode_t mode;
+ ENTRY;
+
+ rc = mdd_la_get(env, obj, la, BYPASS_CAPA);
+ if (rc)
+ RETURN(rc);
+
+ head = (posix_acl_xattr_header *)(buf->lb_buf);
+ entry = head->a_entries;
+ entry_count = (buf->lb_len - sizeof(head->a_version)) /
+ sizeof(posix_acl_xattr_entry);
+ if (entry_count <= 0)
+ RETURN(0);
+
+ LASSERT(la->la_valid & LA_MODE);
+ mode = la->la_mode;
+ rc = lustre_posix_acl_equiv_mode(entry, &mode, entry_count);
+ if (rc < 0)
+ RETURN(rc);
+
+ not_equiv = (rc > 0);
+ mode_change = (mode != la->la_mode);
+
+ handle = mdd_trans_create(env, mdd);
+ if (IS_ERR(handle))
+ RETURN(PTR_ERR(handle));
+
+ /* rc tells whether ACL can be represented by i_mode only */
+ if (not_equiv)
+ rc = mdo_declare_xattr_set(env, obj, buf,
+ XATTR_NAME_ACL_ACCESS, fl, handle);
+ else
+ rc = mdo_declare_xattr_del(env, obj, XATTR_NAME_ACL_ACCESS,
+ handle);
+ if (rc)
+ GOTO(stop, rc);
+
+ if (mode_change) {
+ la->la_mode = mode;
+ rc = mdo_declare_attr_set(env, obj, la, handle);
+ }
+
+ rc = mdd_trans_start(env, mdd, handle);
+ if (rc)
+ GOTO(stop, rc);
+
+ mdd_write_lock(env, obj, MOR_TGT_CHILD);
+ /* whether ACL can be represented by i_mode only */
+ if (not_equiv)
+ rc = mdo_xattr_set(env, obj, buf, XATTR_NAME_ACL_ACCESS, fl,
+ handle, mdd_object_capa(env, obj));
+ else
+ rc = mdo_xattr_del(env, obj, XATTR_NAME_ACL_ACCESS, handle,
+ mdd_object_capa(env, obj));
+ if (rc)
+ GOTO(unlock, rc);
+
+ if (mode_change)
+ rc = mdo_attr_set(env, obj, la, handle,
+ mdd_object_capa(env, obj));
+
+ /* security-replated changes may require sync */
+ handle->th_sync |= !!mdd->mdd_sync_permission;
+unlock:
+ mdd_write_unlock(env, obj);
+stop:
+ mdd_trans_stop(env, mdd, rc, handle);
+
+ RETURN(rc);