If the number of default ACLs in directory is more than 31, then
mdd_acl_init() fails to inherit them for a newly created file.
This limitation is caused by using a fixed-size def_acl_buf buffer
in the mdd_create()->mdd_acl_init() call chain. Instead, the
default ACL buffer should be increased when it is needed.
Patch adds check for -ERANGE after mdd_acl_init(), reallocates
default ACL buffer with required size and calls mdd_acl_init()
again. Thus big default ACL are processed as expected.
Fixes:
6350af100c20 ("LU-3437 mdd: Fix ACL/def_ACL during object creation")
Signed-off-by: Mikhail Pershin <mpershin@whamcloud.com>
Change-Id: I700da90c09f824955fcb8dc7ca0bc2f581f916a0
Reviewed-on: https://review.whamcloud.com/41494
Tested-by: jenkins <devops@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Alex Zhuravlev <bzzz@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
}
/** Read the link EA into a temp buffer.
}
/** Read the link EA into a temp buffer.
- * Uses the mdd_thread_info::mti_big_buf since it is generally large.
+ * Uses the mdd_thread_info::mti_link_buf since it is generally large.
* A pointer to the buffer is stored in \a ldata::ld_buf.
*
* \retval 0 or error
* A pointer to the buffer is stored in \a ldata::ld_buf.
*
* \retval 0 or error
/** Read the link EA into a temp buffer.
* Uses the name_buf since it is generally large.
* \retval IS_ERR err
/** Read the link EA into a temp buffer.
* Uses the name_buf since it is generally large.
* \retval IS_ERR err
- * \retval ptr to \a lu_buf (always \a mti_big_buf)
+ * \retval ptr to \a lu_buf (always \a mti_link_buf)
*/
struct lu_buf *mdd_links_get(const struct lu_env *env,
struct mdd_object *mdd_obj)
*/
struct lu_buf *mdd_links_get(const struct lu_env *env,
struct mdd_object *mdd_obj)
struct lu_buf *acl_buf)
{
int rc;
struct lu_buf *acl_buf)
{
int rc;
ENTRY;
if (S_ISLNK(la->la_mode)) {
ENTRY;
if (S_ISLNK(la->la_mode)) {
const struct lu_name *lname, struct md_object *child,
struct md_op_spec *spec, struct md_attr *ma)
{
const struct lu_name *lname, struct md_object *child,
struct md_op_spec *spec, struct md_attr *ma)
{
- struct mdd_thread_info *info = mdd_env_info(env);
- struct lu_attr *la = &info->mti_la_for_fix;
- struct mdd_object *mdd_pobj = md2mdd_obj(pobj);
- struct mdd_object *son = md2mdd_obj(child);
- struct mdd_device *mdd = mdo2mdd(pobj);
- struct lu_attr *attr = &ma->ma_attr;
- struct thandle *handle;
- struct lu_attr *pattr = &info->mti_pattr;
- struct lu_buf acl_buf;
- struct lu_buf def_acl_buf;
- struct lu_buf hsm_buf;
- struct linkea_data *ldata = &info->mti_link_data;
- const char *name = lname->ln_name;
+ struct mdd_thread_info *info = mdd_env_info(env);
+ struct lu_attr *la = &info->mti_la_for_fix;
+ struct mdd_object *mdd_pobj = md2mdd_obj(pobj);
+ struct mdd_object *son = md2mdd_obj(child);
+ struct mdd_device *mdd = mdo2mdd(pobj);
+ struct lu_attr *attr = &ma->ma_attr;
+ struct thandle *handle;
+ struct lu_attr *pattr = &info->mti_pattr;
+ struct lu_buf acl_buf;
+ struct lu_buf def_acl_buf;
+ struct lu_buf hsm_buf;
+ struct linkea_data *ldata = &info->mti_link_data;
+ const char *name = lname->ln_name;
struct dt_allocation_hint *hint = &mdd_env_info(env)->mti_hint;
struct dt_allocation_hint *hint = &mdd_env_info(env)->mti_hint;
+ int acl_size = LUSTRE_POSIX_ACL_MAX_SIZE_OLD;
+ int rc, rc2;
+
ENTRY;
rc = mdd_la_get(env, mdd_pobj, pattr);
ENTRY;
rc = mdd_la_get(env, mdd_pobj, pattr);
if (IS_ERR(handle))
GOTO(out_free, rc = PTR_ERR(handle));
if (IS_ERR(handle))
GOTO(out_free, rc = PTR_ERR(handle));
- lu_buf_check_and_alloc(&info->mti_xattr_buf,
- min_t(unsigned int, mdd->mdd_dt_conf.ddp_max_ea_size,
- XATTR_SIZE_MAX));
- acl_buf = info->mti_xattr_buf;
- def_acl_buf.lb_buf = info->mti_key;
- def_acl_buf.lb_len = sizeof(info->mti_key);
+use_bigger_buffer:
+ acl_buf = *lu_buf_check_and_alloc(&info->mti_xattr_buf, acl_size);
+ if (!acl_buf.lb_buf)
+ GOTO(out_stop, rc = -ENOMEM);
+ /* mti_big_buf is also used down below in mdd_changelog_ns_store(),
+ * but def_acl_buf is finished with it before then
+ */
+ def_acl_buf = *lu_buf_check_and_alloc(&info->mti_big_buf, acl_size);
+ if (!def_acl_buf.lb_buf)
+ GOTO(out_stop, rc = -ENOMEM);
+
rc = mdd_acl_init(env, mdd_pobj, attr, &def_acl_buf, &acl_buf);
rc = mdd_acl_init(env, mdd_pobj, attr, &def_acl_buf, &acl_buf);
+ if (unlikely(rc == -ERANGE &&
+ acl_size == LUSTRE_POSIX_ACL_MAX_SIZE_OLD)) {
+ /* use maximum-sized xattr buffer for too-big default ACL */
+ acl_size = min_t(unsigned int, mdd->mdd_dt_conf.ddp_max_ea_size,
+ XATTR_SIZE_MAX);
+ goto use_bigger_buffer;
+ }
if (rc < 0)
GOTO(out_stop, rc);
if (rc < 0)
GOTO(out_stop, rc);
}
run_test 103c "'cp -rp' won't set empty acl"
}
run_test 103c "'cp -rp' won't set empty acl"
+test_103e() {
+ (( $MDS1_VERSION >= $(version_code 2.13.59) )) ||
+ skip "MDS needs to be at least 2.13.59"
+
+ mkdir -p $DIR/$tdir
+ # one default ACL will be created for the file owner
+ for U in {2..256}; do
+ setfacl -m default:user:$U:rwx $DIR/$tdir
+ numacl=$(getfacl $DIR/$tdir |& grep -c "default:user")
+ touch $DIR/$tdir/$tfile.$U ||
+ error "failed to create $tfile.$U with $numacl ACLs"
+ done
+}
+run_test 103e "inheritance of big amount of default ACLs"
+
test_104a() {
[ $PARALLEL == "yes" ] && skip "skip parallel run"
test_104a() {
[ $PARALLEL == "yes" ] && skip "skip parallel run"