int mdt_reint_setxattr(struct mdt_thread_info *info, struct mdt_lock_handle *unused) { struct ptlrpc_request *req = mdt_info_req(info); struct md_ucred *uc = mdt_ucred(info); struct mdt_lock_handle *lh; const struct lu_env *env = info->mti_env; struct lu_buf *buf = &info->mti_buf; struct mdt_reint_record *rr = &info->mti_rr; struct md_attr *ma = &info->mti_attr; struct lu_attr *attr = &info->mti_attr.ma_attr; struct mdt_object *obj; struct md_object *child; __u64 valid = attr->la_valid; const char *xattr_name = rr->rr_name; int xattr_len = rr->rr_eadatalen; __u64 lockpart; int rc; posix_acl_xattr_header *new_xattr = NULL; __u32 remote = exp_connect_rmtclient(info->mti_exp); __u32 perm; ENTRY; CDEBUG(D_INODE, "setxattr for "DFID"\n", PFID(rr->rr_fid1)); if (OBD_FAIL_CHECK(OBD_FAIL_MDS_SETXATTR)) RETURN(err_serious(-ENOMEM)); CDEBUG(D_INODE, "%s xattr %s\n", valid & OBD_MD_FLXATTR ? "set" : "remove", xattr_name); rc = mdt_init_ucred_reint(info); if (rc != 0) RETURN(rc); if (valid & OBD_MD_FLRMTRSETFACL) { if (unlikely(!remote)) GOTO(out, rc = err_serious(-EINVAL)); perm = mdt_identity_get_perm(uc->mu_identity, remote, req->rq_peer.nid); if (!(perm & CFS_RMTACL_PERM)) GOTO(out, rc = err_serious(-EPERM)); } if (strncmp(xattr_name, XATTR_USER_PREFIX, sizeof(XATTR_USER_PREFIX) - 1) == 0) { if (!(req->rq_export->exp_connect_flags & OBD_CONNECT_XATTR)) GOTO(out, rc = -EOPNOTSUPP); if (strcmp(xattr_name, XATTR_NAME_LOV) == 0) GOTO(out, rc = -EACCES); if (strcmp(xattr_name, XATTR_NAME_LMA) == 0) GOTO(out, rc = 0); if (strcmp(xattr_name, XATTR_NAME_LINK) == 0) GOTO(out, rc = 0); } else if ((valid & OBD_MD_FLXATTR) && (strncmp(xattr_name, XATTR_NAME_ACL_ACCESS, sizeof(XATTR_NAME_ACL_ACCESS) - 1) == 0 || strncmp(xattr_name, XATTR_NAME_ACL_DEFAULT, sizeof(XATTR_NAME_ACL_DEFAULT) - 1) == 0)) { /* currently lustre limit acl access size */ if (xattr_len > LUSTRE_POSIX_ACL_MAX_SIZE) GOTO(out, -ERANGE); } lockpart = MDS_INODELOCK_UPDATE; /* Revoke all clients' lookup lock, since the access * permissions for this inode is changed when ACL_ACCESS is * set. This isn't needed for ACL_DEFAULT, since that does * not change the access permissions of this inode, nor any * other existing inodes. It is setting the ACLs inherited * by new directories/files at create time. */ if (!strcmp(xattr_name, XATTR_NAME_ACL_ACCESS)) lockpart |= MDS_INODELOCK_LOOKUP; lh = &info->mti_lh[MDT_LH_PARENT]; /* ACLs were sent to clients under LCK_CR locks, so taking LCK_EX * to cancel them. */ mdt_lock_reg_init(lh, LCK_EX); obj = mdt_object_find_lock(info, rr->rr_fid1, lh, lockpart); if (IS_ERR(obj)) GOTO(out, rc = PTR_ERR(obj)); info->mti_mos = obj; rc = mdt_version_get_check_save(info, obj, 0); if (rc) GOTO(out_unlock, rc); if (unlikely(!(valid & OBD_MD_FLCTIME))) { /* This isn't strictly an error, but all current clients * should set OBD_MD_FLCTIME when setting attributes. */ CWARN("%s: client miss to set OBD_MD_FLCTIME when " "setxattr %s: [object "DFID"] [valid "LPU64"]\n", info->mti_exp->exp_obd->obd_name, xattr_name, PFID(rr->rr_fid1), valid); attr->la_ctime = cfs_time_current_sec(); } attr->la_valid = LA_CTIME; child = mdt_object_child(obj); if (valid & OBD_MD_FLXATTR) { char *xattr = (void *)rr->rr_eadata; if (xattr_len > 0) { int flags = 0; if (valid & OBD_MD_FLRMTLSETFACL) { if (unlikely(!remote)) GOTO(out_unlock, rc = -EINVAL); xattr_len = mdt_rmtlsetfacl(info, child, xattr_name, (ext_acl_xattr_header *)xattr, &new_xattr); if (xattr_len < 0) GOTO(out_unlock, rc = xattr_len); xattr = (char *)new_xattr; } if (attr->la_flags & XATTR_REPLACE) flags |= LU_XATTR_REPLACE; if (attr->la_flags & XATTR_CREATE) flags |= LU_XATTR_CREATE; mdt_fail_write(env, info->mti_mdt->mdt_bottom, OBD_FAIL_MDS_SETXATTR_WRITE); buf->lb_buf = xattr; buf->lb_len = xattr_len; rc = mo_xattr_set(env, child, buf, xattr_name, flags); /* update ctime after xattr changed */ if (rc == 0) { ma->ma_attr_flags |= MDS_PERM_BYPASS; mo_attr_set(env, child, ma); } } } else if (valid & OBD_MD_FLXATTRRM) { rc = mo_xattr_del(env, child, xattr_name); /* update ctime after xattr changed */ if (rc == 0) { ma->ma_attr_flags |= MDS_PERM_BYPASS; mo_attr_set(env, child, ma); } } else { CDEBUG(D_INFO, "valid bits: "LPX64"\n", valid); rc = -EINVAL; } if (rc == 0) mdt_counter_incr(req->rq_export, LPROC_MDT_SETXATTR); EXIT; out_unlock: mdt_object_unlock_put(info, obj, lh, rc); if (unlikely(new_xattr != NULL)) lustre_posix_acl_xattr_free(new_xattr, xattr_len); out: mdt_exit_ucred(info); return rc; }
static int ll_setxattr_common(struct inode *inode, const char *name, const void *value, size_t size, int flags, __u64 valid) { struct ll_sb_info *sbi = ll_i2sbi(inode); struct ptlrpc_request *req = NULL; int xattr_type, rc; struct obd_capa *oc; struct rmtacl_ctl_entry *rce = NULL; #ifdef CONFIG_FS_POSIX_ACL posix_acl_xattr_header *new_value = NULL; ext_acl_xattr_header *acl = NULL; #endif const char *pv = value; xattr_type = get_xattr_type(name); rc = xattr_type_filter(sbi, xattr_type); if (rc) return rc; /* b10667: ignore lustre special xattr for now */ if ((xattr_type == XATTR_TRUSTED_T && strcmp(name, "trusted.lov") == 0) || (xattr_type == XATTR_LUSTRE_T && strcmp(name, "lustre.lov") == 0)) return 0; /* b15587: ignore security.capability xattr for now */ if ((xattr_type == XATTR_SECURITY_T && strcmp(name, "security.capability") == 0)) return 0; /* LU-549: Disable security.selinux when selinux is disabled */ if (xattr_type == XATTR_SECURITY_T && !selinux_is_enabled() && strcmp(name, "security.selinux") == 0) return -EOPNOTSUPP; #ifdef CONFIG_FS_POSIX_ACL if (sbi->ll_flags & LL_SBI_RMT_CLIENT && (xattr_type == XATTR_ACL_ACCESS_T || xattr_type == XATTR_ACL_DEFAULT_T)) { rce = rct_search(&sbi->ll_rct, current_pid()); if (rce == NULL || (rce->rce_ops != RMT_LSETFACL && rce->rce_ops != RMT_RSETFACL)) return -EOPNOTSUPP; if (rce->rce_ops == RMT_LSETFACL) { struct eacl_entry *ee; ee = et_search_del(&sbi->ll_et, current_pid(), ll_inode2fid(inode), xattr_type); LASSERT(ee != NULL); if (valid & OBD_MD_FLXATTR) { acl = lustre_acl_xattr_merge2ext( (posix_acl_xattr_header *)value, size, ee->ee_acl); if (IS_ERR(acl)) { ee_free(ee); return PTR_ERR(acl); } size = CFS_ACL_XATTR_SIZE(\ le32_to_cpu(acl->a_count), \ ext_acl_xattr); pv = (const char *)acl; } ee_free(ee); } else if (rce->rce_ops == RMT_RSETFACL) { size = lustre_posix_acl_xattr_filter( (posix_acl_xattr_header *)value, size, &new_value); if (unlikely(size < 0)) return size; pv = (const char *)new_value; } else return -EOPNOTSUPP; valid |= rce_ops2valid(rce->rce_ops); } #endif if (sbi->ll_xattr_cache_enabled && (rce == NULL || rce->rce_ops == RMT_LSETFACL)) { rc = ll_xattr_cache_update(inode, name, pv, size, valid, flags); } else { oc = ll_mdscapa_get(inode); rc = md_setxattr(sbi->ll_md_exp, ll_inode2fid(inode), oc, valid, name, pv, size, 0, flags, ll_i2suppgid(inode), &req); capa_put(oc); } #ifdef CONFIG_FS_POSIX_ACL if (new_value != NULL) lustre_posix_acl_xattr_free(new_value, size); if (acl != NULL) lustre_ext_acl_xattr_free(acl); #endif if (rc) { if (rc == -EOPNOTSUPP && xattr_type == XATTR_USER_T) { LCONSOLE_INFO("Disabling user_xattr feature because " "it is not supported on the server\n"); sbi->ll_flags &= ~LL_SBI_USER_XATTR; } return rc; } ptlrpc_req_finished(req); return 0; }