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