xattr.c 15.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
  File: fs/xattr.c

  Extended attribute handling.

  Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
  Copyright (C) 2001 SGI - Silicon Graphics, Inc <linux-xfs@oss.sgi.com>
  Copyright (c) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
 */
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/file.h>
#include <linux/xattr.h>
14
#include <linux/mount.h>
L
Linus Torvalds 已提交
15 16 17 18
#include <linux/namei.h>
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/module.h>
R
Robert Love 已提交
19
#include <linux/fsnotify.h>
20
#include <linux/audit.h>
L
Linus Torvalds 已提交
21 22
#include <asm/uaccess.h>

23

24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
/*
 * Check permissions for extended attribute access.  This is a bit complicated
 * because different namespaces have very different rules.
 */
static int
xattr_permission(struct inode *inode, const char *name, int mask)
{
	/*
	 * We can never set or remove an extended attribute on a read-only
	 * filesystem  or on an immutable / append-only inode.
	 */
	if (mask & MAY_WRITE) {
		if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
			return -EPERM;
	}

	/*
	 * No restriction for security.* and system.* from the VFS.  Decision
	 * on these is left to the underlying filesystem / security module.
	 */
	if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) ||
	    !strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
		return 0;

	/*
49
	 * The trusted.* namespace can only be accessed by a privileged user.
50 51 52 53
	 */
	if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
		return (capable(CAP_SYS_ADMIN) ? 0 : -EPERM);

54 55 56 57
	/* In user.* namespace, only regular files and directories can have
	 * extended attributes. For sticky directories, only the owner and
	 * privileged user can write attributes.
	 */
58
	if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
59 60 61
		if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
			return -EPERM;
		if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
62
		    (mask & MAY_WRITE) && !inode_owner_or_capable(inode))
63 64 65
			return -EPERM;
	}

66
	return inode_permission(inode, mask);
67 68
}

69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
/**
 *  __vfs_setxattr_noperm - perform setxattr operation without performing
 *  permission checks.
 *
 *  @dentry - object to perform setxattr on
 *  @name - xattr name to set
 *  @value - value to set @name to
 *  @size - size of @value
 *  @flags - flags to pass into filesystem operations
 *
 *  returns the result of the internal setxattr or setsecurity operations.
 *
 *  This function requires the caller to lock the inode's i_mutex before it
 *  is executed. It also assumes that the caller will make the appropriate
 *  permission checks.
 */
int __vfs_setxattr_noperm(struct dentry *dentry, const char *name,
		const void *value, size_t size, int flags)
87 88
{
	struct inode *inode = dentry->d_inode;
89
	int error = -EOPNOTSUPP;
90

91 92 93 94 95 96 97 98
	if (inode->i_op->setxattr) {
		error = inode->i_op->setxattr(dentry, name, value, size, flags);
		if (!error) {
			fsnotify_xattr(dentry);
			security_inode_post_setxattr(dentry, name, value,
						     size, flags);
		}
	} else if (!strncmp(name, XATTR_SECURITY_PREFIX,
99 100
				XATTR_SECURITY_PREFIX_LEN)) {
		const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
101 102 103 104 105
		error = security_inode_setsecurity(inode, suffix, value,
						   size, flags);
		if (!error)
			fsnotify_xattr(dentry);
	}
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128

	return error;
}


int
vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
		size_t size, int flags)
{
	struct inode *inode = dentry->d_inode;
	int error;

	error = xattr_permission(inode, name, MAY_WRITE);
	if (error)
		return error;

	mutex_lock(&inode->i_mutex);
	error = security_inode_setxattr(dentry, name, value, size, flags);
	if (error)
		goto out;

	error = __vfs_setxattr_noperm(dentry, name, value, size, flags);

129 130 131 132 133 134
out:
	mutex_unlock(&inode->i_mutex);
	return error;
}
EXPORT_SYMBOL_GPL(vfs_setxattr);

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
ssize_t
xattr_getsecurity(struct inode *inode, const char *name, void *value,
			size_t size)
{
	void *buffer = NULL;
	ssize_t len;

	if (!value || !size) {
		len = security_inode_getsecurity(inode, name, &buffer, false);
		goto out_noalloc;
	}

	len = security_inode_getsecurity(inode, name, &buffer, true);
	if (len < 0)
		return len;
	if (size < len) {
		len = -ERANGE;
		goto out;
	}
	memcpy(value, buffer, len);
out:
	security_release_secctx(buffer, len);
out_noalloc:
	return len;
}
EXPORT_SYMBOL_GPL(xattr_getsecurity);

