| .. | .. |
|---|
| 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); |
|---|