| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 | 
|  | 2 | #include <linux/ceph/ceph_debug.h> | 
|  | 3 | #include <linux/ceph/pagelist.h> | 
|  | 4 |  | 
|  | 5 | #include "super.h" | 
|  | 6 | #include "mds_client.h" | 
|  | 7 |  | 
|  | 8 | #include <linux/ceph/decode.h> | 
|  | 9 |  | 
|  | 10 | #include <linux/xattr.h> | 
|  | 11 | #include <linux/posix_acl_xattr.h> | 
|  | 12 | #include <linux/slab.h> | 
|  | 13 |  | 
|  | 14 | #define XATTR_CEPH_PREFIX "ceph." | 
|  | 15 | #define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1) | 
|  | 16 |  | 
|  | 17 | static int __remove_xattr(struct ceph_inode_info *ci, | 
|  | 18 | struct ceph_inode_xattr *xattr); | 
|  | 19 |  | 
|  | 20 | static const struct xattr_handler ceph_other_xattr_handler; | 
|  | 21 |  | 
|  | 22 | /* | 
|  | 23 | * List of handlers for synthetic system.* attributes. Other | 
|  | 24 | * attributes are handled directly. | 
|  | 25 | */ | 
|  | 26 | const struct xattr_handler *ceph_xattr_handlers[] = { | 
|  | 27 | #ifdef CONFIG_CEPH_FS_POSIX_ACL | 
|  | 28 | &posix_acl_access_xattr_handler, | 
|  | 29 | &posix_acl_default_xattr_handler, | 
|  | 30 | #endif | 
|  | 31 | &ceph_other_xattr_handler, | 
|  | 32 | NULL, | 
|  | 33 | }; | 
|  | 34 |  | 
|  | 35 | static bool ceph_is_valid_xattr(const char *name) | 
|  | 36 | { | 
|  | 37 | return !strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN) || | 
|  | 38 | !strncmp(name, XATTR_SECURITY_PREFIX, | 
|  | 39 | XATTR_SECURITY_PREFIX_LEN) || | 
|  | 40 | !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) || | 
|  | 41 | !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); | 
|  | 42 | } | 
|  | 43 |  | 
|  | 44 | /* | 
|  | 45 | * These define virtual xattrs exposing the recursive directory | 
|  | 46 | * statistics and layout metadata. | 
|  | 47 | */ | 
|  | 48 | struct ceph_vxattr { | 
|  | 49 | char *name; | 
|  | 50 | size_t name_size;	/* strlen(name) + 1 (for '\0') */ | 
|  | 51 | size_t (*getxattr_cb)(struct ceph_inode_info *ci, char *val, | 
|  | 52 | size_t size); | 
|  | 53 | bool (*exists_cb)(struct ceph_inode_info *ci); | 
|  | 54 | unsigned int flags; | 
|  | 55 | }; | 
|  | 56 |  | 
|  | 57 | #define VXATTR_FLAG_READONLY		(1<<0) | 
|  | 58 | #define VXATTR_FLAG_HIDDEN		(1<<1) | 
|  | 59 | #define VXATTR_FLAG_RSTAT		(1<<2) | 
|  | 60 |  | 
|  | 61 | /* layouts */ | 
|  | 62 |  | 
|  | 63 | static bool ceph_vxattrcb_layout_exists(struct ceph_inode_info *ci) | 
|  | 64 | { | 
|  | 65 | struct ceph_file_layout *fl = &ci->i_layout; | 
|  | 66 | return (fl->stripe_unit > 0 || fl->stripe_count > 0 || | 
|  | 67 | fl->object_size > 0 || fl->pool_id >= 0 || | 
|  | 68 | rcu_dereference_raw(fl->pool_ns) != NULL); | 
|  | 69 | } | 
|  | 70 |  | 
|  | 71 | static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val, | 
|  | 72 | size_t size) | 
|  | 73 | { | 
|  | 74 | struct ceph_fs_client *fsc = ceph_sb_to_client(ci->vfs_inode.i_sb); | 
|  | 75 | struct ceph_osd_client *osdc = &fsc->client->osdc; | 
|  | 76 | struct ceph_string *pool_ns; | 
|  | 77 | s64 pool = ci->i_layout.pool_id; | 
|  | 78 | const char *pool_name; | 
|  | 79 | const char *ns_field = " pool_namespace="; | 
|  | 80 | char buf[128]; | 
|  | 81 | size_t len, total_len = 0; | 
|  | 82 | ssize_t ret; | 
|  | 83 |  | 
|  | 84 | pool_ns = ceph_try_get_string(ci->i_layout.pool_ns); | 
|  | 85 |  | 
|  | 86 | dout("ceph_vxattrcb_layout %p\n", &ci->vfs_inode); | 
|  | 87 | down_read(&osdc->lock); | 
|  | 88 | pool_name = ceph_pg_pool_name_by_id(osdc->osdmap, pool); | 
|  | 89 | if (pool_name) { | 
|  | 90 | len = snprintf(buf, sizeof(buf), | 
|  | 91 | "stripe_unit=%u stripe_count=%u object_size=%u pool=", | 
|  | 92 | ci->i_layout.stripe_unit, ci->i_layout.stripe_count, | 
|  | 93 | ci->i_layout.object_size); | 
|  | 94 | total_len = len + strlen(pool_name); | 
|  | 95 | } else { | 
|  | 96 | len = snprintf(buf, sizeof(buf), | 
|  | 97 | "stripe_unit=%u stripe_count=%u object_size=%u pool=%lld", | 
|  | 98 | ci->i_layout.stripe_unit, ci->i_layout.stripe_count, | 
|  | 99 | ci->i_layout.object_size, (unsigned long long)pool); | 
|  | 100 | total_len = len; | 
|  | 101 | } | 
|  | 102 |  | 
|  | 103 | if (pool_ns) | 
|  | 104 | total_len += strlen(ns_field) + pool_ns->len; | 
|  | 105 |  | 
|  | 106 | ret = total_len; | 
|  | 107 | if (size >= total_len) { | 
|  | 108 | memcpy(val, buf, len); | 
|  | 109 | ret = len; | 
|  | 110 | if (pool_name) { | 
|  | 111 | len = strlen(pool_name); | 
|  | 112 | memcpy(val + ret, pool_name, len); | 
|  | 113 | ret += len; | 
|  | 114 | } | 
|  | 115 | if (pool_ns) { | 
|  | 116 | len = strlen(ns_field); | 
|  | 117 | memcpy(val + ret, ns_field, len); | 
|  | 118 | ret += len; | 
|  | 119 | memcpy(val + ret, pool_ns->str, pool_ns->len); | 
|  | 120 | ret += pool_ns->len; | 
|  | 121 | } | 
|  | 122 | } | 
|  | 123 | up_read(&osdc->lock); | 
|  | 124 | ceph_put_string(pool_ns); | 
|  | 125 | return ret; | 
|  | 126 | } | 
|  | 127 |  | 
|  | 128 | static size_t ceph_vxattrcb_layout_stripe_unit(struct ceph_inode_info *ci, | 
|  | 129 | char *val, size_t size) | 
|  | 130 | { | 
|  | 131 | return snprintf(val, size, "%u", ci->i_layout.stripe_unit); | 
|  | 132 | } | 
|  | 133 |  | 
|  | 134 | static size_t ceph_vxattrcb_layout_stripe_count(struct ceph_inode_info *ci, | 
|  | 135 | char *val, size_t size) | 
|  | 136 | { | 
|  | 137 | return snprintf(val, size, "%u", ci->i_layout.stripe_count); | 
|  | 138 | } | 
|  | 139 |  | 
|  | 140 | static size_t ceph_vxattrcb_layout_object_size(struct ceph_inode_info *ci, | 
|  | 141 | char *val, size_t size) | 
|  | 142 | { | 
|  | 143 | return snprintf(val, size, "%u", ci->i_layout.object_size); | 
|  | 144 | } | 
|  | 145 |  | 
|  | 146 | static size_t ceph_vxattrcb_layout_pool(struct ceph_inode_info *ci, | 
|  | 147 | char *val, size_t size) | 
|  | 148 | { | 
|  | 149 | int ret; | 
|  | 150 | struct ceph_fs_client *fsc = ceph_sb_to_client(ci->vfs_inode.i_sb); | 
|  | 151 | struct ceph_osd_client *osdc = &fsc->client->osdc; | 
|  | 152 | s64 pool = ci->i_layout.pool_id; | 
|  | 153 | const char *pool_name; | 
|  | 154 |  | 
|  | 155 | down_read(&osdc->lock); | 
|  | 156 | pool_name = ceph_pg_pool_name_by_id(osdc->osdmap, pool); | 
|  | 157 | if (pool_name) | 
|  | 158 | ret = snprintf(val, size, "%s", pool_name); | 
|  | 159 | else | 
|  | 160 | ret = snprintf(val, size, "%lld", (unsigned long long)pool); | 
|  | 161 | up_read(&osdc->lock); | 
|  | 162 | return ret; | 
|  | 163 | } | 
|  | 164 |  | 
|  | 165 | static size_t ceph_vxattrcb_layout_pool_namespace(struct ceph_inode_info *ci, | 
|  | 166 | char *val, size_t size) | 
|  | 167 | { | 
|  | 168 | int ret = 0; | 
|  | 169 | struct ceph_string *ns = ceph_try_get_string(ci->i_layout.pool_ns); | 
|  | 170 | if (ns) { | 
|  | 171 | ret = snprintf(val, size, "%.*s", (int)ns->len, ns->str); | 
|  | 172 | ceph_put_string(ns); | 
|  | 173 | } | 
|  | 174 | return ret; | 
|  | 175 | } | 
|  | 176 |  | 
|  | 177 | /* directories */ | 
|  | 178 |  | 
|  | 179 | static size_t ceph_vxattrcb_dir_entries(struct ceph_inode_info *ci, char *val, | 
|  | 180 | size_t size) | 
|  | 181 | { | 
|  | 182 | return snprintf(val, size, "%lld", ci->i_files + ci->i_subdirs); | 
|  | 183 | } | 
|  | 184 |  | 
|  | 185 | static size_t ceph_vxattrcb_dir_files(struct ceph_inode_info *ci, char *val, | 
|  | 186 | size_t size) | 
|  | 187 | { | 
|  | 188 | return snprintf(val, size, "%lld", ci->i_files); | 
|  | 189 | } | 
|  | 190 |  | 
|  | 191 | static size_t ceph_vxattrcb_dir_subdirs(struct ceph_inode_info *ci, char *val, | 
|  | 192 | size_t size) | 
|  | 193 | { | 
|  | 194 | return snprintf(val, size, "%lld", ci->i_subdirs); | 
|  | 195 | } | 
|  | 196 |  | 
|  | 197 | static size_t ceph_vxattrcb_dir_rentries(struct ceph_inode_info *ci, char *val, | 
|  | 198 | size_t size) | 
|  | 199 | { | 
|  | 200 | return snprintf(val, size, "%lld", ci->i_rfiles + ci->i_rsubdirs); | 
|  | 201 | } | 
|  | 202 |  | 
|  | 203 | static size_t ceph_vxattrcb_dir_rfiles(struct ceph_inode_info *ci, char *val, | 
|  | 204 | size_t size) | 
|  | 205 | { | 
|  | 206 | return snprintf(val, size, "%lld", ci->i_rfiles); | 
|  | 207 | } | 
|  | 208 |  | 
|  | 209 | static size_t ceph_vxattrcb_dir_rsubdirs(struct ceph_inode_info *ci, char *val, | 
|  | 210 | size_t size) | 
|  | 211 | { | 
|  | 212 | return snprintf(val, size, "%lld", ci->i_rsubdirs); | 
|  | 213 | } | 
|  | 214 |  | 
|  | 215 | static size_t ceph_vxattrcb_dir_rbytes(struct ceph_inode_info *ci, char *val, | 
|  | 216 | size_t size) | 
|  | 217 | { | 
|  | 218 | return snprintf(val, size, "%lld", ci->i_rbytes); | 
|  | 219 | } | 
|  | 220 |  | 
|  | 221 | static size_t ceph_vxattrcb_dir_rctime(struct ceph_inode_info *ci, char *val, | 
|  | 222 | size_t size) | 
|  | 223 | { | 
|  | 224 | return snprintf(val, size, "%lld.09%ld", ci->i_rctime.tv_sec, | 
|  | 225 | ci->i_rctime.tv_nsec); | 
|  | 226 | } | 
|  | 227 |  | 
|  | 228 | /* quotas */ | 
|  | 229 |  | 
|  | 230 | static bool ceph_vxattrcb_quota_exists(struct ceph_inode_info *ci) | 
|  | 231 | { | 
|  | 232 | bool ret = false; | 
|  | 233 | spin_lock(&ci->i_ceph_lock); | 
|  | 234 | if ((ci->i_max_files || ci->i_max_bytes) && | 
|  | 235 | ci->i_vino.snap == CEPH_NOSNAP && | 
|  | 236 | ci->i_snap_realm && | 
|  | 237 | ci->i_snap_realm->ino == ci->i_vino.ino) | 
|  | 238 | ret = true; | 
|  | 239 | spin_unlock(&ci->i_ceph_lock); | 
|  | 240 | return ret; | 
|  | 241 | } | 
|  | 242 |  | 
|  | 243 | static size_t ceph_vxattrcb_quota(struct ceph_inode_info *ci, char *val, | 
|  | 244 | size_t size) | 
|  | 245 | { | 
|  | 246 | return snprintf(val, size, "max_bytes=%llu max_files=%llu", | 
|  | 247 | ci->i_max_bytes, ci->i_max_files); | 
|  | 248 | } | 
|  | 249 |  | 
|  | 250 | static size_t ceph_vxattrcb_quota_max_bytes(struct ceph_inode_info *ci, | 
|  | 251 | char *val, size_t size) | 
|  | 252 | { | 
|  | 253 | return snprintf(val, size, "%llu", ci->i_max_bytes); | 
|  | 254 | } | 
|  | 255 |  | 
|  | 256 | static size_t ceph_vxattrcb_quota_max_files(struct ceph_inode_info *ci, | 
|  | 257 | char *val, size_t size) | 
|  | 258 | { | 
|  | 259 | return snprintf(val, size, "%llu", ci->i_max_files); | 
|  | 260 | } | 
|  | 261 |  | 
|  | 262 | #define CEPH_XATTR_NAME(_type, _name)	XATTR_CEPH_PREFIX #_type "." #_name | 
|  | 263 | #define CEPH_XATTR_NAME2(_type, _name, _name2)	\ | 
|  | 264 | XATTR_CEPH_PREFIX #_type "." #_name "." #_name2 | 
|  | 265 |  | 
|  | 266 | #define XATTR_NAME_CEPH(_type, _name, _flags)				\ | 
|  | 267 | {								\ | 
|  | 268 | .name = CEPH_XATTR_NAME(_type, _name),			\ | 
|  | 269 | .name_size = sizeof (CEPH_XATTR_NAME(_type, _name)), \ | 
|  | 270 | .getxattr_cb = ceph_vxattrcb_ ## _type ## _ ## _name, \ | 
|  | 271 | .exists_cb = NULL,					\ | 
|  | 272 | .flags = (VXATTR_FLAG_READONLY | _flags),		\ | 
|  | 273 | } | 
|  | 274 | #define XATTR_RSTAT_FIELD(_type, _name)			\ | 
|  | 275 | XATTR_NAME_CEPH(_type, _name, VXATTR_FLAG_RSTAT) | 
|  | 276 | #define XATTR_LAYOUT_FIELD(_type, _name, _field)			\ | 
|  | 277 | {								\ | 
|  | 278 | .name = CEPH_XATTR_NAME2(_type, _name, _field),	\ | 
|  | 279 | .name_size = sizeof (CEPH_XATTR_NAME2(_type, _name, _field)), \ | 
|  | 280 | .getxattr_cb = ceph_vxattrcb_ ## _name ## _ ## _field, \ | 
|  | 281 | .exists_cb = ceph_vxattrcb_layout_exists,	\ | 
|  | 282 | .flags = VXATTR_FLAG_HIDDEN,			\ | 
|  | 283 | } | 
|  | 284 | #define XATTR_QUOTA_FIELD(_type, _name)					\ | 
|  | 285 | {								\ | 
|  | 286 | .name = CEPH_XATTR_NAME(_type, _name),			\ | 
|  | 287 | .name_size = sizeof(CEPH_XATTR_NAME(_type, _name)),	\ | 
|  | 288 | .getxattr_cb = ceph_vxattrcb_ ## _type ## _ ## _name,	\ | 
|  | 289 | .exists_cb = ceph_vxattrcb_quota_exists,		\ | 
|  | 290 | .flags = VXATTR_FLAG_HIDDEN,				\ | 
|  | 291 | } | 
|  | 292 |  | 
|  | 293 | static struct ceph_vxattr ceph_dir_vxattrs[] = { | 
|  | 294 | { | 
|  | 295 | .name = "ceph.dir.layout", | 
|  | 296 | .name_size = sizeof("ceph.dir.layout"), | 
|  | 297 | .getxattr_cb = ceph_vxattrcb_layout, | 
|  | 298 | .exists_cb = ceph_vxattrcb_layout_exists, | 
|  | 299 | .flags = VXATTR_FLAG_HIDDEN, | 
|  | 300 | }, | 
|  | 301 | XATTR_LAYOUT_FIELD(dir, layout, stripe_unit), | 
|  | 302 | XATTR_LAYOUT_FIELD(dir, layout, stripe_count), | 
|  | 303 | XATTR_LAYOUT_FIELD(dir, layout, object_size), | 
|  | 304 | XATTR_LAYOUT_FIELD(dir, layout, pool), | 
|  | 305 | XATTR_LAYOUT_FIELD(dir, layout, pool_namespace), | 
|  | 306 | XATTR_NAME_CEPH(dir, entries, 0), | 
|  | 307 | XATTR_NAME_CEPH(dir, files, 0), | 
|  | 308 | XATTR_NAME_CEPH(dir, subdirs, 0), | 
|  | 309 | XATTR_RSTAT_FIELD(dir, rentries), | 
|  | 310 | XATTR_RSTAT_FIELD(dir, rfiles), | 
|  | 311 | XATTR_RSTAT_FIELD(dir, rsubdirs), | 
|  | 312 | XATTR_RSTAT_FIELD(dir, rbytes), | 
|  | 313 | XATTR_RSTAT_FIELD(dir, rctime), | 
|  | 314 | { | 
|  | 315 | .name = "ceph.quota", | 
|  | 316 | .name_size = sizeof("ceph.quota"), | 
|  | 317 | .getxattr_cb = ceph_vxattrcb_quota, | 
|  | 318 | .exists_cb = ceph_vxattrcb_quota_exists, | 
|  | 319 | .flags = VXATTR_FLAG_HIDDEN, | 
|  | 320 | }, | 
|  | 321 | XATTR_QUOTA_FIELD(quota, max_bytes), | 
|  | 322 | XATTR_QUOTA_FIELD(quota, max_files), | 
|  | 323 | { .name = NULL, 0 }	/* Required table terminator */ | 
|  | 324 | }; | 
|  | 325 | static size_t ceph_dir_vxattrs_name_size;	/* total size of all names */ | 
|  | 326 |  | 
|  | 327 | /* files */ | 
|  | 328 |  | 
|  | 329 | static struct ceph_vxattr ceph_file_vxattrs[] = { | 
|  | 330 | { | 
|  | 331 | .name = "ceph.file.layout", | 
|  | 332 | .name_size = sizeof("ceph.file.layout"), | 
|  | 333 | .getxattr_cb = ceph_vxattrcb_layout, | 
|  | 334 | .exists_cb = ceph_vxattrcb_layout_exists, | 
|  | 335 | .flags = VXATTR_FLAG_HIDDEN, | 
|  | 336 | }, | 
|  | 337 | XATTR_LAYOUT_FIELD(file, layout, stripe_unit), | 
|  | 338 | XATTR_LAYOUT_FIELD(file, layout, stripe_count), | 
|  | 339 | XATTR_LAYOUT_FIELD(file, layout, object_size), | 
|  | 340 | XATTR_LAYOUT_FIELD(file, layout, pool), | 
|  | 341 | XATTR_LAYOUT_FIELD(file, layout, pool_namespace), | 
|  | 342 | { .name = NULL, 0 }	/* Required table terminator */ | 
|  | 343 | }; | 
|  | 344 | static size_t ceph_file_vxattrs_name_size;	/* total size of all names */ | 
|  | 345 |  | 
|  | 346 | static struct ceph_vxattr *ceph_inode_vxattrs(struct inode *inode) | 
|  | 347 | { | 
|  | 348 | if (S_ISDIR(inode->i_mode)) | 
|  | 349 | return ceph_dir_vxattrs; | 
|  | 350 | else if (S_ISREG(inode->i_mode)) | 
|  | 351 | return ceph_file_vxattrs; | 
|  | 352 | return NULL; | 
|  | 353 | } | 
|  | 354 |  | 
|  | 355 | static size_t ceph_vxattrs_name_size(struct ceph_vxattr *vxattrs) | 
|  | 356 | { | 
|  | 357 | if (vxattrs == ceph_dir_vxattrs) | 
|  | 358 | return ceph_dir_vxattrs_name_size; | 
|  | 359 | if (vxattrs == ceph_file_vxattrs) | 
|  | 360 | return ceph_file_vxattrs_name_size; | 
|  | 361 | BUG_ON(vxattrs); | 
|  | 362 | return 0; | 
|  | 363 | } | 
|  | 364 |  | 
|  | 365 | /* | 
|  | 366 | * Compute the aggregate size (including terminating '\0') of all | 
|  | 367 | * virtual extended attribute names in the given vxattr table. | 
|  | 368 | */ | 
|  | 369 | static size_t __init vxattrs_name_size(struct ceph_vxattr *vxattrs) | 
|  | 370 | { | 
|  | 371 | struct ceph_vxattr *vxattr; | 
|  | 372 | size_t size = 0; | 
|  | 373 |  | 
|  | 374 | for (vxattr = vxattrs; vxattr->name; vxattr++) { | 
|  | 375 | if (!(vxattr->flags & VXATTR_FLAG_HIDDEN)) | 
|  | 376 | size += vxattr->name_size; | 
|  | 377 | } | 
|  | 378 |  | 
|  | 379 | return size; | 
|  | 380 | } | 
|  | 381 |  | 
|  | 382 | /* Routines called at initialization and exit time */ | 
|  | 383 |  | 
|  | 384 | void __init ceph_xattr_init(void) | 
|  | 385 | { | 
|  | 386 | ceph_dir_vxattrs_name_size = vxattrs_name_size(ceph_dir_vxattrs); | 
|  | 387 | ceph_file_vxattrs_name_size = vxattrs_name_size(ceph_file_vxattrs); | 
|  | 388 | } | 
|  | 389 |  | 
|  | 390 | void ceph_xattr_exit(void) | 
|  | 391 | { | 
|  | 392 | ceph_dir_vxattrs_name_size = 0; | 
|  | 393 | ceph_file_vxattrs_name_size = 0; | 
|  | 394 | } | 
|  | 395 |  | 
|  | 396 | static struct ceph_vxattr *ceph_match_vxattr(struct inode *inode, | 
|  | 397 | const char *name) | 
|  | 398 | { | 
|  | 399 | struct ceph_vxattr *vxattr = ceph_inode_vxattrs(inode); | 
|  | 400 |  | 
|  | 401 | if (vxattr) { | 
|  | 402 | while (vxattr->name) { | 
|  | 403 | if (!strcmp(vxattr->name, name)) | 
|  | 404 | return vxattr; | 
|  | 405 | vxattr++; | 
|  | 406 | } | 
|  | 407 | } | 
|  | 408 |  | 
|  | 409 | return NULL; | 
|  | 410 | } | 
|  | 411 |  | 
|  | 412 | static int __set_xattr(struct ceph_inode_info *ci, | 
|  | 413 | const char *name, int name_len, | 
|  | 414 | const char *val, int val_len, | 
|  | 415 | int flags, int update_xattr, | 
|  | 416 | struct ceph_inode_xattr **newxattr) | 
|  | 417 | { | 
|  | 418 | struct rb_node **p; | 
|  | 419 | struct rb_node *parent = NULL; | 
|  | 420 | struct ceph_inode_xattr *xattr = NULL; | 
|  | 421 | int c; | 
|  | 422 | int new = 0; | 
|  | 423 |  | 
|  | 424 | p = &ci->i_xattrs.index.rb_node; | 
|  | 425 | while (*p) { | 
|  | 426 | parent = *p; | 
|  | 427 | xattr = rb_entry(parent, struct ceph_inode_xattr, node); | 
|  | 428 | c = strncmp(name, xattr->name, min(name_len, xattr->name_len)); | 
|  | 429 | if (c < 0) | 
|  | 430 | p = &(*p)->rb_left; | 
|  | 431 | else if (c > 0) | 
|  | 432 | p = &(*p)->rb_right; | 
|  | 433 | else { | 
|  | 434 | if (name_len == xattr->name_len) | 
|  | 435 | break; | 
|  | 436 | else if (name_len < xattr->name_len) | 
|  | 437 | p = &(*p)->rb_left; | 
|  | 438 | else | 
|  | 439 | p = &(*p)->rb_right; | 
|  | 440 | } | 
|  | 441 | xattr = NULL; | 
|  | 442 | } | 
|  | 443 |  | 
|  | 444 | if (update_xattr) { | 
|  | 445 | int err = 0; | 
|  | 446 |  | 
|  | 447 | if (xattr && (flags & XATTR_CREATE)) | 
|  | 448 | err = -EEXIST; | 
|  | 449 | else if (!xattr && (flags & XATTR_REPLACE)) | 
|  | 450 | err = -ENODATA; | 
|  | 451 | if (err) { | 
|  | 452 | kfree(name); | 
|  | 453 | kfree(val); | 
|  | 454 | kfree(*newxattr); | 
|  | 455 | return err; | 
|  | 456 | } | 
|  | 457 | if (update_xattr < 0) { | 
|  | 458 | if (xattr) | 
|  | 459 | __remove_xattr(ci, xattr); | 
|  | 460 | kfree(name); | 
|  | 461 | kfree(*newxattr); | 
|  | 462 | return 0; | 
|  | 463 | } | 
|  | 464 | } | 
|  | 465 |  | 
|  | 466 | if (!xattr) { | 
|  | 467 | new = 1; | 
|  | 468 | xattr = *newxattr; | 
|  | 469 | xattr->name = name; | 
|  | 470 | xattr->name_len = name_len; | 
|  | 471 | xattr->should_free_name = update_xattr; | 
|  | 472 |  | 
|  | 473 | ci->i_xattrs.count++; | 
|  | 474 | dout("__set_xattr count=%d\n", ci->i_xattrs.count); | 
|  | 475 | } else { | 
|  | 476 | kfree(*newxattr); | 
|  | 477 | *newxattr = NULL; | 
|  | 478 | if (xattr->should_free_val) | 
|  | 479 | kfree((void *)xattr->val); | 
|  | 480 |  | 
|  | 481 | if (update_xattr) { | 
|  | 482 | kfree((void *)name); | 
|  | 483 | name = xattr->name; | 
|  | 484 | } | 
|  | 485 | ci->i_xattrs.names_size -= xattr->name_len; | 
|  | 486 | ci->i_xattrs.vals_size -= xattr->val_len; | 
|  | 487 | } | 
|  | 488 | ci->i_xattrs.names_size += name_len; | 
|  | 489 | ci->i_xattrs.vals_size += val_len; | 
|  | 490 | if (val) | 
|  | 491 | xattr->val = val; | 
|  | 492 | else | 
|  | 493 | xattr->val = ""; | 
|  | 494 |  | 
|  | 495 | xattr->val_len = val_len; | 
|  | 496 | xattr->dirty = update_xattr; | 
|  | 497 | xattr->should_free_val = (val && update_xattr); | 
|  | 498 |  | 
|  | 499 | if (new) { | 
|  | 500 | rb_link_node(&xattr->node, parent, p); | 
|  | 501 | rb_insert_color(&xattr->node, &ci->i_xattrs.index); | 
|  | 502 | dout("__set_xattr_val p=%p\n", p); | 
|  | 503 | } | 
|  | 504 |  | 
|  | 505 | dout("__set_xattr_val added %llx.%llx xattr %p %s=%.*s\n", | 
|  | 506 | ceph_vinop(&ci->vfs_inode), xattr, name, val_len, val); | 
|  | 507 |  | 
|  | 508 | return 0; | 
|  | 509 | } | 
|  | 510 |  | 
|  | 511 | static struct ceph_inode_xattr *__get_xattr(struct ceph_inode_info *ci, | 
|  | 512 | const char *name) | 
|  | 513 | { | 
|  | 514 | struct rb_node **p; | 
|  | 515 | struct rb_node *parent = NULL; | 
|  | 516 | struct ceph_inode_xattr *xattr = NULL; | 
|  | 517 | int name_len = strlen(name); | 
|  | 518 | int c; | 
|  | 519 |  | 
|  | 520 | p = &ci->i_xattrs.index.rb_node; | 
|  | 521 | while (*p) { | 
|  | 522 | parent = *p; | 
|  | 523 | xattr = rb_entry(parent, struct ceph_inode_xattr, node); | 
|  | 524 | c = strncmp(name, xattr->name, xattr->name_len); | 
|  | 525 | if (c == 0 && name_len > xattr->name_len) | 
|  | 526 | c = 1; | 
|  | 527 | if (c < 0) | 
|  | 528 | p = &(*p)->rb_left; | 
|  | 529 | else if (c > 0) | 
|  | 530 | p = &(*p)->rb_right; | 
|  | 531 | else { | 
|  | 532 | dout("__get_xattr %s: found %.*s\n", name, | 
|  | 533 | xattr->val_len, xattr->val); | 
|  | 534 | return xattr; | 
|  | 535 | } | 
|  | 536 | } | 
|  | 537 |  | 
|  | 538 | dout("__get_xattr %s: not found\n", name); | 
|  | 539 |  | 
|  | 540 | return NULL; | 
|  | 541 | } | 
|  | 542 |  | 
|  | 543 | static void __free_xattr(struct ceph_inode_xattr *xattr) | 
|  | 544 | { | 
|  | 545 | BUG_ON(!xattr); | 
|  | 546 |  | 
|  | 547 | if (xattr->should_free_name) | 
|  | 548 | kfree((void *)xattr->name); | 
|  | 549 | if (xattr->should_free_val) | 
|  | 550 | kfree((void *)xattr->val); | 
|  | 551 |  | 
|  | 552 | kfree(xattr); | 
|  | 553 | } | 
|  | 554 |  | 
|  | 555 | static int __remove_xattr(struct ceph_inode_info *ci, | 
|  | 556 | struct ceph_inode_xattr *xattr) | 
|  | 557 | { | 
|  | 558 | if (!xattr) | 
|  | 559 | return -ENODATA; | 
|  | 560 |  | 
|  | 561 | rb_erase(&xattr->node, &ci->i_xattrs.index); | 
|  | 562 |  | 
|  | 563 | if (xattr->should_free_name) | 
|  | 564 | kfree((void *)xattr->name); | 
|  | 565 | if (xattr->should_free_val) | 
|  | 566 | kfree((void *)xattr->val); | 
|  | 567 |  | 
|  | 568 | ci->i_xattrs.names_size -= xattr->name_len; | 
|  | 569 | ci->i_xattrs.vals_size -= xattr->val_len; | 
|  | 570 | ci->i_xattrs.count--; | 
|  | 571 | kfree(xattr); | 
|  | 572 |  | 
|  | 573 | return 0; | 
|  | 574 | } | 
|  | 575 |  | 
|  | 576 | static char *__copy_xattr_names(struct ceph_inode_info *ci, | 
|  | 577 | char *dest) | 
|  | 578 | { | 
|  | 579 | struct rb_node *p; | 
|  | 580 | struct ceph_inode_xattr *xattr = NULL; | 
|  | 581 |  | 
|  | 582 | p = rb_first(&ci->i_xattrs.index); | 
|  | 583 | dout("__copy_xattr_names count=%d\n", ci->i_xattrs.count); | 
|  | 584 |  | 
|  | 585 | while (p) { | 
|  | 586 | xattr = rb_entry(p, struct ceph_inode_xattr, node); | 
|  | 587 | memcpy(dest, xattr->name, xattr->name_len); | 
|  | 588 | dest[xattr->name_len] = '\0'; | 
|  | 589 |  | 
|  | 590 | dout("dest=%s %p (%s) (%d/%d)\n", dest, xattr, xattr->name, | 
|  | 591 | xattr->name_len, ci->i_xattrs.names_size); | 
|  | 592 |  | 
|  | 593 | dest += xattr->name_len + 1; | 
|  | 594 | p = rb_next(p); | 
|  | 595 | } | 
|  | 596 |  | 
|  | 597 | return dest; | 
|  | 598 | } | 
|  | 599 |  | 
|  | 600 | void __ceph_destroy_xattrs(struct ceph_inode_info *ci) | 
|  | 601 | { | 
|  | 602 | struct rb_node *p, *tmp; | 
|  | 603 | struct ceph_inode_xattr *xattr = NULL; | 
|  | 604 |  | 
|  | 605 | p = rb_first(&ci->i_xattrs.index); | 
|  | 606 |  | 
|  | 607 | dout("__ceph_destroy_xattrs p=%p\n", p); | 
|  | 608 |  | 
|  | 609 | while (p) { | 
|  | 610 | xattr = rb_entry(p, struct ceph_inode_xattr, node); | 
|  | 611 | tmp = p; | 
|  | 612 | p = rb_next(tmp); | 
|  | 613 | dout("__ceph_destroy_xattrs next p=%p (%.*s)\n", p, | 
|  | 614 | xattr->name_len, xattr->name); | 
|  | 615 | rb_erase(tmp, &ci->i_xattrs.index); | 
|  | 616 |  | 
|  | 617 | __free_xattr(xattr); | 
|  | 618 | } | 
|  | 619 |  | 
|  | 620 | ci->i_xattrs.names_size = 0; | 
|  | 621 | ci->i_xattrs.vals_size = 0; | 
|  | 622 | ci->i_xattrs.index_version = 0; | 
|  | 623 | ci->i_xattrs.count = 0; | 
|  | 624 | ci->i_xattrs.index = RB_ROOT; | 
|  | 625 | } | 
|  | 626 |  | 
|  | 627 | static int __build_xattrs(struct inode *inode) | 
|  | 628 | __releases(ci->i_ceph_lock) | 
|  | 629 | __acquires(ci->i_ceph_lock) | 
|  | 630 | { | 
|  | 631 | u32 namelen; | 
|  | 632 | u32 numattr = 0; | 
|  | 633 | void *p, *end; | 
|  | 634 | u32 len; | 
|  | 635 | const char *name, *val; | 
|  | 636 | struct ceph_inode_info *ci = ceph_inode(inode); | 
|  | 637 | int xattr_version; | 
|  | 638 | struct ceph_inode_xattr **xattrs = NULL; | 
|  | 639 | int err = 0; | 
|  | 640 | int i; | 
|  | 641 |  | 
|  | 642 | dout("__build_xattrs() len=%d\n", | 
|  | 643 | ci->i_xattrs.blob ? (int)ci->i_xattrs.blob->vec.iov_len : 0); | 
|  | 644 |  | 
|  | 645 | if (ci->i_xattrs.index_version >= ci->i_xattrs.version) | 
|  | 646 | return 0; /* already built */ | 
|  | 647 |  | 
|  | 648 | __ceph_destroy_xattrs(ci); | 
|  | 649 |  | 
|  | 650 | start: | 
|  | 651 | /* updated internal xattr rb tree */ | 
|  | 652 | if (ci->i_xattrs.blob && ci->i_xattrs.blob->vec.iov_len > 4) { | 
|  | 653 | p = ci->i_xattrs.blob->vec.iov_base; | 
|  | 654 | end = p + ci->i_xattrs.blob->vec.iov_len; | 
|  | 655 | ceph_decode_32_safe(&p, end, numattr, bad); | 
|  | 656 | xattr_version = ci->i_xattrs.version; | 
|  | 657 | spin_unlock(&ci->i_ceph_lock); | 
|  | 658 |  | 
|  | 659 | xattrs = kcalloc(numattr, sizeof(struct ceph_inode_xattr *), | 
|  | 660 | GFP_NOFS); | 
|  | 661 | err = -ENOMEM; | 
|  | 662 | if (!xattrs) | 
|  | 663 | goto bad_lock; | 
|  | 664 |  | 
|  | 665 | for (i = 0; i < numattr; i++) { | 
|  | 666 | xattrs[i] = kmalloc(sizeof(struct ceph_inode_xattr), | 
|  | 667 | GFP_NOFS); | 
|  | 668 | if (!xattrs[i]) | 
|  | 669 | goto bad_lock; | 
|  | 670 | } | 
|  | 671 |  | 
|  | 672 | spin_lock(&ci->i_ceph_lock); | 
|  | 673 | if (ci->i_xattrs.version != xattr_version) { | 
|  | 674 | /* lost a race, retry */ | 
|  | 675 | for (i = 0; i < numattr; i++) | 
|  | 676 | kfree(xattrs[i]); | 
|  | 677 | kfree(xattrs); | 
|  | 678 | xattrs = NULL; | 
|  | 679 | goto start; | 
|  | 680 | } | 
|  | 681 | err = -EIO; | 
|  | 682 | while (numattr--) { | 
|  | 683 | ceph_decode_32_safe(&p, end, len, bad); | 
|  | 684 | namelen = len; | 
|  | 685 | name = p; | 
|  | 686 | p += len; | 
|  | 687 | ceph_decode_32_safe(&p, end, len, bad); | 
|  | 688 | val = p; | 
|  | 689 | p += len; | 
|  | 690 |  | 
|  | 691 | err = __set_xattr(ci, name, namelen, val, len, | 
|  | 692 | 0, 0, &xattrs[numattr]); | 
|  | 693 |  | 
|  | 694 | if (err < 0) | 
|  | 695 | goto bad; | 
|  | 696 | } | 
|  | 697 | kfree(xattrs); | 
|  | 698 | } | 
|  | 699 | ci->i_xattrs.index_version = ci->i_xattrs.version; | 
|  | 700 | ci->i_xattrs.dirty = false; | 
|  | 701 |  | 
|  | 702 | return err; | 
|  | 703 | bad_lock: | 
|  | 704 | spin_lock(&ci->i_ceph_lock); | 
|  | 705 | bad: | 
|  | 706 | if (xattrs) { | 
|  | 707 | for (i = 0; i < numattr; i++) | 
|  | 708 | kfree(xattrs[i]); | 
|  | 709 | kfree(xattrs); | 
|  | 710 | } | 
|  | 711 | ci->i_xattrs.names_size = 0; | 
|  | 712 | return err; | 
|  | 713 | } | 
|  | 714 |  | 
|  | 715 | static int __get_required_blob_size(struct ceph_inode_info *ci, int name_size, | 
|  | 716 | int val_size) | 
|  | 717 | { | 
|  | 718 | /* | 
|  | 719 | * 4 bytes for the length, and additional 4 bytes per each xattr name, | 
|  | 720 | * 4 bytes per each value | 
|  | 721 | */ | 
|  | 722 | int size = 4 + ci->i_xattrs.count*(4 + 4) + | 
|  | 723 | ci->i_xattrs.names_size + | 
|  | 724 | ci->i_xattrs.vals_size; | 
|  | 725 | dout("__get_required_blob_size c=%d names.size=%d vals.size=%d\n", | 
|  | 726 | ci->i_xattrs.count, ci->i_xattrs.names_size, | 
|  | 727 | ci->i_xattrs.vals_size); | 
|  | 728 |  | 
|  | 729 | if (name_size) | 
|  | 730 | size += 4 + 4 + name_size + val_size; | 
|  | 731 |  | 
|  | 732 | return size; | 
|  | 733 | } | 
|  | 734 |  | 
|  | 735 | /* | 
|  | 736 | * If there are dirty xattrs, reencode xattrs into the prealloc_blob | 
|  | 737 | * and swap into place.  It returns the old i_xattrs.blob (or NULL) so | 
|  | 738 | * that it can be freed by the caller as the i_ceph_lock is likely to be | 
|  | 739 | * held. | 
|  | 740 | */ | 
|  | 741 | struct ceph_buffer *__ceph_build_xattrs_blob(struct ceph_inode_info *ci) | 
|  | 742 | { | 
|  | 743 | struct rb_node *p; | 
|  | 744 | struct ceph_inode_xattr *xattr = NULL; | 
|  | 745 | struct ceph_buffer *old_blob = NULL; | 
|  | 746 | void *dest; | 
|  | 747 |  | 
|  | 748 | dout("__build_xattrs_blob %p\n", &ci->vfs_inode); | 
|  | 749 | if (ci->i_xattrs.dirty) { | 
|  | 750 | int need = __get_required_blob_size(ci, 0, 0); | 
|  | 751 |  | 
|  | 752 | BUG_ON(need > ci->i_xattrs.prealloc_blob->alloc_len); | 
|  | 753 |  | 
|  | 754 | p = rb_first(&ci->i_xattrs.index); | 
|  | 755 | dest = ci->i_xattrs.prealloc_blob->vec.iov_base; | 
|  | 756 |  | 
|  | 757 | ceph_encode_32(&dest, ci->i_xattrs.count); | 
|  | 758 | while (p) { | 
|  | 759 | xattr = rb_entry(p, struct ceph_inode_xattr, node); | 
|  | 760 |  | 
|  | 761 | ceph_encode_32(&dest, xattr->name_len); | 
|  | 762 | memcpy(dest, xattr->name, xattr->name_len); | 
|  | 763 | dest += xattr->name_len; | 
|  | 764 | ceph_encode_32(&dest, xattr->val_len); | 
|  | 765 | memcpy(dest, xattr->val, xattr->val_len); | 
|  | 766 | dest += xattr->val_len; | 
|  | 767 |  | 
|  | 768 | p = rb_next(p); | 
|  | 769 | } | 
|  | 770 |  | 
|  | 771 | /* adjust buffer len; it may be larger than we need */ | 
|  | 772 | ci->i_xattrs.prealloc_blob->vec.iov_len = | 
|  | 773 | dest - ci->i_xattrs.prealloc_blob->vec.iov_base; | 
|  | 774 |  | 
|  | 775 | if (ci->i_xattrs.blob) | 
|  | 776 | old_blob = ci->i_xattrs.blob; | 
|  | 777 | ci->i_xattrs.blob = ci->i_xattrs.prealloc_blob; | 
|  | 778 | ci->i_xattrs.prealloc_blob = NULL; | 
|  | 779 | ci->i_xattrs.dirty = false; | 
|  | 780 | ci->i_xattrs.version++; | 
|  | 781 | } | 
|  | 782 |  | 
|  | 783 | return old_blob; | 
|  | 784 | } | 
|  | 785 |  | 
|  | 786 | static inline int __get_request_mask(struct inode *in) { | 
|  | 787 | struct ceph_mds_request *req = current->journal_info; | 
|  | 788 | int mask = 0; | 
|  | 789 | if (req && req->r_target_inode == in) { | 
|  | 790 | if (req->r_op == CEPH_MDS_OP_LOOKUP || | 
|  | 791 | req->r_op == CEPH_MDS_OP_LOOKUPINO || | 
|  | 792 | req->r_op == CEPH_MDS_OP_LOOKUPPARENT || | 
|  | 793 | req->r_op == CEPH_MDS_OP_GETATTR) { | 
|  | 794 | mask = le32_to_cpu(req->r_args.getattr.mask); | 
|  | 795 | } else if (req->r_op == CEPH_MDS_OP_OPEN || | 
|  | 796 | req->r_op == CEPH_MDS_OP_CREATE) { | 
|  | 797 | mask = le32_to_cpu(req->r_args.open.mask); | 
|  | 798 | } | 
|  | 799 | } | 
|  | 800 | return mask; | 
|  | 801 | } | 
|  | 802 |  | 
|  | 803 | ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, | 
|  | 804 | size_t size) | 
|  | 805 | { | 
|  | 806 | struct ceph_inode_info *ci = ceph_inode(inode); | 
|  | 807 | struct ceph_inode_xattr *xattr; | 
|  | 808 | struct ceph_vxattr *vxattr = NULL; | 
|  | 809 | int req_mask; | 
|  | 810 | int err; | 
|  | 811 |  | 
|  | 812 | /* let's see if a virtual xattr was requested */ | 
|  | 813 | vxattr = ceph_match_vxattr(inode, name); | 
|  | 814 | if (vxattr) { | 
|  | 815 | int mask = 0; | 
|  | 816 | if (vxattr->flags & VXATTR_FLAG_RSTAT) | 
|  | 817 | mask |= CEPH_STAT_RSTAT; | 
|  | 818 | err = ceph_do_getattr(inode, mask, true); | 
|  | 819 | if (err) | 
|  | 820 | return err; | 
|  | 821 | err = -ENODATA; | 
|  | 822 | if (!(vxattr->exists_cb && !vxattr->exists_cb(ci))) { | 
|  | 823 | err = vxattr->getxattr_cb(ci, value, size); | 
|  | 824 | if (size && size < err) | 
|  | 825 | err = -ERANGE; | 
|  | 826 | } | 
|  | 827 | return err; | 
|  | 828 | } | 
|  | 829 |  | 
|  | 830 | req_mask = __get_request_mask(inode); | 
|  | 831 |  | 
|  | 832 | spin_lock(&ci->i_ceph_lock); | 
|  | 833 | dout("getxattr %p ver=%lld index_ver=%lld\n", inode, | 
|  | 834 | ci->i_xattrs.version, ci->i_xattrs.index_version); | 
|  | 835 |  | 
|  | 836 | if (ci->i_xattrs.version == 0 || | 
|  | 837 | !((req_mask & CEPH_CAP_XATTR_SHARED) || | 
|  | 838 | __ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1))) { | 
|  | 839 | spin_unlock(&ci->i_ceph_lock); | 
|  | 840 |  | 
|  | 841 | /* security module gets xattr while filling trace */ | 
|  | 842 | if (current->journal_info) { | 
|  | 843 | pr_warn_ratelimited("sync getxattr %p " | 
|  | 844 | "during filling trace\n", inode); | 
|  | 845 | return -EBUSY; | 
|  | 846 | } | 
|  | 847 |  | 
|  | 848 | /* get xattrs from mds (if we don't already have them) */ | 
|  | 849 | err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR, true); | 
|  | 850 | if (err) | 
|  | 851 | return err; | 
|  | 852 | spin_lock(&ci->i_ceph_lock); | 
|  | 853 | } | 
|  | 854 |  | 
|  | 855 | err = __build_xattrs(inode); | 
|  | 856 | if (err < 0) | 
|  | 857 | goto out; | 
|  | 858 |  | 
|  | 859 | err = -ENODATA;  /* == ENOATTR */ | 
|  | 860 | xattr = __get_xattr(ci, name); | 
|  | 861 | if (!xattr) | 
|  | 862 | goto out; | 
|  | 863 |  | 
|  | 864 | err = -ERANGE; | 
|  | 865 | if (size && size < xattr->val_len) | 
|  | 866 | goto out; | 
|  | 867 |  | 
|  | 868 | err = xattr->val_len; | 
|  | 869 | if (size == 0) | 
|  | 870 | goto out; | 
|  | 871 |  | 
|  | 872 | memcpy(value, xattr->val, xattr->val_len); | 
|  | 873 |  | 
|  | 874 | if (current->journal_info && | 
|  | 875 | !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) | 
|  | 876 | ci->i_ceph_flags |= CEPH_I_SEC_INITED; | 
|  | 877 | out: | 
|  | 878 | spin_unlock(&ci->i_ceph_lock); | 
|  | 879 | return err; | 
|  | 880 | } | 
|  | 881 |  | 
|  | 882 | ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size) | 
|  | 883 | { | 
|  | 884 | struct inode *inode = d_inode(dentry); | 
|  | 885 | struct ceph_inode_info *ci = ceph_inode(inode); | 
|  | 886 | struct ceph_vxattr *vxattrs = ceph_inode_vxattrs(inode); | 
|  | 887 | u32 vir_namelen = 0; | 
|  | 888 | u32 namelen; | 
|  | 889 | int err; | 
|  | 890 | u32 len; | 
|  | 891 | int i; | 
|  | 892 |  | 
|  | 893 | spin_lock(&ci->i_ceph_lock); | 
|  | 894 | dout("listxattr %p ver=%lld index_ver=%lld\n", inode, | 
|  | 895 | ci->i_xattrs.version, ci->i_xattrs.index_version); | 
|  | 896 |  | 
|  | 897 | if (ci->i_xattrs.version == 0 || | 
|  | 898 | !__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1)) { | 
|  | 899 | spin_unlock(&ci->i_ceph_lock); | 
|  | 900 | err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR, true); | 
|  | 901 | if (err) | 
|  | 902 | return err; | 
|  | 903 | spin_lock(&ci->i_ceph_lock); | 
|  | 904 | } | 
|  | 905 |  | 
|  | 906 | err = __build_xattrs(inode); | 
|  | 907 | if (err < 0) | 
|  | 908 | goto out; | 
|  | 909 | /* | 
|  | 910 | * Start with virtual dir xattr names (if any) (including | 
|  | 911 | * terminating '\0' characters for each). | 
|  | 912 | */ | 
|  | 913 | vir_namelen = ceph_vxattrs_name_size(vxattrs); | 
|  | 914 |  | 
|  | 915 | /* adding 1 byte per each variable due to the null termination */ | 
|  | 916 | namelen = ci->i_xattrs.names_size + ci->i_xattrs.count; | 
|  | 917 | err = -ERANGE; | 
|  | 918 | if (size && vir_namelen + namelen > size) | 
|  | 919 | goto out; | 
|  | 920 |  | 
|  | 921 | err = namelen + vir_namelen; | 
|  | 922 | if (size == 0) | 
|  | 923 | goto out; | 
|  | 924 |  | 
|  | 925 | names = __copy_xattr_names(ci, names); | 
|  | 926 |  | 
|  | 927 | /* virtual xattr names, too */ | 
|  | 928 | err = namelen; | 
|  | 929 | if (vxattrs) { | 
|  | 930 | for (i = 0; vxattrs[i].name; i++) { | 
|  | 931 | if (!(vxattrs[i].flags & VXATTR_FLAG_HIDDEN) && | 
|  | 932 | !(vxattrs[i].exists_cb && | 
|  | 933 | !vxattrs[i].exists_cb(ci))) { | 
|  | 934 | len = sprintf(names, "%s", vxattrs[i].name); | 
|  | 935 | names += len + 1; | 
|  | 936 | err += len + 1; | 
|  | 937 | } | 
|  | 938 | } | 
|  | 939 | } | 
|  | 940 |  | 
|  | 941 | out: | 
|  | 942 | spin_unlock(&ci->i_ceph_lock); | 
|  | 943 | return err; | 
|  | 944 | } | 
|  | 945 |  | 
|  | 946 | static int ceph_sync_setxattr(struct inode *inode, const char *name, | 
|  | 947 | const char *value, size_t size, int flags) | 
|  | 948 | { | 
|  | 949 | struct ceph_fs_client *fsc = ceph_sb_to_client(inode->i_sb); | 
|  | 950 | struct ceph_inode_info *ci = ceph_inode(inode); | 
|  | 951 | struct ceph_mds_request *req; | 
|  | 952 | struct ceph_mds_client *mdsc = fsc->mdsc; | 
|  | 953 | struct ceph_pagelist *pagelist = NULL; | 
|  | 954 | int op = CEPH_MDS_OP_SETXATTR; | 
|  | 955 | int err; | 
|  | 956 |  | 
|  | 957 | if (size > 0) { | 
|  | 958 | /* copy value into pagelist */ | 
|  | 959 | pagelist = kmalloc(sizeof(*pagelist), GFP_NOFS); | 
|  | 960 | if (!pagelist) | 
|  | 961 | return -ENOMEM; | 
|  | 962 |  | 
|  | 963 | ceph_pagelist_init(pagelist); | 
|  | 964 | err = ceph_pagelist_append(pagelist, value, size); | 
|  | 965 | if (err) | 
|  | 966 | goto out; | 
|  | 967 | } else if (!value) { | 
|  | 968 | if (flags & CEPH_XATTR_REPLACE) | 
|  | 969 | op = CEPH_MDS_OP_RMXATTR; | 
|  | 970 | else | 
|  | 971 | flags |= CEPH_XATTR_REMOVE; | 
|  | 972 | } | 
|  | 973 |  | 
|  | 974 | dout("setxattr value=%.*s\n", (int)size, value); | 
|  | 975 |  | 
|  | 976 | /* do request */ | 
|  | 977 | req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS); | 
|  | 978 | if (IS_ERR(req)) { | 
|  | 979 | err = PTR_ERR(req); | 
|  | 980 | goto out; | 
|  | 981 | } | 
|  | 982 |  | 
|  | 983 | req->r_path2 = kstrdup(name, GFP_NOFS); | 
|  | 984 | if (!req->r_path2) { | 
|  | 985 | ceph_mdsc_put_request(req); | 
|  | 986 | err = -ENOMEM; | 
|  | 987 | goto out; | 
|  | 988 | } | 
|  | 989 |  | 
|  | 990 | if (op == CEPH_MDS_OP_SETXATTR) { | 
|  | 991 | req->r_args.setxattr.flags = cpu_to_le32(flags); | 
|  | 992 | req->r_pagelist = pagelist; | 
|  | 993 | pagelist = NULL; | 
|  | 994 | } | 
|  | 995 |  | 
|  | 996 | req->r_inode = inode; | 
|  | 997 | ihold(inode); | 
|  | 998 | req->r_num_caps = 1; | 
|  | 999 | req->r_inode_drop = CEPH_CAP_XATTR_SHARED; | 
|  | 1000 |  | 
|  | 1001 | dout("xattr.ver (before): %lld\n", ci->i_xattrs.version); | 
|  | 1002 | err = ceph_mdsc_do_request(mdsc, NULL, req); | 
|  | 1003 | ceph_mdsc_put_request(req); | 
|  | 1004 | dout("xattr.ver (after): %lld\n", ci->i_xattrs.version); | 
|  | 1005 |  | 
|  | 1006 | out: | 
|  | 1007 | if (pagelist) | 
|  | 1008 | ceph_pagelist_release(pagelist); | 
|  | 1009 | return err; | 
|  | 1010 | } | 
|  | 1011 |  | 
|  | 1012 | int __ceph_setxattr(struct inode *inode, const char *name, | 
|  | 1013 | const void *value, size_t size, int flags) | 
|  | 1014 | { | 
|  | 1015 | struct ceph_vxattr *vxattr; | 
|  | 1016 | struct ceph_inode_info *ci = ceph_inode(inode); | 
|  | 1017 | struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; | 
|  | 1018 | struct ceph_cap_flush *prealloc_cf = NULL; | 
|  | 1019 | struct ceph_buffer *old_blob = NULL; | 
|  | 1020 | int issued; | 
|  | 1021 | int err; | 
|  | 1022 | int dirty = 0; | 
|  | 1023 | int name_len = strlen(name); | 
|  | 1024 | int val_len = size; | 
|  | 1025 | char *newname = NULL; | 
|  | 1026 | char *newval = NULL; | 
|  | 1027 | struct ceph_inode_xattr *xattr = NULL; | 
|  | 1028 | int required_blob_size; | 
|  | 1029 | bool check_realm = false; | 
|  | 1030 | bool lock_snap_rwsem = false; | 
|  | 1031 |  | 
|  | 1032 | if (ceph_snap(inode) != CEPH_NOSNAP) | 
|  | 1033 | return -EROFS; | 
|  | 1034 |  | 
|  | 1035 | vxattr = ceph_match_vxattr(inode, name); | 
|  | 1036 | if (vxattr) { | 
|  | 1037 | if (vxattr->flags & VXATTR_FLAG_READONLY) | 
|  | 1038 | return -EOPNOTSUPP; | 
|  | 1039 | if (value && !strncmp(vxattr->name, "ceph.quota", 10)) | 
|  | 1040 | check_realm = true; | 
|  | 1041 | } | 
|  | 1042 |  | 
|  | 1043 | /* pass any unhandled ceph.* xattrs through to the MDS */ | 
|  | 1044 | if (!strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN)) | 
|  | 1045 | goto do_sync_unlocked; | 
|  | 1046 |  | 
|  | 1047 | /* preallocate memory for xattr name, value, index node */ | 
|  | 1048 | err = -ENOMEM; | 
|  | 1049 | newname = kmemdup(name, name_len + 1, GFP_NOFS); | 
|  | 1050 | if (!newname) | 
|  | 1051 | goto out; | 
|  | 1052 |  | 
|  | 1053 | if (val_len) { | 
|  | 1054 | newval = kmemdup(value, val_len, GFP_NOFS); | 
|  | 1055 | if (!newval) | 
|  | 1056 | goto out; | 
|  | 1057 | } | 
|  | 1058 |  | 
|  | 1059 | xattr = kmalloc(sizeof(struct ceph_inode_xattr), GFP_NOFS); | 
|  | 1060 | if (!xattr) | 
|  | 1061 | goto out; | 
|  | 1062 |  | 
|  | 1063 | prealloc_cf = ceph_alloc_cap_flush(); | 
|  | 1064 | if (!prealloc_cf) | 
|  | 1065 | goto out; | 
|  | 1066 |  | 
|  | 1067 | spin_lock(&ci->i_ceph_lock); | 
|  | 1068 | retry: | 
|  | 1069 | issued = __ceph_caps_issued(ci, NULL); | 
|  | 1070 | if (ci->i_xattrs.version == 0 || !(issued & CEPH_CAP_XATTR_EXCL)) | 
|  | 1071 | goto do_sync; | 
|  | 1072 |  | 
|  | 1073 | if (!lock_snap_rwsem && !ci->i_head_snapc) { | 
|  | 1074 | lock_snap_rwsem = true; | 
|  | 1075 | if (!down_read_trylock(&mdsc->snap_rwsem)) { | 
|  | 1076 | spin_unlock(&ci->i_ceph_lock); | 
|  | 1077 | down_read(&mdsc->snap_rwsem); | 
|  | 1078 | spin_lock(&ci->i_ceph_lock); | 
|  | 1079 | goto retry; | 
|  | 1080 | } | 
|  | 1081 | } | 
|  | 1082 |  | 
|  | 1083 | dout("setxattr %p issued %s\n", inode, ceph_cap_string(issued)); | 
|  | 1084 | __build_xattrs(inode); | 
|  | 1085 |  | 
|  | 1086 | required_blob_size = __get_required_blob_size(ci, name_len, val_len); | 
|  | 1087 |  | 
|  | 1088 | if (!ci->i_xattrs.prealloc_blob || | 
|  | 1089 | required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) { | 
|  | 1090 | struct ceph_buffer *blob; | 
|  | 1091 |  | 
|  | 1092 | spin_unlock(&ci->i_ceph_lock); | 
|  | 1093 | ceph_buffer_put(old_blob); /* Shouldn't be required */ | 
|  | 1094 | dout(" pre-allocating new blob size=%d\n", required_blob_size); | 
|  | 1095 | blob = ceph_buffer_new(required_blob_size, GFP_NOFS); | 
|  | 1096 | if (!blob) | 
|  | 1097 | goto do_sync_unlocked; | 
|  | 1098 | spin_lock(&ci->i_ceph_lock); | 
|  | 1099 | /* prealloc_blob can't be released while holding i_ceph_lock */ | 
|  | 1100 | if (ci->i_xattrs.prealloc_blob) | 
|  | 1101 | old_blob = ci->i_xattrs.prealloc_blob; | 
|  | 1102 | ci->i_xattrs.prealloc_blob = blob; | 
|  | 1103 | goto retry; | 
|  | 1104 | } | 
|  | 1105 |  | 
|  | 1106 | err = __set_xattr(ci, newname, name_len, newval, val_len, | 
|  | 1107 | flags, value ? 1 : -1, &xattr); | 
|  | 1108 |  | 
|  | 1109 | if (!err) { | 
|  | 1110 | dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL, | 
|  | 1111 | &prealloc_cf); | 
|  | 1112 | ci->i_xattrs.dirty = true; | 
|  | 1113 | inode->i_ctime = current_time(inode); | 
|  | 1114 | } | 
|  | 1115 |  | 
|  | 1116 | spin_unlock(&ci->i_ceph_lock); | 
|  | 1117 | ceph_buffer_put(old_blob); | 
|  | 1118 | if (lock_snap_rwsem) | 
|  | 1119 | up_read(&mdsc->snap_rwsem); | 
|  | 1120 | if (dirty) | 
|  | 1121 | __mark_inode_dirty(inode, dirty); | 
|  | 1122 | ceph_free_cap_flush(prealloc_cf); | 
|  | 1123 | return err; | 
|  | 1124 |  | 
|  | 1125 | do_sync: | 
|  | 1126 | spin_unlock(&ci->i_ceph_lock); | 
|  | 1127 | do_sync_unlocked: | 
|  | 1128 | if (lock_snap_rwsem) | 
|  | 1129 | up_read(&mdsc->snap_rwsem); | 
|  | 1130 |  | 
|  | 1131 | /* security module set xattr while filling trace */ | 
|  | 1132 | if (current->journal_info) { | 
|  | 1133 | pr_warn_ratelimited("sync setxattr %p " | 
|  | 1134 | "during filling trace\n", inode); | 
|  | 1135 | err = -EBUSY; | 
|  | 1136 | } else { | 
|  | 1137 | err = ceph_sync_setxattr(inode, name, value, size, flags); | 
|  | 1138 | if (err >= 0 && check_realm) { | 
|  | 1139 | /* check if snaprealm was created for quota inode */ | 
|  | 1140 | spin_lock(&ci->i_ceph_lock); | 
|  | 1141 | if ((ci->i_max_files || ci->i_max_bytes) && | 
|  | 1142 | !(ci->i_snap_realm && | 
|  | 1143 | ci->i_snap_realm->ino == ci->i_vino.ino)) | 
|  | 1144 | err = -EOPNOTSUPP; | 
|  | 1145 | spin_unlock(&ci->i_ceph_lock); | 
|  | 1146 | } | 
|  | 1147 | } | 
|  | 1148 | out: | 
|  | 1149 | ceph_free_cap_flush(prealloc_cf); | 
|  | 1150 | kfree(newname); | 
|  | 1151 | kfree(newval); | 
|  | 1152 | kfree(xattr); | 
|  | 1153 | return err; | 
|  | 1154 | } | 
|  | 1155 |  | 
|  | 1156 | static int ceph_get_xattr_handler(const struct xattr_handler *handler, | 
|  | 1157 | struct dentry *dentry, struct inode *inode, | 
|  | 1158 | const char *name, void *value, size_t size) | 
|  | 1159 | { | 
|  | 1160 | if (!ceph_is_valid_xattr(name)) | 
|  | 1161 | return -EOPNOTSUPP; | 
|  | 1162 | return __ceph_getxattr(inode, name, value, size); | 
|  | 1163 | } | 
|  | 1164 |  | 
|  | 1165 | static int ceph_set_xattr_handler(const struct xattr_handler *handler, | 
|  | 1166 | struct dentry *unused, struct inode *inode, | 
|  | 1167 | const char *name, const void *value, | 
|  | 1168 | size_t size, int flags) | 
|  | 1169 | { | 
|  | 1170 | if (!ceph_is_valid_xattr(name)) | 
|  | 1171 | return -EOPNOTSUPP; | 
|  | 1172 | return __ceph_setxattr(inode, name, value, size, flags); | 
|  | 1173 | } | 
|  | 1174 |  | 
|  | 1175 | static const struct xattr_handler ceph_other_xattr_handler = { | 
|  | 1176 | .prefix = "",  /* match any name => handlers called with full name */ | 
|  | 1177 | .get = ceph_get_xattr_handler, | 
|  | 1178 | .set = ceph_set_xattr_handler, | 
|  | 1179 | }; | 
|  | 1180 |  | 
|  | 1181 | #ifdef CONFIG_SECURITY | 
|  | 1182 | bool ceph_security_xattr_wanted(struct inode *in) | 
|  | 1183 | { | 
|  | 1184 | return in->i_security != NULL; | 
|  | 1185 | } | 
|  | 1186 |  | 
|  | 1187 | bool ceph_security_xattr_deadlock(struct inode *in) | 
|  | 1188 | { | 
|  | 1189 | struct ceph_inode_info *ci; | 
|  | 1190 | bool ret; | 
|  | 1191 | if (!in->i_security) | 
|  | 1192 | return false; | 
|  | 1193 | ci = ceph_inode(in); | 
|  | 1194 | spin_lock(&ci->i_ceph_lock); | 
|  | 1195 | ret = !(ci->i_ceph_flags & CEPH_I_SEC_INITED) && | 
|  | 1196 | !(ci->i_xattrs.version > 0 && | 
|  | 1197 | __ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0)); | 
|  | 1198 | spin_unlock(&ci->i_ceph_lock); | 
|  | 1199 | return ret; | 
|  | 1200 | } | 
|  | 1201 | #endif |