1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 23d14c5d2SYehuda Sadeh #include <linux/ceph/ceph_debug.h> 325e6bae3SYan, Zheng #include <linux/ceph/pagelist.h> 43d14c5d2SYehuda Sadeh 5355da1ebSSage Weil #include "super.h" 63d14c5d2SYehuda Sadeh #include "mds_client.h" 73d14c5d2SYehuda Sadeh 83d14c5d2SYehuda Sadeh #include <linux/ceph/decode.h> 9355da1ebSSage Weil 10355da1ebSSage Weil #include <linux/xattr.h> 11ac6713ccSYan, Zheng #include <linux/security.h> 124db658eaSLinus Torvalds #include <linux/posix_acl_xattr.h> 135a0e3ad6STejun Heo #include <linux/slab.h> 14355da1ebSSage Weil 1522891907SAlex Elder #define XATTR_CEPH_PREFIX "ceph." 1622891907SAlex Elder #define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1) 1722891907SAlex Elder 18bcdfeb2eSYan, Zheng static int __remove_xattr(struct ceph_inode_info *ci, 19bcdfeb2eSYan, Zheng struct ceph_inode_xattr *xattr); 20bcdfeb2eSYan, Zheng 21355da1ebSSage Weil static bool ceph_is_valid_xattr(const char *name) 22355da1ebSSage Weil { 2322891907SAlex Elder return !strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN) || 24355da1ebSSage Weil !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) || 25355da1ebSSage Weil !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); 26355da1ebSSage Weil } 27355da1ebSSage Weil 28355da1ebSSage Weil /* 29355da1ebSSage Weil * These define virtual xattrs exposing the recursive directory 30355da1ebSSage Weil * statistics and layout metadata. 31355da1ebSSage Weil */ 32881a5fa2SAlex Elder struct ceph_vxattr { 33355da1ebSSage Weil char *name; 343ce6cd12SAlex Elder size_t name_size; /* strlen(name) + 1 (for '\0') */ 35f1d1b51dSJeff Layton ssize_t (*getxattr_cb)(struct ceph_inode_info *ci, char *val, 36355da1ebSSage Weil size_t size); 37f36e4472SSage Weil bool (*exists_cb)(struct ceph_inode_info *ci); 384e9906e7SYan, Zheng unsigned int flags; 39355da1ebSSage Weil }; 40355da1ebSSage Weil 414e9906e7SYan, Zheng #define VXATTR_FLAG_READONLY (1<<0) 424e9906e7SYan, Zheng #define VXATTR_FLAG_HIDDEN (1<<1) 4349a9f4f6SYan, Zheng #define VXATTR_FLAG_RSTAT (1<<2) 444e9906e7SYan, Zheng 4532ab0bd7SSage Weil /* layouts */ 4632ab0bd7SSage Weil 4732ab0bd7SSage Weil static bool ceph_vxattrcb_layout_exists(struct ceph_inode_info *ci) 4832ab0bd7SSage Weil { 49779fe0fbSYan, Zheng struct ceph_file_layout *fl = &ci->i_layout; 50779fe0fbSYan, Zheng return (fl->stripe_unit > 0 || fl->stripe_count > 0 || 51779fe0fbSYan, Zheng fl->object_size > 0 || fl->pool_id >= 0 || 52779fe0fbSYan, Zheng rcu_dereference_raw(fl->pool_ns) != NULL); 5332ab0bd7SSage Weil } 5432ab0bd7SSage Weil 55f1d1b51dSJeff Layton static ssize_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val, 5632ab0bd7SSage Weil size_t size) 5732ab0bd7SSage Weil { 5832ab0bd7SSage Weil struct ceph_fs_client *fsc = ceph_sb_to_client(ci->vfs_inode.i_sb); 5932ab0bd7SSage Weil struct ceph_osd_client *osdc = &fsc->client->osdc; 60779fe0fbSYan, Zheng struct ceph_string *pool_ns; 617627151eSYan, Zheng s64 pool = ci->i_layout.pool_id; 6232ab0bd7SSage Weil const char *pool_name; 63779fe0fbSYan, Zheng const char *ns_field = " pool_namespace="; 641e5c6649SYan, Zheng char buf[128]; 65779fe0fbSYan, Zheng size_t len, total_len = 0; 663b421018SJeff Layton ssize_t ret; 67779fe0fbSYan, Zheng 68779fe0fbSYan, Zheng pool_ns = ceph_try_get_string(ci->i_layout.pool_ns); 6932ab0bd7SSage Weil 7032ab0bd7SSage Weil dout("ceph_vxattrcb_layout %p\n", &ci->vfs_inode); 715aea3dcdSIlya Dryomov down_read(&osdc->lock); 7232ab0bd7SSage Weil pool_name = ceph_pg_pool_name_by_id(osdc->osdmap, pool); 731e5c6649SYan, Zheng if (pool_name) { 74779fe0fbSYan, Zheng len = snprintf(buf, sizeof(buf), 757627151eSYan, Zheng "stripe_unit=%u stripe_count=%u object_size=%u pool=", 767627151eSYan, Zheng ci->i_layout.stripe_unit, ci->i_layout.stripe_count, 777627151eSYan, Zheng ci->i_layout.object_size); 78779fe0fbSYan, Zheng total_len = len + strlen(pool_name); 791e5c6649SYan, Zheng } else { 80779fe0fbSYan, Zheng len = snprintf(buf, sizeof(buf), 817627151eSYan, Zheng "stripe_unit=%u stripe_count=%u object_size=%u pool=%lld", 827627151eSYan, Zheng ci->i_layout.stripe_unit, ci->i_layout.stripe_count, 83f1d1b51dSJeff Layton ci->i_layout.object_size, pool); 84779fe0fbSYan, Zheng total_len = len; 85779fe0fbSYan, Zheng } 86779fe0fbSYan, Zheng 87779fe0fbSYan, Zheng if (pool_ns) 88779fe0fbSYan, Zheng total_len += strlen(ns_field) + pool_ns->len; 89779fe0fbSYan, Zheng 90779fe0fbSYan, Zheng ret = total_len; 913b421018SJeff Layton if (size >= total_len) { 92779fe0fbSYan, Zheng memcpy(val, buf, len); 93779fe0fbSYan, Zheng ret = len; 94779fe0fbSYan, Zheng if (pool_name) { 95779fe0fbSYan, Zheng len = strlen(pool_name); 96779fe0fbSYan, Zheng memcpy(val + ret, pool_name, len); 97779fe0fbSYan, Zheng ret += len; 98779fe0fbSYan, Zheng } 99779fe0fbSYan, Zheng if (pool_ns) { 100779fe0fbSYan, Zheng len = strlen(ns_field); 101779fe0fbSYan, Zheng memcpy(val + ret, ns_field, len); 102779fe0fbSYan, Zheng ret += len; 103779fe0fbSYan, Zheng memcpy(val + ret, pool_ns->str, pool_ns->len); 104779fe0fbSYan, Zheng ret += pool_ns->len; 1051e5c6649SYan, Zheng } 1061e5c6649SYan, Zheng } 1075aea3dcdSIlya Dryomov up_read(&osdc->lock); 108779fe0fbSYan, Zheng ceph_put_string(pool_ns); 10932ab0bd7SSage Weil return ret; 11032ab0bd7SSage Weil } 11132ab0bd7SSage Weil 112*26350535SJeff Layton /* 113*26350535SJeff Layton * The convention with strings in xattrs is that they should not be NULL 114*26350535SJeff Layton * terminated, since we're returning the length with them. snprintf always 115*26350535SJeff Layton * NULL terminates however, so call it on a temporary buffer and then memcpy 116*26350535SJeff Layton * the result into place. 117*26350535SJeff Layton */ 118*26350535SJeff Layton static int ceph_fmt_xattr(char *val, size_t size, const char *fmt, ...) 119*26350535SJeff Layton { 120*26350535SJeff Layton int ret; 121*26350535SJeff Layton va_list args; 122*26350535SJeff Layton char buf[96]; /* NB: reevaluate size if new vxattrs are added */ 123*26350535SJeff Layton 124*26350535SJeff Layton va_start(args, fmt); 125*26350535SJeff Layton ret = vsnprintf(buf, size ? sizeof(buf) : 0, fmt, args); 126*26350535SJeff Layton va_end(args); 127*26350535SJeff Layton 128*26350535SJeff Layton /* Sanity check */ 129*26350535SJeff Layton if (size && ret + 1 > sizeof(buf)) { 130*26350535SJeff Layton WARN_ONCE(true, "Returned length too big (%d)", ret); 131*26350535SJeff Layton return -E2BIG; 132*26350535SJeff Layton } 133*26350535SJeff Layton 134*26350535SJeff Layton if (ret <= size) 135*26350535SJeff Layton memcpy(val, buf, ret); 136*26350535SJeff Layton return ret; 137*26350535SJeff Layton } 138*26350535SJeff Layton 139f1d1b51dSJeff Layton static ssize_t ceph_vxattrcb_layout_stripe_unit(struct ceph_inode_info *ci, 140695b7119SSage Weil char *val, size_t size) 141695b7119SSage Weil { 142*26350535SJeff Layton return ceph_fmt_xattr(val, size, "%u", ci->i_layout.stripe_unit); 143695b7119SSage Weil } 144695b7119SSage Weil 145f1d1b51dSJeff Layton static ssize_t ceph_vxattrcb_layout_stripe_count(struct ceph_inode_info *ci, 146695b7119SSage Weil char *val, size_t size) 147695b7119SSage Weil { 148*26350535SJeff Layton return ceph_fmt_xattr(val, size, "%u", ci->i_layout.stripe_count); 149695b7119SSage Weil } 150695b7119SSage Weil 151f1d1b51dSJeff Layton static ssize_t ceph_vxattrcb_layout_object_size(struct ceph_inode_info *ci, 152695b7119SSage Weil char *val, size_t size) 153695b7119SSage Weil { 154*26350535SJeff Layton return ceph_fmt_xattr(val, size, "%u", ci->i_layout.object_size); 155695b7119SSage Weil } 156695b7119SSage Weil 157f1d1b51dSJeff Layton static ssize_t ceph_vxattrcb_layout_pool(struct ceph_inode_info *ci, 158695b7119SSage Weil char *val, size_t size) 159695b7119SSage Weil { 160f1d1b51dSJeff Layton ssize_t ret; 161695b7119SSage Weil struct ceph_fs_client *fsc = ceph_sb_to_client(ci->vfs_inode.i_sb); 162695b7119SSage Weil struct ceph_osd_client *osdc = &fsc->client->osdc; 1637627151eSYan, Zheng s64 pool = ci->i_layout.pool_id; 164695b7119SSage Weil const char *pool_name; 165695b7119SSage Weil 1665aea3dcdSIlya Dryomov down_read(&osdc->lock); 167695b7119SSage Weil pool_name = ceph_pg_pool_name_by_id(osdc->osdmap, pool); 168*26350535SJeff Layton if (pool_name) { 169*26350535SJeff Layton ret = strlen(pool_name); 170*26350535SJeff Layton if (ret <= size) 171*26350535SJeff Layton memcpy(val, pool_name, ret); 172*26350535SJeff Layton } else { 173*26350535SJeff Layton ret = ceph_fmt_xattr(val, size, "%lld", pool); 174*26350535SJeff Layton } 1755aea3dcdSIlya Dryomov up_read(&osdc->lock); 176695b7119SSage Weil return ret; 177695b7119SSage Weil } 178695b7119SSage Weil 179f1d1b51dSJeff Layton static ssize_t ceph_vxattrcb_layout_pool_namespace(struct ceph_inode_info *ci, 180779fe0fbSYan, Zheng char *val, size_t size) 181779fe0fbSYan, Zheng { 182*26350535SJeff Layton ssize_t ret = 0; 183779fe0fbSYan, Zheng struct ceph_string *ns = ceph_try_get_string(ci->i_layout.pool_ns); 184*26350535SJeff Layton 185779fe0fbSYan, Zheng if (ns) { 186*26350535SJeff Layton ret = ns->len; 187*26350535SJeff Layton if (ret <= size) 188*26350535SJeff Layton memcpy(val, ns->str, ret); 189779fe0fbSYan, Zheng ceph_put_string(ns); 190779fe0fbSYan, Zheng } 191779fe0fbSYan, Zheng return ret; 192779fe0fbSYan, Zheng } 193779fe0fbSYan, Zheng 194355da1ebSSage Weil /* directories */ 195355da1ebSSage Weil 196f1d1b51dSJeff Layton static ssize_t ceph_vxattrcb_dir_entries(struct ceph_inode_info *ci, char *val, 197355da1ebSSage Weil size_t size) 198355da1ebSSage Weil { 199*26350535SJeff Layton return ceph_fmt_xattr(val, size, "%lld", ci->i_files + ci->i_subdirs); 200355da1ebSSage Weil } 201355da1ebSSage Weil 202f1d1b51dSJeff Layton static ssize_t ceph_vxattrcb_dir_files(struct ceph_inode_info *ci, char *val, 203355da1ebSSage Weil size_t size) 204355da1ebSSage Weil { 205*26350535SJeff Layton return ceph_fmt_xattr(val, size, "%lld", ci->i_files); 206355da1ebSSage Weil } 207355da1ebSSage Weil 208f1d1b51dSJeff Layton static ssize_t ceph_vxattrcb_dir_subdirs(struct ceph_inode_info *ci, char *val, 209355da1ebSSage Weil size_t size) 210355da1ebSSage Weil { 211*26350535SJeff Layton return ceph_fmt_xattr(val, size, "%lld", ci->i_subdirs); 212355da1ebSSage Weil } 213355da1ebSSage Weil 214f1d1b51dSJeff Layton static ssize_t ceph_vxattrcb_dir_rentries(struct ceph_inode_info *ci, char *val, 215355da1ebSSage Weil size_t size) 216355da1ebSSage Weil { 217*26350535SJeff Layton return ceph_fmt_xattr(val, size, "%lld", 218*26350535SJeff Layton ci->i_rfiles + ci->i_rsubdirs); 219355da1ebSSage Weil } 220355da1ebSSage Weil 221f1d1b51dSJeff Layton static ssize_t ceph_vxattrcb_dir_rfiles(struct ceph_inode_info *ci, char *val, 222355da1ebSSage Weil size_t size) 223355da1ebSSage Weil { 224*26350535SJeff Layton return ceph_fmt_xattr(val, size, "%lld", ci->i_rfiles); 225355da1ebSSage Weil } 226355da1ebSSage Weil 227f1d1b51dSJeff Layton static ssize_t ceph_vxattrcb_dir_rsubdirs(struct ceph_inode_info *ci, char *val, 228355da1ebSSage Weil size_t size) 229355da1ebSSage Weil { 230*26350535SJeff Layton return ceph_fmt_xattr(val, size, "%lld", ci->i_rsubdirs); 231355da1ebSSage Weil } 232355da1ebSSage Weil 233f1d1b51dSJeff Layton static ssize_t ceph_vxattrcb_dir_rbytes(struct ceph_inode_info *ci, char *val, 234355da1ebSSage Weil size_t size) 235355da1ebSSage Weil { 236*26350535SJeff Layton return ceph_fmt_xattr(val, size, "%lld", ci->i_rbytes); 237355da1ebSSage Weil } 238355da1ebSSage Weil 239f1d1b51dSJeff Layton static ssize_t ceph_vxattrcb_dir_rctime(struct ceph_inode_info *ci, char *val, 240355da1ebSSage Weil size_t size) 241355da1ebSSage Weil { 242*26350535SJeff Layton return ceph_fmt_xattr(val, size, "%lld.%09ld", ci->i_rctime.tv_sec, 2439bbeab41SArnd Bergmann ci->i_rctime.tv_nsec); 244355da1ebSSage Weil } 245355da1ebSSage Weil 24608796873SYan, Zheng /* dir pin */ 24708796873SYan, Zheng static bool ceph_vxattrcb_dir_pin_exists(struct ceph_inode_info *ci) 24808796873SYan, Zheng { 24908796873SYan, Zheng return ci->i_dir_pin != -ENODATA; 25008796873SYan, Zheng } 251fb18a575SLuis Henriques 252f1d1b51dSJeff Layton static ssize_t ceph_vxattrcb_dir_pin(struct ceph_inode_info *ci, char *val, 25308796873SYan, Zheng size_t size) 25408796873SYan, Zheng { 255*26350535SJeff Layton return ceph_fmt_xattr(val, size, "%d", (int)ci->i_dir_pin); 25608796873SYan, Zheng } 25708796873SYan, Zheng 25808796873SYan, Zheng /* quotas */ 259fb18a575SLuis Henriques static bool ceph_vxattrcb_quota_exists(struct ceph_inode_info *ci) 260fb18a575SLuis Henriques { 261f1919826SYan, Zheng bool ret = false; 262f1919826SYan, Zheng spin_lock(&ci->i_ceph_lock); 263f1919826SYan, Zheng if ((ci->i_max_files || ci->i_max_bytes) && 264f1919826SYan, Zheng ci->i_vino.snap == CEPH_NOSNAP && 265f1919826SYan, Zheng ci->i_snap_realm && 266f1919826SYan, Zheng ci->i_snap_realm->ino == ci->i_vino.ino) 267f1919826SYan, Zheng ret = true; 268f1919826SYan, Zheng spin_unlock(&ci->i_ceph_lock); 269f1919826SYan, Zheng return ret; 270fb18a575SLuis Henriques } 271fb18a575SLuis Henriques 272f1d1b51dSJeff Layton static ssize_t ceph_vxattrcb_quota(struct ceph_inode_info *ci, char *val, 273fb18a575SLuis Henriques size_t size) 274fb18a575SLuis Henriques { 275*26350535SJeff Layton return ceph_fmt_xattr(val, size, "max_bytes=%llu max_files=%llu", 276fb18a575SLuis Henriques ci->i_max_bytes, ci->i_max_files); 277fb18a575SLuis Henriques } 278fb18a575SLuis Henriques 279f1d1b51dSJeff Layton static ssize_t ceph_vxattrcb_quota_max_bytes(struct ceph_inode_info *ci, 280fb18a575SLuis Henriques char *val, size_t size) 281fb18a575SLuis Henriques { 282*26350535SJeff Layton return ceph_fmt_xattr(val, size, "%llu", ci->i_max_bytes); 283fb18a575SLuis Henriques } 284fb18a575SLuis Henriques 285f1d1b51dSJeff Layton static ssize_t ceph_vxattrcb_quota_max_files(struct ceph_inode_info *ci, 286fb18a575SLuis Henriques char *val, size_t size) 287fb18a575SLuis Henriques { 288*26350535SJeff Layton return ceph_fmt_xattr(val, size, "%llu", ci->i_max_files); 289fb18a575SLuis Henriques } 29032ab0bd7SSage Weil 291100cc610SDavid Disseldorp /* snapshots */ 292100cc610SDavid Disseldorp static bool ceph_vxattrcb_snap_btime_exists(struct ceph_inode_info *ci) 293100cc610SDavid Disseldorp { 294100cc610SDavid Disseldorp return (ci->i_snap_btime.tv_sec != 0 || ci->i_snap_btime.tv_nsec != 0); 295100cc610SDavid Disseldorp } 296100cc610SDavid Disseldorp 297f1d1b51dSJeff Layton static ssize_t ceph_vxattrcb_snap_btime(struct ceph_inode_info *ci, char *val, 298100cc610SDavid Disseldorp size_t size) 299100cc610SDavid Disseldorp { 300*26350535SJeff Layton return ceph_fmt_xattr(val, size, "%lld.%09ld", ci->i_snap_btime.tv_sec, 301100cc610SDavid Disseldorp ci->i_snap_btime.tv_nsec); 302100cc610SDavid Disseldorp } 303100cc610SDavid Disseldorp 304eb788084SAlex Elder #define CEPH_XATTR_NAME(_type, _name) XATTR_CEPH_PREFIX #_type "." #_name 305695b7119SSage Weil #define CEPH_XATTR_NAME2(_type, _name, _name2) \ 306695b7119SSage Weil XATTR_CEPH_PREFIX #_type "." #_name "." #_name2 307eb788084SAlex Elder 30849a9f4f6SYan, Zheng #define XATTR_NAME_CEPH(_type, _name, _flags) \ 309eb788084SAlex Elder { \ 310eb788084SAlex Elder .name = CEPH_XATTR_NAME(_type, _name), \ 3113ce6cd12SAlex Elder .name_size = sizeof (CEPH_XATTR_NAME(_type, _name)), \ 312aa4066edSAlex Elder .getxattr_cb = ceph_vxattrcb_ ## _type ## _ ## _name, \ 313f36e4472SSage Weil .exists_cb = NULL, \ 31449a9f4f6SYan, Zheng .flags = (VXATTR_FLAG_READONLY | _flags), \ 315eb788084SAlex Elder } 31649a9f4f6SYan, Zheng #define XATTR_RSTAT_FIELD(_type, _name) \ 31749a9f4f6SYan, Zheng XATTR_NAME_CEPH(_type, _name, VXATTR_FLAG_RSTAT) 318695b7119SSage Weil #define XATTR_LAYOUT_FIELD(_type, _name, _field) \ 319695b7119SSage Weil { \ 320695b7119SSage Weil .name = CEPH_XATTR_NAME2(_type, _name, _field), \ 321695b7119SSage Weil .name_size = sizeof (CEPH_XATTR_NAME2(_type, _name, _field)), \ 322695b7119SSage Weil .getxattr_cb = ceph_vxattrcb_ ## _name ## _ ## _field, \ 323695b7119SSage Weil .exists_cb = ceph_vxattrcb_layout_exists, \ 3244e9906e7SYan, Zheng .flags = VXATTR_FLAG_HIDDEN, \ 325695b7119SSage Weil } 326fb18a575SLuis Henriques #define XATTR_QUOTA_FIELD(_type, _name) \ 327fb18a575SLuis Henriques { \ 328fb18a575SLuis Henriques .name = CEPH_XATTR_NAME(_type, _name), \ 329fb18a575SLuis Henriques .name_size = sizeof(CEPH_XATTR_NAME(_type, _name)), \ 330fb18a575SLuis Henriques .getxattr_cb = ceph_vxattrcb_ ## _type ## _ ## _name, \ 331fb18a575SLuis Henriques .exists_cb = ceph_vxattrcb_quota_exists, \ 3324e9906e7SYan, Zheng .flags = VXATTR_FLAG_HIDDEN, \ 333fb18a575SLuis Henriques } 334eb788084SAlex Elder 335881a5fa2SAlex Elder static struct ceph_vxattr ceph_dir_vxattrs[] = { 3361f08f2b0SSage Weil { 3371f08f2b0SSage Weil .name = "ceph.dir.layout", 3381f08f2b0SSage Weil .name_size = sizeof("ceph.dir.layout"), 3391f08f2b0SSage Weil .getxattr_cb = ceph_vxattrcb_layout, 3401f08f2b0SSage Weil .exists_cb = ceph_vxattrcb_layout_exists, 3414e9906e7SYan, Zheng .flags = VXATTR_FLAG_HIDDEN, 3421f08f2b0SSage Weil }, 343695b7119SSage Weil XATTR_LAYOUT_FIELD(dir, layout, stripe_unit), 344695b7119SSage Weil XATTR_LAYOUT_FIELD(dir, layout, stripe_count), 345695b7119SSage Weil XATTR_LAYOUT_FIELD(dir, layout, object_size), 346695b7119SSage Weil XATTR_LAYOUT_FIELD(dir, layout, pool), 347779fe0fbSYan, Zheng XATTR_LAYOUT_FIELD(dir, layout, pool_namespace), 34849a9f4f6SYan, Zheng XATTR_NAME_CEPH(dir, entries, 0), 34949a9f4f6SYan, Zheng XATTR_NAME_CEPH(dir, files, 0), 35049a9f4f6SYan, Zheng XATTR_NAME_CEPH(dir, subdirs, 0), 35149a9f4f6SYan, Zheng XATTR_RSTAT_FIELD(dir, rentries), 35249a9f4f6SYan, Zheng XATTR_RSTAT_FIELD(dir, rfiles), 35349a9f4f6SYan, Zheng XATTR_RSTAT_FIELD(dir, rsubdirs), 35449a9f4f6SYan, Zheng XATTR_RSTAT_FIELD(dir, rbytes), 35549a9f4f6SYan, Zheng XATTR_RSTAT_FIELD(dir, rctime), 356fb18a575SLuis Henriques { 35708796873SYan, Zheng .name = "ceph.dir.pin", 358e1b81439SDavid Disseldorp .name_size = sizeof("ceph.dir.pin"), 35908796873SYan, Zheng .getxattr_cb = ceph_vxattrcb_dir_pin, 36008796873SYan, Zheng .exists_cb = ceph_vxattrcb_dir_pin_exists, 36108796873SYan, Zheng .flags = VXATTR_FLAG_HIDDEN, 36208796873SYan, Zheng }, 36308796873SYan, Zheng { 364fb18a575SLuis Henriques .name = "ceph.quota", 365fb18a575SLuis Henriques .name_size = sizeof("ceph.quota"), 366fb18a575SLuis Henriques .getxattr_cb = ceph_vxattrcb_quota, 367fb18a575SLuis Henriques .exists_cb = ceph_vxattrcb_quota_exists, 3684e9906e7SYan, Zheng .flags = VXATTR_FLAG_HIDDEN, 369fb18a575SLuis Henriques }, 370fb18a575SLuis Henriques XATTR_QUOTA_FIELD(quota, max_bytes), 371fb18a575SLuis Henriques XATTR_QUOTA_FIELD(quota, max_files), 372100cc610SDavid Disseldorp { 373100cc610SDavid Disseldorp .name = "ceph.snap.btime", 374100cc610SDavid Disseldorp .name_size = sizeof("ceph.snap.btime"), 375100cc610SDavid Disseldorp .getxattr_cb = ceph_vxattrcb_snap_btime, 376100cc610SDavid Disseldorp .exists_cb = ceph_vxattrcb_snap_btime_exists, 377100cc610SDavid Disseldorp .flags = VXATTR_FLAG_READONLY, 378100cc610SDavid Disseldorp }, 3792c3dd4ffSAlex Elder { .name = NULL, 0 } /* Required table terminator */ 380355da1ebSSage Weil }; 381355da1ebSSage Weil 382355da1ebSSage Weil /* files */ 383355da1ebSSage Weil 384881a5fa2SAlex Elder static struct ceph_vxattr ceph_file_vxattrs[] = { 38532ab0bd7SSage Weil { 38632ab0bd7SSage Weil .name = "ceph.file.layout", 38732ab0bd7SSage Weil .name_size = sizeof("ceph.file.layout"), 38832ab0bd7SSage Weil .getxattr_cb = ceph_vxattrcb_layout, 38932ab0bd7SSage Weil .exists_cb = ceph_vxattrcb_layout_exists, 3904e9906e7SYan, Zheng .flags = VXATTR_FLAG_HIDDEN, 39132ab0bd7SSage Weil }, 392695b7119SSage Weil XATTR_LAYOUT_FIELD(file, layout, stripe_unit), 393695b7119SSage Weil XATTR_LAYOUT_FIELD(file, layout, stripe_count), 394695b7119SSage Weil XATTR_LAYOUT_FIELD(file, layout, object_size), 395695b7119SSage Weil XATTR_LAYOUT_FIELD(file, layout, pool), 396779fe0fbSYan, Zheng XATTR_LAYOUT_FIELD(file, layout, pool_namespace), 397100cc610SDavid Disseldorp { 398100cc610SDavid Disseldorp .name = "ceph.snap.btime", 399100cc610SDavid Disseldorp .name_size = sizeof("ceph.snap.btime"), 400100cc610SDavid Disseldorp .getxattr_cb = ceph_vxattrcb_snap_btime, 401100cc610SDavid Disseldorp .exists_cb = ceph_vxattrcb_snap_btime_exists, 402100cc610SDavid Disseldorp .flags = VXATTR_FLAG_READONLY, 403100cc610SDavid Disseldorp }, 4042c3dd4ffSAlex Elder { .name = NULL, 0 } /* Required table terminator */ 405355da1ebSSage Weil }; 406355da1ebSSage Weil 407881a5fa2SAlex Elder static struct ceph_vxattr *ceph_inode_vxattrs(struct inode *inode) 408355da1ebSSage Weil { 409355da1ebSSage Weil if (S_ISDIR(inode->i_mode)) 410355da1ebSSage Weil return ceph_dir_vxattrs; 411355da1ebSSage Weil else if (S_ISREG(inode->i_mode)) 412355da1ebSSage Weil return ceph_file_vxattrs; 413355da1ebSSage Weil return NULL; 414355da1ebSSage Weil } 415355da1ebSSage Weil 416881a5fa2SAlex Elder static struct ceph_vxattr *ceph_match_vxattr(struct inode *inode, 417355da1ebSSage Weil const char *name) 418355da1ebSSage Weil { 419881a5fa2SAlex Elder struct ceph_vxattr *vxattr = ceph_inode_vxattrs(inode); 42006476a69SAlex Elder 42106476a69SAlex Elder if (vxattr) { 42206476a69SAlex Elder while (vxattr->name) { 42306476a69SAlex Elder if (!strcmp(vxattr->name, name)) 424355da1ebSSage Weil return vxattr; 425355da1ebSSage Weil vxattr++; 42606476a69SAlex Elder } 42706476a69SAlex Elder } 42806476a69SAlex Elder 429355da1ebSSage Weil return NULL; 430355da1ebSSage Weil } 431355da1ebSSage Weil 432355da1ebSSage Weil static int __set_xattr(struct ceph_inode_info *ci, 433355da1ebSSage Weil const char *name, int name_len, 434355da1ebSSage Weil const char *val, int val_len, 435fbc0b970SYan, Zheng int flags, int update_xattr, 436355da1ebSSage Weil struct ceph_inode_xattr **newxattr) 437355da1ebSSage Weil { 438355da1ebSSage Weil struct rb_node **p; 439355da1ebSSage Weil struct rb_node *parent = NULL; 440355da1ebSSage Weil struct ceph_inode_xattr *xattr = NULL; 441355da1ebSSage Weil int c; 442355da1ebSSage Weil int new = 0; 443355da1ebSSage Weil 444355da1ebSSage Weil p = &ci->i_xattrs.index.rb_node; 445355da1ebSSage Weil while (*p) { 446355da1ebSSage Weil parent = *p; 447355da1ebSSage Weil xattr = rb_entry(parent, struct ceph_inode_xattr, node); 448355da1ebSSage Weil c = strncmp(name, xattr->name, min(name_len, xattr->name_len)); 449355da1ebSSage Weil if (c < 0) 450355da1ebSSage Weil p = &(*p)->rb_left; 451355da1ebSSage Weil else if (c > 0) 452355da1ebSSage Weil p = &(*p)->rb_right; 453355da1ebSSage Weil else { 454355da1ebSSage Weil if (name_len == xattr->name_len) 455355da1ebSSage Weil break; 456355da1ebSSage Weil else if (name_len < xattr->name_len) 457355da1ebSSage Weil p = &(*p)->rb_left; 458355da1ebSSage Weil else 459355da1ebSSage Weil p = &(*p)->rb_right; 460355da1ebSSage Weil } 461355da1ebSSage Weil xattr = NULL; 462355da1ebSSage Weil } 463355da1ebSSage Weil 464fbc0b970SYan, Zheng if (update_xattr) { 465fbc0b970SYan, Zheng int err = 0; 466eeca958dSLuis Henriques 467fbc0b970SYan, Zheng if (xattr && (flags & XATTR_CREATE)) 468fbc0b970SYan, Zheng err = -EEXIST; 469fbc0b970SYan, Zheng else if (!xattr && (flags & XATTR_REPLACE)) 470fbc0b970SYan, Zheng err = -ENODATA; 471fbc0b970SYan, Zheng if (err) { 472fbc0b970SYan, Zheng kfree(name); 473fbc0b970SYan, Zheng kfree(val); 474eeca958dSLuis Henriques kfree(*newxattr); 475fbc0b970SYan, Zheng return err; 476fbc0b970SYan, Zheng } 477bcdfeb2eSYan, Zheng if (update_xattr < 0) { 478bcdfeb2eSYan, Zheng if (xattr) 479bcdfeb2eSYan, Zheng __remove_xattr(ci, xattr); 480bcdfeb2eSYan, Zheng kfree(name); 481eeca958dSLuis Henriques kfree(*newxattr); 482bcdfeb2eSYan, Zheng return 0; 483bcdfeb2eSYan, Zheng } 484fbc0b970SYan, Zheng } 485fbc0b970SYan, Zheng 486355da1ebSSage Weil if (!xattr) { 487355da1ebSSage Weil new = 1; 488355da1ebSSage Weil xattr = *newxattr; 489355da1ebSSage Weil xattr->name = name; 490355da1ebSSage Weil xattr->name_len = name_len; 491fbc0b970SYan, Zheng xattr->should_free_name = update_xattr; 492355da1ebSSage Weil 493355da1ebSSage Weil ci->i_xattrs.count++; 494355da1ebSSage Weil dout("__set_xattr count=%d\n", ci->i_xattrs.count); 495355da1ebSSage Weil } else { 496355da1ebSSage Weil kfree(*newxattr); 497355da1ebSSage Weil *newxattr = NULL; 498355da1ebSSage Weil if (xattr->should_free_val) 499355da1ebSSage Weil kfree((void *)xattr->val); 500355da1ebSSage Weil 501fbc0b970SYan, Zheng if (update_xattr) { 502355da1ebSSage Weil kfree((void *)name); 503355da1ebSSage Weil name = xattr->name; 504355da1ebSSage Weil } 505355da1ebSSage Weil ci->i_xattrs.names_size -= xattr->name_len; 506355da1ebSSage Weil ci->i_xattrs.vals_size -= xattr->val_len; 507355da1ebSSage Weil } 508355da1ebSSage Weil ci->i_xattrs.names_size += name_len; 509355da1ebSSage Weil ci->i_xattrs.vals_size += val_len; 510355da1ebSSage Weil if (val) 511355da1ebSSage Weil xattr->val = val; 512355da1ebSSage Weil else 513355da1ebSSage Weil xattr->val = ""; 514355da1ebSSage Weil 515355da1ebSSage Weil xattr->val_len = val_len; 516fbc0b970SYan, Zheng xattr->dirty = update_xattr; 517fbc0b970SYan, Zheng xattr->should_free_val = (val && update_xattr); 518355da1ebSSage Weil 519355da1ebSSage Weil if (new) { 520355da1ebSSage Weil rb_link_node(&xattr->node, parent, p); 521355da1ebSSage Weil rb_insert_color(&xattr->node, &ci->i_xattrs.index); 522355da1ebSSage Weil dout("__set_xattr_val p=%p\n", p); 523355da1ebSSage Weil } 524355da1ebSSage Weil 52505729781SYan, Zheng dout("__set_xattr_val added %llx.%llx xattr %p %.*s=%.*s\n", 52605729781SYan, Zheng ceph_vinop(&ci->vfs_inode), xattr, name_len, name, val_len, val); 527355da1ebSSage Weil 528355da1ebSSage Weil return 0; 529355da1ebSSage Weil } 530355da1ebSSage Weil 531355da1ebSSage Weil static struct ceph_inode_xattr *__get_xattr(struct ceph_inode_info *ci, 532355da1ebSSage Weil const char *name) 533355da1ebSSage Weil { 534355da1ebSSage Weil struct rb_node **p; 535355da1ebSSage Weil struct rb_node *parent = NULL; 536355da1ebSSage Weil struct ceph_inode_xattr *xattr = NULL; 53717db143fSSage Weil int name_len = strlen(name); 538355da1ebSSage Weil int c; 539355da1ebSSage Weil 540355da1ebSSage Weil p = &ci->i_xattrs.index.rb_node; 541355da1ebSSage Weil while (*p) { 542355da1ebSSage Weil parent = *p; 543355da1ebSSage Weil xattr = rb_entry(parent, struct ceph_inode_xattr, node); 544355da1ebSSage Weil c = strncmp(name, xattr->name, xattr->name_len); 54517db143fSSage Weil if (c == 0 && name_len > xattr->name_len) 54617db143fSSage Weil c = 1; 547355da1ebSSage Weil if (c < 0) 548355da1ebSSage Weil p = &(*p)->rb_left; 549355da1ebSSage Weil else if (c > 0) 550355da1ebSSage Weil p = &(*p)->rb_right; 551355da1ebSSage Weil else { 552355da1ebSSage Weil dout("__get_xattr %s: found %.*s\n", name, 553355da1ebSSage Weil xattr->val_len, xattr->val); 554355da1ebSSage Weil return xattr; 555355da1ebSSage Weil } 556355da1ebSSage Weil } 557355da1ebSSage Weil 558355da1ebSSage Weil dout("__get_xattr %s: not found\n", name); 559355da1ebSSage Weil 560355da1ebSSage Weil return NULL; 561355da1ebSSage Weil } 562355da1ebSSage Weil 563355da1ebSSage Weil static void __free_xattr(struct ceph_inode_xattr *xattr) 564355da1ebSSage Weil { 565355da1ebSSage Weil BUG_ON(!xattr); 566355da1ebSSage Weil 567355da1ebSSage Weil if (xattr->should_free_name) 568355da1ebSSage Weil kfree((void *)xattr->name); 569355da1ebSSage Weil if (xattr->should_free_val) 570355da1ebSSage Weil kfree((void *)xattr->val); 571355da1ebSSage Weil 572355da1ebSSage Weil kfree(xattr); 573355da1ebSSage Weil } 574355da1ebSSage Weil 575355da1ebSSage Weil static int __remove_xattr(struct ceph_inode_info *ci, 576355da1ebSSage Weil struct ceph_inode_xattr *xattr) 577355da1ebSSage Weil { 578355da1ebSSage Weil if (!xattr) 579524186acSYan, Zheng return -ENODATA; 580355da1ebSSage Weil 581355da1ebSSage Weil rb_erase(&xattr->node, &ci->i_xattrs.index); 582355da1ebSSage Weil 583355da1ebSSage Weil if (xattr->should_free_name) 584355da1ebSSage Weil kfree((void *)xattr->name); 585355da1ebSSage Weil if (xattr->should_free_val) 586355da1ebSSage Weil kfree((void *)xattr->val); 587355da1ebSSage Weil 588355da1ebSSage Weil ci->i_xattrs.names_size -= xattr->name_len; 589355da1ebSSage Weil ci->i_xattrs.vals_size -= xattr->val_len; 590355da1ebSSage Weil ci->i_xattrs.count--; 591355da1ebSSage Weil kfree(xattr); 592355da1ebSSage Weil 593355da1ebSSage Weil return 0; 594355da1ebSSage Weil } 595355da1ebSSage Weil 596355da1ebSSage Weil static char *__copy_xattr_names(struct ceph_inode_info *ci, 597355da1ebSSage Weil char *dest) 598355da1ebSSage Weil { 599355da1ebSSage Weil struct rb_node *p; 600355da1ebSSage Weil struct ceph_inode_xattr *xattr = NULL; 601355da1ebSSage Weil 602355da1ebSSage Weil p = rb_first(&ci->i_xattrs.index); 603355da1ebSSage Weil dout("__copy_xattr_names count=%d\n", ci->i_xattrs.count); 604355da1ebSSage Weil 605355da1ebSSage Weil while (p) { 606355da1ebSSage Weil xattr = rb_entry(p, struct ceph_inode_xattr, node); 607355da1ebSSage Weil memcpy(dest, xattr->name, xattr->name_len); 608355da1ebSSage Weil dest[xattr->name_len] = '\0'; 609355da1ebSSage Weil 610355da1ebSSage Weil dout("dest=%s %p (%s) (%d/%d)\n", dest, xattr, xattr->name, 611355da1ebSSage Weil xattr->name_len, ci->i_xattrs.names_size); 612355da1ebSSage Weil 613355da1ebSSage Weil dest += xattr->name_len + 1; 614355da1ebSSage Weil p = rb_next(p); 615355da1ebSSage Weil } 616355da1ebSSage Weil 617355da1ebSSage Weil return dest; 618355da1ebSSage Weil } 619355da1ebSSage Weil 620355da1ebSSage Weil void __ceph_destroy_xattrs(struct ceph_inode_info *ci) 621355da1ebSSage Weil { 622355da1ebSSage Weil struct rb_node *p, *tmp; 623355da1ebSSage Weil struct ceph_inode_xattr *xattr = NULL; 624355da1ebSSage Weil 625355da1ebSSage Weil p = rb_first(&ci->i_xattrs.index); 626355da1ebSSage Weil 627355da1ebSSage Weil dout("__ceph_destroy_xattrs p=%p\n", p); 628355da1ebSSage Weil 629355da1ebSSage Weil while (p) { 630355da1ebSSage Weil xattr = rb_entry(p, struct ceph_inode_xattr, node); 631355da1ebSSage Weil tmp = p; 632355da1ebSSage Weil p = rb_next(tmp); 633355da1ebSSage Weil dout("__ceph_destroy_xattrs next p=%p (%.*s)\n", p, 634355da1ebSSage Weil xattr->name_len, xattr->name); 635355da1ebSSage Weil rb_erase(tmp, &ci->i_xattrs.index); 636355da1ebSSage Weil 637355da1ebSSage Weil __free_xattr(xattr); 638355da1ebSSage Weil } 639355da1ebSSage Weil 640355da1ebSSage Weil ci->i_xattrs.names_size = 0; 641355da1ebSSage Weil ci->i_xattrs.vals_size = 0; 642355da1ebSSage Weil ci->i_xattrs.index_version = 0; 643355da1ebSSage Weil ci->i_xattrs.count = 0; 644355da1ebSSage Weil ci->i_xattrs.index = RB_ROOT; 645355da1ebSSage Weil } 646355da1ebSSage Weil 647355da1ebSSage Weil static int __build_xattrs(struct inode *inode) 648be655596SSage Weil __releases(ci->i_ceph_lock) 649be655596SSage Weil __acquires(ci->i_ceph_lock) 650355da1ebSSage Weil { 651355da1ebSSage Weil u32 namelen; 652355da1ebSSage Weil u32 numattr = 0; 653355da1ebSSage Weil void *p, *end; 654355da1ebSSage Weil u32 len; 655355da1ebSSage Weil const char *name, *val; 656355da1ebSSage Weil struct ceph_inode_info *ci = ceph_inode(inode); 657355da1ebSSage Weil int xattr_version; 658355da1ebSSage Weil struct ceph_inode_xattr **xattrs = NULL; 65963ff78b2SSage Weil int err = 0; 660355da1ebSSage Weil int i; 661355da1ebSSage Weil 662355da1ebSSage Weil dout("__build_xattrs() len=%d\n", 663355da1ebSSage Weil ci->i_xattrs.blob ? (int)ci->i_xattrs.blob->vec.iov_len : 0); 664355da1ebSSage Weil 665355da1ebSSage Weil if (ci->i_xattrs.index_version >= ci->i_xattrs.version) 666355da1ebSSage Weil return 0; /* already built */ 667355da1ebSSage Weil 668355da1ebSSage Weil __ceph_destroy_xattrs(ci); 669355da1ebSSage Weil 670355da1ebSSage Weil start: 671355da1ebSSage Weil /* updated internal xattr rb tree */ 672355da1ebSSage Weil if (ci->i_xattrs.blob && ci->i_xattrs.blob->vec.iov_len > 4) { 673355da1ebSSage Weil p = ci->i_xattrs.blob->vec.iov_base; 674355da1ebSSage Weil end = p + ci->i_xattrs.blob->vec.iov_len; 675355da1ebSSage Weil ceph_decode_32_safe(&p, end, numattr, bad); 676355da1ebSSage Weil xattr_version = ci->i_xattrs.version; 677be655596SSage Weil spin_unlock(&ci->i_ceph_lock); 678355da1ebSSage Weil 6797e8a2952SIlya Dryomov xattrs = kcalloc(numattr, sizeof(struct ceph_inode_xattr *), 680355da1ebSSage Weil GFP_NOFS); 681355da1ebSSage Weil err = -ENOMEM; 682355da1ebSSage Weil if (!xattrs) 683355da1ebSSage Weil goto bad_lock; 6841a295bd8SIlya Dryomov 685355da1ebSSage Weil for (i = 0; i < numattr; i++) { 686355da1ebSSage Weil xattrs[i] = kmalloc(sizeof(struct ceph_inode_xattr), 687355da1ebSSage Weil GFP_NOFS); 688355da1ebSSage Weil if (!xattrs[i]) 689355da1ebSSage Weil goto bad_lock; 690355da1ebSSage Weil } 691355da1ebSSage Weil 692be655596SSage Weil spin_lock(&ci->i_ceph_lock); 693355da1ebSSage Weil if (ci->i_xattrs.version != xattr_version) { 694355da1ebSSage Weil /* lost a race, retry */ 695355da1ebSSage Weil for (i = 0; i < numattr; i++) 696355da1ebSSage Weil kfree(xattrs[i]); 697355da1ebSSage Weil kfree(xattrs); 69821ec6ffaSAlan Cox xattrs = NULL; 699355da1ebSSage Weil goto start; 700355da1ebSSage Weil } 701355da1ebSSage Weil err = -EIO; 702355da1ebSSage Weil while (numattr--) { 703355da1ebSSage Weil ceph_decode_32_safe(&p, end, len, bad); 704355da1ebSSage Weil namelen = len; 705355da1ebSSage Weil name = p; 706355da1ebSSage Weil p += len; 707355da1ebSSage Weil ceph_decode_32_safe(&p, end, len, bad); 708355da1ebSSage Weil val = p; 709355da1ebSSage Weil p += len; 710355da1ebSSage Weil 711355da1ebSSage Weil err = __set_xattr(ci, name, namelen, val, len, 712fbc0b970SYan, Zheng 0, 0, &xattrs[numattr]); 713355da1ebSSage Weil 714355da1ebSSage Weil if (err < 0) 715355da1ebSSage Weil goto bad; 716355da1ebSSage Weil } 717355da1ebSSage Weil kfree(xattrs); 718355da1ebSSage Weil } 719355da1ebSSage Weil ci->i_xattrs.index_version = ci->i_xattrs.version; 720355da1ebSSage Weil ci->i_xattrs.dirty = false; 721355da1ebSSage Weil 722355da1ebSSage Weil return err; 723355da1ebSSage Weil bad_lock: 724be655596SSage Weil spin_lock(&ci->i_ceph_lock); 725355da1ebSSage Weil bad: 726355da1ebSSage Weil if (xattrs) { 727355da1ebSSage Weil for (i = 0; i < numattr; i++) 728355da1ebSSage Weil kfree(xattrs[i]); 729355da1ebSSage Weil kfree(xattrs); 730355da1ebSSage Weil } 731355da1ebSSage Weil ci->i_xattrs.names_size = 0; 732355da1ebSSage Weil return err; 733355da1ebSSage Weil } 734355da1ebSSage Weil 735355da1ebSSage Weil static int __get_required_blob_size(struct ceph_inode_info *ci, int name_size, 736355da1ebSSage Weil int val_size) 737355da1ebSSage Weil { 738355da1ebSSage Weil /* 739355da1ebSSage Weil * 4 bytes for the length, and additional 4 bytes per each xattr name, 740355da1ebSSage Weil * 4 bytes per each value 741355da1ebSSage Weil */ 742355da1ebSSage Weil int size = 4 + ci->i_xattrs.count*(4 + 4) + 743355da1ebSSage Weil ci->i_xattrs.names_size + 744355da1ebSSage Weil ci->i_xattrs.vals_size; 745355da1ebSSage Weil dout("__get_required_blob_size c=%d names.size=%d vals.size=%d\n", 746355da1ebSSage Weil ci->i_xattrs.count, ci->i_xattrs.names_size, 747355da1ebSSage Weil ci->i_xattrs.vals_size); 748355da1ebSSage Weil 749355da1ebSSage Weil if (name_size) 750355da1ebSSage Weil size += 4 + 4 + name_size + val_size; 751355da1ebSSage Weil 752355da1ebSSage Weil return size; 753355da1ebSSage Weil } 754355da1ebSSage Weil 755355da1ebSSage Weil /* 756355da1ebSSage Weil * If there are dirty xattrs, reencode xattrs into the prealloc_blob 757355da1ebSSage Weil * and swap into place. 758355da1ebSSage Weil */ 759355da1ebSSage Weil void __ceph_build_xattrs_blob(struct ceph_inode_info *ci) 760355da1ebSSage Weil { 761355da1ebSSage Weil struct rb_node *p; 762355da1ebSSage Weil struct ceph_inode_xattr *xattr = NULL; 763355da1ebSSage Weil void *dest; 764355da1ebSSage Weil 765355da1ebSSage Weil dout("__build_xattrs_blob %p\n", &ci->vfs_inode); 766355da1ebSSage Weil if (ci->i_xattrs.dirty) { 767355da1ebSSage Weil int need = __get_required_blob_size(ci, 0, 0); 768355da1ebSSage Weil 769355da1ebSSage Weil BUG_ON(need > ci->i_xattrs.prealloc_blob->alloc_len); 770355da1ebSSage Weil 771355da1ebSSage Weil p = rb_first(&ci->i_xattrs.index); 772355da1ebSSage Weil dest = ci->i_xattrs.prealloc_blob->vec.iov_base; 773355da1ebSSage Weil 774355da1ebSSage Weil ceph_encode_32(&dest, ci->i_xattrs.count); 775355da1ebSSage Weil while (p) { 776355da1ebSSage Weil xattr = rb_entry(p, struct ceph_inode_xattr, node); 777355da1ebSSage Weil 778355da1ebSSage Weil ceph_encode_32(&dest, xattr->name_len); 779355da1ebSSage Weil memcpy(dest, xattr->name, xattr->name_len); 780355da1ebSSage Weil dest += xattr->name_len; 781355da1ebSSage Weil ceph_encode_32(&dest, xattr->val_len); 782355da1ebSSage Weil memcpy(dest, xattr->val, xattr->val_len); 783355da1ebSSage Weil dest += xattr->val_len; 784355da1ebSSage Weil 785355da1ebSSage Weil p = rb_next(p); 786355da1ebSSage Weil } 787355da1ebSSage Weil 788355da1ebSSage Weil /* adjust buffer len; it may be larger than we need */ 789355da1ebSSage Weil ci->i_xattrs.prealloc_blob->vec.iov_len = 790355da1ebSSage Weil dest - ci->i_xattrs.prealloc_blob->vec.iov_base; 791355da1ebSSage Weil 792b6c1d5b8SSage Weil if (ci->i_xattrs.blob) 793355da1ebSSage Weil ceph_buffer_put(ci->i_xattrs.blob); 794355da1ebSSage Weil ci->i_xattrs.blob = ci->i_xattrs.prealloc_blob; 795355da1ebSSage Weil ci->i_xattrs.prealloc_blob = NULL; 796355da1ebSSage Weil ci->i_xattrs.dirty = false; 7974a625be4SSage Weil ci->i_xattrs.version++; 798355da1ebSSage Weil } 799355da1ebSSage Weil } 800355da1ebSSage Weil 801315f2408SYan, Zheng static inline int __get_request_mask(struct inode *in) { 802315f2408SYan, Zheng struct ceph_mds_request *req = current->journal_info; 803315f2408SYan, Zheng int mask = 0; 804315f2408SYan, Zheng if (req && req->r_target_inode == in) { 805315f2408SYan, Zheng if (req->r_op == CEPH_MDS_OP_LOOKUP || 806315f2408SYan, Zheng req->r_op == CEPH_MDS_OP_LOOKUPINO || 807315f2408SYan, Zheng req->r_op == CEPH_MDS_OP_LOOKUPPARENT || 808315f2408SYan, Zheng req->r_op == CEPH_MDS_OP_GETATTR) { 809315f2408SYan, Zheng mask = le32_to_cpu(req->r_args.getattr.mask); 810315f2408SYan, Zheng } else if (req->r_op == CEPH_MDS_OP_OPEN || 811315f2408SYan, Zheng req->r_op == CEPH_MDS_OP_CREATE) { 812315f2408SYan, Zheng mask = le32_to_cpu(req->r_args.open.mask); 813315f2408SYan, Zheng } 814315f2408SYan, Zheng } 815315f2408SYan, Zheng return mask; 816315f2408SYan, Zheng } 817315f2408SYan, Zheng 8187221fe4cSGuangliang Zhao ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, 819355da1ebSSage Weil size_t size) 820355da1ebSSage Weil { 821355da1ebSSage Weil struct ceph_inode_info *ci = ceph_inode(inode); 822355da1ebSSage Weil struct ceph_inode_xattr *xattr; 823881a5fa2SAlex Elder struct ceph_vxattr *vxattr = NULL; 824315f2408SYan, Zheng int req_mask; 825f1d1b51dSJeff Layton ssize_t err; 826355da1ebSSage Weil 8270bee82fbSSage Weil /* let's see if a virtual xattr was requested */ 8280bee82fbSSage Weil vxattr = ceph_match_vxattr(inode, name); 82929dccfa5SYan, Zheng if (vxattr) { 83049a9f4f6SYan, Zheng int mask = 0; 83149a9f4f6SYan, Zheng if (vxattr->flags & VXATTR_FLAG_RSTAT) 83249a9f4f6SYan, Zheng mask |= CEPH_STAT_RSTAT; 83349a9f4f6SYan, Zheng err = ceph_do_getattr(inode, mask, true); 8341684dd03SYan, Zheng if (err) 8351684dd03SYan, Zheng return err; 83629dccfa5SYan, Zheng err = -ENODATA; 8373b421018SJeff Layton if (!(vxattr->exists_cb && !vxattr->exists_cb(ci))) { 8380bee82fbSSage Weil err = vxattr->getxattr_cb(ci, value, size); 8393b421018SJeff Layton if (size && size < err) 8403b421018SJeff Layton err = -ERANGE; 8413b421018SJeff Layton } 842a1dc1937Smajianpeng return err; 8430bee82fbSSage Weil } 8440bee82fbSSage Weil 845315f2408SYan, Zheng req_mask = __get_request_mask(inode); 846315f2408SYan, Zheng 847a1dc1937Smajianpeng spin_lock(&ci->i_ceph_lock); 848a1dc1937Smajianpeng dout("getxattr %p ver=%lld index_ver=%lld\n", inode, 849a1dc1937Smajianpeng ci->i_xattrs.version, ci->i_xattrs.index_version); 850a1dc1937Smajianpeng 851508b32d8SYan, Zheng if (ci->i_xattrs.version == 0 || 852315f2408SYan, Zheng !((req_mask & CEPH_CAP_XATTR_SHARED) || 853315f2408SYan, Zheng __ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1))) { 854be655596SSage Weil spin_unlock(&ci->i_ceph_lock); 855315f2408SYan, Zheng 856315f2408SYan, Zheng /* security module gets xattr while filling trace */ 857d37b1d99SMarkus Elfring if (current->journal_info) { 858315f2408SYan, Zheng pr_warn_ratelimited("sync getxattr %p " 859315f2408SYan, Zheng "during filling trace\n", inode); 860315f2408SYan, Zheng return -EBUSY; 861315f2408SYan, Zheng } 862315f2408SYan, Zheng 863355da1ebSSage Weil /* get xattrs from mds (if we don't already have them) */ 864508b32d8SYan, Zheng err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR, true); 865355da1ebSSage Weil if (err) 866355da1ebSSage Weil return err; 867be655596SSage Weil spin_lock(&ci->i_ceph_lock); 868508b32d8SYan, Zheng } 869355da1ebSSage Weil 870355da1ebSSage Weil err = __build_xattrs(inode); 871355da1ebSSage Weil if (err < 0) 872355da1ebSSage Weil goto out; 873355da1ebSSage Weil 874355da1ebSSage Weil err = -ENODATA; /* == ENOATTR */ 875355da1ebSSage Weil xattr = __get_xattr(ci, name); 8760bee82fbSSage Weil if (!xattr) 877355da1ebSSage Weil goto out; 878355da1ebSSage Weil 879355da1ebSSage Weil err = -ERANGE; 880355da1ebSSage Weil if (size && size < xattr->val_len) 881355da1ebSSage Weil goto out; 882355da1ebSSage Weil 883355da1ebSSage Weil err = xattr->val_len; 884355da1ebSSage Weil if (size == 0) 885355da1ebSSage Weil goto out; 886355da1ebSSage Weil 887355da1ebSSage Weil memcpy(value, xattr->val, xattr->val_len); 888355da1ebSSage Weil 889d37b1d99SMarkus Elfring if (current->journal_info && 890315f2408SYan, Zheng !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) 891315f2408SYan, Zheng ci->i_ceph_flags |= CEPH_I_SEC_INITED; 892355da1ebSSage Weil out: 893be655596SSage Weil spin_unlock(&ci->i_ceph_lock); 894355da1ebSSage Weil return err; 895355da1ebSSage Weil } 896355da1ebSSage Weil 897355da1ebSSage Weil ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size) 898355da1ebSSage Weil { 8992b0143b5SDavid Howells struct inode *inode = d_inode(dentry); 900355da1ebSSage Weil struct ceph_inode_info *ci = ceph_inode(inode); 901881a5fa2SAlex Elder struct ceph_vxattr *vxattrs = ceph_inode_vxattrs(inode); 9022b2abcacSDavid Disseldorp bool len_only = (size == 0); 903355da1ebSSage Weil u32 namelen; 904355da1ebSSage Weil int err; 905355da1ebSSage Weil int i; 906355da1ebSSage Weil 907be655596SSage Weil spin_lock(&ci->i_ceph_lock); 908355da1ebSSage Weil dout("listxattr %p ver=%lld index_ver=%lld\n", inode, 909355da1ebSSage Weil ci->i_xattrs.version, ci->i_xattrs.index_version); 910355da1ebSSage Weil 911508b32d8SYan, Zheng if (ci->i_xattrs.version == 0 || 912508b32d8SYan, Zheng !__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1)) { 913be655596SSage Weil spin_unlock(&ci->i_ceph_lock); 914508b32d8SYan, Zheng err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR, true); 915355da1ebSSage Weil if (err) 916355da1ebSSage Weil return err; 917be655596SSage Weil spin_lock(&ci->i_ceph_lock); 918508b32d8SYan, Zheng } 919355da1ebSSage Weil 920355da1ebSSage Weil err = __build_xattrs(inode); 921355da1ebSSage Weil if (err < 0) 922355da1ebSSage Weil goto out; 9233ce6cd12SAlex Elder 9242b2abcacSDavid Disseldorp /* add 1 byte for each xattr due to the null termination */ 925b65917ddSSage Weil namelen = ci->i_xattrs.names_size + ci->i_xattrs.count; 9262b2abcacSDavid Disseldorp if (!len_only) { 9272b2abcacSDavid Disseldorp if (namelen > size) { 928355da1ebSSage Weil err = -ERANGE; 929355da1ebSSage Weil goto out; 9302b2abcacSDavid Disseldorp } 931355da1ebSSage Weil names = __copy_xattr_names(ci, names); 9322b2abcacSDavid Disseldorp size -= namelen; 9332b2abcacSDavid Disseldorp } 9342b2abcacSDavid Disseldorp 935355da1ebSSage Weil 936355da1ebSSage Weil /* virtual xattr names, too */ 937b65917ddSSage Weil if (vxattrs) { 938355da1ebSSage Weil for (i = 0; vxattrs[i].name; i++) { 9392b2abcacSDavid Disseldorp size_t this_len; 9402b2abcacSDavid Disseldorp 9412b2abcacSDavid Disseldorp if (vxattrs[i].flags & VXATTR_FLAG_HIDDEN) 9422b2abcacSDavid Disseldorp continue; 9432b2abcacSDavid Disseldorp if (vxattrs[i].exists_cb && !vxattrs[i].exists_cb(ci)) 9442b2abcacSDavid Disseldorp continue; 9452b2abcacSDavid Disseldorp 9462b2abcacSDavid Disseldorp this_len = strlen(vxattrs[i].name) + 1; 9472b2abcacSDavid Disseldorp namelen += this_len; 9482b2abcacSDavid Disseldorp if (len_only) 9492b2abcacSDavid Disseldorp continue; 9502b2abcacSDavid Disseldorp 9512b2abcacSDavid Disseldorp if (this_len > size) { 9522b2abcacSDavid Disseldorp err = -ERANGE; 9532b2abcacSDavid Disseldorp goto out; 954355da1ebSSage Weil } 955355da1ebSSage Weil 9562b2abcacSDavid Disseldorp memcpy(names, vxattrs[i].name, this_len); 9572b2abcacSDavid Disseldorp names += this_len; 9582b2abcacSDavid Disseldorp size -= this_len; 9592b2abcacSDavid Disseldorp } 9602b2abcacSDavid Disseldorp } 9612b2abcacSDavid Disseldorp err = namelen; 962355da1ebSSage Weil out: 963be655596SSage Weil spin_unlock(&ci->i_ceph_lock); 964355da1ebSSage Weil return err; 965355da1ebSSage Weil } 966355da1ebSSage Weil 967a26feccaSAndreas Gruenbacher static int ceph_sync_setxattr(struct inode *inode, const char *name, 968355da1ebSSage Weil const char *value, size_t size, int flags) 969355da1ebSSage Weil { 970a26feccaSAndreas Gruenbacher struct ceph_fs_client *fsc = ceph_sb_to_client(inode->i_sb); 971355da1ebSSage Weil struct ceph_inode_info *ci = ceph_inode(inode); 972355da1ebSSage Weil struct ceph_mds_request *req; 9733d14c5d2SYehuda Sadeh struct ceph_mds_client *mdsc = fsc->mdsc; 97425e6bae3SYan, Zheng struct ceph_pagelist *pagelist = NULL; 97504303d8aSYan, Zheng int op = CEPH_MDS_OP_SETXATTR; 976355da1ebSSage Weil int err; 977355da1ebSSage Weil 9780aeff37aSYan, Zheng if (size > 0) { 97925e6bae3SYan, Zheng /* copy value into pagelist */ 98033165d47SIlya Dryomov pagelist = ceph_pagelist_alloc(GFP_NOFS); 98125e6bae3SYan, Zheng if (!pagelist) 982355da1ebSSage Weil return -ENOMEM; 98325e6bae3SYan, Zheng 98425e6bae3SYan, Zheng err = ceph_pagelist_append(pagelist, value, size); 98525e6bae3SYan, Zheng if (err) 986355da1ebSSage Weil goto out; 9870aeff37aSYan, Zheng } else if (!value) { 98804303d8aSYan, Zheng if (flags & CEPH_XATTR_REPLACE) 98904303d8aSYan, Zheng op = CEPH_MDS_OP_RMXATTR; 99004303d8aSYan, Zheng else 99125e6bae3SYan, Zheng flags |= CEPH_XATTR_REMOVE; 992355da1ebSSage Weil } 993355da1ebSSage Weil 994355da1ebSSage Weil dout("setxattr value=%.*s\n", (int)size, value); 995355da1ebSSage Weil 996355da1ebSSage Weil /* do request */ 99704303d8aSYan, Zheng req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS); 99860d87733SJulia Lawall if (IS_ERR(req)) { 99960d87733SJulia Lawall err = PTR_ERR(req); 100060d87733SJulia Lawall goto out; 100160d87733SJulia Lawall } 1002a149bb9aSSanidhya Kashyap 1003355da1ebSSage Weil req->r_path2 = kstrdup(name, GFP_NOFS); 1004a149bb9aSSanidhya Kashyap if (!req->r_path2) { 1005a149bb9aSSanidhya Kashyap ceph_mdsc_put_request(req); 1006a149bb9aSSanidhya Kashyap err = -ENOMEM; 1007a149bb9aSSanidhya Kashyap goto out; 1008a149bb9aSSanidhya Kashyap } 1009355da1ebSSage Weil 101004303d8aSYan, Zheng if (op == CEPH_MDS_OP_SETXATTR) { 101104303d8aSYan, Zheng req->r_args.setxattr.flags = cpu_to_le32(flags); 101225e6bae3SYan, Zheng req->r_pagelist = pagelist; 101325e6bae3SYan, Zheng pagelist = NULL; 101404303d8aSYan, Zheng } 1015355da1ebSSage Weil 1016a149bb9aSSanidhya Kashyap req->r_inode = inode; 1017a149bb9aSSanidhya Kashyap ihold(inode); 1018a149bb9aSSanidhya Kashyap req->r_num_caps = 1; 1019a149bb9aSSanidhya Kashyap req->r_inode_drop = CEPH_CAP_XATTR_SHARED; 1020a149bb9aSSanidhya Kashyap 1021355da1ebSSage Weil dout("xattr.ver (before): %lld\n", ci->i_xattrs.version); 1022752c8bdcSSage Weil err = ceph_mdsc_do_request(mdsc, NULL, req); 1023355da1ebSSage Weil ceph_mdsc_put_request(req); 1024355da1ebSSage Weil dout("xattr.ver (after): %lld\n", ci->i_xattrs.version); 1025355da1ebSSage Weil 1026355da1ebSSage Weil out: 102725e6bae3SYan, Zheng if (pagelist) 102825e6bae3SYan, Zheng ceph_pagelist_release(pagelist); 1029355da1ebSSage Weil return err; 1030355da1ebSSage Weil } 1031355da1ebSSage Weil 1032a26feccaSAndreas Gruenbacher int __ceph_setxattr(struct inode *inode, const char *name, 1033355da1ebSSage Weil const void *value, size_t size, int flags) 1034355da1ebSSage Weil { 1035881a5fa2SAlex Elder struct ceph_vxattr *vxattr; 1036355da1ebSSage Weil struct ceph_inode_info *ci = ceph_inode(inode); 1037a26feccaSAndreas Gruenbacher struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; 1038f66fd9f0SYan, Zheng struct ceph_cap_flush *prealloc_cf = NULL; 103918fa8b3fSAlex Elder int issued; 1040355da1ebSSage Weil int err; 1041fbc0b970SYan, Zheng int dirty = 0; 1042355da1ebSSage Weil int name_len = strlen(name); 1043355da1ebSSage Weil int val_len = size; 1044355da1ebSSage Weil char *newname = NULL; 1045355da1ebSSage Weil char *newval = NULL; 1046355da1ebSSage Weil struct ceph_inode_xattr *xattr = NULL; 1047355da1ebSSage Weil int required_blob_size; 1048f1919826SYan, Zheng bool check_realm = false; 1049604d1b02SYan, Zheng bool lock_snap_rwsem = false; 1050355da1ebSSage Weil 10512cdeb1e4SAndreas Gruenbacher if (ceph_snap(inode) != CEPH_NOSNAP) 10522cdeb1e4SAndreas Gruenbacher return -EROFS; 1053355da1ebSSage Weil 105406476a69SAlex Elder vxattr = ceph_match_vxattr(inode, name); 1055f1919826SYan, Zheng if (vxattr) { 10564e9906e7SYan, Zheng if (vxattr->flags & VXATTR_FLAG_READONLY) 1057355da1ebSSage Weil return -EOPNOTSUPP; 1058f1919826SYan, Zheng if (value && !strncmp(vxattr->name, "ceph.quota", 10)) 1059f1919826SYan, Zheng check_realm = true; 1060f1919826SYan, Zheng } 1061355da1ebSSage Weil 10623adf654dSSage Weil /* pass any unhandled ceph.* xattrs through to the MDS */ 10633adf654dSSage Weil if (!strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN)) 10643adf654dSSage Weil goto do_sync_unlocked; 10653adf654dSSage Weil 1066355da1ebSSage Weil /* preallocate memory for xattr name, value, index node */ 1067355da1ebSSage Weil err = -ENOMEM; 106861413c2fSJulia Lawall newname = kmemdup(name, name_len + 1, GFP_NOFS); 1069355da1ebSSage Weil if (!newname) 1070355da1ebSSage Weil goto out; 1071355da1ebSSage Weil 1072355da1ebSSage Weil if (val_len) { 1073b829c195SAlex Elder newval = kmemdup(value, val_len, GFP_NOFS); 1074355da1ebSSage Weil if (!newval) 1075355da1ebSSage Weil goto out; 1076355da1ebSSage Weil } 1077355da1ebSSage Weil 1078355da1ebSSage Weil xattr = kmalloc(sizeof(struct ceph_inode_xattr), GFP_NOFS); 1079355da1ebSSage Weil if (!xattr) 1080355da1ebSSage Weil goto out; 1081355da1ebSSage Weil 1082f66fd9f0SYan, Zheng prealloc_cf = ceph_alloc_cap_flush(); 1083f66fd9f0SYan, Zheng if (!prealloc_cf) 1084f66fd9f0SYan, Zheng goto out; 1085f66fd9f0SYan, Zheng 1086be655596SSage Weil spin_lock(&ci->i_ceph_lock); 1087355da1ebSSage Weil retry: 1088355da1ebSSage Weil issued = __ceph_caps_issued(ci, NULL); 1089508b32d8SYan, Zheng if (ci->i_xattrs.version == 0 || !(issued & CEPH_CAP_XATTR_EXCL)) 1090355da1ebSSage Weil goto do_sync; 1091604d1b02SYan, Zheng 1092604d1b02SYan, Zheng if (!lock_snap_rwsem && !ci->i_head_snapc) { 1093604d1b02SYan, Zheng lock_snap_rwsem = true; 1094604d1b02SYan, Zheng if (!down_read_trylock(&mdsc->snap_rwsem)) { 1095604d1b02SYan, Zheng spin_unlock(&ci->i_ceph_lock); 1096604d1b02SYan, Zheng down_read(&mdsc->snap_rwsem); 1097604d1b02SYan, Zheng spin_lock(&ci->i_ceph_lock); 1098604d1b02SYan, Zheng goto retry; 1099604d1b02SYan, Zheng } 1100604d1b02SYan, Zheng } 1101604d1b02SYan, Zheng 1102604d1b02SYan, Zheng dout("setxattr %p issued %s\n", inode, ceph_cap_string(issued)); 1103355da1ebSSage Weil __build_xattrs(inode); 1104355da1ebSSage Weil 1105355da1ebSSage Weil required_blob_size = __get_required_blob_size(ci, name_len, val_len); 1106355da1ebSSage Weil 1107355da1ebSSage Weil if (!ci->i_xattrs.prealloc_blob || 1108355da1ebSSage Weil required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) { 110918fa8b3fSAlex Elder struct ceph_buffer *blob; 1110355da1ebSSage Weil 1111be655596SSage Weil spin_unlock(&ci->i_ceph_lock); 1112355da1ebSSage Weil dout(" preaallocating new blob size=%d\n", required_blob_size); 1113b6c1d5b8SSage Weil blob = ceph_buffer_new(required_blob_size, GFP_NOFS); 1114355da1ebSSage Weil if (!blob) 1115604d1b02SYan, Zheng goto do_sync_unlocked; 1116be655596SSage Weil spin_lock(&ci->i_ceph_lock); 1117b6c1d5b8SSage Weil if (ci->i_xattrs.prealloc_blob) 1118355da1ebSSage Weil ceph_buffer_put(ci->i_xattrs.prealloc_blob); 1119355da1ebSSage Weil ci->i_xattrs.prealloc_blob = blob; 1120355da1ebSSage Weil goto retry; 1121355da1ebSSage Weil } 1122355da1ebSSage Weil 1123bcdfeb2eSYan, Zheng err = __set_xattr(ci, newname, name_len, newval, val_len, 1124bcdfeb2eSYan, Zheng flags, value ? 1 : -1, &xattr); 112518fa8b3fSAlex Elder 1126fbc0b970SYan, Zheng if (!err) { 1127f66fd9f0SYan, Zheng dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL, 1128f66fd9f0SYan, Zheng &prealloc_cf); 1129355da1ebSSage Weil ci->i_xattrs.dirty = true; 1130c2050a45SDeepa Dinamani inode->i_ctime = current_time(inode); 1131fbc0b970SYan, Zheng } 113218fa8b3fSAlex Elder 1133be655596SSage Weil spin_unlock(&ci->i_ceph_lock); 1134604d1b02SYan, Zheng if (lock_snap_rwsem) 1135604d1b02SYan, Zheng up_read(&mdsc->snap_rwsem); 1136fca65b4aSSage Weil if (dirty) 1137fca65b4aSSage Weil __mark_inode_dirty(inode, dirty); 1138f66fd9f0SYan, Zheng ceph_free_cap_flush(prealloc_cf); 1139355da1ebSSage Weil return err; 1140355da1ebSSage Weil 1141355da1ebSSage Weil do_sync: 1142be655596SSage Weil spin_unlock(&ci->i_ceph_lock); 11433adf654dSSage Weil do_sync_unlocked: 1144604d1b02SYan, Zheng if (lock_snap_rwsem) 1145604d1b02SYan, Zheng up_read(&mdsc->snap_rwsem); 1146315f2408SYan, Zheng 1147315f2408SYan, Zheng /* security module set xattr while filling trace */ 1148d37b1d99SMarkus Elfring if (current->journal_info) { 1149315f2408SYan, Zheng pr_warn_ratelimited("sync setxattr %p " 1150315f2408SYan, Zheng "during filling trace\n", inode); 1151315f2408SYan, Zheng err = -EBUSY; 1152315f2408SYan, Zheng } else { 1153a26feccaSAndreas Gruenbacher err = ceph_sync_setxattr(inode, name, value, size, flags); 1154f1919826SYan, Zheng if (err >= 0 && check_realm) { 1155f1919826SYan, Zheng /* check if snaprealm was created for quota inode */ 1156f1919826SYan, Zheng spin_lock(&ci->i_ceph_lock); 1157f1919826SYan, Zheng if ((ci->i_max_files || ci->i_max_bytes) && 1158f1919826SYan, Zheng !(ci->i_snap_realm && 1159f1919826SYan, Zheng ci->i_snap_realm->ino == ci->i_vino.ino)) 1160f1919826SYan, Zheng err = -EOPNOTSUPP; 1161f1919826SYan, Zheng spin_unlock(&ci->i_ceph_lock); 1162f1919826SYan, Zheng } 1163315f2408SYan, Zheng } 1164355da1ebSSage Weil out: 1165f66fd9f0SYan, Zheng ceph_free_cap_flush(prealloc_cf); 1166355da1ebSSage Weil kfree(newname); 1167355da1ebSSage Weil kfree(newval); 1168355da1ebSSage Weil kfree(xattr); 1169355da1ebSSage Weil return err; 1170355da1ebSSage Weil } 1171355da1ebSSage Weil 11722cdeb1e4SAndreas Gruenbacher static int ceph_get_xattr_handler(const struct xattr_handler *handler, 11732cdeb1e4SAndreas Gruenbacher struct dentry *dentry, struct inode *inode, 11742cdeb1e4SAndreas Gruenbacher const char *name, void *value, size_t size) 11757221fe4cSGuangliang Zhao { 11762cdeb1e4SAndreas Gruenbacher if (!ceph_is_valid_xattr(name)) 11772cdeb1e4SAndreas Gruenbacher return -EOPNOTSUPP; 11782cdeb1e4SAndreas Gruenbacher return __ceph_getxattr(inode, name, value, size); 11797221fe4cSGuangliang Zhao } 1180315f2408SYan, Zheng 11812cdeb1e4SAndreas Gruenbacher static int ceph_set_xattr_handler(const struct xattr_handler *handler, 118259301226SAl Viro struct dentry *unused, struct inode *inode, 118359301226SAl Viro const char *name, const void *value, 118459301226SAl Viro size_t size, int flags) 11852cdeb1e4SAndreas Gruenbacher { 11862cdeb1e4SAndreas Gruenbacher if (!ceph_is_valid_xattr(name)) 11872cdeb1e4SAndreas Gruenbacher return -EOPNOTSUPP; 118859301226SAl Viro return __ceph_setxattr(inode, name, value, size, flags); 11892cdeb1e4SAndreas Gruenbacher } 11902cdeb1e4SAndreas Gruenbacher 11915130cceaSWei Yongjun static const struct xattr_handler ceph_other_xattr_handler = { 11922cdeb1e4SAndreas Gruenbacher .prefix = "", /* match any name => handlers called with full name */ 11932cdeb1e4SAndreas Gruenbacher .get = ceph_get_xattr_handler, 11942cdeb1e4SAndreas Gruenbacher .set = ceph_set_xattr_handler, 11952cdeb1e4SAndreas Gruenbacher }; 11962cdeb1e4SAndreas Gruenbacher 1197315f2408SYan, Zheng #ifdef CONFIG_SECURITY 1198315f2408SYan, Zheng bool ceph_security_xattr_wanted(struct inode *in) 1199315f2408SYan, Zheng { 1200315f2408SYan, Zheng return in->i_security != NULL; 1201315f2408SYan, Zheng } 1202315f2408SYan, Zheng 1203315f2408SYan, Zheng bool ceph_security_xattr_deadlock(struct inode *in) 1204315f2408SYan, Zheng { 1205315f2408SYan, Zheng struct ceph_inode_info *ci; 1206315f2408SYan, Zheng bool ret; 1207d37b1d99SMarkus Elfring if (!in->i_security) 1208315f2408SYan, Zheng return false; 1209315f2408SYan, Zheng ci = ceph_inode(in); 1210315f2408SYan, Zheng spin_lock(&ci->i_ceph_lock); 1211315f2408SYan, Zheng ret = !(ci->i_ceph_flags & CEPH_I_SEC_INITED) && 1212315f2408SYan, Zheng !(ci->i_xattrs.version > 0 && 1213315f2408SYan, Zheng __ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0)); 1214315f2408SYan, Zheng spin_unlock(&ci->i_ceph_lock); 1215315f2408SYan, Zheng return ret; 1216315f2408SYan, Zheng } 1217ac6713ccSYan, Zheng 1218ac6713ccSYan, Zheng #ifdef CONFIG_CEPH_FS_SECURITY_LABEL 1219ac6713ccSYan, Zheng int ceph_security_init_secctx(struct dentry *dentry, umode_t mode, 1220ac6713ccSYan, Zheng struct ceph_acl_sec_ctx *as_ctx) 1221ac6713ccSYan, Zheng { 1222ac6713ccSYan, Zheng struct ceph_pagelist *pagelist = as_ctx->pagelist; 1223ac6713ccSYan, Zheng const char *name; 1224ac6713ccSYan, Zheng size_t name_len; 1225ac6713ccSYan, Zheng int err; 1226ac6713ccSYan, Zheng 1227ac6713ccSYan, Zheng err = security_dentry_init_security(dentry, mode, &dentry->d_name, 1228ac6713ccSYan, Zheng &as_ctx->sec_ctx, 1229ac6713ccSYan, Zheng &as_ctx->sec_ctxlen); 1230ac6713ccSYan, Zheng if (err < 0) { 1231ac6713ccSYan, Zheng WARN_ON_ONCE(err != -EOPNOTSUPP); 1232ac6713ccSYan, Zheng err = 0; /* do nothing */ 1233ac6713ccSYan, Zheng goto out; 1234ac6713ccSYan, Zheng } 1235ac6713ccSYan, Zheng 1236ac6713ccSYan, Zheng err = -ENOMEM; 1237ac6713ccSYan, Zheng if (!pagelist) { 1238ac6713ccSYan, Zheng pagelist = ceph_pagelist_alloc(GFP_KERNEL); 1239ac6713ccSYan, Zheng if (!pagelist) 1240ac6713ccSYan, Zheng goto out; 1241ac6713ccSYan, Zheng err = ceph_pagelist_reserve(pagelist, PAGE_SIZE); 1242ac6713ccSYan, Zheng if (err) 1243ac6713ccSYan, Zheng goto out; 1244ac6713ccSYan, Zheng ceph_pagelist_encode_32(pagelist, 1); 1245ac6713ccSYan, Zheng } 1246ac6713ccSYan, Zheng 1247ac6713ccSYan, Zheng /* 1248ac6713ccSYan, Zheng * FIXME: Make security_dentry_init_security() generic. Currently 1249ac6713ccSYan, Zheng * It only supports single security module and only selinux has 1250ac6713ccSYan, Zheng * dentry_init_security hook. 1251ac6713ccSYan, Zheng */ 1252ac6713ccSYan, Zheng name = XATTR_NAME_SELINUX; 1253ac6713ccSYan, Zheng name_len = strlen(name); 1254ac6713ccSYan, Zheng err = ceph_pagelist_reserve(pagelist, 1255ac6713ccSYan, Zheng 4 * 2 + name_len + as_ctx->sec_ctxlen); 1256ac6713ccSYan, Zheng if (err) 1257ac6713ccSYan, Zheng goto out; 1258ac6713ccSYan, Zheng 1259ac6713ccSYan, Zheng if (as_ctx->pagelist) { 1260ac6713ccSYan, Zheng /* update count of KV pairs */ 1261ac6713ccSYan, Zheng BUG_ON(pagelist->length <= sizeof(__le32)); 1262ac6713ccSYan, Zheng if (list_is_singular(&pagelist->head)) { 1263ac6713ccSYan, Zheng le32_add_cpu((__le32*)pagelist->mapped_tail, 1); 1264ac6713ccSYan, Zheng } else { 1265ac6713ccSYan, Zheng struct page *page = list_first_entry(&pagelist->head, 1266ac6713ccSYan, Zheng struct page, lru); 1267ac6713ccSYan, Zheng void *addr = kmap_atomic(page); 1268ac6713ccSYan, Zheng le32_add_cpu((__le32*)addr, 1); 1269ac6713ccSYan, Zheng kunmap_atomic(addr); 1270ac6713ccSYan, Zheng } 1271ac6713ccSYan, Zheng } else { 1272ac6713ccSYan, Zheng as_ctx->pagelist = pagelist; 1273ac6713ccSYan, Zheng } 1274ac6713ccSYan, Zheng 1275ac6713ccSYan, Zheng ceph_pagelist_encode_32(pagelist, name_len); 1276ac6713ccSYan, Zheng ceph_pagelist_append(pagelist, name, name_len); 1277ac6713ccSYan, Zheng 1278ac6713ccSYan, Zheng ceph_pagelist_encode_32(pagelist, as_ctx->sec_ctxlen); 1279ac6713ccSYan, Zheng ceph_pagelist_append(pagelist, as_ctx->sec_ctx, as_ctx->sec_ctxlen); 1280ac6713ccSYan, Zheng 1281ac6713ccSYan, Zheng err = 0; 1282ac6713ccSYan, Zheng out: 1283ac6713ccSYan, Zheng if (pagelist && !as_ctx->pagelist) 1284ac6713ccSYan, Zheng ceph_pagelist_release(pagelist); 1285ac6713ccSYan, Zheng return err; 1286ac6713ccSYan, Zheng } 1287ac6713ccSYan, Zheng 1288ac6713ccSYan, Zheng void ceph_security_invalidate_secctx(struct inode *inode) 1289ac6713ccSYan, Zheng { 1290ac6713ccSYan, Zheng security_inode_invalidate_secctx(inode); 1291ac6713ccSYan, Zheng } 1292ac6713ccSYan, Zheng 1293ac6713ccSYan, Zheng static int ceph_xattr_set_security_label(const struct xattr_handler *handler, 1294ac6713ccSYan, Zheng struct dentry *unused, struct inode *inode, 1295ac6713ccSYan, Zheng const char *key, const void *buf, 1296ac6713ccSYan, Zheng size_t buflen, int flags) 1297ac6713ccSYan, Zheng { 1298ac6713ccSYan, Zheng if (security_ismaclabel(key)) { 1299ac6713ccSYan, Zheng const char *name = xattr_full_name(handler, key); 1300ac6713ccSYan, Zheng return __ceph_setxattr(inode, name, buf, buflen, flags); 1301ac6713ccSYan, Zheng } 1302ac6713ccSYan, Zheng return -EOPNOTSUPP; 1303ac6713ccSYan, Zheng } 1304ac6713ccSYan, Zheng 1305ac6713ccSYan, Zheng static int ceph_xattr_get_security_label(const struct xattr_handler *handler, 1306ac6713ccSYan, Zheng struct dentry *unused, struct inode *inode, 1307ac6713ccSYan, Zheng const char *key, void *buf, size_t buflen) 1308ac6713ccSYan, Zheng { 1309ac6713ccSYan, Zheng if (security_ismaclabel(key)) { 1310ac6713ccSYan, Zheng const char *name = xattr_full_name(handler, key); 1311ac6713ccSYan, Zheng return __ceph_getxattr(inode, name, buf, buflen); 1312ac6713ccSYan, Zheng } 1313ac6713ccSYan, Zheng return -EOPNOTSUPP; 1314ac6713ccSYan, Zheng } 1315ac6713ccSYan, Zheng 1316ac6713ccSYan, Zheng static const struct xattr_handler ceph_security_label_handler = { 1317ac6713ccSYan, Zheng .prefix = XATTR_SECURITY_PREFIX, 1318ac6713ccSYan, Zheng .get = ceph_xattr_get_security_label, 1319ac6713ccSYan, Zheng .set = ceph_xattr_set_security_label, 1320ac6713ccSYan, Zheng }; 1321ac6713ccSYan, Zheng #endif 1322315f2408SYan, Zheng #endif 13235c31e92dSYan, Zheng 13245c31e92dSYan, Zheng void ceph_release_acl_sec_ctx(struct ceph_acl_sec_ctx *as_ctx) 13255c31e92dSYan, Zheng { 13265c31e92dSYan, Zheng #ifdef CONFIG_CEPH_FS_POSIX_ACL 13275c31e92dSYan, Zheng posix_acl_release(as_ctx->acl); 13285c31e92dSYan, Zheng posix_acl_release(as_ctx->default_acl); 13295c31e92dSYan, Zheng #endif 1330ac6713ccSYan, Zheng #ifdef CONFIG_CEPH_FS_SECURITY_LABEL 1331ac6713ccSYan, Zheng security_release_secctx(as_ctx->sec_ctx, as_ctx->sec_ctxlen); 1332ac6713ccSYan, Zheng #endif 13335c31e92dSYan, Zheng if (as_ctx->pagelist) 13345c31e92dSYan, Zheng ceph_pagelist_release(as_ctx->pagelist); 13355c31e92dSYan, Zheng } 1336ac6713ccSYan, Zheng 1337ac6713ccSYan, Zheng /* 1338ac6713ccSYan, Zheng * List of handlers for synthetic system.* attributes. Other 1339ac6713ccSYan, Zheng * attributes are handled directly. 1340ac6713ccSYan, Zheng */ 1341ac6713ccSYan, Zheng const struct xattr_handler *ceph_xattr_handlers[] = { 1342ac6713ccSYan, Zheng #ifdef CONFIG_CEPH_FS_POSIX_ACL 1343ac6713ccSYan, Zheng &posix_acl_access_xattr_handler, 1344ac6713ccSYan, Zheng &posix_acl_default_xattr_handler, 1345ac6713ccSYan, Zheng #endif 1346ac6713ccSYan, Zheng #ifdef CONFIG_CEPH_FS_SECURITY_LABEL 1347ac6713ccSYan, Zheng &ceph_security_label_handler, 1348ac6713ccSYan, Zheng #endif 1349ac6713ccSYan, Zheng &ceph_other_xattr_handler, 1350ac6713ccSYan, Zheng NULL, 1351ac6713ccSYan, Zheng }; 1352