162
ssize_t
163
vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
164 165 166 167
{
	struct inode *inode = dentry->d_inode;
	int error;

168 169 170 171
	error = xattr_permission(inode, name, MAY_READ);
	if (error)
		return error;

172 173 174 175 176
	error = security_inode_getxattr(dentry, name);
	if (error)
		return error;

	if (!strncmp(name, XATTR_SECURITY_PREFIX,
177 178
				XATTR_SECURITY_PREFIX_LEN)) {
		const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
179
		int ret = xattr_getsecurity(inode, suffix, value, size);
180 181 182 183
		/*
		 * Only overwrite the return value if a security module
		 * is actually active.
		 */
184 185 186
		if (ret == -EOPNOTSUPP)
			goto nolsm;
		return ret;
187
	}
188 189 190 191 192
nolsm:
	if (inode->i_op->getxattr)
		error = inode->i_op->getxattr(dentry, name, value, size);
	else
		error = -EOPNOTSUPP;
193 194 195 196 197

	return error;
}
EXPORT_SYMBOL_GPL(vfs_getxattr);

B
Bill Nottingham 已提交
198 199 200 201 202 203 204 205 206
ssize_t
vfs_listxattr(struct dentry *d, char *list, size_t size)
{
	ssize_t error;

	error = security_inode_listxattr(d);
	if (error)
		return error;
	error = -EOPNOTSUPP;
A
Al Viro 已提交
207
	if (d->d_inode->i_op->listxattr) {
B
Bill Nottingham 已提交
208 209 210 211 212 213 214 215 216 217
		error = d->d_inode->i_op->listxattr(d, list, size);
	} else {
		error = security_inode_listsecurity(d->d_inode, list, size);
		if (size && error > size)
			error = -ERANGE;
	}
	return error;
}
EXPORT_SYMBOL_GPL(vfs_listxattr);

218
int
219
vfs_removexattr(struct dentry *dentry, const char *name)
220 221 222 223 224 225 226
{
	struct inode *inode = dentry->d_inode;
	int error;

	if (!inode->i_op->removexattr)
		return -EOPNOTSUPP;

227 228 229 230
	error = xattr_permission(inode, name, MAY_WRITE);
	if (error)
		return error;

231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
	error = security_inode_removexattr(dentry, name);
	if (error)
		return error;

	mutex_lock(&inode->i_mutex);
	error = inode->i_op->removexattr(dentry, name);
	mutex_unlock(&inode->i_mutex);

	if (!error)
		fsnotify_xattr(dentry);
	return error;
}
EXPORT_SYMBOL_GPL(vfs_removexattr);


L
Linus Torvalds 已提交
246 247 248 249
/*
 * Extended attribute SET operations
 */
static long
250
setxattr(struct dentry *d, const char __user *name, const void __user *value,
L
Linus Torvalds 已提交
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
	 size_t size, int flags)
{
	int error;
	void *kvalue = NULL;
	char kname[XATTR_NAME_MAX + 1];

	if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
		return -EINVAL;

	error = strncpy_from_user(kname, name, sizeof(kname));
	if (error == 0 || error == sizeof(kname))
		error = -ERANGE;
	if (error < 0)
		return error;

	if (size) {
		if (size > XATTR_SIZE_MAX)
			return -E2BIG;
L
Li Zefan 已提交
269 270 271
		kvalue = memdup_user(value, size);
		if (IS_ERR(kvalue))
			return PTR_ERR(kvalue);
L
Linus Torvalds 已提交
272 273
	}

274
	error = vfs_setxattr(d, kname, kvalue, size, flags);
J
Jesper Juhl 已提交
275
	kfree(kvalue);
L
Linus Torvalds 已提交
276 277 278
	return error;
}

279 280 281
SYSCALL_DEFINE5(setxattr, const char __user *, pathname,
		const char __user *, name, const void __user *, value,
		size_t, size, int, flags)
L
Linus Torvalds 已提交
282
{
283
	struct path path;
L
Linus Torvalds 已提交
284 285
	int error;

286
	error = user_path(pathname, &path);
L
Linus Torvalds 已提交
287 288
	if (error)
		return error;
289
	error = mnt_want_write(path.mnt);
290
	if (!error) {
291 292
		error = setxattr(path.dentry, name, value, size, flags);
		mnt_drop_write(path.mnt);
293
	}
294
	path_put(&path);
L
Linus Torvalds 已提交
295 296 297
	return error;
}

