162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/ceph/ceph_debug.h> 362306a36Sopenharmony_ci#include <linux/ceph/pagelist.h> 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include "super.h" 662306a36Sopenharmony_ci#include "mds_client.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/ceph/decode.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/xattr.h> 1162306a36Sopenharmony_ci#include <linux/security.h> 1262306a36Sopenharmony_ci#include <linux/posix_acl_xattr.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define XATTR_CEPH_PREFIX "ceph." 1662306a36Sopenharmony_ci#define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1) 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic int __remove_xattr(struct ceph_inode_info *ci, 1962306a36Sopenharmony_ci struct ceph_inode_xattr *xattr); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic bool ceph_is_valid_xattr(const char *name) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci return !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) || 2462306a36Sopenharmony_ci !strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN) || 2562306a36Sopenharmony_ci !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) || 2662306a36Sopenharmony_ci !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); 2762306a36Sopenharmony_ci} 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* 3062306a36Sopenharmony_ci * These define virtual xattrs exposing the recursive directory 3162306a36Sopenharmony_ci * statistics and layout metadata. 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_cistruct ceph_vxattr { 3462306a36Sopenharmony_ci char *name; 3562306a36Sopenharmony_ci size_t name_size; /* strlen(name) + 1 (for '\0') */ 3662306a36Sopenharmony_ci ssize_t (*getxattr_cb)(struct ceph_inode_info *ci, char *val, 3762306a36Sopenharmony_ci size_t size); 3862306a36Sopenharmony_ci bool (*exists_cb)(struct ceph_inode_info *ci); 3962306a36Sopenharmony_ci unsigned int flags; 4062306a36Sopenharmony_ci}; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define VXATTR_FLAG_READONLY (1<<0) 4362306a36Sopenharmony_ci#define VXATTR_FLAG_HIDDEN (1<<1) 4462306a36Sopenharmony_ci#define VXATTR_FLAG_RSTAT (1<<2) 4562306a36Sopenharmony_ci#define VXATTR_FLAG_DIRSTAT (1<<3) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* layouts */ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic bool ceph_vxattrcb_layout_exists(struct ceph_inode_info *ci) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct ceph_file_layout *fl = &ci->i_layout; 5262306a36Sopenharmony_ci return (fl->stripe_unit > 0 || fl->stripe_count > 0 || 5362306a36Sopenharmony_ci fl->object_size > 0 || fl->pool_id >= 0 || 5462306a36Sopenharmony_ci rcu_dereference_raw(fl->pool_ns) != NULL); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val, 5862306a36Sopenharmony_ci size_t size) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct ceph_fs_client *fsc = ceph_sb_to_client(ci->netfs.inode.i_sb); 6162306a36Sopenharmony_ci struct ceph_osd_client *osdc = &fsc->client->osdc; 6262306a36Sopenharmony_ci struct ceph_string *pool_ns; 6362306a36Sopenharmony_ci s64 pool = ci->i_layout.pool_id; 6462306a36Sopenharmony_ci const char *pool_name; 6562306a36Sopenharmony_ci const char *ns_field = " pool_namespace="; 6662306a36Sopenharmony_ci char buf[128]; 6762306a36Sopenharmony_ci size_t len, total_len = 0; 6862306a36Sopenharmony_ci ssize_t ret; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci pool_ns = ceph_try_get_string(ci->i_layout.pool_ns); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci dout("ceph_vxattrcb_layout %p\n", &ci->netfs.inode); 7362306a36Sopenharmony_ci down_read(&osdc->lock); 7462306a36Sopenharmony_ci pool_name = ceph_pg_pool_name_by_id(osdc->osdmap, pool); 7562306a36Sopenharmony_ci if (pool_name) { 7662306a36Sopenharmony_ci len = snprintf(buf, sizeof(buf), 7762306a36Sopenharmony_ci "stripe_unit=%u stripe_count=%u object_size=%u pool=", 7862306a36Sopenharmony_ci ci->i_layout.stripe_unit, ci->i_layout.stripe_count, 7962306a36Sopenharmony_ci ci->i_layout.object_size); 8062306a36Sopenharmony_ci total_len = len + strlen(pool_name); 8162306a36Sopenharmony_ci } else { 8262306a36Sopenharmony_ci len = snprintf(buf, sizeof(buf), 8362306a36Sopenharmony_ci "stripe_unit=%u stripe_count=%u object_size=%u pool=%lld", 8462306a36Sopenharmony_ci ci->i_layout.stripe_unit, ci->i_layout.stripe_count, 8562306a36Sopenharmony_ci ci->i_layout.object_size, pool); 8662306a36Sopenharmony_ci total_len = len; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (pool_ns) 9062306a36Sopenharmony_ci total_len += strlen(ns_field) + pool_ns->len; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci ret = total_len; 9362306a36Sopenharmony_ci if (size >= total_len) { 9462306a36Sopenharmony_ci memcpy(val, buf, len); 9562306a36Sopenharmony_ci ret = len; 9662306a36Sopenharmony_ci if (pool_name) { 9762306a36Sopenharmony_ci len = strlen(pool_name); 9862306a36Sopenharmony_ci memcpy(val + ret, pool_name, len); 9962306a36Sopenharmony_ci ret += len; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci if (pool_ns) { 10262306a36Sopenharmony_ci len = strlen(ns_field); 10362306a36Sopenharmony_ci memcpy(val + ret, ns_field, len); 10462306a36Sopenharmony_ci ret += len; 10562306a36Sopenharmony_ci memcpy(val + ret, pool_ns->str, pool_ns->len); 10662306a36Sopenharmony_ci ret += pool_ns->len; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci up_read(&osdc->lock); 11062306a36Sopenharmony_ci ceph_put_string(pool_ns); 11162306a36Sopenharmony_ci return ret; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/* 11562306a36Sopenharmony_ci * The convention with strings in xattrs is that they should not be NULL 11662306a36Sopenharmony_ci * terminated, since we're returning the length with them. snprintf always 11762306a36Sopenharmony_ci * NULL terminates however, so call it on a temporary buffer and then memcpy 11862306a36Sopenharmony_ci * the result into place. 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_cistatic __printf(3, 4) 12162306a36Sopenharmony_ciint ceph_fmt_xattr(char *val, size_t size, const char *fmt, ...) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci int ret; 12462306a36Sopenharmony_ci va_list args; 12562306a36Sopenharmony_ci char buf[96]; /* NB: reevaluate size if new vxattrs are added */ 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci va_start(args, fmt); 12862306a36Sopenharmony_ci ret = vsnprintf(buf, size ? sizeof(buf) : 0, fmt, args); 12962306a36Sopenharmony_ci va_end(args); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* Sanity check */ 13262306a36Sopenharmony_ci if (size && ret + 1 > sizeof(buf)) { 13362306a36Sopenharmony_ci WARN_ONCE(true, "Returned length too big (%d)", ret); 13462306a36Sopenharmony_ci return -E2BIG; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (ret <= size) 13862306a36Sopenharmony_ci memcpy(val, buf, ret); 13962306a36Sopenharmony_ci return ret; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_layout_stripe_unit(struct ceph_inode_info *ci, 14362306a36Sopenharmony_ci char *val, size_t size) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "%u", ci->i_layout.stripe_unit); 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_layout_stripe_count(struct ceph_inode_info *ci, 14962306a36Sopenharmony_ci char *val, size_t size) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "%u", ci->i_layout.stripe_count); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_layout_object_size(struct ceph_inode_info *ci, 15562306a36Sopenharmony_ci char *val, size_t size) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "%u", ci->i_layout.object_size); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_layout_pool(struct ceph_inode_info *ci, 16162306a36Sopenharmony_ci char *val, size_t size) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci ssize_t ret; 16462306a36Sopenharmony_ci struct ceph_fs_client *fsc = ceph_sb_to_client(ci->netfs.inode.i_sb); 16562306a36Sopenharmony_ci struct ceph_osd_client *osdc = &fsc->client->osdc; 16662306a36Sopenharmony_ci s64 pool = ci->i_layout.pool_id; 16762306a36Sopenharmony_ci const char *pool_name; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci down_read(&osdc->lock); 17062306a36Sopenharmony_ci pool_name = ceph_pg_pool_name_by_id(osdc->osdmap, pool); 17162306a36Sopenharmony_ci if (pool_name) { 17262306a36Sopenharmony_ci ret = strlen(pool_name); 17362306a36Sopenharmony_ci if (ret <= size) 17462306a36Sopenharmony_ci memcpy(val, pool_name, ret); 17562306a36Sopenharmony_ci } else { 17662306a36Sopenharmony_ci ret = ceph_fmt_xattr(val, size, "%lld", pool); 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci up_read(&osdc->lock); 17962306a36Sopenharmony_ci return ret; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_layout_pool_namespace(struct ceph_inode_info *ci, 18362306a36Sopenharmony_ci char *val, size_t size) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci ssize_t ret = 0; 18662306a36Sopenharmony_ci struct ceph_string *ns = ceph_try_get_string(ci->i_layout.pool_ns); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (ns) { 18962306a36Sopenharmony_ci ret = ns->len; 19062306a36Sopenharmony_ci if (ret <= size) 19162306a36Sopenharmony_ci memcpy(val, ns->str, ret); 19262306a36Sopenharmony_ci ceph_put_string(ns); 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci return ret; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/* directories */ 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_dir_entries(struct ceph_inode_info *ci, char *val, 20062306a36Sopenharmony_ci size_t size) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "%lld", ci->i_files + ci->i_subdirs); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_dir_files(struct ceph_inode_info *ci, char *val, 20662306a36Sopenharmony_ci size_t size) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "%lld", ci->i_files); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_dir_subdirs(struct ceph_inode_info *ci, char *val, 21262306a36Sopenharmony_ci size_t size) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "%lld", ci->i_subdirs); 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_dir_rentries(struct ceph_inode_info *ci, char *val, 21862306a36Sopenharmony_ci size_t size) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "%lld", 22162306a36Sopenharmony_ci ci->i_rfiles + ci->i_rsubdirs); 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_dir_rfiles(struct ceph_inode_info *ci, char *val, 22562306a36Sopenharmony_ci size_t size) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "%lld", ci->i_rfiles); 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_dir_rsubdirs(struct ceph_inode_info *ci, char *val, 23162306a36Sopenharmony_ci size_t size) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "%lld", ci->i_rsubdirs); 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_dir_rsnaps(struct ceph_inode_info *ci, char *val, 23762306a36Sopenharmony_ci size_t size) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "%lld", ci->i_rsnaps); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_dir_rbytes(struct ceph_inode_info *ci, char *val, 24362306a36Sopenharmony_ci size_t size) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "%lld", ci->i_rbytes); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_dir_rctime(struct ceph_inode_info *ci, char *val, 24962306a36Sopenharmony_ci size_t size) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "%lld.%09ld", ci->i_rctime.tv_sec, 25262306a36Sopenharmony_ci ci->i_rctime.tv_nsec); 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci/* dir pin */ 25662306a36Sopenharmony_cistatic bool ceph_vxattrcb_dir_pin_exists(struct ceph_inode_info *ci) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci return ci->i_dir_pin != -ENODATA; 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_dir_pin(struct ceph_inode_info *ci, char *val, 26262306a36Sopenharmony_ci size_t size) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "%d", (int)ci->i_dir_pin); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci/* quotas */ 26862306a36Sopenharmony_cistatic bool ceph_vxattrcb_quota_exists(struct ceph_inode_info *ci) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci bool ret = false; 27162306a36Sopenharmony_ci spin_lock(&ci->i_ceph_lock); 27262306a36Sopenharmony_ci if ((ci->i_max_files || ci->i_max_bytes) && 27362306a36Sopenharmony_ci ci->i_vino.snap == CEPH_NOSNAP && 27462306a36Sopenharmony_ci ci->i_snap_realm && 27562306a36Sopenharmony_ci ci->i_snap_realm->ino == ci->i_vino.ino) 27662306a36Sopenharmony_ci ret = true; 27762306a36Sopenharmony_ci spin_unlock(&ci->i_ceph_lock); 27862306a36Sopenharmony_ci return ret; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_quota(struct ceph_inode_info *ci, char *val, 28262306a36Sopenharmony_ci size_t size) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "max_bytes=%llu max_files=%llu", 28562306a36Sopenharmony_ci ci->i_max_bytes, ci->i_max_files); 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_quota_max_bytes(struct ceph_inode_info *ci, 28962306a36Sopenharmony_ci char *val, size_t size) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "%llu", ci->i_max_bytes); 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_quota_max_files(struct ceph_inode_info *ci, 29562306a36Sopenharmony_ci char *val, size_t size) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "%llu", ci->i_max_files); 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/* snapshots */ 30162306a36Sopenharmony_cistatic bool ceph_vxattrcb_snap_btime_exists(struct ceph_inode_info *ci) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci return (ci->i_snap_btime.tv_sec != 0 || ci->i_snap_btime.tv_nsec != 0); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_snap_btime(struct ceph_inode_info *ci, char *val, 30762306a36Sopenharmony_ci size_t size) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "%lld.%09ld", ci->i_snap_btime.tv_sec, 31062306a36Sopenharmony_ci ci->i_snap_btime.tv_nsec); 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_cluster_fsid(struct ceph_inode_info *ci, 31462306a36Sopenharmony_ci char *val, size_t size) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct ceph_fs_client *fsc = ceph_sb_to_client(ci->netfs.inode.i_sb); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "%pU", &fsc->client->fsid); 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_client_id(struct ceph_inode_info *ci, 32262306a36Sopenharmony_ci char *val, size_t size) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct ceph_fs_client *fsc = ceph_sb_to_client(ci->netfs.inode.i_sb); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "client%lld", 32762306a36Sopenharmony_ci ceph_client_gid(fsc->client)); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_caps(struct ceph_inode_info *ci, char *val, 33162306a36Sopenharmony_ci size_t size) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci int issued; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci spin_lock(&ci->i_ceph_lock); 33662306a36Sopenharmony_ci issued = __ceph_caps_issued(ci, NULL); 33762306a36Sopenharmony_ci spin_unlock(&ci->i_ceph_lock); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci return ceph_fmt_xattr(val, size, "%s/0x%x", 34062306a36Sopenharmony_ci ceph_cap_string(issued), issued); 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_auth_mds(struct ceph_inode_info *ci, 34462306a36Sopenharmony_ci char *val, size_t size) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci int ret; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci spin_lock(&ci->i_ceph_lock); 34962306a36Sopenharmony_ci ret = ceph_fmt_xattr(val, size, "%d", 35062306a36Sopenharmony_ci ci->i_auth_cap ? ci->i_auth_cap->session->s_mds : -1); 35162306a36Sopenharmony_ci spin_unlock(&ci->i_ceph_lock); 35262306a36Sopenharmony_ci return ret; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_FS_ENCRYPTION) 35662306a36Sopenharmony_cistatic bool ceph_vxattrcb_fscrypt_auth_exists(struct ceph_inode_info *ci) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci return ci->fscrypt_auth_len; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic ssize_t ceph_vxattrcb_fscrypt_auth(struct ceph_inode_info *ci, 36262306a36Sopenharmony_ci char *val, size_t size) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci if (size) { 36562306a36Sopenharmony_ci if (size < ci->fscrypt_auth_len) 36662306a36Sopenharmony_ci return -ERANGE; 36762306a36Sopenharmony_ci memcpy(val, ci->fscrypt_auth, ci->fscrypt_auth_len); 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci return ci->fscrypt_auth_len; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci#endif /* CONFIG_FS_ENCRYPTION */ 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci#define CEPH_XATTR_NAME(_type, _name) XATTR_CEPH_PREFIX #_type "." #_name 37462306a36Sopenharmony_ci#define CEPH_XATTR_NAME2(_type, _name, _name2) \ 37562306a36Sopenharmony_ci XATTR_CEPH_PREFIX #_type "." #_name "." #_name2 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci#define XATTR_NAME_CEPH(_type, _name, _flags) \ 37862306a36Sopenharmony_ci { \ 37962306a36Sopenharmony_ci .name = CEPH_XATTR_NAME(_type, _name), \ 38062306a36Sopenharmony_ci .name_size = sizeof (CEPH_XATTR_NAME(_type, _name)), \ 38162306a36Sopenharmony_ci .getxattr_cb = ceph_vxattrcb_ ## _type ## _ ## _name, \ 38262306a36Sopenharmony_ci .exists_cb = NULL, \ 38362306a36Sopenharmony_ci .flags = (VXATTR_FLAG_READONLY | _flags), \ 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci#define XATTR_RSTAT_FIELD(_type, _name) \ 38662306a36Sopenharmony_ci XATTR_NAME_CEPH(_type, _name, VXATTR_FLAG_RSTAT) 38762306a36Sopenharmony_ci#define XATTR_RSTAT_FIELD_UPDATABLE(_type, _name) \ 38862306a36Sopenharmony_ci { \ 38962306a36Sopenharmony_ci .name = CEPH_XATTR_NAME(_type, _name), \ 39062306a36Sopenharmony_ci .name_size = sizeof (CEPH_XATTR_NAME(_type, _name)), \ 39162306a36Sopenharmony_ci .getxattr_cb = ceph_vxattrcb_ ## _type ## _ ## _name, \ 39262306a36Sopenharmony_ci .exists_cb = NULL, \ 39362306a36Sopenharmony_ci .flags = VXATTR_FLAG_RSTAT, \ 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci#define XATTR_LAYOUT_FIELD(_type, _name, _field) \ 39662306a36Sopenharmony_ci { \ 39762306a36Sopenharmony_ci .name = CEPH_XATTR_NAME2(_type, _name, _field), \ 39862306a36Sopenharmony_ci .name_size = sizeof (CEPH_XATTR_NAME2(_type, _name, _field)), \ 39962306a36Sopenharmony_ci .getxattr_cb = ceph_vxattrcb_ ## _name ## _ ## _field, \ 40062306a36Sopenharmony_ci .exists_cb = ceph_vxattrcb_layout_exists, \ 40162306a36Sopenharmony_ci .flags = VXATTR_FLAG_HIDDEN, \ 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci#define XATTR_QUOTA_FIELD(_type, _name) \ 40462306a36Sopenharmony_ci { \ 40562306a36Sopenharmony_ci .name = CEPH_XATTR_NAME(_type, _name), \ 40662306a36Sopenharmony_ci .name_size = sizeof(CEPH_XATTR_NAME(_type, _name)), \ 40762306a36Sopenharmony_ci .getxattr_cb = ceph_vxattrcb_ ## _type ## _ ## _name, \ 40862306a36Sopenharmony_ci .exists_cb = ceph_vxattrcb_quota_exists, \ 40962306a36Sopenharmony_ci .flags = VXATTR_FLAG_HIDDEN, \ 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic struct ceph_vxattr ceph_dir_vxattrs[] = { 41362306a36Sopenharmony_ci { 41462306a36Sopenharmony_ci .name = "ceph.dir.layout", 41562306a36Sopenharmony_ci .name_size = sizeof("ceph.dir.layout"), 41662306a36Sopenharmony_ci .getxattr_cb = ceph_vxattrcb_layout, 41762306a36Sopenharmony_ci .exists_cb = ceph_vxattrcb_layout_exists, 41862306a36Sopenharmony_ci .flags = VXATTR_FLAG_HIDDEN, 41962306a36Sopenharmony_ci }, 42062306a36Sopenharmony_ci XATTR_LAYOUT_FIELD(dir, layout, stripe_unit), 42162306a36Sopenharmony_ci XATTR_LAYOUT_FIELD(dir, layout, stripe_count), 42262306a36Sopenharmony_ci XATTR_LAYOUT_FIELD(dir, layout, object_size), 42362306a36Sopenharmony_ci XATTR_LAYOUT_FIELD(dir, layout, pool), 42462306a36Sopenharmony_ci XATTR_LAYOUT_FIELD(dir, layout, pool_namespace), 42562306a36Sopenharmony_ci XATTR_NAME_CEPH(dir, entries, VXATTR_FLAG_DIRSTAT), 42662306a36Sopenharmony_ci XATTR_NAME_CEPH(dir, files, VXATTR_FLAG_DIRSTAT), 42762306a36Sopenharmony_ci XATTR_NAME_CEPH(dir, subdirs, VXATTR_FLAG_DIRSTAT), 42862306a36Sopenharmony_ci XATTR_RSTAT_FIELD(dir, rentries), 42962306a36Sopenharmony_ci XATTR_RSTAT_FIELD(dir, rfiles), 43062306a36Sopenharmony_ci XATTR_RSTAT_FIELD(dir, rsubdirs), 43162306a36Sopenharmony_ci XATTR_RSTAT_FIELD(dir, rsnaps), 43262306a36Sopenharmony_ci XATTR_RSTAT_FIELD(dir, rbytes), 43362306a36Sopenharmony_ci XATTR_RSTAT_FIELD_UPDATABLE(dir, rctime), 43462306a36Sopenharmony_ci { 43562306a36Sopenharmony_ci .name = "ceph.dir.pin", 43662306a36Sopenharmony_ci .name_size = sizeof("ceph.dir.pin"), 43762306a36Sopenharmony_ci .getxattr_cb = ceph_vxattrcb_dir_pin, 43862306a36Sopenharmony_ci .exists_cb = ceph_vxattrcb_dir_pin_exists, 43962306a36Sopenharmony_ci .flags = VXATTR_FLAG_HIDDEN, 44062306a36Sopenharmony_ci }, 44162306a36Sopenharmony_ci { 44262306a36Sopenharmony_ci .name = "ceph.quota", 44362306a36Sopenharmony_ci .name_size = sizeof("ceph.quota"), 44462306a36Sopenharmony_ci .getxattr_cb = ceph_vxattrcb_quota, 44562306a36Sopenharmony_ci .exists_cb = ceph_vxattrcb_quota_exists, 44662306a36Sopenharmony_ci .flags = VXATTR_FLAG_HIDDEN, 44762306a36Sopenharmony_ci }, 44862306a36Sopenharmony_ci XATTR_QUOTA_FIELD(quota, max_bytes), 44962306a36Sopenharmony_ci XATTR_QUOTA_FIELD(quota, max_files), 45062306a36Sopenharmony_ci { 45162306a36Sopenharmony_ci .name = "ceph.snap.btime", 45262306a36Sopenharmony_ci .name_size = sizeof("ceph.snap.btime"), 45362306a36Sopenharmony_ci .getxattr_cb = ceph_vxattrcb_snap_btime, 45462306a36Sopenharmony_ci .exists_cb = ceph_vxattrcb_snap_btime_exists, 45562306a36Sopenharmony_ci .flags = VXATTR_FLAG_READONLY, 45662306a36Sopenharmony_ci }, 45762306a36Sopenharmony_ci { 45862306a36Sopenharmony_ci .name = "ceph.caps", 45962306a36Sopenharmony_ci .name_size = sizeof("ceph.caps"), 46062306a36Sopenharmony_ci .getxattr_cb = ceph_vxattrcb_caps, 46162306a36Sopenharmony_ci .exists_cb = NULL, 46262306a36Sopenharmony_ci .flags = VXATTR_FLAG_HIDDEN, 46362306a36Sopenharmony_ci }, 46462306a36Sopenharmony_ci { .name = NULL, 0 } /* Required table terminator */ 46562306a36Sopenharmony_ci}; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci/* files */ 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic struct ceph_vxattr ceph_file_vxattrs[] = { 47062306a36Sopenharmony_ci { 47162306a36Sopenharmony_ci .name = "ceph.file.layout", 47262306a36Sopenharmony_ci .name_size = sizeof("ceph.file.layout"), 47362306a36Sopenharmony_ci .getxattr_cb = ceph_vxattrcb_layout, 47462306a36Sopenharmony_ci .exists_cb = ceph_vxattrcb_layout_exists, 47562306a36Sopenharmony_ci .flags = VXATTR_FLAG_HIDDEN, 47662306a36Sopenharmony_ci }, 47762306a36Sopenharmony_ci XATTR_LAYOUT_FIELD(file, layout, stripe_unit), 47862306a36Sopenharmony_ci XATTR_LAYOUT_FIELD(file, layout, stripe_count), 47962306a36Sopenharmony_ci XATTR_LAYOUT_FIELD(file, layout, object_size), 48062306a36Sopenharmony_ci XATTR_LAYOUT_FIELD(file, layout, pool), 48162306a36Sopenharmony_ci XATTR_LAYOUT_FIELD(file, layout, pool_namespace), 48262306a36Sopenharmony_ci { 48362306a36Sopenharmony_ci .name = "ceph.snap.btime", 48462306a36Sopenharmony_ci .name_size = sizeof("ceph.snap.btime"), 48562306a36Sopenharmony_ci .getxattr_cb = ceph_vxattrcb_snap_btime, 48662306a36Sopenharmony_ci .exists_cb = ceph_vxattrcb_snap_btime_exists, 48762306a36Sopenharmony_ci .flags = VXATTR_FLAG_READONLY, 48862306a36Sopenharmony_ci }, 48962306a36Sopenharmony_ci { 49062306a36Sopenharmony_ci .name = "ceph.caps", 49162306a36Sopenharmony_ci .name_size = sizeof("ceph.caps"), 49262306a36Sopenharmony_ci .getxattr_cb = ceph_vxattrcb_caps, 49362306a36Sopenharmony_ci .exists_cb = NULL, 49462306a36Sopenharmony_ci .flags = VXATTR_FLAG_HIDDEN, 49562306a36Sopenharmony_ci }, 49662306a36Sopenharmony_ci { .name = NULL, 0 } /* Required table terminator */ 49762306a36Sopenharmony_ci}; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic struct ceph_vxattr ceph_common_vxattrs[] = { 50062306a36Sopenharmony_ci { 50162306a36Sopenharmony_ci .name = "ceph.cluster_fsid", 50262306a36Sopenharmony_ci .name_size = sizeof("ceph.cluster_fsid"), 50362306a36Sopenharmony_ci .getxattr_cb = ceph_vxattrcb_cluster_fsid, 50462306a36Sopenharmony_ci .exists_cb = NULL, 50562306a36Sopenharmony_ci .flags = VXATTR_FLAG_READONLY, 50662306a36Sopenharmony_ci }, 50762306a36Sopenharmony_ci { 50862306a36Sopenharmony_ci .name = "ceph.client_id", 50962306a36Sopenharmony_ci .name_size = sizeof("ceph.client_id"), 51062306a36Sopenharmony_ci .getxattr_cb = ceph_vxattrcb_client_id, 51162306a36Sopenharmony_ci .exists_cb = NULL, 51262306a36Sopenharmony_ci .flags = VXATTR_FLAG_READONLY, 51362306a36Sopenharmony_ci }, 51462306a36Sopenharmony_ci { 51562306a36Sopenharmony_ci .name = "ceph.auth_mds", 51662306a36Sopenharmony_ci .name_size = sizeof("ceph.auth_mds"), 51762306a36Sopenharmony_ci .getxattr_cb = ceph_vxattrcb_auth_mds, 51862306a36Sopenharmony_ci .exists_cb = NULL, 51962306a36Sopenharmony_ci .flags = VXATTR_FLAG_READONLY, 52062306a36Sopenharmony_ci }, 52162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_FS_ENCRYPTION) 52262306a36Sopenharmony_ci { 52362306a36Sopenharmony_ci .name = "ceph.fscrypt.auth", 52462306a36Sopenharmony_ci .name_size = sizeof("ceph.fscrypt.auth"), 52562306a36Sopenharmony_ci .getxattr_cb = ceph_vxattrcb_fscrypt_auth, 52662306a36Sopenharmony_ci .exists_cb = ceph_vxattrcb_fscrypt_auth_exists, 52762306a36Sopenharmony_ci .flags = VXATTR_FLAG_READONLY, 52862306a36Sopenharmony_ci }, 52962306a36Sopenharmony_ci#endif /* CONFIG_FS_ENCRYPTION */ 53062306a36Sopenharmony_ci { .name = NULL, 0 } /* Required table terminator */ 53162306a36Sopenharmony_ci}; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic struct ceph_vxattr *ceph_inode_vxattrs(struct inode *inode) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci if (S_ISDIR(inode->i_mode)) 53662306a36Sopenharmony_ci return ceph_dir_vxattrs; 53762306a36Sopenharmony_ci else if (S_ISREG(inode->i_mode)) 53862306a36Sopenharmony_ci return ceph_file_vxattrs; 53962306a36Sopenharmony_ci return NULL; 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_cistatic struct ceph_vxattr *ceph_match_vxattr(struct inode *inode, 54362306a36Sopenharmony_ci const char *name) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci struct ceph_vxattr *vxattr = ceph_inode_vxattrs(inode); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (vxattr) { 54862306a36Sopenharmony_ci while (vxattr->name) { 54962306a36Sopenharmony_ci if (!strcmp(vxattr->name, name)) 55062306a36Sopenharmony_ci return vxattr; 55162306a36Sopenharmony_ci vxattr++; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci vxattr = ceph_common_vxattrs; 55662306a36Sopenharmony_ci while (vxattr->name) { 55762306a36Sopenharmony_ci if (!strcmp(vxattr->name, name)) 55862306a36Sopenharmony_ci return vxattr; 55962306a36Sopenharmony_ci vxattr++; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci return NULL; 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci#define MAX_XATTR_VAL_PRINT_LEN 256 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cistatic int __set_xattr(struct ceph_inode_info *ci, 56862306a36Sopenharmony_ci const char *name, int name_len, 56962306a36Sopenharmony_ci const char *val, int val_len, 57062306a36Sopenharmony_ci int flags, int update_xattr, 57162306a36Sopenharmony_ci struct ceph_inode_xattr **newxattr) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci struct rb_node **p; 57462306a36Sopenharmony_ci struct rb_node *parent = NULL; 57562306a36Sopenharmony_ci struct ceph_inode_xattr *xattr = NULL; 57662306a36Sopenharmony_ci int c; 57762306a36Sopenharmony_ci int new = 0; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci p = &ci->i_xattrs.index.rb_node; 58062306a36Sopenharmony_ci while (*p) { 58162306a36Sopenharmony_ci parent = *p; 58262306a36Sopenharmony_ci xattr = rb_entry(parent, struct ceph_inode_xattr, node); 58362306a36Sopenharmony_ci c = strncmp(name, xattr->name, min(name_len, xattr->name_len)); 58462306a36Sopenharmony_ci if (c < 0) 58562306a36Sopenharmony_ci p = &(*p)->rb_left; 58662306a36Sopenharmony_ci else if (c > 0) 58762306a36Sopenharmony_ci p = &(*p)->rb_right; 58862306a36Sopenharmony_ci else { 58962306a36Sopenharmony_ci if (name_len == xattr->name_len) 59062306a36Sopenharmony_ci break; 59162306a36Sopenharmony_ci else if (name_len < xattr->name_len) 59262306a36Sopenharmony_ci p = &(*p)->rb_left; 59362306a36Sopenharmony_ci else 59462306a36Sopenharmony_ci p = &(*p)->rb_right; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci xattr = NULL; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci if (update_xattr) { 60062306a36Sopenharmony_ci int err = 0; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci if (xattr && (flags & XATTR_CREATE)) 60362306a36Sopenharmony_ci err = -EEXIST; 60462306a36Sopenharmony_ci else if (!xattr && (flags & XATTR_REPLACE)) 60562306a36Sopenharmony_ci err = -ENODATA; 60662306a36Sopenharmony_ci if (err) { 60762306a36Sopenharmony_ci kfree(name); 60862306a36Sopenharmony_ci kfree(val); 60962306a36Sopenharmony_ci kfree(*newxattr); 61062306a36Sopenharmony_ci return err; 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci if (update_xattr < 0) { 61362306a36Sopenharmony_ci if (xattr) 61462306a36Sopenharmony_ci __remove_xattr(ci, xattr); 61562306a36Sopenharmony_ci kfree(name); 61662306a36Sopenharmony_ci kfree(*newxattr); 61762306a36Sopenharmony_ci return 0; 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci if (!xattr) { 62262306a36Sopenharmony_ci new = 1; 62362306a36Sopenharmony_ci xattr = *newxattr; 62462306a36Sopenharmony_ci xattr->name = name; 62562306a36Sopenharmony_ci xattr->name_len = name_len; 62662306a36Sopenharmony_ci xattr->should_free_name = update_xattr; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci ci->i_xattrs.count++; 62962306a36Sopenharmony_ci dout("%s count=%d\n", __func__, ci->i_xattrs.count); 63062306a36Sopenharmony_ci } else { 63162306a36Sopenharmony_ci kfree(*newxattr); 63262306a36Sopenharmony_ci *newxattr = NULL; 63362306a36Sopenharmony_ci if (xattr->should_free_val) 63462306a36Sopenharmony_ci kfree(xattr->val); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (update_xattr) { 63762306a36Sopenharmony_ci kfree(name); 63862306a36Sopenharmony_ci name = xattr->name; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci ci->i_xattrs.names_size -= xattr->name_len; 64162306a36Sopenharmony_ci ci->i_xattrs.vals_size -= xattr->val_len; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci ci->i_xattrs.names_size += name_len; 64462306a36Sopenharmony_ci ci->i_xattrs.vals_size += val_len; 64562306a36Sopenharmony_ci if (val) 64662306a36Sopenharmony_ci xattr->val = val; 64762306a36Sopenharmony_ci else 64862306a36Sopenharmony_ci xattr->val = ""; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci xattr->val_len = val_len; 65162306a36Sopenharmony_ci xattr->dirty = update_xattr; 65262306a36Sopenharmony_ci xattr->should_free_val = (val && update_xattr); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci if (new) { 65562306a36Sopenharmony_ci rb_link_node(&xattr->node, parent, p); 65662306a36Sopenharmony_ci rb_insert_color(&xattr->node, &ci->i_xattrs.index); 65762306a36Sopenharmony_ci dout("%s p=%p\n", __func__, p); 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci dout("%s added %llx.%llx xattr %p %.*s=%.*s%s\n", __func__, 66162306a36Sopenharmony_ci ceph_vinop(&ci->netfs.inode), xattr, name_len, name, 66262306a36Sopenharmony_ci min(val_len, MAX_XATTR_VAL_PRINT_LEN), val, 66362306a36Sopenharmony_ci val_len > MAX_XATTR_VAL_PRINT_LEN ? "..." : ""); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci return 0; 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic struct ceph_inode_xattr *__get_xattr(struct ceph_inode_info *ci, 66962306a36Sopenharmony_ci const char *name) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci struct rb_node **p; 67262306a36Sopenharmony_ci struct rb_node *parent = NULL; 67362306a36Sopenharmony_ci struct ceph_inode_xattr *xattr = NULL; 67462306a36Sopenharmony_ci int name_len = strlen(name); 67562306a36Sopenharmony_ci int c; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci p = &ci->i_xattrs.index.rb_node; 67862306a36Sopenharmony_ci while (*p) { 67962306a36Sopenharmony_ci parent = *p; 68062306a36Sopenharmony_ci xattr = rb_entry(parent, struct ceph_inode_xattr, node); 68162306a36Sopenharmony_ci c = strncmp(name, xattr->name, xattr->name_len); 68262306a36Sopenharmony_ci if (c == 0 && name_len > xattr->name_len) 68362306a36Sopenharmony_ci c = 1; 68462306a36Sopenharmony_ci if (c < 0) 68562306a36Sopenharmony_ci p = &(*p)->rb_left; 68662306a36Sopenharmony_ci else if (c > 0) 68762306a36Sopenharmony_ci p = &(*p)->rb_right; 68862306a36Sopenharmony_ci else { 68962306a36Sopenharmony_ci int len = min(xattr->val_len, MAX_XATTR_VAL_PRINT_LEN); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci dout("%s %s: found %.*s%s\n", __func__, name, len, 69262306a36Sopenharmony_ci xattr->val, xattr->val_len > len ? "..." : ""); 69362306a36Sopenharmony_ci return xattr; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci dout("%s %s: not found\n", __func__, name); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci return NULL; 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cistatic void __free_xattr(struct ceph_inode_xattr *xattr) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci BUG_ON(!xattr); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (xattr->should_free_name) 70762306a36Sopenharmony_ci kfree(xattr->name); 70862306a36Sopenharmony_ci if (xattr->should_free_val) 70962306a36Sopenharmony_ci kfree(xattr->val); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci kfree(xattr); 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_cistatic int __remove_xattr(struct ceph_inode_info *ci, 71562306a36Sopenharmony_ci struct ceph_inode_xattr *xattr) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci if (!xattr) 71862306a36Sopenharmony_ci return -ENODATA; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci rb_erase(&xattr->node, &ci->i_xattrs.index); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci if (xattr->should_free_name) 72362306a36Sopenharmony_ci kfree(xattr->name); 72462306a36Sopenharmony_ci if (xattr->should_free_val) 72562306a36Sopenharmony_ci kfree(xattr->val); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci ci->i_xattrs.names_size -= xattr->name_len; 72862306a36Sopenharmony_ci ci->i_xattrs.vals_size -= xattr->val_len; 72962306a36Sopenharmony_ci ci->i_xattrs.count--; 73062306a36Sopenharmony_ci kfree(xattr); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci return 0; 73362306a36Sopenharmony_ci} 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_cistatic char *__copy_xattr_names(struct ceph_inode_info *ci, 73662306a36Sopenharmony_ci char *dest) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci struct rb_node *p; 73962306a36Sopenharmony_ci struct ceph_inode_xattr *xattr = NULL; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci p = rb_first(&ci->i_xattrs.index); 74262306a36Sopenharmony_ci dout("__copy_xattr_names count=%d\n", ci->i_xattrs.count); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci while (p) { 74562306a36Sopenharmony_ci xattr = rb_entry(p, struct ceph_inode_xattr, node); 74662306a36Sopenharmony_ci memcpy(dest, xattr->name, xattr->name_len); 74762306a36Sopenharmony_ci dest[xattr->name_len] = '\0'; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci dout("dest=%s %p (%s) (%d/%d)\n", dest, xattr, xattr->name, 75062306a36Sopenharmony_ci xattr->name_len, ci->i_xattrs.names_size); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci dest += xattr->name_len + 1; 75362306a36Sopenharmony_ci p = rb_next(p); 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci return dest; 75762306a36Sopenharmony_ci} 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_civoid __ceph_destroy_xattrs(struct ceph_inode_info *ci) 76062306a36Sopenharmony_ci{ 76162306a36Sopenharmony_ci struct rb_node *p, *tmp; 76262306a36Sopenharmony_ci struct ceph_inode_xattr *xattr = NULL; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci p = rb_first(&ci->i_xattrs.index); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci dout("__ceph_destroy_xattrs p=%p\n", p); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci while (p) { 76962306a36Sopenharmony_ci xattr = rb_entry(p, struct ceph_inode_xattr, node); 77062306a36Sopenharmony_ci tmp = p; 77162306a36Sopenharmony_ci p = rb_next(tmp); 77262306a36Sopenharmony_ci dout("__ceph_destroy_xattrs next p=%p (%.*s)\n", p, 77362306a36Sopenharmony_ci xattr->name_len, xattr->name); 77462306a36Sopenharmony_ci rb_erase(tmp, &ci->i_xattrs.index); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci __free_xattr(xattr); 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci ci->i_xattrs.names_size = 0; 78062306a36Sopenharmony_ci ci->i_xattrs.vals_size = 0; 78162306a36Sopenharmony_ci ci->i_xattrs.index_version = 0; 78262306a36Sopenharmony_ci ci->i_xattrs.count = 0; 78362306a36Sopenharmony_ci ci->i_xattrs.index = RB_ROOT; 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_cistatic int __build_xattrs(struct inode *inode) 78762306a36Sopenharmony_ci __releases(ci->i_ceph_lock) 78862306a36Sopenharmony_ci __acquires(ci->i_ceph_lock) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci u32 namelen; 79162306a36Sopenharmony_ci u32 numattr = 0; 79262306a36Sopenharmony_ci void *p, *end; 79362306a36Sopenharmony_ci u32 len; 79462306a36Sopenharmony_ci const char *name, *val; 79562306a36Sopenharmony_ci struct ceph_inode_info *ci = ceph_inode(inode); 79662306a36Sopenharmony_ci u64 xattr_version; 79762306a36Sopenharmony_ci struct ceph_inode_xattr **xattrs = NULL; 79862306a36Sopenharmony_ci int err = 0; 79962306a36Sopenharmony_ci int i; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci dout("__build_xattrs() len=%d\n", 80262306a36Sopenharmony_ci ci->i_xattrs.blob ? (int)ci->i_xattrs.blob->vec.iov_len : 0); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci if (ci->i_xattrs.index_version >= ci->i_xattrs.version) 80562306a36Sopenharmony_ci return 0; /* already built */ 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci __ceph_destroy_xattrs(ci); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_cistart: 81062306a36Sopenharmony_ci /* updated internal xattr rb tree */ 81162306a36Sopenharmony_ci if (ci->i_xattrs.blob && ci->i_xattrs.blob->vec.iov_len > 4) { 81262306a36Sopenharmony_ci p = ci->i_xattrs.blob->vec.iov_base; 81362306a36Sopenharmony_ci end = p + ci->i_xattrs.blob->vec.iov_len; 81462306a36Sopenharmony_ci ceph_decode_32_safe(&p, end, numattr, bad); 81562306a36Sopenharmony_ci xattr_version = ci->i_xattrs.version; 81662306a36Sopenharmony_ci spin_unlock(&ci->i_ceph_lock); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci xattrs = kcalloc(numattr, sizeof(struct ceph_inode_xattr *), 81962306a36Sopenharmony_ci GFP_NOFS); 82062306a36Sopenharmony_ci err = -ENOMEM; 82162306a36Sopenharmony_ci if (!xattrs) 82262306a36Sopenharmony_ci goto bad_lock; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci for (i = 0; i < numattr; i++) { 82562306a36Sopenharmony_ci xattrs[i] = kmalloc(sizeof(struct ceph_inode_xattr), 82662306a36Sopenharmony_ci GFP_NOFS); 82762306a36Sopenharmony_ci if (!xattrs[i]) 82862306a36Sopenharmony_ci goto bad_lock; 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci spin_lock(&ci->i_ceph_lock); 83262306a36Sopenharmony_ci if (ci->i_xattrs.version != xattr_version) { 83362306a36Sopenharmony_ci /* lost a race, retry */ 83462306a36Sopenharmony_ci for (i = 0; i < numattr; i++) 83562306a36Sopenharmony_ci kfree(xattrs[i]); 83662306a36Sopenharmony_ci kfree(xattrs); 83762306a36Sopenharmony_ci xattrs = NULL; 83862306a36Sopenharmony_ci goto start; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci err = -EIO; 84162306a36Sopenharmony_ci while (numattr--) { 84262306a36Sopenharmony_ci ceph_decode_32_safe(&p, end, len, bad); 84362306a36Sopenharmony_ci namelen = len; 84462306a36Sopenharmony_ci name = p; 84562306a36Sopenharmony_ci p += len; 84662306a36Sopenharmony_ci ceph_decode_32_safe(&p, end, len, bad); 84762306a36Sopenharmony_ci val = p; 84862306a36Sopenharmony_ci p += len; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci err = __set_xattr(ci, name, namelen, val, len, 85162306a36Sopenharmony_ci 0, 0, &xattrs[numattr]); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if (err < 0) 85462306a36Sopenharmony_ci goto bad; 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci kfree(xattrs); 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci ci->i_xattrs.index_version = ci->i_xattrs.version; 85962306a36Sopenharmony_ci ci->i_xattrs.dirty = false; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci return err; 86262306a36Sopenharmony_cibad_lock: 86362306a36Sopenharmony_ci spin_lock(&ci->i_ceph_lock); 86462306a36Sopenharmony_cibad: 86562306a36Sopenharmony_ci if (xattrs) { 86662306a36Sopenharmony_ci for (i = 0; i < numattr; i++) 86762306a36Sopenharmony_ci kfree(xattrs[i]); 86862306a36Sopenharmony_ci kfree(xattrs); 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci ci->i_xattrs.names_size = 0; 87162306a36Sopenharmony_ci return err; 87262306a36Sopenharmony_ci} 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_cistatic int __get_required_blob_size(struct ceph_inode_info *ci, int name_size, 87562306a36Sopenharmony_ci int val_size) 87662306a36Sopenharmony_ci{ 87762306a36Sopenharmony_ci /* 87862306a36Sopenharmony_ci * 4 bytes for the length, and additional 4 bytes per each xattr name, 87962306a36Sopenharmony_ci * 4 bytes per each value 88062306a36Sopenharmony_ci */ 88162306a36Sopenharmony_ci int size = 4 + ci->i_xattrs.count*(4 + 4) + 88262306a36Sopenharmony_ci ci->i_xattrs.names_size + 88362306a36Sopenharmony_ci ci->i_xattrs.vals_size; 88462306a36Sopenharmony_ci dout("__get_required_blob_size c=%d names.size=%d vals.size=%d\n", 88562306a36Sopenharmony_ci ci->i_xattrs.count, ci->i_xattrs.names_size, 88662306a36Sopenharmony_ci ci->i_xattrs.vals_size); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci if (name_size) 88962306a36Sopenharmony_ci size += 4 + 4 + name_size + val_size; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci return size; 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci/* 89562306a36Sopenharmony_ci * If there are dirty xattrs, reencode xattrs into the prealloc_blob 89662306a36Sopenharmony_ci * and swap into place. It returns the old i_xattrs.blob (or NULL) so 89762306a36Sopenharmony_ci * that it can be freed by the caller as the i_ceph_lock is likely to be 89862306a36Sopenharmony_ci * held. 89962306a36Sopenharmony_ci */ 90062306a36Sopenharmony_cistruct ceph_buffer *__ceph_build_xattrs_blob(struct ceph_inode_info *ci) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci struct rb_node *p; 90362306a36Sopenharmony_ci struct ceph_inode_xattr *xattr = NULL; 90462306a36Sopenharmony_ci struct ceph_buffer *old_blob = NULL; 90562306a36Sopenharmony_ci void *dest; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci dout("__build_xattrs_blob %p\n", &ci->netfs.inode); 90862306a36Sopenharmony_ci if (ci->i_xattrs.dirty) { 90962306a36Sopenharmony_ci int need = __get_required_blob_size(ci, 0, 0); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci BUG_ON(need > ci->i_xattrs.prealloc_blob->alloc_len); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci p = rb_first(&ci->i_xattrs.index); 91462306a36Sopenharmony_ci dest = ci->i_xattrs.prealloc_blob->vec.iov_base; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci ceph_encode_32(&dest, ci->i_xattrs.count); 91762306a36Sopenharmony_ci while (p) { 91862306a36Sopenharmony_ci xattr = rb_entry(p, struct ceph_inode_xattr, node); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci ceph_encode_32(&dest, xattr->name_len); 92162306a36Sopenharmony_ci memcpy(dest, xattr->name, xattr->name_len); 92262306a36Sopenharmony_ci dest += xattr->name_len; 92362306a36Sopenharmony_ci ceph_encode_32(&dest, xattr->val_len); 92462306a36Sopenharmony_ci memcpy(dest, xattr->val, xattr->val_len); 92562306a36Sopenharmony_ci dest += xattr->val_len; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci p = rb_next(p); 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci /* adjust buffer len; it may be larger than we need */ 93162306a36Sopenharmony_ci ci->i_xattrs.prealloc_blob->vec.iov_len = 93262306a36Sopenharmony_ci dest - ci->i_xattrs.prealloc_blob->vec.iov_base; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci if (ci->i_xattrs.blob) 93562306a36Sopenharmony_ci old_blob = ci->i_xattrs.blob; 93662306a36Sopenharmony_ci ci->i_xattrs.blob = ci->i_xattrs.prealloc_blob; 93762306a36Sopenharmony_ci ci->i_xattrs.prealloc_blob = NULL; 93862306a36Sopenharmony_ci ci->i_xattrs.dirty = false; 93962306a36Sopenharmony_ci ci->i_xattrs.version++; 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci return old_blob; 94362306a36Sopenharmony_ci} 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_cistatic inline int __get_request_mask(struct inode *in) { 94662306a36Sopenharmony_ci struct ceph_mds_request *req = current->journal_info; 94762306a36Sopenharmony_ci int mask = 0; 94862306a36Sopenharmony_ci if (req && req->r_target_inode == in) { 94962306a36Sopenharmony_ci if (req->r_op == CEPH_MDS_OP_LOOKUP || 95062306a36Sopenharmony_ci req->r_op == CEPH_MDS_OP_LOOKUPINO || 95162306a36Sopenharmony_ci req->r_op == CEPH_MDS_OP_LOOKUPPARENT || 95262306a36Sopenharmony_ci req->r_op == CEPH_MDS_OP_GETATTR) { 95362306a36Sopenharmony_ci mask = le32_to_cpu(req->r_args.getattr.mask); 95462306a36Sopenharmony_ci } else if (req->r_op == CEPH_MDS_OP_OPEN || 95562306a36Sopenharmony_ci req->r_op == CEPH_MDS_OP_CREATE) { 95662306a36Sopenharmony_ci mask = le32_to_cpu(req->r_args.open.mask); 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci } 95962306a36Sopenharmony_ci return mask; 96062306a36Sopenharmony_ci} 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_cissize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, 96362306a36Sopenharmony_ci size_t size) 96462306a36Sopenharmony_ci{ 96562306a36Sopenharmony_ci struct ceph_inode_info *ci = ceph_inode(inode); 96662306a36Sopenharmony_ci struct ceph_inode_xattr *xattr; 96762306a36Sopenharmony_ci struct ceph_vxattr *vxattr; 96862306a36Sopenharmony_ci int req_mask; 96962306a36Sopenharmony_ci ssize_t err; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci if (strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN)) 97262306a36Sopenharmony_ci goto handle_non_vxattrs; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci /* let's see if a virtual xattr was requested */ 97562306a36Sopenharmony_ci vxattr = ceph_match_vxattr(inode, name); 97662306a36Sopenharmony_ci if (vxattr) { 97762306a36Sopenharmony_ci int mask = 0; 97862306a36Sopenharmony_ci if (vxattr->flags & VXATTR_FLAG_RSTAT) 97962306a36Sopenharmony_ci mask |= CEPH_STAT_RSTAT; 98062306a36Sopenharmony_ci if (vxattr->flags & VXATTR_FLAG_DIRSTAT) 98162306a36Sopenharmony_ci mask |= CEPH_CAP_FILE_SHARED; 98262306a36Sopenharmony_ci err = ceph_do_getattr(inode, mask, true); 98362306a36Sopenharmony_ci if (err) 98462306a36Sopenharmony_ci return err; 98562306a36Sopenharmony_ci err = -ENODATA; 98662306a36Sopenharmony_ci if (!(vxattr->exists_cb && !vxattr->exists_cb(ci))) { 98762306a36Sopenharmony_ci err = vxattr->getxattr_cb(ci, value, size); 98862306a36Sopenharmony_ci if (size && size < err) 98962306a36Sopenharmony_ci err = -ERANGE; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci return err; 99262306a36Sopenharmony_ci } else { 99362306a36Sopenharmony_ci err = ceph_do_getvxattr(inode, name, value, size); 99462306a36Sopenharmony_ci /* this would happen with a new client and old server combo */ 99562306a36Sopenharmony_ci if (err == -EOPNOTSUPP) 99662306a36Sopenharmony_ci err = -ENODATA; 99762306a36Sopenharmony_ci return err; 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_cihandle_non_vxattrs: 100062306a36Sopenharmony_ci req_mask = __get_request_mask(inode); 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci spin_lock(&ci->i_ceph_lock); 100362306a36Sopenharmony_ci dout("getxattr %p name '%s' ver=%lld index_ver=%lld\n", inode, name, 100462306a36Sopenharmony_ci ci->i_xattrs.version, ci->i_xattrs.index_version); 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci if (ci->i_xattrs.version == 0 || 100762306a36Sopenharmony_ci !((req_mask & CEPH_CAP_XATTR_SHARED) || 100862306a36Sopenharmony_ci __ceph_caps_issued_mask_metric(ci, CEPH_CAP_XATTR_SHARED, 1))) { 100962306a36Sopenharmony_ci spin_unlock(&ci->i_ceph_lock); 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci /* security module gets xattr while filling trace */ 101262306a36Sopenharmony_ci if (current->journal_info) { 101362306a36Sopenharmony_ci pr_warn_ratelimited("sync getxattr %p " 101462306a36Sopenharmony_ci "during filling trace\n", inode); 101562306a36Sopenharmony_ci return -EBUSY; 101662306a36Sopenharmony_ci } 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci /* get xattrs from mds (if we don't already have them) */ 101962306a36Sopenharmony_ci err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR, true); 102062306a36Sopenharmony_ci if (err) 102162306a36Sopenharmony_ci return err; 102262306a36Sopenharmony_ci spin_lock(&ci->i_ceph_lock); 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci err = __build_xattrs(inode); 102662306a36Sopenharmony_ci if (err < 0) 102762306a36Sopenharmony_ci goto out; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci err = -ENODATA; /* == ENOATTR */ 103062306a36Sopenharmony_ci xattr = __get_xattr(ci, name); 103162306a36Sopenharmony_ci if (!xattr) 103262306a36Sopenharmony_ci goto out; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci err = -ERANGE; 103562306a36Sopenharmony_ci if (size && size < xattr->val_len) 103662306a36Sopenharmony_ci goto out; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci err = xattr->val_len; 103962306a36Sopenharmony_ci if (size == 0) 104062306a36Sopenharmony_ci goto out; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci memcpy(value, xattr->val, xattr->val_len); 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci if (current->journal_info && 104562306a36Sopenharmony_ci !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && 104662306a36Sopenharmony_ci security_ismaclabel(name + XATTR_SECURITY_PREFIX_LEN)) 104762306a36Sopenharmony_ci ci->i_ceph_flags |= CEPH_I_SEC_INITED; 104862306a36Sopenharmony_ciout: 104962306a36Sopenharmony_ci spin_unlock(&ci->i_ceph_lock); 105062306a36Sopenharmony_ci return err; 105162306a36Sopenharmony_ci} 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_cissize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size) 105462306a36Sopenharmony_ci{ 105562306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 105662306a36Sopenharmony_ci struct ceph_inode_info *ci = ceph_inode(inode); 105762306a36Sopenharmony_ci bool len_only = (size == 0); 105862306a36Sopenharmony_ci u32 namelen; 105962306a36Sopenharmony_ci int err; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci spin_lock(&ci->i_ceph_lock); 106262306a36Sopenharmony_ci dout("listxattr %p ver=%lld index_ver=%lld\n", inode, 106362306a36Sopenharmony_ci ci->i_xattrs.version, ci->i_xattrs.index_version); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci if (ci->i_xattrs.version == 0 || 106662306a36Sopenharmony_ci !__ceph_caps_issued_mask_metric(ci, CEPH_CAP_XATTR_SHARED, 1)) { 106762306a36Sopenharmony_ci spin_unlock(&ci->i_ceph_lock); 106862306a36Sopenharmony_ci err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR, true); 106962306a36Sopenharmony_ci if (err) 107062306a36Sopenharmony_ci return err; 107162306a36Sopenharmony_ci spin_lock(&ci->i_ceph_lock); 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci err = __build_xattrs(inode); 107562306a36Sopenharmony_ci if (err < 0) 107662306a36Sopenharmony_ci goto out; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci /* add 1 byte for each xattr due to the null termination */ 107962306a36Sopenharmony_ci namelen = ci->i_xattrs.names_size + ci->i_xattrs.count; 108062306a36Sopenharmony_ci if (!len_only) { 108162306a36Sopenharmony_ci if (namelen > size) { 108262306a36Sopenharmony_ci err = -ERANGE; 108362306a36Sopenharmony_ci goto out; 108462306a36Sopenharmony_ci } 108562306a36Sopenharmony_ci names = __copy_xattr_names(ci, names); 108662306a36Sopenharmony_ci size -= namelen; 108762306a36Sopenharmony_ci } 108862306a36Sopenharmony_ci err = namelen; 108962306a36Sopenharmony_ciout: 109062306a36Sopenharmony_ci spin_unlock(&ci->i_ceph_lock); 109162306a36Sopenharmony_ci return err; 109262306a36Sopenharmony_ci} 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_cistatic int ceph_sync_setxattr(struct inode *inode, const char *name, 109562306a36Sopenharmony_ci const char *value, size_t size, int flags) 109662306a36Sopenharmony_ci{ 109762306a36Sopenharmony_ci struct ceph_fs_client *fsc = ceph_sb_to_client(inode->i_sb); 109862306a36Sopenharmony_ci struct ceph_inode_info *ci = ceph_inode(inode); 109962306a36Sopenharmony_ci struct ceph_mds_request *req; 110062306a36Sopenharmony_ci struct ceph_mds_client *mdsc = fsc->mdsc; 110162306a36Sopenharmony_ci struct ceph_osd_client *osdc = &fsc->client->osdc; 110262306a36Sopenharmony_ci struct ceph_pagelist *pagelist = NULL; 110362306a36Sopenharmony_ci int op = CEPH_MDS_OP_SETXATTR; 110462306a36Sopenharmony_ci int err; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci if (size > 0) { 110762306a36Sopenharmony_ci /* copy value into pagelist */ 110862306a36Sopenharmony_ci pagelist = ceph_pagelist_alloc(GFP_NOFS); 110962306a36Sopenharmony_ci if (!pagelist) 111062306a36Sopenharmony_ci return -ENOMEM; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci err = ceph_pagelist_append(pagelist, value, size); 111362306a36Sopenharmony_ci if (err) 111462306a36Sopenharmony_ci goto out; 111562306a36Sopenharmony_ci } else if (!value) { 111662306a36Sopenharmony_ci if (flags & CEPH_XATTR_REPLACE) 111762306a36Sopenharmony_ci op = CEPH_MDS_OP_RMXATTR; 111862306a36Sopenharmony_ci else 111962306a36Sopenharmony_ci flags |= CEPH_XATTR_REMOVE; 112062306a36Sopenharmony_ci } 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci dout("setxattr value size: %zu\n", size); 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci /* do request */ 112562306a36Sopenharmony_ci req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS); 112662306a36Sopenharmony_ci if (IS_ERR(req)) { 112762306a36Sopenharmony_ci err = PTR_ERR(req); 112862306a36Sopenharmony_ci goto out; 112962306a36Sopenharmony_ci } 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci req->r_path2 = kstrdup(name, GFP_NOFS); 113262306a36Sopenharmony_ci if (!req->r_path2) { 113362306a36Sopenharmony_ci ceph_mdsc_put_request(req); 113462306a36Sopenharmony_ci err = -ENOMEM; 113562306a36Sopenharmony_ci goto out; 113662306a36Sopenharmony_ci } 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci if (op == CEPH_MDS_OP_SETXATTR) { 113962306a36Sopenharmony_ci req->r_args.setxattr.flags = cpu_to_le32(flags); 114062306a36Sopenharmony_ci req->r_args.setxattr.osdmap_epoch = 114162306a36Sopenharmony_ci cpu_to_le32(osdc->osdmap->epoch); 114262306a36Sopenharmony_ci req->r_pagelist = pagelist; 114362306a36Sopenharmony_ci pagelist = NULL; 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci req->r_inode = inode; 114762306a36Sopenharmony_ci ihold(inode); 114862306a36Sopenharmony_ci req->r_num_caps = 1; 114962306a36Sopenharmony_ci req->r_inode_drop = CEPH_CAP_XATTR_SHARED; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci dout("xattr.ver (before): %lld\n", ci->i_xattrs.version); 115262306a36Sopenharmony_ci err = ceph_mdsc_do_request(mdsc, NULL, req); 115362306a36Sopenharmony_ci ceph_mdsc_put_request(req); 115462306a36Sopenharmony_ci dout("xattr.ver (after): %lld\n", ci->i_xattrs.version); 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ciout: 115762306a36Sopenharmony_ci if (pagelist) 115862306a36Sopenharmony_ci ceph_pagelist_release(pagelist); 115962306a36Sopenharmony_ci return err; 116062306a36Sopenharmony_ci} 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ciint __ceph_setxattr(struct inode *inode, const char *name, 116362306a36Sopenharmony_ci const void *value, size_t size, int flags) 116462306a36Sopenharmony_ci{ 116562306a36Sopenharmony_ci struct ceph_vxattr *vxattr; 116662306a36Sopenharmony_ci struct ceph_inode_info *ci = ceph_inode(inode); 116762306a36Sopenharmony_ci struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; 116862306a36Sopenharmony_ci struct ceph_cap_flush *prealloc_cf = NULL; 116962306a36Sopenharmony_ci struct ceph_buffer *old_blob = NULL; 117062306a36Sopenharmony_ci int issued; 117162306a36Sopenharmony_ci int err; 117262306a36Sopenharmony_ci int dirty = 0; 117362306a36Sopenharmony_ci int name_len = strlen(name); 117462306a36Sopenharmony_ci int val_len = size; 117562306a36Sopenharmony_ci char *newname = NULL; 117662306a36Sopenharmony_ci char *newval = NULL; 117762306a36Sopenharmony_ci struct ceph_inode_xattr *xattr = NULL; 117862306a36Sopenharmony_ci int required_blob_size; 117962306a36Sopenharmony_ci bool check_realm = false; 118062306a36Sopenharmony_ci bool lock_snap_rwsem = false; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci if (ceph_snap(inode) != CEPH_NOSNAP) 118362306a36Sopenharmony_ci return -EROFS; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci vxattr = ceph_match_vxattr(inode, name); 118662306a36Sopenharmony_ci if (vxattr) { 118762306a36Sopenharmony_ci if (vxattr->flags & VXATTR_FLAG_READONLY) 118862306a36Sopenharmony_ci return -EOPNOTSUPP; 118962306a36Sopenharmony_ci if (value && !strncmp(vxattr->name, "ceph.quota", 10)) 119062306a36Sopenharmony_ci check_realm = true; 119162306a36Sopenharmony_ci } 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci /* pass any unhandled ceph.* xattrs through to the MDS */ 119462306a36Sopenharmony_ci if (!strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN)) 119562306a36Sopenharmony_ci goto do_sync_unlocked; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci /* preallocate memory for xattr name, value, index node */ 119862306a36Sopenharmony_ci err = -ENOMEM; 119962306a36Sopenharmony_ci newname = kmemdup(name, name_len + 1, GFP_NOFS); 120062306a36Sopenharmony_ci if (!newname) 120162306a36Sopenharmony_ci goto out; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci if (val_len) { 120462306a36Sopenharmony_ci newval = kmemdup(value, val_len, GFP_NOFS); 120562306a36Sopenharmony_ci if (!newval) 120662306a36Sopenharmony_ci goto out; 120762306a36Sopenharmony_ci } 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci xattr = kmalloc(sizeof(struct ceph_inode_xattr), GFP_NOFS); 121062306a36Sopenharmony_ci if (!xattr) 121162306a36Sopenharmony_ci goto out; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci prealloc_cf = ceph_alloc_cap_flush(); 121462306a36Sopenharmony_ci if (!prealloc_cf) 121562306a36Sopenharmony_ci goto out; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci spin_lock(&ci->i_ceph_lock); 121862306a36Sopenharmony_ciretry: 121962306a36Sopenharmony_ci issued = __ceph_caps_issued(ci, NULL); 122062306a36Sopenharmony_ci required_blob_size = __get_required_blob_size(ci, name_len, val_len); 122162306a36Sopenharmony_ci if ((ci->i_xattrs.version == 0) || !(issued & CEPH_CAP_XATTR_EXCL) || 122262306a36Sopenharmony_ci (required_blob_size > mdsc->mdsmap->m_max_xattr_size)) { 122362306a36Sopenharmony_ci dout("%s do sync setxattr: version: %llu size: %d max: %llu\n", 122462306a36Sopenharmony_ci __func__, ci->i_xattrs.version, required_blob_size, 122562306a36Sopenharmony_ci mdsc->mdsmap->m_max_xattr_size); 122662306a36Sopenharmony_ci goto do_sync; 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci if (!lock_snap_rwsem && !ci->i_head_snapc) { 123062306a36Sopenharmony_ci lock_snap_rwsem = true; 123162306a36Sopenharmony_ci if (!down_read_trylock(&mdsc->snap_rwsem)) { 123262306a36Sopenharmony_ci spin_unlock(&ci->i_ceph_lock); 123362306a36Sopenharmony_ci down_read(&mdsc->snap_rwsem); 123462306a36Sopenharmony_ci spin_lock(&ci->i_ceph_lock); 123562306a36Sopenharmony_ci goto retry; 123662306a36Sopenharmony_ci } 123762306a36Sopenharmony_ci } 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci dout("setxattr %p name '%s' issued %s\n", inode, name, 124062306a36Sopenharmony_ci ceph_cap_string(issued)); 124162306a36Sopenharmony_ci __build_xattrs(inode); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci if (!ci->i_xattrs.prealloc_blob || 124462306a36Sopenharmony_ci required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) { 124562306a36Sopenharmony_ci struct ceph_buffer *blob; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci spin_unlock(&ci->i_ceph_lock); 124862306a36Sopenharmony_ci ceph_buffer_put(old_blob); /* Shouldn't be required */ 124962306a36Sopenharmony_ci dout(" pre-allocating new blob size=%d\n", required_blob_size); 125062306a36Sopenharmony_ci blob = ceph_buffer_new(required_blob_size, GFP_NOFS); 125162306a36Sopenharmony_ci if (!blob) 125262306a36Sopenharmony_ci goto do_sync_unlocked; 125362306a36Sopenharmony_ci spin_lock(&ci->i_ceph_lock); 125462306a36Sopenharmony_ci /* prealloc_blob can't be released while holding i_ceph_lock */ 125562306a36Sopenharmony_ci if (ci->i_xattrs.prealloc_blob) 125662306a36Sopenharmony_ci old_blob = ci->i_xattrs.prealloc_blob; 125762306a36Sopenharmony_ci ci->i_xattrs.prealloc_blob = blob; 125862306a36Sopenharmony_ci goto retry; 125962306a36Sopenharmony_ci } 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci err = __set_xattr(ci, newname, name_len, newval, val_len, 126262306a36Sopenharmony_ci flags, value ? 1 : -1, &xattr); 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci if (!err) { 126562306a36Sopenharmony_ci dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL, 126662306a36Sopenharmony_ci &prealloc_cf); 126762306a36Sopenharmony_ci ci->i_xattrs.dirty = true; 126862306a36Sopenharmony_ci inode_set_ctime_current(inode); 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci spin_unlock(&ci->i_ceph_lock); 127262306a36Sopenharmony_ci ceph_buffer_put(old_blob); 127362306a36Sopenharmony_ci if (lock_snap_rwsem) 127462306a36Sopenharmony_ci up_read(&mdsc->snap_rwsem); 127562306a36Sopenharmony_ci if (dirty) 127662306a36Sopenharmony_ci __mark_inode_dirty(inode, dirty); 127762306a36Sopenharmony_ci ceph_free_cap_flush(prealloc_cf); 127862306a36Sopenharmony_ci return err; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_cido_sync: 128162306a36Sopenharmony_ci spin_unlock(&ci->i_ceph_lock); 128262306a36Sopenharmony_cido_sync_unlocked: 128362306a36Sopenharmony_ci if (lock_snap_rwsem) 128462306a36Sopenharmony_ci up_read(&mdsc->snap_rwsem); 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci /* security module set xattr while filling trace */ 128762306a36Sopenharmony_ci if (current->journal_info) { 128862306a36Sopenharmony_ci pr_warn_ratelimited("sync setxattr %p " 128962306a36Sopenharmony_ci "during filling trace\n", inode); 129062306a36Sopenharmony_ci err = -EBUSY; 129162306a36Sopenharmony_ci } else { 129262306a36Sopenharmony_ci err = ceph_sync_setxattr(inode, name, value, size, flags); 129362306a36Sopenharmony_ci if (err >= 0 && check_realm) { 129462306a36Sopenharmony_ci /* check if snaprealm was created for quota inode */ 129562306a36Sopenharmony_ci spin_lock(&ci->i_ceph_lock); 129662306a36Sopenharmony_ci if ((ci->i_max_files || ci->i_max_bytes) && 129762306a36Sopenharmony_ci !(ci->i_snap_realm && 129862306a36Sopenharmony_ci ci->i_snap_realm->ino == ci->i_vino.ino)) 129962306a36Sopenharmony_ci err = -EOPNOTSUPP; 130062306a36Sopenharmony_ci spin_unlock(&ci->i_ceph_lock); 130162306a36Sopenharmony_ci } 130262306a36Sopenharmony_ci } 130362306a36Sopenharmony_ciout: 130462306a36Sopenharmony_ci ceph_free_cap_flush(prealloc_cf); 130562306a36Sopenharmony_ci kfree(newname); 130662306a36Sopenharmony_ci kfree(newval); 130762306a36Sopenharmony_ci kfree(xattr); 130862306a36Sopenharmony_ci return err; 130962306a36Sopenharmony_ci} 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_cistatic int ceph_get_xattr_handler(const struct xattr_handler *handler, 131262306a36Sopenharmony_ci struct dentry *dentry, struct inode *inode, 131362306a36Sopenharmony_ci const char *name, void *value, size_t size) 131462306a36Sopenharmony_ci{ 131562306a36Sopenharmony_ci if (!ceph_is_valid_xattr(name)) 131662306a36Sopenharmony_ci return -EOPNOTSUPP; 131762306a36Sopenharmony_ci return __ceph_getxattr(inode, name, value, size); 131862306a36Sopenharmony_ci} 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_cistatic int ceph_set_xattr_handler(const struct xattr_handler *handler, 132162306a36Sopenharmony_ci struct mnt_idmap *idmap, 132262306a36Sopenharmony_ci struct dentry *unused, struct inode *inode, 132362306a36Sopenharmony_ci const char *name, const void *value, 132462306a36Sopenharmony_ci size_t size, int flags) 132562306a36Sopenharmony_ci{ 132662306a36Sopenharmony_ci if (!ceph_is_valid_xattr(name)) 132762306a36Sopenharmony_ci return -EOPNOTSUPP; 132862306a36Sopenharmony_ci return __ceph_setxattr(inode, name, value, size, flags); 132962306a36Sopenharmony_ci} 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_cistatic const struct xattr_handler ceph_other_xattr_handler = { 133262306a36Sopenharmony_ci .prefix = "", /* match any name => handlers called with full name */ 133362306a36Sopenharmony_ci .get = ceph_get_xattr_handler, 133462306a36Sopenharmony_ci .set = ceph_set_xattr_handler, 133562306a36Sopenharmony_ci}; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci#ifdef CONFIG_SECURITY 133862306a36Sopenharmony_cibool ceph_security_xattr_wanted(struct inode *in) 133962306a36Sopenharmony_ci{ 134062306a36Sopenharmony_ci return in->i_security != NULL; 134162306a36Sopenharmony_ci} 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_cibool ceph_security_xattr_deadlock(struct inode *in) 134462306a36Sopenharmony_ci{ 134562306a36Sopenharmony_ci struct ceph_inode_info *ci; 134662306a36Sopenharmony_ci bool ret; 134762306a36Sopenharmony_ci if (!in->i_security) 134862306a36Sopenharmony_ci return false; 134962306a36Sopenharmony_ci ci = ceph_inode(in); 135062306a36Sopenharmony_ci spin_lock(&ci->i_ceph_lock); 135162306a36Sopenharmony_ci ret = !(ci->i_ceph_flags & CEPH_I_SEC_INITED) && 135262306a36Sopenharmony_ci !(ci->i_xattrs.version > 0 && 135362306a36Sopenharmony_ci __ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0)); 135462306a36Sopenharmony_ci spin_unlock(&ci->i_ceph_lock); 135562306a36Sopenharmony_ci return ret; 135662306a36Sopenharmony_ci} 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci#ifdef CONFIG_CEPH_FS_SECURITY_LABEL 135962306a36Sopenharmony_ciint ceph_security_init_secctx(struct dentry *dentry, umode_t mode, 136062306a36Sopenharmony_ci struct ceph_acl_sec_ctx *as_ctx) 136162306a36Sopenharmony_ci{ 136262306a36Sopenharmony_ci struct ceph_pagelist *pagelist = as_ctx->pagelist; 136362306a36Sopenharmony_ci const char *name; 136462306a36Sopenharmony_ci size_t name_len; 136562306a36Sopenharmony_ci int err; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci err = security_dentry_init_security(dentry, mode, &dentry->d_name, 136862306a36Sopenharmony_ci &name, &as_ctx->sec_ctx, 136962306a36Sopenharmony_ci &as_ctx->sec_ctxlen); 137062306a36Sopenharmony_ci if (err < 0) { 137162306a36Sopenharmony_ci WARN_ON_ONCE(err != -EOPNOTSUPP); 137262306a36Sopenharmony_ci err = 0; /* do nothing */ 137362306a36Sopenharmony_ci goto out; 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci err = -ENOMEM; 137762306a36Sopenharmony_ci if (!pagelist) { 137862306a36Sopenharmony_ci pagelist = ceph_pagelist_alloc(GFP_KERNEL); 137962306a36Sopenharmony_ci if (!pagelist) 138062306a36Sopenharmony_ci goto out; 138162306a36Sopenharmony_ci err = ceph_pagelist_reserve(pagelist, PAGE_SIZE); 138262306a36Sopenharmony_ci if (err) 138362306a36Sopenharmony_ci goto out; 138462306a36Sopenharmony_ci ceph_pagelist_encode_32(pagelist, 1); 138562306a36Sopenharmony_ci } 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci /* 138862306a36Sopenharmony_ci * FIXME: Make security_dentry_init_security() generic. Currently 138962306a36Sopenharmony_ci * It only supports single security module and only selinux has 139062306a36Sopenharmony_ci * dentry_init_security hook. 139162306a36Sopenharmony_ci */ 139262306a36Sopenharmony_ci name_len = strlen(name); 139362306a36Sopenharmony_ci err = ceph_pagelist_reserve(pagelist, 139462306a36Sopenharmony_ci 4 * 2 + name_len + as_ctx->sec_ctxlen); 139562306a36Sopenharmony_ci if (err) 139662306a36Sopenharmony_ci goto out; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci if (as_ctx->pagelist) { 139962306a36Sopenharmony_ci /* update count of KV pairs */ 140062306a36Sopenharmony_ci BUG_ON(pagelist->length <= sizeof(__le32)); 140162306a36Sopenharmony_ci if (list_is_singular(&pagelist->head)) { 140262306a36Sopenharmony_ci le32_add_cpu((__le32*)pagelist->mapped_tail, 1); 140362306a36Sopenharmony_ci } else { 140462306a36Sopenharmony_ci struct page *page = list_first_entry(&pagelist->head, 140562306a36Sopenharmony_ci struct page, lru); 140662306a36Sopenharmony_ci void *addr = kmap_atomic(page); 140762306a36Sopenharmony_ci le32_add_cpu((__le32*)addr, 1); 140862306a36Sopenharmony_ci kunmap_atomic(addr); 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci } else { 141162306a36Sopenharmony_ci as_ctx->pagelist = pagelist; 141262306a36Sopenharmony_ci } 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci ceph_pagelist_encode_32(pagelist, name_len); 141562306a36Sopenharmony_ci ceph_pagelist_append(pagelist, name, name_len); 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci ceph_pagelist_encode_32(pagelist, as_ctx->sec_ctxlen); 141862306a36Sopenharmony_ci ceph_pagelist_append(pagelist, as_ctx->sec_ctx, as_ctx->sec_ctxlen); 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci err = 0; 142162306a36Sopenharmony_ciout: 142262306a36Sopenharmony_ci if (pagelist && !as_ctx->pagelist) 142362306a36Sopenharmony_ci ceph_pagelist_release(pagelist); 142462306a36Sopenharmony_ci return err; 142562306a36Sopenharmony_ci} 142662306a36Sopenharmony_ci#endif /* CONFIG_CEPH_FS_SECURITY_LABEL */ 142762306a36Sopenharmony_ci#endif /* CONFIG_SECURITY */ 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_civoid ceph_release_acl_sec_ctx(struct ceph_acl_sec_ctx *as_ctx) 143062306a36Sopenharmony_ci{ 143162306a36Sopenharmony_ci#ifdef CONFIG_CEPH_FS_POSIX_ACL 143262306a36Sopenharmony_ci posix_acl_release(as_ctx->acl); 143362306a36Sopenharmony_ci posix_acl_release(as_ctx->default_acl); 143462306a36Sopenharmony_ci#endif 143562306a36Sopenharmony_ci#ifdef CONFIG_CEPH_FS_SECURITY_LABEL 143662306a36Sopenharmony_ci security_release_secctx(as_ctx->sec_ctx, as_ctx->sec_ctxlen); 143762306a36Sopenharmony_ci#endif 143862306a36Sopenharmony_ci#ifdef CONFIG_FS_ENCRYPTION 143962306a36Sopenharmony_ci kfree(as_ctx->fscrypt_auth); 144062306a36Sopenharmony_ci#endif 144162306a36Sopenharmony_ci if (as_ctx->pagelist) 144262306a36Sopenharmony_ci ceph_pagelist_release(as_ctx->pagelist); 144362306a36Sopenharmony_ci} 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci/* 144662306a36Sopenharmony_ci * List of handlers for synthetic system.* attributes. Other 144762306a36Sopenharmony_ci * attributes are handled directly. 144862306a36Sopenharmony_ci */ 144962306a36Sopenharmony_ciconst struct xattr_handler *ceph_xattr_handlers[] = { 145062306a36Sopenharmony_ci &ceph_other_xattr_handler, 145162306a36Sopenharmony_ci NULL, 145262306a36Sopenharmony_ci}; 1453