162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * This file is part of UBIFS.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2006-2008 Nokia Corporation.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Authors: Artem Bityutskiy (Битюцкий Артём)
862306a36Sopenharmony_ci *          Adrian Hunter
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/*
1262306a36Sopenharmony_ci * This file implements UBIFS extended attributes support.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * Extended attributes are implemented as regular inodes with attached data,
1562306a36Sopenharmony_ci * which limits extended attribute size to UBIFS block size (4KiB). Names of
1662306a36Sopenharmony_ci * extended attributes are described by extended attribute entries (xentries),
1762306a36Sopenharmony_ci * which are almost identical to directory entries, but have different key type.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * In other words, the situation with extended attributes is very similar to
2062306a36Sopenharmony_ci * directories. Indeed, any inode (but of course not xattr inodes) may have a
2162306a36Sopenharmony_ci * number of associated xentries, just like directory inodes have associated
2262306a36Sopenharmony_ci * directory entries. Extended attribute entries store the name of the extended
2362306a36Sopenharmony_ci * attribute, the host inode number, and the extended attribute inode number.
2462306a36Sopenharmony_ci * Similarly, direntries store the name, the parent and the target inode
2562306a36Sopenharmony_ci * numbers. Thus, most of the common UBIFS mechanisms may be re-used for
2662306a36Sopenharmony_ci * extended attributes.
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * The number of extended attributes is not limited, but there is Linux
2962306a36Sopenharmony_ci * limitation on the maximum possible size of the list of all extended
3062306a36Sopenharmony_ci * attributes associated with an inode (%XATTR_LIST_MAX), so UBIFS makes sure
3162306a36Sopenharmony_ci * the sum of all extended attribute names of the inode does not exceed that
3262306a36Sopenharmony_ci * limit.
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * Extended attributes are synchronous, which means they are written to the
3562306a36Sopenharmony_ci * flash media synchronously and there is no write-back for extended attribute
3662306a36Sopenharmony_ci * inodes. The extended attribute values are not stored in compressed form on
3762306a36Sopenharmony_ci * the media.
3862306a36Sopenharmony_ci *
3962306a36Sopenharmony_ci * Since extended attributes are represented by regular inodes, they are cached
4062306a36Sopenharmony_ci * in the VFS inode cache. The xentries are cached in the LNC cache (see
4162306a36Sopenharmony_ci * tnc.c).
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci * ACL support is not implemented.
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#include "ubifs.h"
4762306a36Sopenharmony_ci#include <linux/fs.h>
4862306a36Sopenharmony_ci#include <linux/slab.h>
4962306a36Sopenharmony_ci#include <linux/xattr.h>
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/*
5262306a36Sopenharmony_ci * Extended attribute type constants.
5362306a36Sopenharmony_ci *
5462306a36Sopenharmony_ci * USER_XATTR: user extended attribute ("user.*")
5562306a36Sopenharmony_ci * TRUSTED_XATTR: trusted extended attribute ("trusted.*)
5662306a36Sopenharmony_ci * SECURITY_XATTR: security extended attribute ("security.*")
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_cienum {
5962306a36Sopenharmony_ci	USER_XATTR,
6062306a36Sopenharmony_ci	TRUSTED_XATTR,
6162306a36Sopenharmony_ci	SECURITY_XATTR,
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic const struct inode_operations empty_iops;
6562306a36Sopenharmony_cistatic const struct file_operations empty_fops;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/**
6862306a36Sopenharmony_ci * create_xattr - create an extended attribute.
6962306a36Sopenharmony_ci * @c: UBIFS file-system description object
7062306a36Sopenharmony_ci * @host: host inode
7162306a36Sopenharmony_ci * @nm: extended attribute name
7262306a36Sopenharmony_ci * @value: extended attribute value
7362306a36Sopenharmony_ci * @size: size of extended attribute value
7462306a36Sopenharmony_ci *
7562306a36Sopenharmony_ci * This is a helper function which creates an extended attribute of name @nm
7662306a36Sopenharmony_ci * and value @value for inode @host. The host inode is also updated on flash
7762306a36Sopenharmony_ci * because the ctime and extended attribute accounting data changes. This
7862306a36Sopenharmony_ci * function returns zero in case of success and a negative error code in case
7962306a36Sopenharmony_ci * of failure.
8062306a36Sopenharmony_ci */
8162306a36Sopenharmony_cistatic int create_xattr(struct ubifs_info *c, struct inode *host,
8262306a36Sopenharmony_ci			const struct fscrypt_name *nm, const void *value, int size)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	int err, names_len;
8562306a36Sopenharmony_ci	struct inode *inode;
8662306a36Sopenharmony_ci	struct ubifs_inode *ui, *host_ui = ubifs_inode(host);
8762306a36Sopenharmony_ci	struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
8862306a36Sopenharmony_ci				.new_ino_d = ALIGN(size, 8), .dirtied_ino = 1,
8962306a36Sopenharmony_ci				.dirtied_ino_d = ALIGN(host_ui->data_len, 8) };
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	if (host_ui->xattr_cnt >= ubifs_xattr_max_cnt(c)) {
9262306a36Sopenharmony_ci		ubifs_err(c, "inode %lu already has too many xattrs (%d), cannot create more",
9362306a36Sopenharmony_ci			  host->i_ino, host_ui->xattr_cnt);
9462306a36Sopenharmony_ci		return -ENOSPC;
9562306a36Sopenharmony_ci	}
9662306a36Sopenharmony_ci	/*
9762306a36Sopenharmony_ci	 * Linux limits the maximum size of the extended attribute names list
9862306a36Sopenharmony_ci	 * to %XATTR_LIST_MAX. This means we should not allow creating more
9962306a36Sopenharmony_ci	 * extended attributes if the name list becomes larger. This limitation
10062306a36Sopenharmony_ci	 * is artificial for UBIFS, though.
10162306a36Sopenharmony_ci	 */
10262306a36Sopenharmony_ci	names_len = host_ui->xattr_names + host_ui->xattr_cnt + fname_len(nm) + 1;
10362306a36Sopenharmony_ci	if (names_len > XATTR_LIST_MAX) {
10462306a36Sopenharmony_ci		ubifs_err(c, "cannot add one more xattr name to inode %lu, total names length would become %d, max. is %d",
10562306a36Sopenharmony_ci			  host->i_ino, names_len, XATTR_LIST_MAX);
10662306a36Sopenharmony_ci		return -ENOSPC;
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	err = ubifs_budget_space(c, &req);
11062306a36Sopenharmony_ci	if (err)
11162306a36Sopenharmony_ci		return err;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	inode = ubifs_new_inode(c, host, S_IFREG | S_IRWXUGO, true);
11462306a36Sopenharmony_ci	if (IS_ERR(inode)) {
11562306a36Sopenharmony_ci		err = PTR_ERR(inode);
11662306a36Sopenharmony_ci		goto out_budg;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	/* Re-define all operations to be "nothing" */
12062306a36Sopenharmony_ci	inode->i_mapping->a_ops = &empty_aops;
12162306a36Sopenharmony_ci	inode->i_op = &empty_iops;
12262306a36Sopenharmony_ci	inode->i_fop = &empty_fops;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	inode->i_flags |= S_SYNC | S_NOATIME | S_NOCMTIME;
12562306a36Sopenharmony_ci	ui = ubifs_inode(inode);
12662306a36Sopenharmony_ci	ui->xattr = 1;
12762306a36Sopenharmony_ci	ui->flags |= UBIFS_XATTR_FL;
12862306a36Sopenharmony_ci	ui->data = kmemdup(value, size, GFP_NOFS);
12962306a36Sopenharmony_ci	if (!ui->data) {
13062306a36Sopenharmony_ci		err = -ENOMEM;
13162306a36Sopenharmony_ci		goto out_free;
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci	inode->i_size = ui->ui_size = size;
13462306a36Sopenharmony_ci	ui->data_len = size;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	mutex_lock(&host_ui->ui_mutex);
13762306a36Sopenharmony_ci	inode_set_ctime_current(host);
13862306a36Sopenharmony_ci	host_ui->xattr_cnt += 1;
13962306a36Sopenharmony_ci	host_ui->xattr_size += CALC_DENT_SIZE(fname_len(nm));
14062306a36Sopenharmony_ci	host_ui->xattr_size += CALC_XATTR_BYTES(size);
14162306a36Sopenharmony_ci	host_ui->xattr_names += fname_len(nm);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	/*
14462306a36Sopenharmony_ci	 * We handle UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT here because we
14562306a36Sopenharmony_ci	 * have to set the UBIFS_CRYPT_FL flag on the host inode.
14662306a36Sopenharmony_ci	 * To avoid multiple updates of the same inode in the same operation,
14762306a36Sopenharmony_ci	 * let's do it here.
14862306a36Sopenharmony_ci	 */
14962306a36Sopenharmony_ci	if (strcmp(fname_name(nm), UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) == 0)
15062306a36Sopenharmony_ci		host_ui->flags |= UBIFS_CRYPT_FL;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	err = ubifs_jnl_update(c, host, nm, inode, 0, 1);
15362306a36Sopenharmony_ci	if (err)
15462306a36Sopenharmony_ci		goto out_cancel;
15562306a36Sopenharmony_ci	ubifs_set_inode_flags(host);
15662306a36Sopenharmony_ci	mutex_unlock(&host_ui->ui_mutex);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	ubifs_release_budget(c, &req);
15962306a36Sopenharmony_ci	insert_inode_hash(inode);
16062306a36Sopenharmony_ci	iput(inode);
16162306a36Sopenharmony_ci	return 0;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ciout_cancel:
16462306a36Sopenharmony_ci	host_ui->xattr_cnt -= 1;
16562306a36Sopenharmony_ci	host_ui->xattr_size -= CALC_DENT_SIZE(fname_len(nm));
16662306a36Sopenharmony_ci	host_ui->xattr_size -= CALC_XATTR_BYTES(size);
16762306a36Sopenharmony_ci	host_ui->xattr_names -= fname_len(nm);
16862306a36Sopenharmony_ci	host_ui->flags &= ~UBIFS_CRYPT_FL;
16962306a36Sopenharmony_ci	mutex_unlock(&host_ui->ui_mutex);
17062306a36Sopenharmony_ciout_free:
17162306a36Sopenharmony_ci	make_bad_inode(inode);
17262306a36Sopenharmony_ci	iput(inode);
17362306a36Sopenharmony_ciout_budg:
17462306a36Sopenharmony_ci	ubifs_release_budget(c, &req);
17562306a36Sopenharmony_ci	return err;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci/**
17962306a36Sopenharmony_ci * change_xattr - change an extended attribute.
18062306a36Sopenharmony_ci * @c: UBIFS file-system description object
18162306a36Sopenharmony_ci * @host: host inode
18262306a36Sopenharmony_ci * @inode: extended attribute inode
18362306a36Sopenharmony_ci * @value: extended attribute value
18462306a36Sopenharmony_ci * @size: size of extended attribute value
18562306a36Sopenharmony_ci *
18662306a36Sopenharmony_ci * This helper function changes the value of extended attribute @inode with new
18762306a36Sopenharmony_ci * data from @value. Returns zero in case of success and a negative error code
18862306a36Sopenharmony_ci * in case of failure.
18962306a36Sopenharmony_ci */
19062306a36Sopenharmony_cistatic int change_xattr(struct ubifs_info *c, struct inode *host,
19162306a36Sopenharmony_ci			struct inode *inode, const void *value, int size)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	int err;
19462306a36Sopenharmony_ci	struct ubifs_inode *host_ui = ubifs_inode(host);
19562306a36Sopenharmony_ci	struct ubifs_inode *ui = ubifs_inode(inode);
19662306a36Sopenharmony_ci	void *buf = NULL;
19762306a36Sopenharmony_ci	int old_size;
19862306a36Sopenharmony_ci	struct ubifs_budget_req req = { .dirtied_ino = 2,
19962306a36Sopenharmony_ci		.dirtied_ino_d = ALIGN(size, 8) + ALIGN(host_ui->data_len, 8) };
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	ubifs_assert(c, ui->data_len == inode->i_size);
20262306a36Sopenharmony_ci	err = ubifs_budget_space(c, &req);
20362306a36Sopenharmony_ci	if (err)
20462306a36Sopenharmony_ci		return err;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	buf = kmemdup(value, size, GFP_NOFS);
20762306a36Sopenharmony_ci	if (!buf) {
20862306a36Sopenharmony_ci		err = -ENOMEM;
20962306a36Sopenharmony_ci		goto out_free;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci	kfree(ui->data);
21262306a36Sopenharmony_ci	ui->data = buf;
21362306a36Sopenharmony_ci	inode->i_size = ui->ui_size = size;
21462306a36Sopenharmony_ci	old_size = ui->data_len;
21562306a36Sopenharmony_ci	ui->data_len = size;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	mutex_lock(&host_ui->ui_mutex);
21862306a36Sopenharmony_ci	inode_set_ctime_current(host);
21962306a36Sopenharmony_ci	host_ui->xattr_size -= CALC_XATTR_BYTES(old_size);
22062306a36Sopenharmony_ci	host_ui->xattr_size += CALC_XATTR_BYTES(size);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	/*
22362306a36Sopenharmony_ci	 * It is important to write the host inode after the xattr inode
22462306a36Sopenharmony_ci	 * because if the host inode gets synchronized (via 'fsync()'), then
22562306a36Sopenharmony_ci	 * the extended attribute inode gets synchronized, because it goes
22662306a36Sopenharmony_ci	 * before the host inode in the write-buffer.
22762306a36Sopenharmony_ci	 */
22862306a36Sopenharmony_ci	err = ubifs_jnl_change_xattr(c, inode, host);
22962306a36Sopenharmony_ci	if (err)
23062306a36Sopenharmony_ci		goto out_cancel;
23162306a36Sopenharmony_ci	mutex_unlock(&host_ui->ui_mutex);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	ubifs_release_budget(c, &req);
23462306a36Sopenharmony_ci	return 0;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ciout_cancel:
23762306a36Sopenharmony_ci	host_ui->xattr_size -= CALC_XATTR_BYTES(size);
23862306a36Sopenharmony_ci	host_ui->xattr_size += CALC_XATTR_BYTES(old_size);
23962306a36Sopenharmony_ci	mutex_unlock(&host_ui->ui_mutex);
24062306a36Sopenharmony_ci	make_bad_inode(inode);
24162306a36Sopenharmony_ciout_free:
24262306a36Sopenharmony_ci	ubifs_release_budget(c, &req);
24362306a36Sopenharmony_ci	return err;
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic struct inode *iget_xattr(struct ubifs_info *c, ino_t inum)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	struct inode *inode;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	inode = ubifs_iget(c->vfs_sb, inum);
25162306a36Sopenharmony_ci	if (IS_ERR(inode)) {
25262306a36Sopenharmony_ci		ubifs_err(c, "dead extended attribute entry, error %d",
25362306a36Sopenharmony_ci			  (int)PTR_ERR(inode));
25462306a36Sopenharmony_ci		return inode;
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci	if (ubifs_inode(inode)->xattr)
25762306a36Sopenharmony_ci		return inode;
25862306a36Sopenharmony_ci	ubifs_err(c, "corrupt extended attribute entry");
25962306a36Sopenharmony_ci	iput(inode);
26062306a36Sopenharmony_ci	return ERR_PTR(-EINVAL);
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ciint ubifs_xattr_set(struct inode *host, const char *name, const void *value,
26462306a36Sopenharmony_ci		    size_t size, int flags, bool check_lock)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	struct inode *inode;
26762306a36Sopenharmony_ci	struct ubifs_info *c = host->i_sb->s_fs_info;
26862306a36Sopenharmony_ci	struct fscrypt_name nm = { .disk_name = FSTR_INIT((char *)name, strlen(name))};
26962306a36Sopenharmony_ci	struct ubifs_dent_node *xent;
27062306a36Sopenharmony_ci	union ubifs_key key;
27162306a36Sopenharmony_ci	int err;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	if (check_lock)
27462306a36Sopenharmony_ci		ubifs_assert(c, inode_is_locked(host));
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	if (size > UBIFS_MAX_INO_DATA)
27762306a36Sopenharmony_ci		return -ERANGE;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	if (fname_len(&nm) > UBIFS_MAX_NLEN)
28062306a36Sopenharmony_ci		return -ENAMETOOLONG;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
28362306a36Sopenharmony_ci	if (!xent)
28462306a36Sopenharmony_ci		return -ENOMEM;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	down_write(&ubifs_inode(host)->xattr_sem);
28762306a36Sopenharmony_ci	/*
28862306a36Sopenharmony_ci	 * The extended attribute entries are stored in LNC, so multiple
28962306a36Sopenharmony_ci	 * look-ups do not involve reading the flash.
29062306a36Sopenharmony_ci	 */
29162306a36Sopenharmony_ci	xent_key_init(c, &key, host->i_ino, &nm);
29262306a36Sopenharmony_ci	err = ubifs_tnc_lookup_nm(c, &key, xent, &nm);
29362306a36Sopenharmony_ci	if (err) {
29462306a36Sopenharmony_ci		if (err != -ENOENT)
29562306a36Sopenharmony_ci			goto out_free;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci		if (flags & XATTR_REPLACE)
29862306a36Sopenharmony_ci			/* We are asked not to create the xattr */
29962306a36Sopenharmony_ci			err = -ENODATA;
30062306a36Sopenharmony_ci		else
30162306a36Sopenharmony_ci			err = create_xattr(c, host, &nm, value, size);
30262306a36Sopenharmony_ci		goto out_free;
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	if (flags & XATTR_CREATE) {
30662306a36Sopenharmony_ci		/* We are asked not to replace the xattr */
30762306a36Sopenharmony_ci		err = -EEXIST;
30862306a36Sopenharmony_ci		goto out_free;
30962306a36Sopenharmony_ci	}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	inode = iget_xattr(c, le64_to_cpu(xent->inum));
31262306a36Sopenharmony_ci	if (IS_ERR(inode)) {
31362306a36Sopenharmony_ci		err = PTR_ERR(inode);
31462306a36Sopenharmony_ci		goto out_free;
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	err = change_xattr(c, host, inode, value, size);
31862306a36Sopenharmony_ci	iput(inode);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ciout_free:
32162306a36Sopenharmony_ci	up_write(&ubifs_inode(host)->xattr_sem);
32262306a36Sopenharmony_ci	kfree(xent);
32362306a36Sopenharmony_ci	return err;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cissize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf,
32762306a36Sopenharmony_ci			size_t size)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	struct inode *inode;
33062306a36Sopenharmony_ci	struct ubifs_info *c = host->i_sb->s_fs_info;
33162306a36Sopenharmony_ci	struct fscrypt_name nm = { .disk_name = FSTR_INIT((char *)name, strlen(name))};
33262306a36Sopenharmony_ci	struct ubifs_inode *ui;
33362306a36Sopenharmony_ci	struct ubifs_dent_node *xent;
33462306a36Sopenharmony_ci	union ubifs_key key;
33562306a36Sopenharmony_ci	int err;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	if (fname_len(&nm) > UBIFS_MAX_NLEN)
33862306a36Sopenharmony_ci		return -ENAMETOOLONG;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
34162306a36Sopenharmony_ci	if (!xent)
34262306a36Sopenharmony_ci		return -ENOMEM;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	down_read(&ubifs_inode(host)->xattr_sem);
34562306a36Sopenharmony_ci	xent_key_init(c, &key, host->i_ino, &nm);
34662306a36Sopenharmony_ci	err = ubifs_tnc_lookup_nm(c, &key, xent, &nm);
34762306a36Sopenharmony_ci	if (err) {
34862306a36Sopenharmony_ci		if (err == -ENOENT)
34962306a36Sopenharmony_ci			err = -ENODATA;
35062306a36Sopenharmony_ci		goto out_cleanup;
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	inode = iget_xattr(c, le64_to_cpu(xent->inum));
35462306a36Sopenharmony_ci	if (IS_ERR(inode)) {
35562306a36Sopenharmony_ci		err = PTR_ERR(inode);
35662306a36Sopenharmony_ci		goto out_cleanup;
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	ui = ubifs_inode(inode);
36062306a36Sopenharmony_ci	ubifs_assert(c, inode->i_size == ui->data_len);
36162306a36Sopenharmony_ci	ubifs_assert(c, ubifs_inode(host)->xattr_size > ui->data_len);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	if (buf) {
36462306a36Sopenharmony_ci		/* If @buf is %NULL we are supposed to return the length */
36562306a36Sopenharmony_ci		if (ui->data_len > size) {
36662306a36Sopenharmony_ci			err = -ERANGE;
36762306a36Sopenharmony_ci			goto out_iput;
36862306a36Sopenharmony_ci		}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci		memcpy(buf, ui->data, ui->data_len);
37162306a36Sopenharmony_ci	}
37262306a36Sopenharmony_ci	err = ui->data_len;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ciout_iput:
37562306a36Sopenharmony_ci	iput(inode);
37662306a36Sopenharmony_ciout_cleanup:
37762306a36Sopenharmony_ci	up_read(&ubifs_inode(host)->xattr_sem);
37862306a36Sopenharmony_ci	kfree(xent);
37962306a36Sopenharmony_ci	return err;
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic bool xattr_visible(const char *name)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	/* File encryption related xattrs are for internal use only */
38562306a36Sopenharmony_ci	if (strcmp(name, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) == 0)
38662306a36Sopenharmony_ci		return false;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	/* Show trusted namespace only for "power" users */
38962306a36Sopenharmony_ci	if (strncmp(name, XATTR_TRUSTED_PREFIX,
39062306a36Sopenharmony_ci		    XATTR_TRUSTED_PREFIX_LEN) == 0 && !capable(CAP_SYS_ADMIN))
39162306a36Sopenharmony_ci		return false;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	return true;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cissize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	union ubifs_key key;
39962306a36Sopenharmony_ci	struct inode *host = d_inode(dentry);
40062306a36Sopenharmony_ci	struct ubifs_info *c = host->i_sb->s_fs_info;
40162306a36Sopenharmony_ci	struct ubifs_inode *host_ui = ubifs_inode(host);
40262306a36Sopenharmony_ci	struct ubifs_dent_node *xent, *pxent = NULL;
40362306a36Sopenharmony_ci	int err, len, written = 0;
40462306a36Sopenharmony_ci	struct fscrypt_name nm = {0};
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	dbg_gen("ino %lu ('%pd'), buffer size %zd", host->i_ino,
40762306a36Sopenharmony_ci		dentry, size);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	down_read(&host_ui->xattr_sem);
41062306a36Sopenharmony_ci	len = host_ui->xattr_names + host_ui->xattr_cnt;
41162306a36Sopenharmony_ci	if (!buffer) {
41262306a36Sopenharmony_ci		/*
41362306a36Sopenharmony_ci		 * We should return the minimum buffer size which will fit a
41462306a36Sopenharmony_ci		 * null-terminated list of all the extended attribute names.
41562306a36Sopenharmony_ci		 */
41662306a36Sopenharmony_ci		err = len;
41762306a36Sopenharmony_ci		goto out_err;
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	if (len > size) {
42162306a36Sopenharmony_ci		err = -ERANGE;
42262306a36Sopenharmony_ci		goto out_err;
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	lowest_xent_key(c, &key, host->i_ino);
42662306a36Sopenharmony_ci	while (1) {
42762306a36Sopenharmony_ci		xent = ubifs_tnc_next_ent(c, &key, &nm);
42862306a36Sopenharmony_ci		if (IS_ERR(xent)) {
42962306a36Sopenharmony_ci			err = PTR_ERR(xent);
43062306a36Sopenharmony_ci			break;
43162306a36Sopenharmony_ci		}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci		fname_name(&nm) = xent->name;
43462306a36Sopenharmony_ci		fname_len(&nm) = le16_to_cpu(xent->nlen);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci		if (xattr_visible(xent->name)) {
43762306a36Sopenharmony_ci			memcpy(buffer + written, fname_name(&nm), fname_len(&nm) + 1);
43862306a36Sopenharmony_ci			written += fname_len(&nm) + 1;
43962306a36Sopenharmony_ci		}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci		kfree(pxent);
44262306a36Sopenharmony_ci		pxent = xent;
44362306a36Sopenharmony_ci		key_read(c, &xent->key, &key);
44462306a36Sopenharmony_ci	}
44562306a36Sopenharmony_ci	kfree(pxent);
44662306a36Sopenharmony_ci	up_read(&host_ui->xattr_sem);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	if (err != -ENOENT) {
44962306a36Sopenharmony_ci		ubifs_err(c, "cannot find next direntry, error %d", err);
45062306a36Sopenharmony_ci		return err;
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	ubifs_assert(c, written <= size);
45462306a36Sopenharmony_ci	return written;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ciout_err:
45762306a36Sopenharmony_ci	up_read(&host_ui->xattr_sem);
45862306a36Sopenharmony_ci	return err;
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic int remove_xattr(struct ubifs_info *c, struct inode *host,
46262306a36Sopenharmony_ci			struct inode *inode, const struct fscrypt_name *nm)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	int err;
46562306a36Sopenharmony_ci	struct ubifs_inode *host_ui = ubifs_inode(host);
46662306a36Sopenharmony_ci	struct ubifs_inode *ui = ubifs_inode(inode);
46762306a36Sopenharmony_ci	struct ubifs_budget_req req = { .dirtied_ino = 2, .mod_dent = 1,
46862306a36Sopenharmony_ci				.dirtied_ino_d = ALIGN(host_ui->data_len, 8) };
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	ubifs_assert(c, ui->data_len == inode->i_size);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	err = ubifs_budget_space(c, &req);
47362306a36Sopenharmony_ci	if (err)
47462306a36Sopenharmony_ci		return err;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	mutex_lock(&host_ui->ui_mutex);
47762306a36Sopenharmony_ci	inode_set_ctime_current(host);
47862306a36Sopenharmony_ci	host_ui->xattr_cnt -= 1;
47962306a36Sopenharmony_ci	host_ui->xattr_size -= CALC_DENT_SIZE(fname_len(nm));
48062306a36Sopenharmony_ci	host_ui->xattr_size -= CALC_XATTR_BYTES(ui->data_len);
48162306a36Sopenharmony_ci	host_ui->xattr_names -= fname_len(nm);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	err = ubifs_jnl_delete_xattr(c, host, inode, nm);
48462306a36Sopenharmony_ci	if (err)
48562306a36Sopenharmony_ci		goto out_cancel;
48662306a36Sopenharmony_ci	mutex_unlock(&host_ui->ui_mutex);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	ubifs_release_budget(c, &req);
48962306a36Sopenharmony_ci	return 0;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ciout_cancel:
49262306a36Sopenharmony_ci	host_ui->xattr_cnt += 1;
49362306a36Sopenharmony_ci	host_ui->xattr_size += CALC_DENT_SIZE(fname_len(nm));
49462306a36Sopenharmony_ci	host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len);
49562306a36Sopenharmony_ci	host_ui->xattr_names += fname_len(nm);
49662306a36Sopenharmony_ci	mutex_unlock(&host_ui->ui_mutex);
49762306a36Sopenharmony_ci	ubifs_release_budget(c, &req);
49862306a36Sopenharmony_ci	make_bad_inode(inode);
49962306a36Sopenharmony_ci	return err;
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ciint ubifs_purge_xattrs(struct inode *host)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	union ubifs_key key;
50562306a36Sopenharmony_ci	struct ubifs_info *c = host->i_sb->s_fs_info;
50662306a36Sopenharmony_ci	struct ubifs_dent_node *xent, *pxent = NULL;
50762306a36Sopenharmony_ci	struct inode *xino;
50862306a36Sopenharmony_ci	struct fscrypt_name nm = {0};
50962306a36Sopenharmony_ci	int err;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	if (ubifs_inode(host)->xattr_cnt <= ubifs_xattr_max_cnt(c))
51262306a36Sopenharmony_ci		return 0;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	ubifs_warn(c, "inode %lu has too many xattrs, doing a non-atomic deletion",
51562306a36Sopenharmony_ci		   host->i_ino);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	down_write(&ubifs_inode(host)->xattr_sem);
51862306a36Sopenharmony_ci	lowest_xent_key(c, &key, host->i_ino);
51962306a36Sopenharmony_ci	while (1) {
52062306a36Sopenharmony_ci		xent = ubifs_tnc_next_ent(c, &key, &nm);
52162306a36Sopenharmony_ci		if (IS_ERR(xent)) {
52262306a36Sopenharmony_ci			err = PTR_ERR(xent);
52362306a36Sopenharmony_ci			break;
52462306a36Sopenharmony_ci		}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci		fname_name(&nm) = xent->name;
52762306a36Sopenharmony_ci		fname_len(&nm) = le16_to_cpu(xent->nlen);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci		xino = ubifs_iget(c->vfs_sb, le64_to_cpu(xent->inum));
53062306a36Sopenharmony_ci		if (IS_ERR(xino)) {
53162306a36Sopenharmony_ci			err = PTR_ERR(xino);
53262306a36Sopenharmony_ci			ubifs_err(c, "dead directory entry '%s', error %d",
53362306a36Sopenharmony_ci				  xent->name, err);
53462306a36Sopenharmony_ci			ubifs_ro_mode(c, err);
53562306a36Sopenharmony_ci			kfree(pxent);
53662306a36Sopenharmony_ci			kfree(xent);
53762306a36Sopenharmony_ci			goto out_err;
53862306a36Sopenharmony_ci		}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci		ubifs_assert(c, ubifs_inode(xino)->xattr);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci		clear_nlink(xino);
54362306a36Sopenharmony_ci		err = remove_xattr(c, host, xino, &nm);
54462306a36Sopenharmony_ci		if (err) {
54562306a36Sopenharmony_ci			kfree(pxent);
54662306a36Sopenharmony_ci			kfree(xent);
54762306a36Sopenharmony_ci			iput(xino);
54862306a36Sopenharmony_ci			ubifs_err(c, "cannot remove xattr, error %d", err);
54962306a36Sopenharmony_ci			goto out_err;
55062306a36Sopenharmony_ci		}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci		iput(xino);
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci		kfree(pxent);
55562306a36Sopenharmony_ci		pxent = xent;
55662306a36Sopenharmony_ci		key_read(c, &xent->key, &key);
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci	kfree(pxent);
55962306a36Sopenharmony_ci	up_write(&ubifs_inode(host)->xattr_sem);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	if (err != -ENOENT) {
56262306a36Sopenharmony_ci		ubifs_err(c, "cannot find next direntry, error %d", err);
56362306a36Sopenharmony_ci		return err;
56462306a36Sopenharmony_ci	}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	return 0;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ciout_err:
56962306a36Sopenharmony_ci	up_write(&ubifs_inode(host)->xattr_sem);
57062306a36Sopenharmony_ci	return err;
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci/**
57462306a36Sopenharmony_ci * ubifs_evict_xattr_inode - Evict an xattr inode.
57562306a36Sopenharmony_ci * @c: UBIFS file-system description object
57662306a36Sopenharmony_ci * @xattr_inum: xattr inode number
57762306a36Sopenharmony_ci *
57862306a36Sopenharmony_ci * When an inode that hosts xattrs is being removed we have to make sure
57962306a36Sopenharmony_ci * that cached inodes of the xattrs also get removed from the inode cache
58062306a36Sopenharmony_ci * otherwise we'd waste memory. This function looks up an inode from the
58162306a36Sopenharmony_ci * inode cache and clears the link counter such that iput() will evict
58262306a36Sopenharmony_ci * the inode.
58362306a36Sopenharmony_ci */
58462306a36Sopenharmony_civoid ubifs_evict_xattr_inode(struct ubifs_info *c, ino_t xattr_inum)
58562306a36Sopenharmony_ci{
58662306a36Sopenharmony_ci	struct inode *inode;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	inode = ilookup(c->vfs_sb, xattr_inum);
58962306a36Sopenharmony_ci	if (inode) {
59062306a36Sopenharmony_ci		clear_nlink(inode);
59162306a36Sopenharmony_ci		iput(inode);
59262306a36Sopenharmony_ci	}
59362306a36Sopenharmony_ci}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_cistatic int ubifs_xattr_remove(struct inode *host, const char *name)
59662306a36Sopenharmony_ci{
59762306a36Sopenharmony_ci	struct inode *inode;
59862306a36Sopenharmony_ci	struct ubifs_info *c = host->i_sb->s_fs_info;
59962306a36Sopenharmony_ci	struct fscrypt_name nm = { .disk_name = FSTR_INIT((char *)name, strlen(name))};
60062306a36Sopenharmony_ci	struct ubifs_dent_node *xent;
60162306a36Sopenharmony_ci	union ubifs_key key;
60262306a36Sopenharmony_ci	int err;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	ubifs_assert(c, inode_is_locked(host));
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	if (fname_len(&nm) > UBIFS_MAX_NLEN)
60762306a36Sopenharmony_ci		return -ENAMETOOLONG;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
61062306a36Sopenharmony_ci	if (!xent)
61162306a36Sopenharmony_ci		return -ENOMEM;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	down_write(&ubifs_inode(host)->xattr_sem);
61462306a36Sopenharmony_ci	xent_key_init(c, &key, host->i_ino, &nm);
61562306a36Sopenharmony_ci	err = ubifs_tnc_lookup_nm(c, &key, xent, &nm);
61662306a36Sopenharmony_ci	if (err) {
61762306a36Sopenharmony_ci		if (err == -ENOENT)
61862306a36Sopenharmony_ci			err = -ENODATA;
61962306a36Sopenharmony_ci		goto out_free;
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	inode = iget_xattr(c, le64_to_cpu(xent->inum));
62362306a36Sopenharmony_ci	if (IS_ERR(inode)) {
62462306a36Sopenharmony_ci		err = PTR_ERR(inode);
62562306a36Sopenharmony_ci		goto out_free;
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	ubifs_assert(c, inode->i_nlink == 1);
62962306a36Sopenharmony_ci	clear_nlink(inode);
63062306a36Sopenharmony_ci	err = remove_xattr(c, host, inode, &nm);
63162306a36Sopenharmony_ci	if (err)
63262306a36Sopenharmony_ci		set_nlink(inode, 1);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	/* If @i_nlink is 0, 'iput()' will delete the inode */
63562306a36Sopenharmony_ci	iput(inode);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ciout_free:
63862306a36Sopenharmony_ci	up_write(&ubifs_inode(host)->xattr_sem);
63962306a36Sopenharmony_ci	kfree(xent);
64062306a36Sopenharmony_ci	return err;
64162306a36Sopenharmony_ci}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci#ifdef CONFIG_UBIFS_FS_SECURITY
64462306a36Sopenharmony_cistatic int init_xattrs(struct inode *inode, const struct xattr *xattr_array,
64562306a36Sopenharmony_ci		      void *fs_info)
64662306a36Sopenharmony_ci{
64762306a36Sopenharmony_ci	const struct xattr *xattr;
64862306a36Sopenharmony_ci	char *name;
64962306a36Sopenharmony_ci	int err = 0;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
65262306a36Sopenharmony_ci		name = kmalloc(XATTR_SECURITY_PREFIX_LEN +
65362306a36Sopenharmony_ci			       strlen(xattr->name) + 1, GFP_NOFS);
65462306a36Sopenharmony_ci		if (!name) {
65562306a36Sopenharmony_ci			err = -ENOMEM;
65662306a36Sopenharmony_ci			break;
65762306a36Sopenharmony_ci		}
65862306a36Sopenharmony_ci		strcpy(name, XATTR_SECURITY_PREFIX);
65962306a36Sopenharmony_ci		strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name);
66062306a36Sopenharmony_ci		/*
66162306a36Sopenharmony_ci		 * creating a new inode without holding the inode rwsem,
66262306a36Sopenharmony_ci		 * no need to check whether inode is locked.
66362306a36Sopenharmony_ci		 */
66462306a36Sopenharmony_ci		err = ubifs_xattr_set(inode, name, xattr->value,
66562306a36Sopenharmony_ci				      xattr->value_len, 0, false);
66662306a36Sopenharmony_ci		kfree(name);
66762306a36Sopenharmony_ci		if (err < 0)
66862306a36Sopenharmony_ci			break;
66962306a36Sopenharmony_ci	}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	return err;
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ciint ubifs_init_security(struct inode *dentry, struct inode *inode,
67562306a36Sopenharmony_ci			const struct qstr *qstr)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	int err;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	err = security_inode_init_security(inode, dentry, qstr,
68062306a36Sopenharmony_ci					   &init_xattrs, NULL);
68162306a36Sopenharmony_ci	if (err) {
68262306a36Sopenharmony_ci		struct ubifs_info *c = dentry->i_sb->s_fs_info;
68362306a36Sopenharmony_ci		ubifs_err(c, "cannot initialize security for inode %lu, error %d",
68462306a36Sopenharmony_ci			  inode->i_ino, err);
68562306a36Sopenharmony_ci	}
68662306a36Sopenharmony_ci	return err;
68762306a36Sopenharmony_ci}
68862306a36Sopenharmony_ci#endif
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_cistatic int xattr_get(const struct xattr_handler *handler,
69162306a36Sopenharmony_ci			   struct dentry *dentry, struct inode *inode,
69262306a36Sopenharmony_ci			   const char *name, void *buffer, size_t size)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	dbg_gen("xattr '%s', ino %lu ('%pd'), buf size %zd", name,
69562306a36Sopenharmony_ci		inode->i_ino, dentry, size);
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	name = xattr_full_name(handler, name);
69862306a36Sopenharmony_ci	return ubifs_xattr_get(inode, name, buffer, size);
69962306a36Sopenharmony_ci}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_cistatic int xattr_set(const struct xattr_handler *handler,
70262306a36Sopenharmony_ci			   struct mnt_idmap *idmap,
70362306a36Sopenharmony_ci			   struct dentry *dentry, struct inode *inode,
70462306a36Sopenharmony_ci			   const char *name, const void *value,
70562306a36Sopenharmony_ci			   size_t size, int flags)
70662306a36Sopenharmony_ci{
70762306a36Sopenharmony_ci	dbg_gen("xattr '%s', host ino %lu ('%pd'), size %zd",
70862306a36Sopenharmony_ci		name, inode->i_ino, dentry, size);
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	name = xattr_full_name(handler, name);
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	if (value)
71362306a36Sopenharmony_ci		return ubifs_xattr_set(inode, name, value, size, flags, true);
71462306a36Sopenharmony_ci	else
71562306a36Sopenharmony_ci		return ubifs_xattr_remove(inode, name);
71662306a36Sopenharmony_ci}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_cistatic const struct xattr_handler ubifs_user_xattr_handler = {
71962306a36Sopenharmony_ci	.prefix = XATTR_USER_PREFIX,
72062306a36Sopenharmony_ci	.get = xattr_get,
72162306a36Sopenharmony_ci	.set = xattr_set,
72262306a36Sopenharmony_ci};
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_cistatic const struct xattr_handler ubifs_trusted_xattr_handler = {
72562306a36Sopenharmony_ci	.prefix = XATTR_TRUSTED_PREFIX,
72662306a36Sopenharmony_ci	.get = xattr_get,
72762306a36Sopenharmony_ci	.set = xattr_set,
72862306a36Sopenharmony_ci};
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci#ifdef CONFIG_UBIFS_FS_SECURITY
73162306a36Sopenharmony_cistatic const struct xattr_handler ubifs_security_xattr_handler = {
73262306a36Sopenharmony_ci	.prefix = XATTR_SECURITY_PREFIX,
73362306a36Sopenharmony_ci	.get = xattr_get,
73462306a36Sopenharmony_ci	.set = xattr_set,
73562306a36Sopenharmony_ci};
73662306a36Sopenharmony_ci#endif
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ciconst struct xattr_handler *ubifs_xattr_handlers[] = {
73962306a36Sopenharmony_ci	&ubifs_user_xattr_handler,
74062306a36Sopenharmony_ci	&ubifs_trusted_xattr_handler,
74162306a36Sopenharmony_ci#ifdef CONFIG_UBIFS_FS_SECURITY
74262306a36Sopenharmony_ci	&ubifs_security_xattr_handler,
74362306a36Sopenharmony_ci#endif
74462306a36Sopenharmony_ci	NULL
74562306a36Sopenharmony_ci};
746