298 299 300
SYSCALL_DEFINE5(lsetxattr, const char __user *, pathname,
		const char __user *, name, const void __user *, value,
		size_t, size, int, flags)
L
Linus Torvalds 已提交
301
{
302
	struct path path;
L
Linus Torvalds 已提交
303 304
	int error;

305
	error = user_lpath(pathname, &path);
L
Linus Torvalds 已提交
306 307
	if (error)
		return error;
308
	error = mnt_want_write(path.mnt);
309
	if (!error) {
310 311
		error = setxattr(path.dentry, name, value, size, flags);
		mnt_drop_write(path.mnt);
312
	}
313
	path_put(&path);
L
Linus Torvalds 已提交
314 315 316
	return error;
}

317 318
SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
		const void __user *,value, size_t, size, int, flags)
L
Linus Torvalds 已提交
319 320
{
	struct file *f;
321
	struct dentry *dentry;
L
Linus Torvalds 已提交
322 323 324 325 326
	int error = -EBADF;

	f = fget(fd);
	if (!f)
		return error;
327
	dentry = f->f_path.dentry;
328
	audit_inode(NULL, dentry);
N
npiggin@suse.de 已提交
329
	error = mnt_want_write_file(f);
330 331 332 333
	if (!error) {
		error = setxattr(dentry, name, value, size, flags);
		mnt_drop_write(f->f_path.mnt);
	}
L
Linus Torvalds 已提交
334 335 336 337 338 339 340 341
	fput(f);
	return error;
}

/*
 * Extended attribute GET operations
 */
static ssize_t
342 343
getxattr(struct dentry *d, const char __user *name, void __user *value,
	 size_t size)
L
Linus Torvalds 已提交
344 345 346 347 348 349 350 351 352 353 354 355 356 357
{
	ssize_t error;
	void *kvalue = NULL;
	char kname[XATTR_NAME_MAX + 1];

	error = strncpy_from_user(kname, name, sizeof(kname));
	if (error == 0 || error == sizeof(kname))
		error = -ERANGE;
	if (error < 0)
		return error;

	if (size) {
		if (size > XATTR_SIZE_MAX)
			size = XATTR_SIZE_MAX;
358
		kvalue = kzalloc(size, GFP_KERNEL);
L
Linus Torvalds 已提交
359 360 361 362
		if (!kvalue)
			return -ENOMEM;
	}

363
	error = vfs_getxattr(d, kname, kvalue, size);
364 365 366 367 368 369 370
	if (error > 0) {
		if (size && copy_to_user(value, kvalue, error))
			error = -EFAULT;
	} else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {
		/* The file system tried to returned a value bigger
		   than XATTR_SIZE_MAX bytes. Not possible. */
		error = -E2BIG;
L
Linus Torvalds 已提交
371
	}
J
Jesper Juhl 已提交
372
	kfree(kvalue);
L
Linus Torvalds 已提交
373 374 375
	return error;
}

376 377
SYSCALL_DEFINE4(getxattr, const char __user *, pathname,
		const char __user *, name, void __user *, value, size_t, size)
L
Linus Torvalds 已提交
378
{
379
	struct path path;
L
Linus Torvalds 已提交
380 381
	ssize_t error;

382
	error = user_path(pathname, &path);
L
Linus Torvalds 已提交
383 384
	if (error)
		return error;
385 386
	error = getxattr(path.dentry, name, value, size);
	path_put(&path);
L
Linus Torvalds 已提交
387 388 389
	return error;
}

390 391
SYSCALL_DEFINE4(lgetxattr, const char __user *, pathname,
		const char __user *, name, void __user *, value, size_t, size)
L
Linus Torvalds 已提交
392
{
393
	struct path path;
L
Linus Torvalds 已提交
394 395
	ssize_t error;

396
	error = user_lpath(pathname, &path);
L
Linus Torvalds 已提交
397 398
	if (error)
		return error;
399 400
	error = getxattr(path.dentry, name, value, size);
	path_put(&path);
L
Linus Torvalds 已提交
401 402 403
	return error;
}

404 405
SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name,
		void __user *, value, size_t, size)
L
Linus Torvalds 已提交
406 407 408 409 410 411 412
{
	struct file *f;
	ssize_t error = -EBADF;

	f = fget(fd);
	if (!f)
		return error;
413
	audit_inode(NULL, f->f_path.dentry);
414
	error = getxattr(f->f_path.dentry, name, value, size);
L
Linus Torvalds 已提交
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
	fput(f);
	return error;
}

/*
 * Extended attribute LIST operations
 */
