ia64/linux-2.6.18-xen.hg

annotate fs/xattr.c @ 524:7f8b544237bf

netfront: Allow netfront in domain 0.

This is useful if your physical network device is in a utility domain.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Apr 15 15:18:58 2008 +0100 (2008-04-15)
parents 831230e53067
children
rev   line source
ian@0 1 /*
ian@0 2 File: fs/xattr.c
ian@0 3
ian@0 4 Extended attribute handling.
ian@0 5
ian@0 6 Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
ian@0 7 Copyright (C) 2001 SGI - Silicon Graphics, Inc <linux-xfs@oss.sgi.com>
ian@0 8 Copyright (c) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
ian@0 9 */
ian@0 10 #include <linux/fs.h>
ian@0 11 #include <linux/slab.h>
ian@0 12 #include <linux/smp_lock.h>
ian@0 13 #include <linux/file.h>
ian@0 14 #include <linux/xattr.h>
ian@0 15 #include <linux/namei.h>
ian@0 16 #include <linux/security.h>
ian@0 17 #include <linux/syscalls.h>
ian@0 18 #include <linux/module.h>
ian@0 19 #include <linux/fsnotify.h>
ian@0 20 #include <linux/audit.h>
ian@0 21 #include <asm/uaccess.h>
ian@0 22
ian@0 23
ian@0 24 /*
ian@0 25 * Check permissions for extended attribute access. This is a bit complicated
ian@0 26 * because different namespaces have very different rules.
ian@0 27 */
ian@0 28 static int
ian@0 29 xattr_permission(struct inode *inode, const char *name, int mask)
ian@0 30 {
ian@0 31 /*
ian@0 32 * We can never set or remove an extended attribute on a read-only
ian@0 33 * filesystem or on an immutable / append-only inode.
ian@0 34 */
ian@0 35 if (mask & MAY_WRITE) {
ian@0 36 if (IS_RDONLY(inode))
ian@0 37 return -EROFS;
ian@0 38 if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
ian@0 39 return -EPERM;
ian@0 40 }
ian@0 41
ian@0 42 /*
ian@0 43 * No restriction for security.* and system.* from the VFS. Decision
ian@0 44 * on these is left to the underlying filesystem / security module.
ian@0 45 */
ian@0 46 if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) ||
ian@0 47 !strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
ian@0 48 return 0;
ian@0 49
ian@0 50 /*
ian@0 51 * The trusted.* namespace can only accessed by a privilegued user.
ian@0 52 */
ian@0 53 if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
ian@0 54 return (capable(CAP_SYS_ADMIN) ? 0 : -EPERM);
ian@0 55
ian@0 56 if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
ian@0 57 if (!S_ISREG(inode->i_mode) &&
ian@0 58 (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
ian@0 59 return -EPERM;
ian@0 60 }
ian@0 61
ian@0 62 return permission(inode, mask, NULL);
ian@0 63 }
ian@0 64
ian@0 65 int
ian@0 66 vfs_setxattr(struct dentry *dentry, char *name, void *value,
ian@0 67 size_t size, int flags)
ian@0 68 {
ian@0 69 struct inode *inode = dentry->d_inode;
ian@0 70 int error;
ian@0 71
ian@0 72 error = xattr_permission(inode, name, MAY_WRITE);
ian@0 73 if (error)
ian@0 74 return error;
ian@0 75
ian@0 76 mutex_lock(&inode->i_mutex);
ian@0 77 error = security_inode_setxattr(dentry, name, value, size, flags);
ian@0 78 if (error)
ian@0 79 goto out;
ian@0 80 error = -EOPNOTSUPP;
ian@0 81 if (inode->i_op->setxattr) {
ian@0 82 error = inode->i_op->setxattr(dentry, name, value, size, flags);
ian@0 83 if (!error) {
ian@0 84 fsnotify_xattr(dentry);
ian@0 85 security_inode_post_setxattr(dentry, name, value,
ian@0 86 size, flags);
ian@0 87 }
ian@0 88 } else if (!strncmp(name, XATTR_SECURITY_PREFIX,
ian@0 89 XATTR_SECURITY_PREFIX_LEN)) {
ian@0 90 const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
ian@0 91 error = security_inode_setsecurity(inode, suffix, value,
ian@0 92 size, flags);
ian@0 93 if (!error)
ian@0 94 fsnotify_xattr(dentry);
ian@0 95 }
ian@0 96 out:
ian@0 97 mutex_unlock(&inode->i_mutex);
ian@0 98 return error;
ian@0 99 }
ian@0 100 EXPORT_SYMBOL_GPL(vfs_setxattr);
ian@0 101
ian@0 102 ssize_t
ian@0 103 vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size)
ian@0 104 {
ian@0 105 struct inode *inode = dentry->d_inode;
ian@0 106 int error;
ian@0 107
ian@0 108 error = xattr_permission(inode, name, MAY_READ);
ian@0 109 if (error)
ian@0 110 return error;
ian@0 111
ian@0 112 error = security_inode_getxattr(dentry, name);
ian@0 113 if (error)
ian@0 114 return error;
ian@0 115
ian@0 116 if (inode->i_op->getxattr)
ian@0 117 error = inode->i_op->getxattr(dentry, name, value, size);
ian@0 118 else
ian@0 119 error = -EOPNOTSUPP;
ian@0 120
ian@0 121 if (!strncmp(name, XATTR_SECURITY_PREFIX,
ian@0 122 XATTR_SECURITY_PREFIX_LEN)) {
ian@0 123 const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
ian@0 124 int ret = security_inode_getsecurity(inode, suffix, value,
ian@0 125 size, error);
ian@0 126 /*
ian@0 127 * Only overwrite the return value if a security module
ian@0 128 * is actually active.
ian@0 129 */
ian@0 130 if (ret != -EOPNOTSUPP)
ian@0 131 error = ret;
ian@0 132 }
ian@0 133
ian@0 134 return error;
ian@0 135 }
ian@0 136 EXPORT_SYMBOL_GPL(vfs_getxattr);
ian@0 137
ian@0 138 int
ian@0 139 vfs_removexattr(struct dentry *dentry, char *name)
ian@0 140 {
ian@0 141 struct inode *inode = dentry->d_inode;
ian@0 142 int error;
ian@0 143
ian@0 144 if (!inode->i_op->removexattr)
ian@0 145 return -EOPNOTSUPP;
ian@0 146
ian@0 147 error = xattr_permission(inode, name, MAY_WRITE);
ian@0 148 if (error)
ian@0 149 return error;
ian@0 150
ian@0 151 error = security_inode_removexattr(dentry, name);
ian@0 152 if (error)
ian@0 153 return error;
ian@0 154
ian@0 155 mutex_lock(&inode->i_mutex);
ian@0 156 error = inode->i_op->removexattr(dentry, name);
ian@0 157 mutex_unlock(&inode->i_mutex);
ian@0 158
ian@0 159 if (!error)
ian@0 160 fsnotify_xattr(dentry);
ian@0 161 return error;
ian@0 162 }
ian@0 163 EXPORT_SYMBOL_GPL(vfs_removexattr);
ian@0 164
ian@0 165
ian@0 166 /*
ian@0 167 * Extended attribute SET operations
ian@0 168 */
ian@0 169 static long
ian@0 170 setxattr(struct dentry *d, char __user *name, void __user *value,
ian@0 171 size_t size, int flags)
ian@0 172 {
ian@0 173 int error;
ian@0 174 void *kvalue = NULL;
ian@0 175 char kname[XATTR_NAME_MAX + 1];
ian@0 176
ian@0 177 if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
ian@0 178 return -EINVAL;
ian@0 179
ian@0 180 error = strncpy_from_user(kname, name, sizeof(kname));
ian@0 181 if (error == 0 || error == sizeof(kname))
ian@0 182 error = -ERANGE;
ian@0 183 if (error < 0)
ian@0 184 return error;
ian@0 185
ian@0 186 if (size) {
ian@0 187 if (size > XATTR_SIZE_MAX)
ian@0 188 return -E2BIG;
ian@0 189 kvalue = kmalloc(size, GFP_KERNEL);
ian@0 190 if (!kvalue)
ian@0 191 return -ENOMEM;
ian@0 192 if (copy_from_user(kvalue, value, size)) {
ian@0 193 kfree(kvalue);
ian@0 194 return -EFAULT;
ian@0 195 }
ian@0 196 }
ian@0 197
ian@0 198 error = vfs_setxattr(d, kname, kvalue, size, flags);
ian@0 199 kfree(kvalue);
ian@0 200 return error;
ian@0 201 }
ian@0 202
ian@0 203 asmlinkage long
ian@0 204 sys_setxattr(char __user *path, char __user *name, void __user *value,
ian@0 205 size_t size, int flags)
ian@0 206 {
ian@0 207 struct nameidata nd;
ian@0 208 int error;
ian@0 209
ian@0 210 error = user_path_walk(path, &nd);
ian@0 211 if (error)
ian@0 212 return error;
ian@0 213 error = setxattr(nd.dentry, name, value, size, flags);
ian@0 214 path_release(&nd);
ian@0 215 return error;
ian@0 216 }
ian@0 217
ian@0 218 asmlinkage long
ian@0 219 sys_lsetxattr(char __user *path, char __user *name, void __user *value,
ian@0 220 size_t size, int flags)
ian@0 221 {
ian@0 222 struct nameidata nd;
ian@0 223 int error;
ian@0 224
ian@0 225 error = user_path_walk_link(path, &nd);
ian@0 226 if (error)
ian@0 227 return error;
ian@0 228 error = setxattr(nd.dentry, name, value, size, flags);
ian@0 229 path_release(&nd);
ian@0 230 return error;
ian@0 231 }
ian@0 232
ian@0 233 asmlinkage long
ian@0 234 sys_fsetxattr(int fd, char __user *name, void __user *value,
ian@0 235 size_t size, int flags)
ian@0 236 {
ian@0 237 struct file *f;
ian@0 238 struct dentry *dentry;
ian@0 239 int error = -EBADF;
ian@0 240
ian@0 241 f = fget(fd);
ian@0 242 if (!f)
ian@0 243 return error;
ian@0 244 dentry = f->f_dentry;
ian@0 245 audit_inode(NULL, dentry->d_inode);
ian@0 246 error = setxattr(dentry, name, value, size, flags);
ian@0 247 fput(f);
ian@0 248 return error;
ian@0 249 }
ian@0 250
ian@0 251 /*
ian@0 252 * Extended attribute GET operations
ian@0 253 */
ian@0 254 static ssize_t
ian@0 255 getxattr(struct dentry *d, char __user *name, void __user *value, size_t size)
ian@0 256 {
ian@0 257 ssize_t error;
ian@0 258 void *kvalue = NULL;
ian@0 259 char kname[XATTR_NAME_MAX + 1];
ian@0 260
ian@0 261 error = strncpy_from_user(kname, name, sizeof(kname));
ian@0 262 if (error == 0 || error == sizeof(kname))
ian@0 263 error = -ERANGE;
ian@0 264 if (error < 0)
ian@0 265 return error;
ian@0 266
ian@0 267 if (size) {
ian@0 268 if (size > XATTR_SIZE_MAX)
ian@0 269 size = XATTR_SIZE_MAX;
ian@0 270 kvalue = kzalloc(size, GFP_KERNEL);
ian@0 271 if (!kvalue)
ian@0 272 return -ENOMEM;
ian@0 273 }
ian@0 274
ian@0 275 error = vfs_getxattr(d, kname, kvalue, size);
ian@0 276 if (error > 0) {
ian@0 277 if (size && copy_to_user(value, kvalue, error))
ian@0 278 error = -EFAULT;
ian@0 279 } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {
ian@0 280 /* The file system tried to returned a value bigger
ian@0 281 than XATTR_SIZE_MAX bytes. Not possible. */
ian@0 282 error = -E2BIG;
ian@0 283 }
ian@0 284 kfree(kvalue);
ian@0 285 return error;
ian@0 286 }
ian@0 287
ian@0 288 asmlinkage ssize_t
ian@0 289 sys_getxattr(char __user *path, char __user *name, void __user *value,
ian@0 290 size_t size)
ian@0 291 {
ian@0 292 struct nameidata nd;
ian@0 293 ssize_t error;
ian@0 294
ian@0 295 error = user_path_walk(path, &nd);
ian@0 296 if (error)
ian@0 297 return error;
ian@0 298 error = getxattr(nd.dentry, name, value, size);
ian@0 299 path_release(&nd);
ian@0 300 return error;
ian@0 301 }
ian@0 302
ian@0 303 asmlinkage ssize_t
ian@0 304 sys_lgetxattr(char __user *path, char __user *name, void __user *value,
ian@0 305 size_t size)
ian@0 306 {
ian@0 307 struct nameidata nd;
ian@0 308 ssize_t error;
ian@0 309
ian@0 310 error = user_path_walk_link(path, &nd);
ian@0 311 if (error)
ian@0 312 return error;
ian@0 313 error = getxattr(nd.dentry, name, value, size);
ian@0 314 path_release(&nd);
ian@0 315 return error;
ian@0 316 }
ian@0 317
ian@0 318 asmlinkage ssize_t
ian@0 319 sys_fgetxattr(int fd, char __user *name, void __user *value, size_t size)
ian@0 320 {
ian@0 321 struct file *f;
ian@0 322 ssize_t error = -EBADF;
ian@0 323
ian@0 324 f = fget(fd);
ian@0 325 if (!f)
ian@0 326 return error;
ian@0 327 error = getxattr(f->f_dentry, name, value, size);
ian@0 328 fput(f);
ian@0 329 return error;
ian@0 330 }
ian@0 331
ian@0 332 /*
ian@0 333 * Extended attribute LIST operations
ian@0 334 */
ian@0 335 static ssize_t
ian@0 336 listxattr(struct dentry *d, char __user *list, size_t size)
ian@0 337 {
ian@0 338 ssize_t error;
ian@0 339 char *klist = NULL;
ian@0 340
ian@0 341 if (size) {
ian@0 342 if (size > XATTR_LIST_MAX)
ian@0 343 size = XATTR_LIST_MAX;
ian@0 344 klist = kmalloc(size, GFP_KERNEL);
ian@0 345 if (!klist)
ian@0 346 return -ENOMEM;
ian@0 347 }
ian@0 348
ian@0 349 error = security_inode_listxattr(d);
ian@0 350 if (error)
ian@0 351 goto out;
ian@0 352 error = -EOPNOTSUPP;
ian@0 353 if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
ian@0 354 error = d->d_inode->i_op->listxattr(d, klist, size);
ian@0 355 } else {
ian@0 356 error = security_inode_listsecurity(d->d_inode, klist, size);
ian@0 357 if (size && error > size)
ian@0 358 error = -ERANGE;
ian@0 359 }
ian@0 360 if (error > 0) {
ian@0 361 if (size && copy_to_user(list, klist, error))
ian@0 362 error = -EFAULT;
ian@0 363 } else if (error == -ERANGE && size >= XATTR_LIST_MAX) {
ian@0 364 /* The file system tried to returned a list bigger
ian@0 365 than XATTR_LIST_MAX bytes. Not possible. */
ian@0 366 error = -E2BIG;
ian@0 367 }
ian@0 368 out:
ian@0 369 kfree(klist);
ian@0 370 return error;
ian@0 371 }
ian@0 372
ian@0 373 asmlinkage ssize_t
ian@0 374 sys_listxattr(char __user *path, char __user *list, size_t size)
ian@0 375 {
ian@0 376 struct nameidata nd;
ian@0 377 ssize_t error;
ian@0 378
ian@0 379 error = user_path_walk(path, &nd);
ian@0 380 if (error)
ian@0 381 return error;
ian@0 382 error = listxattr(nd.dentry, list, size);
ian@0 383 path_release(&nd);
ian@0 384 return error;
ian@0 385 }
ian@0 386
ian@0 387 asmlinkage ssize_t
ian@0 388 sys_llistxattr(char __user *path, char __user *list, size_t size)
ian@0 389 {
ian@0 390 struct nameidata nd;
ian@0 391 ssize_t error;
ian@0 392
ian@0 393 error = user_path_walk_link(path, &nd);
ian@0 394 if (error)
ian@0 395 return error;
ian@0 396 error = listxattr(nd.dentry, list, size);
ian@0 397 path_release(&nd);
ian@0 398 return error;
ian@0 399 }
ian@0 400
ian@0 401 asmlinkage ssize_t
ian@0 402 sys_flistxattr(int fd, char __user *list, size_t size)
ian@0 403 {
ian@0 404 struct file *f;
ian@0 405 ssize_t error = -EBADF;
ian@0 406
ian@0 407 f = fget(fd);
ian@0 408 if (!f)
ian@0 409 return error;
ian@0 410 error = listxattr(f->f_dentry, list, size);
ian@0 411 fput(f);
ian@0 412 return error;
ian@0 413 }
ian@0 414
ian@0 415 /*
ian@0 416 * Extended attribute REMOVE operations
ian@0 417 */
ian@0 418 static long
ian@0 419 removexattr(struct dentry *d, char __user *name)
ian@0 420 {
ian@0 421 int error;
ian@0 422 char kname[XATTR_NAME_MAX + 1];
ian@0 423
ian@0 424 error = strncpy_from_user(kname, name, sizeof(kname));
ian@0 425 if (error == 0 || error == sizeof(kname))
ian@0 426 error = -ERANGE;
ian@0 427 if (error < 0)
ian@0 428 return error;
ian@0 429
ian@0 430 return vfs_removexattr(d, kname);
ian@0 431 }
ian@0 432
ian@0 433 asmlinkage long
ian@0 434 sys_removexattr(char __user *path, char __user *name)
ian@0 435 {
ian@0 436 struct nameidata nd;
ian@0 437 int error;
ian@0 438
ian@0 439 error = user_path_walk(path, &nd);
ian@0 440 if (error)
ian@0 441 return error;
ian@0 442 error = removexattr(nd.dentry, name);
ian@0 443 path_release(&nd);
ian@0 444 return error;
ian@0 445 }
ian@0 446
ian@0 447 asmlinkage long
ian@0 448 sys_lremovexattr(char __user *path, char __user *name)
ian@0 449 {
ian@0 450 struct nameidata nd;
ian@0 451 int error;
ian@0 452
ian@0 453 error = user_path_walk_link(path, &nd);
ian@0 454 if (error)
ian@0 455 return error;
ian@0 456 error = removexattr(nd.dentry, name);
ian@0 457 path_release(&nd);
ian@0 458 return error;
ian@0 459 }
ian@0 460
ian@0 461 asmlinkage long
ian@0 462 sys_fremovexattr(int fd, char __user *name)
ian@0 463 {
ian@0 464 struct file *f;
ian@0 465 struct dentry *dentry;
ian@0 466 int error = -EBADF;
ian@0 467
ian@0 468 f = fget(fd);
ian@0 469 if (!f)
ian@0 470 return error;
ian@0 471 dentry = f->f_dentry;
ian@0 472 audit_inode(NULL, dentry->d_inode);
ian@0 473 error = removexattr(dentry, name);
ian@0 474 fput(f);
ian@0 475 return error;
ian@0 476 }
ian@0 477
ian@0 478
ian@0 479 static const char *
ian@0 480 strcmp_prefix(const char *a, const char *a_prefix)
ian@0 481 {
ian@0 482 while (*a_prefix && *a == *a_prefix) {
ian@0 483 a++;
ian@0 484 a_prefix++;
ian@0 485 }
ian@0 486 return *a_prefix ? NULL : a;
ian@0 487 }
ian@0 488
ian@0 489 /*
ian@0 490 * In order to implement different sets of xattr operations for each xattr
ian@0 491 * prefix with the generic xattr API, a filesystem should create a
ian@0 492 * null-terminated array of struct xattr_handler (one for each prefix) and
ian@0 493 * hang a pointer to it off of the s_xattr field of the superblock.
ian@0 494 *
ian@0 495 * The generic_fooxattr() functions will use this list to dispatch xattr
ian@0 496 * operations to the correct xattr_handler.
ian@0 497 */
ian@0 498 #define for_each_xattr_handler(handlers, handler) \
ian@0 499 for ((handler) = *(handlers)++; \
ian@0 500 (handler) != NULL; \
ian@0 501 (handler) = *(handlers)++)
ian@0 502
ian@0 503 /*
ian@0 504 * Find the xattr_handler with the matching prefix.
ian@0 505 */
ian@0 506 static struct xattr_handler *
ian@0 507 xattr_resolve_name(struct xattr_handler **handlers, const char **name)
ian@0 508 {
ian@0 509 struct xattr_handler *handler;
ian@0 510
ian@0 511 if (!*name)
ian@0 512 return NULL;
ian@0 513
ian@0 514 for_each_xattr_handler(handlers, handler) {
ian@0 515 const char *n = strcmp_prefix(*name, handler->prefix);
ian@0 516 if (n) {
ian@0 517 *name = n;
ian@0 518 break;
ian@0 519 }
ian@0 520 }
ian@0 521 return handler;
ian@0 522 }
ian@0 523
ian@0 524 /*
ian@0 525 * Find the handler for the prefix and dispatch its get() operation.
ian@0 526 */
ian@0 527 ssize_t
ian@0 528 generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size)
ian@0 529 {
ian@0 530 struct xattr_handler *handler;
ian@0 531 struct inode *inode = dentry->d_inode;
ian@0 532
ian@0 533 handler = xattr_resolve_name(inode->i_sb->s_xattr, &name);
ian@0 534 if (!handler)
ian@0 535 return -EOPNOTSUPP;
ian@0 536 return handler->get(inode, name, buffer, size);
ian@0 537 }
ian@0 538
ian@0 539 /*
ian@0 540 * Combine the results of the list() operation from every xattr_handler in the
ian@0 541 * list.
ian@0 542 */
ian@0 543 ssize_t
ian@0 544 generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
ian@0 545 {
ian@0 546 struct inode *inode = dentry->d_inode;
ian@0 547 struct xattr_handler *handler, **handlers = inode->i_sb->s_xattr;
ian@0 548 unsigned int size = 0;
ian@0 549
ian@0 550 if (!buffer) {
ian@0 551 for_each_xattr_handler(handlers, handler)
ian@0 552 size += handler->list(inode, NULL, 0, NULL, 0);
ian@0 553 } else {
ian@0 554 char *buf = buffer;
ian@0 555
ian@0 556 for_each_xattr_handler(handlers, handler) {
ian@0 557 size = handler->list(inode, buf, buffer_size, NULL, 0);
ian@0 558 if (size > buffer_size)
ian@0 559 return -ERANGE;
ian@0 560 buf += size;
ian@0 561 buffer_size -= size;
ian@0 562 }
ian@0 563 size = buf - buffer;
ian@0 564 }
ian@0 565 return size;
ian@0 566 }
ian@0 567
ian@0 568 /*
ian@0 569 * Find the handler for the prefix and dispatch its set() operation.
ian@0 570 */
ian@0 571 int
ian@0 572 generic_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags)
ian@0 573 {
ian@0 574 struct xattr_handler *handler;
ian@0 575 struct inode *inode = dentry->d_inode;
ian@0 576
ian@0 577 if (size == 0)
ian@0 578 value = ""; /* empty EA, do not remove */
ian@0 579 handler = xattr_resolve_name(inode->i_sb->s_xattr, &name);
ian@0 580 if (!handler)
ian@0 581 return -EOPNOTSUPP;
ian@0 582 return handler->set(inode, name, value, size, flags);
ian@0 583 }
ian@0 584
ian@0 585 /*
ian@0 586 * Find the handler for the prefix and dispatch its set() operation to remove
ian@0 587 * any associated extended attribute.
ian@0 588 */
ian@0 589 int
ian@0 590 generic_removexattr(struct dentry *dentry, const char *name)
ian@0 591 {
ian@0 592 struct xattr_handler *handler;
ian@0 593 struct inode *inode = dentry->d_inode;
ian@0 594
ian@0 595 handler = xattr_resolve_name(inode->i_sb->s_xattr, &name);
ian@0 596 if (!handler)
ian@0 597 return -EOPNOTSUPP;
ian@0 598 return handler->set(inode, name, NULL, 0, XATTR_REPLACE);
ian@0 599 }
ian@0 600
ian@0 601 EXPORT_SYMBOL(generic_getxattr);
ian@0 602 EXPORT_SYMBOL(generic_listxattr);
ian@0 603 EXPORT_SYMBOL(generic_setxattr);
ian@0 604 EXPORT_SYMBOL(generic_removexattr);