.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * This file is part of UBIFS. |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2006-2008 Nokia Corporation. |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify it |
---|
7 | | - * under the terms of the GNU General Public License version 2 as published by |
---|
8 | | - * the Free Software Foundation. |
---|
9 | | - * |
---|
10 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
---|
11 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
12 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
13 | | - * more details. |
---|
14 | | - * |
---|
15 | | - * You should have received a copy of the GNU General Public License along with |
---|
16 | | - * this program; if not, write to the Free Software Foundation, Inc., 51 |
---|
17 | | - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
---|
18 | 6 | * |
---|
19 | 7 | * Authors: Artem Bityutskiy (Битюцкий Артём) |
---|
20 | 8 | * Adrian Hunter |
---|
.. | .. |
---|
61 | 49 | #include <linux/xattr.h> |
---|
62 | 50 | |
---|
63 | 51 | /* |
---|
64 | | - * Limit the number of extended attributes per inode so that the total size |
---|
65 | | - * (@xattr_size) is guaranteeded to fit in an 'unsigned int'. |
---|
66 | | - */ |
---|
67 | | -#define MAX_XATTRS_PER_INODE 65535 |
---|
68 | | - |
---|
69 | | -/* |
---|
70 | 52 | * Extended attribute type constants. |
---|
71 | 53 | * |
---|
72 | 54 | * USER_XATTR: user extended attribute ("user.*") |
---|
.. | .. |
---|
106 | 88 | .new_ino_d = ALIGN(size, 8), .dirtied_ino = 1, |
---|
107 | 89 | .dirtied_ino_d = ALIGN(host_ui->data_len, 8) }; |
---|
108 | 90 | |
---|
109 | | - if (host_ui->xattr_cnt >= MAX_XATTRS_PER_INODE) { |
---|
| 91 | + if (host_ui->xattr_cnt >= ubifs_xattr_max_cnt(c)) { |
---|
110 | 92 | ubifs_err(c, "inode %lu already has too many xattrs (%d), cannot create more", |
---|
111 | 93 | host->i_ino, host_ui->xattr_cnt); |
---|
112 | 94 | return -ENOSPC; |
---|
.. | .. |
---|
303 | 285 | if (!xent) |
---|
304 | 286 | return -ENOMEM; |
---|
305 | 287 | |
---|
| 288 | + down_write(&ubifs_inode(host)->xattr_sem); |
---|
306 | 289 | /* |
---|
307 | 290 | * The extended attribute entries are stored in LNC, so multiple |
---|
308 | 291 | * look-ups do not involve reading the flash. |
---|
.. | .. |
---|
337 | 320 | iput(inode); |
---|
338 | 321 | |
---|
339 | 322 | out_free: |
---|
| 323 | + up_write(&ubifs_inode(host)->xattr_sem); |
---|
340 | 324 | kfree(xent); |
---|
341 | 325 | return err; |
---|
342 | 326 | } |
---|
.. | .. |
---|
359 | 343 | if (!xent) |
---|
360 | 344 | return -ENOMEM; |
---|
361 | 345 | |
---|
| 346 | + down_read(&ubifs_inode(host)->xattr_sem); |
---|
362 | 347 | xent_key_init(c, &key, host->i_ino, &nm); |
---|
363 | 348 | err = ubifs_tnc_lookup_nm(c, &key, xent, &nm); |
---|
364 | 349 | if (err) { |
---|
365 | 350 | if (err == -ENOENT) |
---|
366 | 351 | err = -ENODATA; |
---|
367 | | - goto out_unlock; |
---|
| 352 | + goto out_cleanup; |
---|
368 | 353 | } |
---|
369 | 354 | |
---|
370 | 355 | inode = iget_xattr(c, le64_to_cpu(xent->inum)); |
---|
371 | 356 | if (IS_ERR(inode)) { |
---|
372 | 357 | err = PTR_ERR(inode); |
---|
373 | | - goto out_unlock; |
---|
| 358 | + goto out_cleanup; |
---|
374 | 359 | } |
---|
375 | 360 | |
---|
376 | 361 | ui = ubifs_inode(inode); |
---|
.. | .. |
---|
392 | 377 | out_iput: |
---|
393 | 378 | mutex_unlock(&ui->ui_mutex); |
---|
394 | 379 | iput(inode); |
---|
395 | | -out_unlock: |
---|
| 380 | +out_cleanup: |
---|
| 381 | + up_read(&ubifs_inode(host)->xattr_sem); |
---|
396 | 382 | kfree(xent); |
---|
397 | 383 | return err; |
---|
398 | 384 | } |
---|
.. | .. |
---|
424 | 410 | dbg_gen("ino %lu ('%pd'), buffer size %zd", host->i_ino, |
---|
425 | 411 | dentry, size); |
---|
426 | 412 | |
---|
| 413 | + down_read(&host_ui->xattr_sem); |
---|
427 | 414 | len = host_ui->xattr_names + host_ui->xattr_cnt; |
---|
428 | | - if (!buffer) |
---|
| 415 | + if (!buffer) { |
---|
429 | 416 | /* |
---|
430 | 417 | * We should return the minimum buffer size which will fit a |
---|
431 | 418 | * null-terminated list of all the extended attribute names. |
---|
432 | 419 | */ |
---|
433 | | - return len; |
---|
| 420 | + err = len; |
---|
| 421 | + goto out_err; |
---|
| 422 | + } |
---|
434 | 423 | |
---|
435 | | - if (len > size) |
---|
436 | | - return -ERANGE; |
---|
| 424 | + if (len > size) { |
---|
| 425 | + err = -ERANGE; |
---|
| 426 | + goto out_err; |
---|
| 427 | + } |
---|
437 | 428 | |
---|
438 | 429 | lowest_xent_key(c, &key, host->i_ino); |
---|
439 | 430 | while (1) { |
---|
.. | .. |
---|
455 | 446 | pxent = xent; |
---|
456 | 447 | key_read(c, &xent->key, &key); |
---|
457 | 448 | } |
---|
458 | | - |
---|
459 | 449 | kfree(pxent); |
---|
| 450 | + up_read(&host_ui->xattr_sem); |
---|
| 451 | + |
---|
460 | 452 | if (err != -ENOENT) { |
---|
461 | 453 | ubifs_err(c, "cannot find next direntry, error %d", err); |
---|
462 | 454 | return err; |
---|
.. | .. |
---|
464 | 456 | |
---|
465 | 457 | ubifs_assert(c, written <= size); |
---|
466 | 458 | return written; |
---|
| 459 | + |
---|
| 460 | +out_err: |
---|
| 461 | + up_read(&host_ui->xattr_sem); |
---|
| 462 | + return err; |
---|
467 | 463 | } |
---|
468 | 464 | |
---|
469 | 465 | static int remove_xattr(struct ubifs_info *c, struct inode *host, |
---|
.. | .. |
---|
507 | 503 | return err; |
---|
508 | 504 | } |
---|
509 | 505 | |
---|
| 506 | +int ubifs_purge_xattrs(struct inode *host) |
---|
| 507 | +{ |
---|
| 508 | + union ubifs_key key; |
---|
| 509 | + struct ubifs_info *c = host->i_sb->s_fs_info; |
---|
| 510 | + struct ubifs_dent_node *xent, *pxent = NULL; |
---|
| 511 | + struct inode *xino; |
---|
| 512 | + struct fscrypt_name nm = {0}; |
---|
| 513 | + int err; |
---|
| 514 | + |
---|
| 515 | + if (ubifs_inode(host)->xattr_cnt <= ubifs_xattr_max_cnt(c)) |
---|
| 516 | + return 0; |
---|
| 517 | + |
---|
| 518 | + ubifs_warn(c, "inode %lu has too many xattrs, doing a non-atomic deletion", |
---|
| 519 | + host->i_ino); |
---|
| 520 | + |
---|
| 521 | + down_write(&ubifs_inode(host)->xattr_sem); |
---|
| 522 | + lowest_xent_key(c, &key, host->i_ino); |
---|
| 523 | + while (1) { |
---|
| 524 | + xent = ubifs_tnc_next_ent(c, &key, &nm); |
---|
| 525 | + if (IS_ERR(xent)) { |
---|
| 526 | + err = PTR_ERR(xent); |
---|
| 527 | + break; |
---|
| 528 | + } |
---|
| 529 | + |
---|
| 530 | + fname_name(&nm) = xent->name; |
---|
| 531 | + fname_len(&nm) = le16_to_cpu(xent->nlen); |
---|
| 532 | + |
---|
| 533 | + xino = ubifs_iget(c->vfs_sb, le64_to_cpu(xent->inum)); |
---|
| 534 | + if (IS_ERR(xino)) { |
---|
| 535 | + err = PTR_ERR(xino); |
---|
| 536 | + ubifs_err(c, "dead directory entry '%s', error %d", |
---|
| 537 | + xent->name, err); |
---|
| 538 | + ubifs_ro_mode(c, err); |
---|
| 539 | + kfree(pxent); |
---|
| 540 | + kfree(xent); |
---|
| 541 | + goto out_err; |
---|
| 542 | + } |
---|
| 543 | + |
---|
| 544 | + ubifs_assert(c, ubifs_inode(xino)->xattr); |
---|
| 545 | + |
---|
| 546 | + clear_nlink(xino); |
---|
| 547 | + err = remove_xattr(c, host, xino, &nm); |
---|
| 548 | + if (err) { |
---|
| 549 | + kfree(pxent); |
---|
| 550 | + kfree(xent); |
---|
| 551 | + iput(xino); |
---|
| 552 | + ubifs_err(c, "cannot remove xattr, error %d", err); |
---|
| 553 | + goto out_err; |
---|
| 554 | + } |
---|
| 555 | + |
---|
| 556 | + iput(xino); |
---|
| 557 | + |
---|
| 558 | + kfree(pxent); |
---|
| 559 | + pxent = xent; |
---|
| 560 | + key_read(c, &xent->key, &key); |
---|
| 561 | + } |
---|
| 562 | + kfree(pxent); |
---|
| 563 | + up_write(&ubifs_inode(host)->xattr_sem); |
---|
| 564 | + |
---|
| 565 | + if (err != -ENOENT) { |
---|
| 566 | + ubifs_err(c, "cannot find next direntry, error %d", err); |
---|
| 567 | + return err; |
---|
| 568 | + } |
---|
| 569 | + |
---|
| 570 | + return 0; |
---|
| 571 | + |
---|
| 572 | +out_err: |
---|
| 573 | + up_write(&ubifs_inode(host)->xattr_sem); |
---|
| 574 | + return err; |
---|
| 575 | +} |
---|
| 576 | + |
---|
510 | 577 | /** |
---|
511 | 578 | * ubifs_evict_xattr_inode - Evict an xattr inode. |
---|
512 | 579 | * @c: UBIFS file-system description object |
---|
.. | .. |
---|
547 | 614 | if (!xent) |
---|
548 | 615 | return -ENOMEM; |
---|
549 | 616 | |
---|
| 617 | + down_write(&ubifs_inode(host)->xattr_sem); |
---|
550 | 618 | xent_key_init(c, &key, host->i_ino, &nm); |
---|
551 | 619 | err = ubifs_tnc_lookup_nm(c, &key, xent, &nm); |
---|
552 | 620 | if (err) { |
---|
.. | .. |
---|
571 | 639 | iput(inode); |
---|
572 | 640 | |
---|
573 | 641 | out_free: |
---|
| 642 | + up_write(&ubifs_inode(host)->xattr_sem); |
---|
574 | 643 | kfree(xent); |
---|
575 | 644 | return err; |
---|
576 | 645 | } |
---|
.. | .. |
---|
624 | 693 | |
---|
625 | 694 | static int xattr_get(const struct xattr_handler *handler, |
---|
626 | 695 | struct dentry *dentry, struct inode *inode, |
---|
627 | | - const char *name, void *buffer, size_t size) |
---|
| 696 | + const char *name, void *buffer, size_t size, |
---|
| 697 | + int flags) |
---|
628 | 698 | { |
---|
629 | 699 | dbg_gen("xattr '%s', ino %lu ('%pd'), buf size %zd", name, |
---|
630 | 700 | inode->i_ino, dentry, size); |
---|