static ssize_t
listxattr(struct dentry *d, char __user *list, size_t size)
{
	ssize_t error;
	char *klist = NULL;

	if (size) {
		if (size > XATTR_LIST_MAX)
			size = XATTR_LIST_MAX;
		klist = kmalloc(size, GFP_KERNEL);
		if (!klist)
			return -ENOMEM;
	}

B
Bill Nottingham 已提交
436
	error = vfs_listxattr(d, klist, size);
437 438 439 440 441 442 443
	if (error > 0) {
		if (size && copy_to_user(list, klist, error))
			error = -EFAULT;
	} else if (error == -ERANGE && size >= XATTR_LIST_MAX) {
		/* The file system tried to returned a list bigger
		   than XATTR_LIST_MAX bytes. Not possible. */
		error = -E2BIG;
L
Linus Torvalds 已提交
444
	}
J
Jesper Juhl 已提交
445
	kfree(klist);
L
Linus Torvalds 已提交
446 447 448
	return error;
}

449 450
SYSCALL_DEFINE3(listxattr, const char __user *, pathname, char __user *, list,
		size_t, size)
L
Linus Torvalds 已提交
451
{
452
	struct path path;
L
Linus Torvalds 已提交
453 454
	ssize_t error;

455
	error = user_path(pathname, &path);
L
Linus Torvalds 已提交
456 457
	if (error)
		return error;
458 459
	error = listxattr(path.dentry, list, size);
	path_put(&path);
L
Linus Torvalds 已提交
460 461 462
	return error;
}

463 464
SYSCALL_DEFINE3(llistxattr, const char __user *, pathname, char __user *, list,
		size_t, size)
L
Linus Torvalds 已提交
465
{
466
	struct path path;
L
Linus Torvalds 已提交
467 468
	ssize_t error;

469
	error = user_lpath(pathname, &path);
L
Linus Torvalds 已提交
470 471
	if (error)
		return error;
472 473
	error = listxattr(path.dentry, list, size);
	path_put(&path);
L
Linus Torvalds 已提交
474 475 476
	return error;
}

477
SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size)
L
Linus Torvalds 已提交
478 479 480 481 482 483 484
{
	struct file *f;
	ssize_t error = -EBADF;

	f = fget(fd);
	if (!f)
		return error;
485
	audit_inode(NULL, f->f_path.dentry);
486
	error = listxattr(f->f_path.dentry, list, size);
L
Linus Torvalds 已提交
487 488 489 490 491 492 493 494
	fput(f);
	return error;
}

/*
 * Extended attribute REMOVE operations
 */
static long
495
removexattr(struct dentry *d, const char __user *name)
L
Linus Torvalds 已提交
496 497 498 499 500 501 502 503 504 505
{
	int error;
	char kname[XATTR_NAME_MAX + 1];

	error = strncpy_from_user(kname, name, sizeof(kname));
	if (error == 0 || error == sizeof(kname))
		error = -ERANGE;
	if (error < 0)
		return error;

506
	return vfs_removexattr(d, kname);
L
Linus Torvalds 已提交
507 508
}

509 510
SYSCALL_DEFINE2(removexattr, const char __user *, pathname,
		const char __user *, name)
L
Linus Torvalds 已提交
511
{
512
	struct path path;
L
Linus Torvalds 已提交
513 514
	int error;

515
	error = user_path(pathname, &path);
L
Linus Torvalds 已提交
516 517
	if (error)
		return error;
518
	error = mnt_want_write(path.mnt);
519
	if (!error) {
520 521
		error = removexattr(path.dentry, name);
		mnt_drop_write(path.mnt);
522
	}
523
	path_put(&path);
L
Linus Torvalds 已提交
524 525 526
	return error;
}

527 528
SYSCALL_DEFINE2(lremovexattr, const char __user *, pathname,
		const char __user *, name)
L
Linus Torvalds 已提交
529
{
530
	struct path path;
L
Linus Torvalds 已提交
531 532
	int error;

533
	error = user_lpath(pathname, &path);
L
Linus Torvalds 已提交
534 535
	if (error)
		return error;
536
	error = mnt_want_write(path.mnt);
537
	if (!error) {
538 539
		error = removexattr(path.dentry, name);
		mnt_drop_write(path.mnt);
540
	}
541
	path_put(&path);
L
Linus Torvalds 已提交
542 543 544
	return error;
}

