Blame view
fs/orangefs/xattr.c
12.4 KB
b24413180 License cleanup: ... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
1182fca3b Orangefs: kernel ... |
2 3 4 5 6 7 8 9 10 11 12 |
/* * (C) 2001 Clemson University and The University of Chicago * * See COPYING in top-level directory. */ /* * Linux VFS extended attribute operations. */ #include "protocol.h" |
575e94612 Orangefs: change ... |
13 14 |
#include "orangefs-kernel.h" #include "orangefs-bufmap.h" |
1182fca3b Orangefs: kernel ... |
15 16 |
#include <linux/posix_acl_xattr.h> #include <linux/xattr.h> |
8bb8aefd5 OrangeFS: Change ... |
17 18 |
#define SYSTEM_ORANGEFS_KEY "system.pvfs2." #define SYSTEM_ORANGEFS_KEY_LEN 13 |
1182fca3b Orangefs: kernel ... |
19 20 21 22 23 24 25 |
/* * this function returns * 0 if the key corresponding to name is not meant to be printed as part * of a listxattr. * 1 if the key corresponding to name is meant to be returned as part of * a listxattr. |
8bb8aefd5 OrangeFS: Change ... |
26 |
* The ones that start SYSTEM_ORANGEFS_KEY are the ones to avoid printing. |
1182fca3b Orangefs: kernel ... |
27 28 29 |
*/ static int is_reserved_key(const char *key, size_t size) { |
8bb8aefd5 OrangeFS: Change ... |
30 |
if (size < SYSTEM_ORANGEFS_KEY_LEN) |
1182fca3b Orangefs: kernel ... |
31 |
return 1; |
8bb8aefd5 OrangeFS: Change ... |
32 |
return strncmp(key, SYSTEM_ORANGEFS_KEY, SYSTEM_ORANGEFS_KEY_LEN) ? 1 : 0; |
1182fca3b Orangefs: kernel ... |
33 34 35 36 37 38 39 40 |
} static inline int convert_to_internal_xattr_flags(int setxattr_flags) { int internal_flag = 0; if (setxattr_flags & XATTR_REPLACE) { /* Attribute must exist! */ |
8bb8aefd5 OrangeFS: Change ... |
41 |
internal_flag = ORANGEFS_XATTR_REPLACE; |
1182fca3b Orangefs: kernel ... |
42 43 |
} else if (setxattr_flags & XATTR_CREATE) { /* Attribute must not exist */ |
8bb8aefd5 OrangeFS: Change ... |
44 |
internal_flag = ORANGEFS_XATTR_CREATE; |
1182fca3b Orangefs: kernel ... |
45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
} return internal_flag; } /* * Tries to get a specified key's attributes of a given * file into a user-specified buffer. Note that the getxattr * interface allows for the users to probe the size of an * extended attribute by passing in a value of 0 to size. * Thus our return value is always the size of the attribute * unless the key does not exist for the file and/or if * there were errors in fetching the attribute value. */ |
d373a712c orangefs: Remove ... |
59 60 |
ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name, void *buffer, size_t size) |
1182fca3b Orangefs: kernel ... |
61 |
{ |
8bb8aefd5 OrangeFS: Change ... |
62 63 |
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); struct orangefs_kernel_op_s *new_op = NULL; |
1182fca3b Orangefs: kernel ... |
64 65 66 67 68 69 |
ssize_t ret = -ENOMEM; ssize_t length = 0; int fsuid; int fsgid; gossip_debug(GOSSIP_XATTR_DEBUG, |
d373a712c orangefs: Remove ... |
70 71 72 |
"%s: name %s, buffer_size %zd ", __func__, name, size); |
1182fca3b Orangefs: kernel ... |
73 |
|
6c6ef9f26 xattr: Stop calli... |
74 75 |
if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; |
5f13e5876 orangefs: off by ... |
76 |
if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) |
1182fca3b Orangefs: kernel ... |
77 |
return -EINVAL; |
1182fca3b Orangefs: kernel ... |
78 |
|
78fee0b68 orangefs: fix nam... |
79 80 |
fsuid = from_kuid(&init_user_ns, current_fsuid()); fsgid = from_kgid(&init_user_ns, current_fsgid()); |
1182fca3b Orangefs: kernel ... |
81 82 83 84 85 86 87 88 89 |
gossip_debug(GOSSIP_XATTR_DEBUG, "getxattr on inode %pU, name %s " "(uid %o, gid %o) ", get_khandle_from_ino(inode), name, fsuid, fsgid); |
8bb8aefd5 OrangeFS: Change ... |
90 |
down_read(&orangefs_inode->xattr_sem); |
1182fca3b Orangefs: kernel ... |
91 |
|
8bb8aefd5 OrangeFS: Change ... |
92 |
new_op = op_alloc(ORANGEFS_VFS_OP_GETXATTR); |
1182fca3b Orangefs: kernel ... |
93 94 |
if (!new_op) goto out_unlock; |
8bb8aefd5 OrangeFS: Change ... |
95 |
new_op->upcall.req.getxattr.refn = orangefs_inode->refn; |
d373a712c orangefs: Remove ... |
96 |
strcpy(new_op->upcall.req.getxattr.key, name); |
1182fca3b Orangefs: kernel ... |
97 98 99 100 101 102 |
/* * NOTE: Although keys are meant to be NULL terminated textual * strings, I am going to explicitly pass the length just in case * we change this later on... */ |
d373a712c orangefs: Remove ... |
103 |
new_op->upcall.req.getxattr.key_sz = strlen(name) + 1; |
1182fca3b Orangefs: kernel ... |
104 |
|
8bb8aefd5 OrangeFS: Change ... |
105 |
ret = service_operation(new_op, "orangefs_inode_getxattr", |
1182fca3b Orangefs: kernel ... |
106 107 108 109 110 |
get_interruptible_flag(inode)); if (ret != 0) { if (ret == -ENOENT) { ret = -ENODATA; gossip_debug(GOSSIP_XATTR_DEBUG, |
8bb8aefd5 OrangeFS: Change ... |
111 |
"orangefs_inode_getxattr: inode %pU key %s" |
1182fca3b Orangefs: kernel ... |
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
" does not exist! ", get_khandle_from_ino(inode), (char *)new_op->upcall.req.getxattr.key); } goto out_release_op; } /* * Length returned includes null terminator. */ length = new_op->downcall.resp.getxattr.val_sz; /* * Just return the length of the queried attribute. */ if (size == 0) { ret = length; goto out_release_op; } /* * Check to see if key length is > provided buffer size. */ if (length > size) { ret = -ERANGE; goto out_release_op; } |
1182fca3b Orangefs: kernel ... |
140 |
memcpy(buffer, new_op->downcall.resp.getxattr.val, length); |
a9bb3ba81 Orangefs: optimiz... |
141 |
memset(buffer + length, 0, size - length); |
1182fca3b Orangefs: kernel ... |
142 |
gossip_debug(GOSSIP_XATTR_DEBUG, |
8bb8aefd5 OrangeFS: Change ... |
143 |
"orangefs_inode_getxattr: inode %pU " |
1182fca3b Orangefs: kernel ... |
144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
"key %s key_sz %d, val_len %d ", get_khandle_from_ino(inode), (char *)new_op-> upcall.req.getxattr.key, (int)new_op-> upcall.req.getxattr.key_sz, (int)ret); ret = length; out_release_op: op_release(new_op); out_unlock: |
8bb8aefd5 OrangeFS: Change ... |
158 |
up_read(&orangefs_inode->xattr_sem); |
1182fca3b Orangefs: kernel ... |
159 160 |
return ret; } |
d373a712c orangefs: Remove ... |
161 162 |
static int orangefs_inode_removexattr(struct inode *inode, const char *name, int flags) |
1182fca3b Orangefs: kernel ... |
163 |
{ |
8bb8aefd5 OrangeFS: Change ... |
164 165 |
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); struct orangefs_kernel_op_s *new_op = NULL; |
1182fca3b Orangefs: kernel ... |
166 |
int ret = -ENOMEM; |
5f13e5876 orangefs: off by ... |
167 |
if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) |
e675c5ec5 orangefs: clean u... |
168 |
return -EINVAL; |
8bb8aefd5 OrangeFS: Change ... |
169 170 |
down_write(&orangefs_inode->xattr_sem); new_op = op_alloc(ORANGEFS_VFS_OP_REMOVEXATTR); |
1182fca3b Orangefs: kernel ... |
171 172 |
if (!new_op) goto out_unlock; |
8bb8aefd5 OrangeFS: Change ... |
173 |
new_op->upcall.req.removexattr.refn = orangefs_inode->refn; |
1182fca3b Orangefs: kernel ... |
174 175 176 177 178 |
/* * NOTE: Although keys are meant to be NULL terminated * textual strings, I am going to explicitly pass the * length just in case we change this later on... */ |
d373a712c orangefs: Remove ... |
179 180 |
strcpy(new_op->upcall.req.removexattr.key, name); new_op->upcall.req.removexattr.key_sz = strlen(name) + 1; |
1182fca3b Orangefs: kernel ... |
181 182 |
gossip_debug(GOSSIP_XATTR_DEBUG, |
8bb8aefd5 OrangeFS: Change ... |
183 184 |
"orangefs_inode_removexattr: key %s, key_sz %d ", |
1182fca3b Orangefs: kernel ... |
185 186 187 188 |
(char *)new_op->upcall.req.removexattr.key, (int)new_op->upcall.req.removexattr.key_sz); ret = service_operation(new_op, |
8bb8aefd5 OrangeFS: Change ... |
189 |
"orangefs_inode_removexattr", |
1182fca3b Orangefs: kernel ... |
190 191 192 193 194 195 196 197 198 199 200 201 |
get_interruptible_flag(inode)); if (ret == -ENOENT) { /* * Request to replace a non-existent attribute is an error. */ if (flags & XATTR_REPLACE) ret = -ENODATA; else ret = 0; } gossip_debug(GOSSIP_XATTR_DEBUG, |
8bb8aefd5 OrangeFS: Change ... |
202 203 |
"orangefs_inode_removexattr: returning %d ", ret); |
1182fca3b Orangefs: kernel ... |
204 205 206 |
op_release(new_op); out_unlock: |
8bb8aefd5 OrangeFS: Change ... |
207 |
up_write(&orangefs_inode->xattr_sem); |
1182fca3b Orangefs: kernel ... |
208 209 210 211 212 213 214 215 216 |
return ret; } /* * Tries to set an attribute for a given key on a file. * * Returns a -ve number on error and 0 on success. Key is text, but value * can be binary! */ |
d373a712c orangefs: Remove ... |
217 218 |
int orangefs_inode_setxattr(struct inode *inode, const char *name, const void *value, size_t size, int flags) |
1182fca3b Orangefs: kernel ... |
219 |
{ |
8bb8aefd5 OrangeFS: Change ... |
220 221 |
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); struct orangefs_kernel_op_s *new_op; |
1182fca3b Orangefs: kernel ... |
222 223 224 225 |
int internal_flag = 0; int ret = -ENOMEM; gossip_debug(GOSSIP_XATTR_DEBUG, |
d373a712c orangefs: Remove ... |
226 227 228 |
"%s: name %s, buffer_size %zd ", __func__, name, size); |
1182fca3b Orangefs: kernel ... |
229 |
|
e675c5ec5 orangefs: clean u... |
230 231 |
if (size > ORANGEFS_MAX_XATTR_VALUELEN) return -EINVAL; |
5f13e5876 orangefs: off by ... |
232 |
if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) |
1182fca3b Orangefs: kernel ... |
233 |
return -EINVAL; |
1182fca3b Orangefs: kernel ... |
234 |
|
1182fca3b Orangefs: kernel ... |
235 |
internal_flag = convert_to_internal_xattr_flags(flags); |
1182fca3b Orangefs: kernel ... |
236 |
/* This is equivalent to a removexattr */ |
0b08273c8 orangefs: Adjust ... |
237 |
if (size == 0 && !value) { |
1182fca3b Orangefs: kernel ... |
238 |
gossip_debug(GOSSIP_XATTR_DEBUG, |
d373a712c orangefs: Remove ... |
239 240 |
"removing xattr (%s) ", |
1182fca3b Orangefs: kernel ... |
241 |
name); |
d373a712c orangefs: Remove ... |
242 |
return orangefs_inode_removexattr(inode, name, flags); |
1182fca3b Orangefs: kernel ... |
243 244 245 246 247 248 249 |
} gossip_debug(GOSSIP_XATTR_DEBUG, "setxattr on inode %pU, name %s ", get_khandle_from_ino(inode), name); |
8bb8aefd5 OrangeFS: Change ... |
250 251 |
down_write(&orangefs_inode->xattr_sem); new_op = op_alloc(ORANGEFS_VFS_OP_SETXATTR); |
1182fca3b Orangefs: kernel ... |
252 253 |
if (!new_op) goto out_unlock; |
8bb8aefd5 OrangeFS: Change ... |
254 |
new_op->upcall.req.setxattr.refn = orangefs_inode->refn; |
1182fca3b Orangefs: kernel ... |
255 256 257 258 259 260 |
new_op->upcall.req.setxattr.flags = internal_flag; /* * NOTE: Although keys are meant to be NULL terminated textual * strings, I am going to explicitly pass the length just in * case we change this later on... */ |
d373a712c orangefs: Remove ... |
261 262 |
strcpy(new_op->upcall.req.setxattr.keyval.key, name); new_op->upcall.req.setxattr.keyval.key_sz = strlen(name) + 1; |
1182fca3b Orangefs: kernel ... |
263 264 265 266 |
memcpy(new_op->upcall.req.setxattr.keyval.val, value, size); new_op->upcall.req.setxattr.keyval.val_sz = size; gossip_debug(GOSSIP_XATTR_DEBUG, |
8bb8aefd5 OrangeFS: Change ... |
267 |
"orangefs_inode_setxattr: key %s, key_sz %d " |
1182fca3b Orangefs: kernel ... |
268 269 270 271 272 273 274 |
" value size %zd ", (char *)new_op->upcall.req.setxattr.keyval.key, (int)new_op->upcall.req.setxattr.keyval.key_sz, size); ret = service_operation(new_op, |
8bb8aefd5 OrangeFS: Change ... |
275 |
"orangefs_inode_setxattr", |
1182fca3b Orangefs: kernel ... |
276 277 278 |
get_interruptible_flag(inode)); gossip_debug(GOSSIP_XATTR_DEBUG, |
8bb8aefd5 OrangeFS: Change ... |
279 280 |
"orangefs_inode_setxattr: returning %d ", |
1182fca3b Orangefs: kernel ... |
281 282 283 284 285 |
ret); /* when request is serviced properly, free req op struct */ op_release(new_op); out_unlock: |
8bb8aefd5 OrangeFS: Change ... |
286 |
up_write(&orangefs_inode->xattr_sem); |
1182fca3b Orangefs: kernel ... |
287 288 289 290 291 292 293 294 295 296 |
return ret; } /* * Tries to get a specified object's keys into a user-specified buffer of a * given size. Note that like the previous instances of xattr routines, this * also allows you to pass in a NULL pointer and 0 size to probe the size for * subsequent memory allocations. Thus our return value is always the size of * all the keys unless there were errors in fetching the keys! */ |
8bb8aefd5 OrangeFS: Change ... |
297 |
ssize_t orangefs_listxattr(struct dentry *dentry, char *buffer, size_t size) |
1182fca3b Orangefs: kernel ... |
298 299 |
{ struct inode *inode = dentry->d_inode; |
8bb8aefd5 OrangeFS: Change ... |
300 301 302 |
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); struct orangefs_kernel_op_s *new_op; __u64 token = ORANGEFS_ITERATE_START; |
1182fca3b Orangefs: kernel ... |
303 304 |
ssize_t ret = -ENOMEM; ssize_t total = 0; |
1182fca3b Orangefs: kernel ... |
305 306 307 |
int count_keys = 0; int key_size; int i = 0; |
62441fa53 Orangefs: validat... |
308 |
int returned_count = 0; |
1182fca3b Orangefs: kernel ... |
309 |
|
0b08273c8 orangefs: Adjust ... |
310 |
if (size > 0 && !buffer) { |
1182fca3b Orangefs: kernel ... |
311 312 313 314 |
gossip_err("%s: bogus NULL pointers ", __func__); return -EINVAL; } |
1182fca3b Orangefs: kernel ... |
315 |
|
8bb8aefd5 OrangeFS: Change ... |
316 317 |
down_read(&orangefs_inode->xattr_sem); new_op = op_alloc(ORANGEFS_VFS_OP_LISTXATTR); |
1182fca3b Orangefs: kernel ... |
318 319 320 321 322 323 324 325 |
if (!new_op) goto out_unlock; if (buffer && size > 0) memset(buffer, 0, size); try_again: key_size = 0; |
8bb8aefd5 OrangeFS: Change ... |
326 |
new_op->upcall.req.listxattr.refn = orangefs_inode->refn; |
1182fca3b Orangefs: kernel ... |
327 328 |
new_op->upcall.req.listxattr.token = token; new_op->upcall.req.listxattr.requested_count = |
8bb8aefd5 OrangeFS: Change ... |
329 |
(size == 0) ? 0 : ORANGEFS_MAX_XATTR_LISTLEN; |
1182fca3b Orangefs: kernel ... |
330 331 332 333 334 335 336 337 338 339 340 341 |
ret = service_operation(new_op, __func__, get_interruptible_flag(inode)); if (ret != 0) goto done; if (size == 0) { /* * This is a bit of a big upper limit, but I did not want to * spend too much time getting this correct, since users end * up allocating memory rather than us... */ total = new_op->downcall.resp.listxattr.returned_count * |
8bb8aefd5 OrangeFS: Change ... |
342 |
ORANGEFS_MAX_XATTR_NAMELEN; |
1182fca3b Orangefs: kernel ... |
343 344 |
goto done; } |
62441fa53 Orangefs: validat... |
345 346 |
returned_count = new_op->downcall.resp.listxattr.returned_count; if (returned_count < 0 || |
a956af337 orangefs: fix bou... |
347 |
returned_count > ORANGEFS_MAX_XATTR_LISTLEN) { |
62441fa53 Orangefs: validat... |
348 349 350 351 |
gossip_err("%s: impossible value for returned_count:%d: ", __func__, returned_count); |
02a5cc537 orangefs: sanitiz... |
352 |
ret = -EIO; |
62441fa53 Orangefs: validat... |
353 354 |
goto done; } |
1182fca3b Orangefs: kernel ... |
355 356 357 |
/* * Check to see how much can be fit in the buffer. Fit only whole keys. */ |
62441fa53 Orangefs: validat... |
358 |
for (i = 0; i < returned_count; i++) { |
02a5cc537 orangefs: sanitiz... |
359 360 361 362 363 364 365 366 367 368 |
if (new_op->downcall.resp.listxattr.lengths[i] < 0 || new_op->downcall.resp.listxattr.lengths[i] > ORANGEFS_MAX_XATTR_NAMELEN) { gossip_err("%s: impossible value for lengths[%d] ", __func__, new_op->downcall.resp.listxattr.lengths[i]); ret = -EIO; goto done; } |
1182fca3b Orangefs: kernel ... |
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 |
if (total + new_op->downcall.resp.listxattr.lengths[i] > size) goto done; /* * Since many dumb programs try to setxattr() on our reserved * xattrs this is a feeble attempt at defeating those by not * listing them in the output of listxattr.. sigh */ if (is_reserved_key(new_op->downcall.resp.listxattr.key + key_size, new_op->downcall.resp. listxattr.lengths[i])) { gossip_debug(GOSSIP_XATTR_DEBUG, "Copying key %d -> %s ", i, new_op->downcall.resp.listxattr.key + key_size); memcpy(buffer + total, new_op->downcall.resp.listxattr.key + key_size, new_op->downcall.resp.listxattr.lengths[i]); total += new_op->downcall.resp.listxattr.lengths[i]; count_keys++; } else { gossip_debug(GOSSIP_XATTR_DEBUG, "[RESERVED] key %d -> %s ", i, new_op->downcall.resp.listxattr.key + key_size); } key_size += new_op->downcall.resp.listxattr.lengths[i]; } /* * Since the buffer was large enough, we might have to continue * fetching more keys! */ token = new_op->downcall.resp.listxattr.token; |
8bb8aefd5 OrangeFS: Change ... |
404 |
if (token != ORANGEFS_ITERATE_END) |
1182fca3b Orangefs: kernel ... |
405 406 407 408 409 410 411 412 413 414 415 416 417 418 |
goto try_again; done: gossip_debug(GOSSIP_XATTR_DEBUG, "%s: returning %d" " [size of buffer %ld] (filled in %d keys) ", __func__, ret ? (int)ret : (int)total, (long)size, count_keys); op_release(new_op); if (ret == 0) ret = total; out_unlock: |
8bb8aefd5 OrangeFS: Change ... |
419 |
up_read(&orangefs_inode->xattr_sem); |
1182fca3b Orangefs: kernel ... |
420 421 |
return ret; } |
8bb8aefd5 OrangeFS: Change ... |
422 |
static int orangefs_xattr_set_default(const struct xattr_handler *handler, |
593012268 switch xattr_hand... |
423 424 |
struct dentry *unused, struct inode *inode, |
8bb8aefd5 OrangeFS: Change ... |
425 426 427 428 |
const char *name, const void *buffer, size_t size, int flags) |
1182fca3b Orangefs: kernel ... |
429 |
{ |
d373a712c orangefs: Remove ... |
430 |
return orangefs_inode_setxattr(inode, name, buffer, size, flags); |
1182fca3b Orangefs: kernel ... |
431 |
} |
8bb8aefd5 OrangeFS: Change ... |
432 |
static int orangefs_xattr_get_default(const struct xattr_handler *handler, |
b296821a7 xattr_handler: pa... |
433 434 |
struct dentry *unused, struct inode *inode, |
8bb8aefd5 OrangeFS: Change ... |
435 436 437 |
const char *name, void *buffer, size_t size) |
1182fca3b Orangefs: kernel ... |
438 |
{ |
d373a712c orangefs: Remove ... |
439 |
return orangefs_inode_getxattr(inode, name, buffer, size); |
1182fca3b Orangefs: kernel ... |
440 441 |
} |
121744440 orangefs: constif... |
442 |
static const struct xattr_handler orangefs_xattr_default_handler = { |
972a7344f orangefs: Remove ... |
443 |
.prefix = "", /* match any name => handlers called with full name */ |
8bb8aefd5 OrangeFS: Change ... |
444 445 |
.get = orangefs_xattr_get_default, .set = orangefs_xattr_set_default, |
1182fca3b Orangefs: kernel ... |
446 |
}; |
8bb8aefd5 OrangeFS: Change ... |
447 |
const struct xattr_handler *orangefs_xattr_handlers[] = { |
1182fca3b Orangefs: kernel ... |
448 449 |
&posix_acl_access_xattr_handler, &posix_acl_default_xattr_handler, |
8bb8aefd5 OrangeFS: Change ... |
450 |
&orangefs_xattr_default_handler, |
1182fca3b Orangefs: kernel ... |
451 452 |
NULL }; |