// SPDX-License-Identifier: GPL-2.0-only /* * This file is part of UBIFS. * * Copyright (C) 2006-2008 Nokia Corporation. * * Authors: Artem Bityutskiy (Битюцкий Артём) * Adrian Hunter
*/
/* * This file implements UBIFS extended attributes support. * * Extended attributes are implemented as regular inodes with attached data, * which limits extended attribute size to UBIFS block size (4KiB). Names of * extended attributes are described by extended attribute entries (xentries), * which are almost identical to directory entries, but have different key type. * * In other words, the situation with extended attributes is very similar to * directories. Indeed, any inode (but of course not xattr inodes) may have a * number of associated xentries, just like directory inodes have associated * directory entries. Extended attribute entries store the name of the extended * attribute, the host inode number, and the extended attribute inode number. * Similarly, direntries store the name, the parent and the target inode * numbers. Thus, most of the common UBIFS mechanisms may be re-used for * extended attributes. * * The number of extended attributes is not limited, but there is Linux * limitation on the maximum possible size of the list of all extended * attributes associated with an inode (%XATTR_LIST_MAX), so UBIFS makes sure * the sum of all extended attribute names of the inode does not exceed that * limit. * * Extended attributes are synchronous, which means they are written to the * flash media synchronously and there is no write-back for extended attribute * inodes. The extended attribute values are not stored in compressed form on * the media. * * Since extended attributes are represented by regular inodes, they are cached * in the VFS inode cache. The xentries are cached in the LNC cache (see * tnc.c). * * ACL support is not implemented.
*/
/** * create_xattr - create an extended attribute. * @c: UBIFS file-system description object * @host: host inode * @nm: extended attribute name * @value: extended attribute value * @size: size of extended attribute value * * This is a helper function which creates an extended attribute of name @nm * and value @value for inode @host. The host inode is also updated on flash * because the ctime and extended attribute accounting data changes. This * function returns zero in case of success and a negative error code in case * of failure.
*/ staticint create_xattr(struct ubifs_info *c, struct inode *host, conststruct fscrypt_name *nm, constvoid *value, int size)
{ int err, names_len; struct inode *inode; struct ubifs_inode *ui, *host_ui = ubifs_inode(host); struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
.new_ino_d = ALIGN(size, 8), .dirtied_ino = 1,
.dirtied_ino_d = ALIGN(host_ui->data_len, 8) };
if (host_ui->xattr_cnt >= ubifs_xattr_max_cnt(c)) {
ubifs_err(c, "inode %lu already has too many xattrs (%d), cannot create more",
host->i_ino, host_ui->xattr_cnt); return -ENOSPC;
} /* * Linux limits the maximum size of the extended attribute names list * to %XATTR_LIST_MAX. This means we should not allow creating more * extended attributes if the name list becomes larger. This limitation * is artificial for UBIFS, though.
*/
names_len = host_ui->xattr_names + host_ui->xattr_cnt + fname_len(nm) + 1; if (names_len > XATTR_LIST_MAX) {
ubifs_err(c, "cannot add one more xattr name to inode %lu, total names length would become %d, max. is %d",
host->i_ino, names_len, XATTR_LIST_MAX); return -ENOSPC;
}
err = ubifs_budget_space(c, &req); if (err) return err;
/* * We handle UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT here because we * have to set the UBIFS_CRYPT_FL flag on the host inode. * To avoid multiple updates of the same inode in the same operation, * let's do it here.
*/ if (strcmp(fname_name(nm), UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) == 0)
host_ui->flags |= UBIFS_CRYPT_FL;
/** * change_xattr - change an extended attribute. * @c: UBIFS file-system description object * @host: host inode * @inode: extended attribute inode * @value: extended attribute value * @size: size of extended attribute value * * This helper function changes the value of extended attribute @inode with new * data from @value. Returns zero in case of success and a negative error code * in case of failure.
*/ staticint change_xattr(struct ubifs_info *c, struct inode *host, struct inode *inode, constvoid *value, int size)
{ int err; struct ubifs_inode *host_ui = ubifs_inode(host); struct ubifs_inode *ui = ubifs_inode(inode); void *buf = NULL; int old_size; struct ubifs_budget_req req = { .dirtied_ino = 2,
.dirtied_ino_d = ALIGN(size, 8) + ALIGN(host_ui->data_len, 8) };
/* * It is important to write the host inode after the xattr inode * because if the host inode gets synchronized (via 'fsync()'), then * the extended attribute inode gets synchronized, because it goes * before the host inode in the write-buffer.
*/
err = ubifs_jnl_change_xattr(c, inode, host); if (err) goto out_cancel;
mutex_unlock(&host_ui->ui_mutex);
if (check_lock)
ubifs_assert(c, inode_is_locked(host));
if (size > UBIFS_MAX_INO_DATA) return -ERANGE;
if (fname_len(&nm) > UBIFS_MAX_NLEN) return -ENAMETOOLONG;
xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS); if (!xent) return -ENOMEM;
down_write(&ubifs_inode(host)->xattr_sem); /* * The extended attribute entries are stored in LNC, so multiple * look-ups do not involve reading the flash.
*/
xent_key_init(c, &key, host->i_ino, &nm);
err = ubifs_tnc_lookup_nm(c, &key, xent, &nm); if (err) { if (err != -ENOENT) goto out_free;
if (flags & XATTR_REPLACE) /* We are asked not to create the xattr */
err = -ENODATA; else
err = create_xattr(c, host, &nm, value, size); goto out_free;
}
if (flags & XATTR_CREATE) { /* We are asked not to replace the xattr */
err = -EEXIST; goto out_free;
}
staticbool xattr_visible(constchar *name)
{ /* File encryption related xattrs are for internal use only */ if (strcmp(name, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) == 0) returnfalse;
/* Show trusted namespace only for "power" users */ if (strncmp(name, XATTR_TRUSTED_PREFIX,
XATTR_TRUSTED_PREFIX_LEN) == 0 && !capable(CAP_SYS_ADMIN)) returnfalse;
down_read(&host_ui->xattr_sem);
len = host_ui->xattr_names + host_ui->xattr_cnt; if (!buffer) { /* * We should return the minimum buffer size which will fit a * null-terminated list of all the extended attribute names.
*/
err = len; goto out_err;
}
if (len > size) {
err = -ERANGE; goto out_err;
}
lowest_xent_key(c, &key, host->i_ino); while (1) {
xent = ubifs_tnc_next_ent(c, &key, &nm); if (IS_ERR(xent)) {
err = PTR_ERR(xent); break;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.