545
SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)
L
Linus Torvalds 已提交
546 547
{
	struct file *f;
548
	struct dentry *dentry;
L
Linus Torvalds 已提交
549 550 551 552 553
	int error = -EBADF;

	f = fget(fd);
	if (!f)
		return error;
554
	dentry = f->f_path.dentry;
555
	audit_inode(NULL, dentry);
N
npiggin@suse.de 已提交
556
	error = mnt_want_write_file(f);
557 558 559 560
	if (!error) {
		error = removexattr(dentry, name);
		mnt_drop_write(f->f_path.mnt);
	}
L
Linus Torvalds 已提交
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
	fput(f);
	return error;
}


static const char *
strcmp_prefix(const char *a, const char *a_prefix)
{
	while (*a_prefix && *a == *a_prefix) {
		a++;
		a_prefix++;
	}
	return *a_prefix ? NULL : a;
}

/*
 * In order to implement different sets of xattr operations for each xattr
 * prefix with the generic xattr API, a filesystem should create a
 * null-terminated array of struct xattr_handler (one for each prefix) and
 * hang a pointer to it off of the s_xattr field of the superblock.
 *
 * The generic_fooxattr() functions will use this list to dispatch xattr
 * operations to the correct xattr_handler.
 */
#define for_each_xattr_handler(handlers, handler)		\
		for ((handler) = *(handlers)++;			\
			(handler) != NULL;			\
			(handler) = *(handlers)++)

/*
 * Find the xattr_handler with the matching prefix.
 */
593 594
static const struct xattr_handler *
xattr_resolve_name(const struct xattr_handler **handlers, const char **name)
L
Linus Torvalds 已提交
595
{
596
	const struct xattr_handler *handler;
L
Linus Torvalds 已提交
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616

	if (!*name)
		return NULL;

	for_each_xattr_handler(handlers, handler) {
		const char *n = strcmp_prefix(*name, handler->prefix);
		if (n) {
			*name = n;
			break;
		}
	}
	return handler;
}

/*
 * Find the handler for the prefix and dispatch its get() operation.
 */
ssize_t
generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size)
{
617
	const struct xattr_handler *handler;
L
Linus Torvalds 已提交
618

619
	handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
L
Linus Torvalds 已提交
620 621
	if (!handler)
		return -EOPNOTSUPP;
622
	return handler->get(dentry, name, buffer, size, handler->flags);
L
Linus Torvalds 已提交
623 624 625 626 627 628 629 630 631
}

/*
 * Combine the results of the list() operation from every xattr_handler in the
 * list.
 */
ssize_t
generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
{
632
	const struct xattr_handler *handler, **handlers = dentry->d_sb->s_xattr;
L
Linus Torvalds 已提交
633 634 635
	unsigned int size = 0;

	if (!buffer) {
636 637 638 639
		for_each_xattr_handler(handlers, handler) {
			size += handler->list(dentry, NULL, 0, NULL, 0,
					      handler->flags);
		}
L
Linus Torvalds 已提交
640 641 642 643
	} else {
		char *buf = buffer;

		for_each_xattr_handler(handlers, handler) {
644 645
			size = handler->list(dentry, buf, buffer_size,
					     NULL, 0, handler->flags);
L
Linus Torvalds 已提交
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
			if (size > buffer_size)
				return -ERANGE;
			buf += size;
			buffer_size -= size;
		}
		size = buf - buffer;
	}
	return size;
}

/*
 * Find the handler for the prefix and dispatch its set() operation.
 */
int
generic_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags)
{
662
	const struct xattr_handler *handler;
L
Linus Torvalds 已提交
663 664 665

	if (size == 0)
		value = "";  /* empty EA, do not remove */
666
	handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
L
Linus Torvalds 已提交
667 668
	if (!handler)
		return -EOPNOTSUPP;
669
	return handler->set(dentry, name, value, size, 0, handler->flags);
L
Linus Torvalds 已提交
670 671 672 673 674 675 676 677 678
}

/*
 * Find the handler for the prefix and dispatch its set() operation to remove
 * any associated extended attribute.
 */
int
generic_removexattr(struct dentry *dentry, const char *name)
{
679
	const struct xattr_handler *handler;
L
Linus Torvalds 已提交
680

681
	handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
L
Linus Torvalds 已提交
682 683
	if (!handler)
		return -EOPNOTSUPP;
684 685
	return handler->set(dentry, name, NULL, 0,
			    XATTR_REPLACE, handler->flags);
L
Linus Torvalds 已提交
686 687 688 689 690 691
}

EXPORT_SYMBOL(generic_getxattr);
EXPORT_SYMBOL(generic_listxattr);
EXPORT_SYMBOL(generic_setxattr);
EXPORT_SYMBOL(generic_removexattr);