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