From 7b3bfb09dbcc20ddce2fbdd9d8c30e4a2a95741e Mon Sep 17 00:00:00 2001 From: Alex Zhuravlev Date: Tue, 4 Sep 2012 19:20:22 +0400 Subject: [PATCH] LU-1304 mdd: changes related to acl ACL/i_mode consistency in maintained within MDD, so that ACLs functionality do not depend on OSD indirectly. required for ZFS backend. Signed-off-by: Alex Zhuravlev Change-Id: I8f20e21734097ee2d962cc487265d6e1d9b3b805 Reviewed-on: http://review.whamcloud.com/3866 Tested-by: Hudson Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: wangdi Reviewed-by: Fan Yong --- lustre/include/lustre_eacl.h | 2 + lustre/mdd/mdd_dir.c | 81 +++++++++++--------- lustre/mdd/mdd_internal.h | 4 + lustre/mdd/mdd_object.c | 5 ++ lustre/mdd/mdd_permission.c | 171 +++++++++++++++++++++++++++++++++---------- lustre/obdclass/acl.c | 43 +++++++++++ 6 files changed, 236 insertions(+), 70 deletions(-) diff --git a/lustre/include/lustre_eacl.h b/lustre/include/lustre_eacl.h index f7f86f3..2781e39 100644 --- a/lustre/include/lustre_eacl.h +++ b/lustre/include/lustre_eacl.h @@ -81,6 +81,8 @@ extern int lustre_posix_acl_chmod_masq(posix_acl_xattr_entry *entry, __u32 mode, int count); extern int lustre_posix_acl_create_masq(posix_acl_xattr_entry *entry, __u32 *pmode, int count); +extern int lustre_posix_acl_equiv_mode(posix_acl_xattr_entry *entry, mode_t *mode_p, + int count); extern ext_acl_xattr_header * lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size); diff --git a/lustre/mdd/mdd_dir.c b/lustre/mdd/mdd_dir.c index bb76584..69fd1dc 100644 --- a/lustre/mdd/mdd_dir.c +++ b/lustre/mdd/mdd_dir.c @@ -1516,9 +1516,11 @@ static int mdd_declare_create(const struct lu_env *env, const struct lu_name *name, struct md_attr *ma, int lmm_size, + int got_def_acl, struct thandle *handle, const struct md_op_spec *spec) { + struct mdd_thread_info *info = mdd_env_info(env); struct lu_buf *buf = &mdd_env_info(env)->mti_buf; int rc = 0; @@ -1526,22 +1528,39 @@ static int mdd_declare_create(const struct lu_env *env, if (rc) GOTO(out, rc); +#ifdef CONFIG_FS_POSIX_ACL + if (got_def_acl > 0) { + struct lu_buf *acl_buf; + + acl_buf = mdd_buf_get(env, NULL, got_def_acl); + /* if dir, then can inherit default ACl */ + if (S_ISDIR(ma->ma_attr.la_mode)) { + rc = mdo_declare_xattr_set(env, c, acl_buf, + XATTR_NAME_ACL_DEFAULT, + 0, handle); + if (rc) + GOTO(out, rc); + } + + rc = mdo_declare_attr_set(env, c, &info->mti_pattr, handle); + if (rc) + GOTO(out, rc); + + rc = mdo_declare_xattr_set(env, c, acl_buf, + XATTR_NAME_ACL_ACCESS, 0, handle); + if (rc) + GOTO(out, rc); + } +#endif + /* if dir, then can inherit default ACl */ buf->lb_buf = NULL; buf->lb_len = lmm_size; - if (S_ISDIR(ma->ma_attr.la_mode)) { - rc = mdo_declare_xattr_set(env, c, buf, XATTR_NAME_ACL_DEFAULT, - 0, handle); - if (rc == 0) - rc = mdo_declare_ref_add(env, p, handle); + if (S_ISDIR(ma->ma_attr.la_mode)) { + rc = mdo_declare_ref_add(env, p, handle); + if (rc) + GOTO(out, rc); } - if (rc) - GOTO(out, rc); - - rc = mdo_declare_xattr_set(env, c, buf, XATTR_NAME_ACL_ACCESS, - 0, handle); - if (rc) - GOTO(out, rc); rc = mdd_declare_object_initialize(env, c, ma, handle); if (rc) @@ -1591,7 +1610,6 @@ static int mdd_create(const struct lu_env *env, { struct mdd_thread_info *info = mdd_env_info(env); struct lu_attr *la = &info->mti_la_for_fix; - struct md_attr *ma_acl = &info->mti_ma; struct mdd_object *mdd_pobj = md2mdd_obj(pobj); struct mdd_object *son = md2mdd_obj(child); struct mdd_device *mdd = mdo2mdd(pobj); @@ -1716,18 +1734,18 @@ static int mdd_create(const struct lu_env *env, } if (!S_ISLNK(attr->la_mode)) { - ma_acl->ma_acl_size = sizeof info->mti_xattr_buf; - ma_acl->ma_acl = info->mti_xattr_buf; - ma_acl->ma_need = MA_ACL_DEF; - ma_acl->ma_valid = 0; + struct lu_buf *acl_buf; + acl_buf = mdd_buf_get(env, info->mti_xattr_buf, + sizeof(info->mti_xattr_buf)); mdd_read_lock(env, mdd_pobj, MOR_TGT_PARENT); - rc = mdd_def_acl_get(env, mdd_pobj, ma_acl); + rc = mdo_xattr_get(env, mdd_pobj, acl_buf, + XATTR_NAME_ACL_DEFAULT, BYPASS_CAPA); mdd_read_unlock(env, mdd_pobj); - if (rc) - GOTO(out_free, rc); - else if (ma_acl->ma_valid & MA_ACL_DEF) - got_def_acl = 1; + if (rc > 0) + got_def_acl = rc; + else if (rc < 0 && rc != -EOPNOTSUPP && rc != -ENODATA) + GOTO(out_free, rc); } mdd_object_make_hint(env, mdd_pobj, son, attr); @@ -1737,7 +1755,7 @@ static int mdd_create(const struct lu_env *env, GOTO(out_free, rc = PTR_ERR(handle)); rc = mdd_declare_create(env, mdd, mdd_pobj, son, lname, ma, - lmm_size, handle, spec); + got_def_acl, lmm_size, handle, spec); if (rc) GOTO(out_stop, rc); @@ -1760,17 +1778,14 @@ static int mdd_create(const struct lu_env *env, #ifdef CONFIG_FS_POSIX_ACL if (got_def_acl) { - struct lu_buf *acl_buf = &info->mti_buf; - acl_buf->lb_buf = ma_acl->ma_acl; - acl_buf->lb_len = ma_acl->ma_acl_size; + struct lu_buf *acl_buf; - rc = __mdd_acl_init(env, son, acl_buf, &attr->la_mode, handle); - if (rc) { - mdd_write_unlock(env, son); - GOTO(cleanup, rc); - } else { - ma->ma_attr.la_valid |= LA_MODE; - } + acl_buf = mdd_buf_get(env, info->mti_xattr_buf, got_def_acl); + rc = __mdd_acl_init(env, son, acl_buf, &attr->la_mode, handle); + if (rc) { + mdd_write_unlock(env, son); + GOTO(cleanup, rc); + } } #endif diff --git a/lustre/mdd/mdd_internal.h b/lustre/mdd/mdd_internal.h index 5a03b8c..09de0a1 100644 --- a/lustre/mdd/mdd_internal.h +++ b/lustre/mdd/mdd_internal.h @@ -183,6 +183,8 @@ struct mdd_thread_info { /* mti_orph_ent and mti_orph_key must be conjoint, * then mti_orph_ent::lde_name will be mti_orph_key. */ struct lu_dirent mti_orph_ent; + struct lu_attr mti_pattr; + struct lu_attr mti_cattr; char mti_orph_key[NAME_MAX + 1]; struct obd_trans_info mti_oti; struct lu_buf mti_buf; @@ -515,6 +517,8 @@ int mdd_acl_chmod(const struct lu_env *env, struct mdd_object *o, __u32 mode, struct thandle *handle); int __mdd_declare_acl_init(const struct lu_env *env, struct mdd_object *obj, int is_dir, struct thandle *handle); +int mdd_acl_set(const struct lu_env *env, struct mdd_object *obj, + const struct lu_buf *buf, int fl); int __mdd_acl_init(const struct lu_env *env, struct mdd_object *obj, struct lu_buf *buf, __u32 *mode, struct thandle *handle); int __mdd_permission_internal(const struct lu_env *env, struct mdd_object *obj, diff --git a/lustre/mdd/mdd_object.c b/lustre/mdd/mdd_object.c index f15697f..9aa7170 100644 --- a/lustre/mdd/mdd_object.c +++ b/lustre/mdd/mdd_object.c @@ -1864,6 +1864,11 @@ static int mdd_xattr_set(const struct lu_env *env, struct md_object *obj, int rc; ENTRY; + if (!strcmp(name, XATTR_NAME_ACL_ACCESS)) { + rc = mdd_acl_set(env, mdd_obj, buf, fl); + RETURN(rc); + } + rc = mdd_xattr_sanity_check(env, mdd_obj); if (rc) RETURN(rc); diff --git a/lustre/mdd/mdd_permission.c b/lustre/mdd/mdd_permission.c index 21e1659..1f3ba34 100644 --- a/lustre/mdd/mdd_permission.c +++ b/lustre/mdd/mdd_permission.c @@ -81,40 +81,121 @@ int mdd_def_acl_get(const struct lu_env *env, struct mdd_object *mdd_obj, * Hold write_lock for o. */ int mdd_acl_chmod(const struct lu_env *env, struct mdd_object *o, __u32 mode, - struct thandle *handle) + struct thandle *handle) { - struct lu_buf *buf; - posix_acl_xattr_header *head; - posix_acl_xattr_entry *entry; - int entry_count; - int rc; - - ENTRY; - - buf = mdd_buf_get(env, mdd_env_info(env)->mti_xattr_buf, - sizeof(mdd_env_info(env)->mti_xattr_buf)); - - rc = mdo_xattr_get(env, o, buf, XATTR_NAME_ACL_ACCESS, BYPASS_CAPA); - if ((rc == -EOPNOTSUPP) || (rc == -ENODATA)) - RETURN(0); - else if (rc <= 0) - RETURN(rc); - - buf->lb_len = 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); - - rc = lustre_posix_acl_chmod_masq(entry, mode, entry_count); - if (rc) - RETURN(rc); + struct lu_buf *buf; + posix_acl_xattr_header *head; + posix_acl_xattr_entry *entry; + int entry_count; + int rc; + + ENTRY; + + buf = mdd_buf_get(env, mdd_env_info(env)->mti_xattr_buf, + sizeof(mdd_env_info(env)->mti_xattr_buf)); + + rc = mdo_xattr_get(env, o, buf, XATTR_NAME_ACL_ACCESS, BYPASS_CAPA); + if ((rc == -EOPNOTSUPP) || (rc == -ENODATA)) + RETURN(0); + else if (rc <= 0) + RETURN(rc); + + buf->lb_len = 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); + + rc = lustre_posix_acl_chmod_masq(entry, mode, entry_count); + if (rc) + RETURN(rc); + + rc = mdo_xattr_set(env, o, buf, XATTR_NAME_ACL_ACCESS, + 0, handle, BYPASS_CAPA); + RETURN(rc); +} - rc = mdo_xattr_set(env, o, buf, XATTR_NAME_ACL_ACCESS, - 0, handle, BYPASS_CAPA); - RETURN(rc); +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); } /* @@ -126,7 +207,8 @@ int __mdd_acl_init(const struct lu_env *env, struct mdd_object *obj, posix_acl_xattr_header *head; posix_acl_xattr_entry *entry; int entry_count; - int rc; + __u32 old = *mode; + int rc, rc2; ENTRY; @@ -145,12 +227,27 @@ int __mdd_acl_init(const struct lu_env *env, struct mdd_object *obj, } rc = lustre_posix_acl_create_masq(entry, mode, entry_count); - if (rc <= 0) + if (rc < 0) RETURN(rc); - rc = mdo_xattr_set(env, obj, buf, XATTR_NAME_ACL_ACCESS, 0, handle, - BYPASS_CAPA); - RETURN(rc); + /* part of ACL went into i_mode */ + if (*mode != old) { + struct mdd_thread_info *info = mdd_env_info(env); + struct lu_attr *pattr = &info->mti_pattr; + + /* mode was initialized within object creation, + * so we need explict ->attr_set() to update it */ + pattr->la_valid = LA_MODE; + pattr->la_mode = *mode; + rc2 = mdo_attr_set(env, obj, pattr, handle, BYPASS_CAPA); + if (rc2 < 0) + rc = rc2; + } + + if (rc > 0) + rc = mdo_xattr_set(env, obj, buf, XATTR_NAME_ACL_ACCESS, 0, + handle, BYPASS_CAPA); + RETURN(rc); } #endif diff --git a/lustre/obdclass/acl.c b/lustre/obdclass/acl.c index b48acf8..7adbd59 100644 --- a/lustre/obdclass/acl.c +++ b/lustre/obdclass/acl.c @@ -205,6 +205,49 @@ int lustre_posix_acl_chmod_masq(posix_acl_xattr_entry *entry, __u32 mode, EXPORT_SYMBOL(lustre_posix_acl_chmod_masq); /* + * Returns 0 if the acl can be exactly represented in the traditional + * file mode permission bits, or else 1. Returns -E... on error. + */ + int +lustre_posix_acl_equiv_mode(posix_acl_xattr_entry *entry, mode_t *mode_p, + int count) +{ + posix_acl_xattr_entry *pa, *pe; + mode_t mode = 0; + int not_equiv = 0; + + for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) { + __u16 perm = le16_to_cpu(pa->e_perm); + switch (le16_to_cpu(pa->e_tag)) { + case ACL_USER_OBJ: + mode |= (perm & S_IRWXO) << 6; + break; + case ACL_GROUP_OBJ: + mode |= (perm & S_IRWXO) << 3; + break; + case ACL_OTHER: + mode |= perm & S_IRWXO; + break; + case ACL_MASK: + mode = (mode & ~S_IRWXG) | + ((perm & S_IRWXO) << 3); + not_equiv = 1; + break; + case ACL_USER: + case ACL_GROUP: + not_equiv = 1; + break; + default: + return -EINVAL; + } + } + if (mode_p) + *mode_p = (*mode_p & ~S_IRWXUGO) | mode; + return not_equiv; +} +EXPORT_SYMBOL(lustre_posix_acl_equiv_mode); + +/* * Modify acl when creating a new object. */ int lustre_posix_acl_create_masq(posix_acl_xattr_entry *entry, __u32 *pmode, -- 1.8.3.1