mirror of
https://github.com/torvalds/linux.git
synced 2024-12-25 12:21:37 +00:00
This pull request contains the following changes for UBI/UBIFS
- fscrypt framework usage updates - One huge fix for xattr unlink - Cleanup of fscrypt ifdefs - Fix for our new UBIFS auth feature -----BEGIN PGP SIGNATURE----- iQJKBAABCAA0FiEEdgfidid8lnn52cLTZvlZhesYu8EFAlzYkIgWHHJpY2hhcmRA c2lnbWEtc3Rhci5hdAAKCRBm+VmF6xi7wTRrD/99iBd4f8F0jF1wmB8/9kDAnz5s KaK+VtC0RVRijRijYzo+/2kDXpXEbmPycg6AVl5EfKxXCVFw1K7pQvuBX43qyv4o BINRv1av8FEBA9eTjvBgZJUrjB1AuvV37716/OeM2bnvuCsp1escnvTEh6S3VFYw oWDBgZJd+DE10CYtZjuLoyDPcYdNrzebbmu3Xbfl2XsPwZFUJIrymMd6NE8Xdk3I EQbZ3guEM5Djui+nrko3iKzfoZ4eK7WguO3DOEjUHpwea4ZfnZtnlH345aYOAqRE N5qrDCzXOsWs6Zs+clODMQgg+aTN3kGBNV534culcpMAbUp7WXynUQ1DDqtOJNJO pGFjhAfGi4E6YgB3UwqxMbXxI4Tg/X2ckc77hWZlC7h/1Y/i89nacT6Ij5rPNOn1 mby1mFxWHI04uSEICWyocFK4m/J2b17Tmte2Mc5ZOigQqREUB7J8wiT4NWm6GhV1 nTb5DA8MepC3zopbsL/iAiKPhSkH1h6AkabBw1ADTksacgNUfhjzALkxqa64tIqv C43QG3n/HqsNZJ4aLdizLLb8KIt4pWsIaqHOeDGSfr3I1GEBrpfKiR72P/h3fSF9 9GIFJU5HiV+3zeAC2024muaV7KjcimZ6t/hPFTCFH9pMGNk2Mtn/gZFfmqnjLKbj TDxUTrZF9Lujonrbwg== =ymCJ -----END PGP SIGNATURE----- Merge tag 'upstream-5.2-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/rw/ubifs Pull UBI/UBIFS updates from Richard Weinberger: - fscrypt framework usage updates - One huge fix for xattr unlink - Cleanup of fscrypt ifdefs - Fix for our new UBIFS auth feature * tag 'upstream-5.2-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/rw/ubifs: ubi: wl: Fix uninitialized variable ubifs: Drop unnecessary setting of zbr->znode ubifs: Remove ifdefs around CONFIG_UBIFS_ATIME_SUPPORT ubifs: Remove #ifdef around CONFIG_FS_ENCRYPTION ubifs: Limit number of xattrs per inode ubifs: orphan: Handle xattrs like files ubifs: journal: Handle xattrs like files ubifs: find.c: replace swap function with built-in one ubifs: Do not skip hash checking in data nodes ubifs: work around high stack usage with clang ubifs: remove unused function __ubifs_shash_final ubifs: remove unnecessary #ifdef around fscrypt_ioctl_get_policy() ubifs: remove unnecessary calls to set up directory key
This commit is contained in:
commit
d7a02fa0a8
@ -1475,7 +1475,7 @@ static bool scrub_possible(struct ubi_device *ubi, struct ubi_wl_entry *e)
|
||||
*/
|
||||
int ubi_bitflip_check(struct ubi_device *ubi, int pnum, int force)
|
||||
{
|
||||
int err;
|
||||
int err = 0;
|
||||
struct ubi_wl_entry *e;
|
||||
|
||||
if (pnum < 0 || pnum >= ubi->peb_count) {
|
||||
|
@ -76,7 +76,6 @@ static int ubifs_hash_calc_hmac(const struct ubifs_info *c, const u8 *hash,
|
||||
int ubifs_prepare_auth_node(struct ubifs_info *c, void *node,
|
||||
struct shash_desc *inhash)
|
||||
{
|
||||
SHASH_DESC_ON_STACK(hash_desc, c->hash_tfm);
|
||||
struct ubifs_auth_node *auth = node;
|
||||
u8 *hash;
|
||||
int err;
|
||||
@ -85,12 +84,16 @@ int ubifs_prepare_auth_node(struct ubifs_info *c, void *node,
|
||||
if (!hash)
|
||||
return -ENOMEM;
|
||||
|
||||
hash_desc->tfm = c->hash_tfm;
|
||||
ubifs_shash_copy_state(c, inhash, hash_desc);
|
||||
{
|
||||
SHASH_DESC_ON_STACK(hash_desc, c->hash_tfm);
|
||||
|
||||
err = crypto_shash_final(hash_desc, hash);
|
||||
if (err)
|
||||
goto out;
|
||||
hash_desc->tfm = c->hash_tfm;
|
||||
ubifs_shash_copy_state(c, inhash, hash_desc);
|
||||
|
||||
err = crypto_shash_final(hash_desc, hash);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = ubifs_hash_calc_hmac(c, hash, auth->hmac);
|
||||
if (err)
|
||||
@ -142,24 +145,6 @@ struct shash_desc *__ubifs_hash_get_desc(const struct ubifs_info *c)
|
||||
return ubifs_get_desc(c, c->hash_tfm);
|
||||
}
|
||||
|
||||
/**
|
||||
* __ubifs_shash_final - finalize shash
|
||||
* @c: UBIFS file-system description object
|
||||
* @desc: the descriptor
|
||||
* @out: the output hash
|
||||
*
|
||||
* Simple wrapper around crypto_shash_final(), safe to be called with
|
||||
* disabled authentication.
|
||||
*/
|
||||
int __ubifs_shash_final(const struct ubifs_info *c, struct shash_desc *desc,
|
||||
u8 *out)
|
||||
{
|
||||
if (ubifs_authenticated(c))
|
||||
return crypto_shash_final(desc, out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_bad_hash - Report hash mismatches
|
||||
* @c: UBIFS file-system description object
|
||||
|
@ -1603,7 +1603,6 @@ int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb,
|
||||
err = PTR_ERR(child);
|
||||
goto out_unlock;
|
||||
}
|
||||
zbr->znode = child;
|
||||
}
|
||||
|
||||
znode = child;
|
||||
|
@ -790,16 +790,14 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
dentry, inode->i_ino,
|
||||
inode->i_nlink, dir->i_ino);
|
||||
|
||||
if (ubifs_crypt_is_encrypted(dir)) {
|
||||
err = fscrypt_get_encryption_info(dir);
|
||||
if (err && err != -ENOKEY)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = ubifs_purge_xattrs(inode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
sz_change = CALC_DENT_SIZE(fname_len(&nm));
|
||||
|
||||
ubifs_assert(c, inode_is_locked(dir));
|
||||
@ -900,16 +898,14 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (ubifs_crypt_is_encrypted(dir)) {
|
||||
err = fscrypt_get_encryption_info(dir);
|
||||
if (err && err != -ENOKEY)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = ubifs_purge_xattrs(inode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
sz_change = CALC_DENT_SIZE(fname_len(&nm));
|
||||
|
||||
err = ubifs_budget_space(c, &req);
|
||||
@ -1292,9 +1288,14 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
old_dentry, old_inode->i_ino, old_dir->i_ino,
|
||||
new_dentry, new_dir->i_ino, flags);
|
||||
|
||||
if (unlink)
|
||||
if (unlink) {
|
||||
ubifs_assert(c, inode_is_locked(new_inode));
|
||||
|
||||
err = ubifs_purge_xattrs(new_inode);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (unlink && is_dir) {
|
||||
err = ubifs_check_dir_empty(new_inode);
|
||||
if (err)
|
||||
@ -1650,9 +1651,7 @@ const struct inode_operations ubifs_dir_inode_operations = {
|
||||
#ifdef CONFIG_UBIFS_FS_XATTR
|
||||
.listxattr = ubifs_listxattr,
|
||||
#endif
|
||||
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
|
||||
.update_time = ubifs_update_time,
|
||||
#endif
|
||||
.tmpfile = ubifs_tmpfile,
|
||||
};
|
||||
|
||||
|
@ -1375,7 +1375,6 @@ static inline int mctime_update_needed(const struct inode *inode,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
|
||||
/**
|
||||
* ubifs_update_time - update time of inode.
|
||||
* @inode: inode to update
|
||||
@ -1392,6 +1391,9 @@ int ubifs_update_time(struct inode *inode, struct timespec64 *time,
|
||||
int iflags = I_DIRTY_TIME;
|
||||
int err, release;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT))
|
||||
return generic_update_time(inode, time, flags);
|
||||
|
||||
err = ubifs_budget_space(c, &req);
|
||||
if (err)
|
||||
return err;
|
||||
@ -1414,7 +1416,6 @@ int ubifs_update_time(struct inode *inode, struct timespec64 *time,
|
||||
ubifs_release_budget(c, &req);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* update_mctime - update mtime and ctime of an inode.
|
||||
@ -1623,9 +1624,10 @@ static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
if (err)
|
||||
return err;
|
||||
vma->vm_ops = &ubifs_file_vm_ops;
|
||||
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
|
||||
file_accessed(file);
|
||||
#endif
|
||||
|
||||
if (IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT))
|
||||
file_accessed(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1663,9 +1665,7 @@ const struct inode_operations ubifs_file_inode_operations = {
|
||||
#ifdef CONFIG_UBIFS_FS_XATTR
|
||||
.listxattr = ubifs_listxattr,
|
||||
#endif
|
||||
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
|
||||
.update_time = ubifs_update_time,
|
||||
#endif
|
||||
};
|
||||
|
||||
const struct inode_operations ubifs_symlink_inode_operations = {
|
||||
@ -1675,9 +1675,7 @@ const struct inode_operations ubifs_symlink_inode_operations = {
|
||||
#ifdef CONFIG_UBIFS_FS_XATTR
|
||||
.listxattr = ubifs_listxattr,
|
||||
#endif
|
||||
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
|
||||
.update_time = ubifs_update_time,
|
||||
#endif
|
||||
};
|
||||
|
||||
const struct file_operations ubifs_file_operations = {
|
||||
|
@ -747,12 +747,6 @@ static int cmp_dirty_idx(const struct ubifs_lprops **a,
|
||||
return lpa->dirty + lpa->free - lpb->dirty - lpb->free;
|
||||
}
|
||||
|
||||
static void swap_dirty_idx(struct ubifs_lprops **a, struct ubifs_lprops **b,
|
||||
int size)
|
||||
{
|
||||
swap(*a, *b);
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_save_dirty_idx_lnums - save an array of the most dirty index LEB nos.
|
||||
* @c: the UBIFS file-system description object
|
||||
@ -772,8 +766,7 @@ int ubifs_save_dirty_idx_lnums(struct ubifs_info *c)
|
||||
sizeof(void *) * c->dirty_idx.cnt);
|
||||
/* Sort it so that the dirtiest is now at the end */
|
||||
sort(c->dirty_idx.arr, c->dirty_idx.cnt, sizeof(void *),
|
||||
(int (*)(const void *, const void *))cmp_dirty_idx,
|
||||
(void (*)(void *, void *, int))swap_dirty_idx);
|
||||
(int (*)(const void *, const void *))cmp_dirty_idx, NULL);
|
||||
dbg_find("found %d dirty index LEBs", c->dirty_idx.cnt);
|
||||
if (c->dirty_idx.cnt)
|
||||
dbg_find("dirtiest index LEB is %d with dirty %d and free %d",
|
||||
|
@ -193,7 +193,6 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
return err;
|
||||
}
|
||||
case FS_IOC_SET_ENCRYPTION_POLICY: {
|
||||
#ifdef CONFIG_FS_ENCRYPTION
|
||||
struct ubifs_info *c = inode->i_sb->s_fs_info;
|
||||
|
||||
err = ubifs_enable_encryption(c);
|
||||
@ -201,17 +200,9 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
return err;
|
||||
|
||||
return fscrypt_ioctl_set_policy(file, (const void __user *)arg);
|
||||
#else
|
||||
return -EOPNOTSUPP;
|
||||
#endif
|
||||
}
|
||||
case FS_IOC_GET_ENCRYPTION_POLICY: {
|
||||
#ifdef CONFIG_FS_ENCRYPTION
|
||||
case FS_IOC_GET_ENCRYPTION_POLICY:
|
||||
return fscrypt_ioctl_get_policy(file, (void __user *)arg);
|
||||
#else
|
||||
return -EOPNOTSUPP;
|
||||
#endif
|
||||
}
|
||||
|
||||
default:
|
||||
return -ENOTTY;
|
||||
|
@ -852,10 +852,11 @@ out_free:
|
||||
int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
|
||||
{
|
||||
int err, lnum, offs;
|
||||
struct ubifs_ino_node *ino;
|
||||
struct ubifs_ino_node *ino, *ino_start;
|
||||
struct ubifs_inode *ui = ubifs_inode(inode);
|
||||
int sync = 0, write_len, ilen = UBIFS_INO_NODE_SZ;
|
||||
int sync = 0, write_len = 0, ilen = UBIFS_INO_NODE_SZ;
|
||||
int last_reference = !inode->i_nlink;
|
||||
int kill_xattrs = ui->xattr_cnt && last_reference;
|
||||
u8 hash[UBIFS_HASH_ARR_SZ];
|
||||
|
||||
dbg_jnl("ino %lu, nlink %u", inode->i_ino, inode->i_nlink);
|
||||
@ -867,14 +868,16 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
|
||||
if (!last_reference) {
|
||||
ilen += ui->data_len;
|
||||
sync = IS_SYNC(inode);
|
||||
} else if (kill_xattrs) {
|
||||
write_len += UBIFS_INO_NODE_SZ * ui->xattr_cnt;
|
||||
}
|
||||
|
||||
if (ubifs_authenticated(c))
|
||||
write_len = ALIGN(ilen, 8) + ubifs_auth_node_sz(c);
|
||||
write_len += ALIGN(ilen, 8) + ubifs_auth_node_sz(c);
|
||||
else
|
||||
write_len = ilen;
|
||||
write_len += ilen;
|
||||
|
||||
ino = kmalloc(write_len, GFP_NOFS);
|
||||
ino_start = ino = kmalloc(write_len, GFP_NOFS);
|
||||
if (!ino)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -883,12 +886,59 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
|
||||
if (err)
|
||||
goto out_free;
|
||||
|
||||
if (kill_xattrs) {
|
||||
union ubifs_key key;
|
||||
struct fscrypt_name nm = {0};
|
||||
struct inode *xino;
|
||||
struct ubifs_dent_node *xent, *pxent = NULL;
|
||||
|
||||
if (ui->xattr_cnt >= ubifs_xattr_max_cnt(c)) {
|
||||
ubifs_err(c, "Cannot delete inode, it has too much xattrs!");
|
||||
goto out_release;
|
||||
}
|
||||
|
||||
lowest_xent_key(c, &key, inode->i_ino);
|
||||
while (1) {
|
||||
xent = ubifs_tnc_next_ent(c, &key, &nm);
|
||||
if (IS_ERR(xent)) {
|
||||
err = PTR_ERR(xent);
|
||||
if (err == -ENOENT)
|
||||
break;
|
||||
|
||||
goto out_release;
|
||||
}
|
||||
|
||||
fname_name(&nm) = xent->name;
|
||||
fname_len(&nm) = le16_to_cpu(xent->nlen);
|
||||
|
||||
xino = ubifs_iget(c->vfs_sb, xent->inum);
|
||||
if (IS_ERR(xino)) {
|
||||
err = PTR_ERR(xino);
|
||||
ubifs_err(c, "dead directory entry '%s', error %d",
|
||||
xent->name, err);
|
||||
ubifs_ro_mode(c, err);
|
||||
goto out_release;
|
||||
}
|
||||
ubifs_assert(c, ubifs_inode(xino)->xattr);
|
||||
|
||||
clear_nlink(xino);
|
||||
pack_inode(c, ino, xino, 0);
|
||||
ino = (void *)ino + UBIFS_INO_NODE_SZ;
|
||||
iput(xino);
|
||||
|
||||
kfree(pxent);
|
||||
pxent = xent;
|
||||
key_read(c, &xent->key, &key);
|
||||
}
|
||||
kfree(pxent);
|
||||
}
|
||||
|
||||
pack_inode(c, ino, inode, 1);
|
||||
err = ubifs_node_calc_hash(c, ino, hash);
|
||||
if (err)
|
||||
goto out_release;
|
||||
|
||||
err = write_head(c, BASEHD, ino, write_len, &lnum, &offs, sync);
|
||||
err = write_head(c, BASEHD, ino_start, write_len, &lnum, &offs, sync);
|
||||
if (err)
|
||||
goto out_release;
|
||||
if (!sync)
|
||||
@ -903,7 +953,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
|
||||
if (err)
|
||||
goto out_ro;
|
||||
ubifs_delete_orphan(c, inode->i_ino);
|
||||
err = ubifs_add_dirt(c, lnum, ilen);
|
||||
err = ubifs_add_dirt(c, lnum, write_len);
|
||||
} else {
|
||||
union ubifs_key key;
|
||||
|
||||
@ -917,7 +967,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
|
||||
spin_lock(&ui->ui_lock);
|
||||
ui->synced_i_size = ui->ui_size;
|
||||
spin_unlock(&ui->ui_lock);
|
||||
kfree(ino);
|
||||
kfree(ino_start);
|
||||
return 0;
|
||||
|
||||
out_release:
|
||||
@ -926,7 +976,7 @@ out_ro:
|
||||
ubifs_ro_mode(c, err);
|
||||
finish_reservation(c);
|
||||
out_free:
|
||||
kfree(ino);
|
||||
kfree(ino_start);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -966,8 +1016,8 @@ int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode)
|
||||
|
||||
ubifs_assert(c, inode->i_nlink == 0);
|
||||
|
||||
if (ui->del_cmtno != c->cmt_no)
|
||||
/* A commit happened for sure */
|
||||
if (ui->xattr_cnt || ui->del_cmtno != c->cmt_no)
|
||||
/* A commit happened for sure or inode hosts xattrs */
|
||||
return ubifs_jnl_write_inode(c, inode);
|
||||
|
||||
down_read(&c->commit_sem);
|
||||
|
@ -288,6 +288,14 @@ static inline int ubifs_next_log_lnum(const struct ubifs_info *c, int lnum)
|
||||
return lnum;
|
||||
}
|
||||
|
||||
static inline int ubifs_xattr_max_cnt(struct ubifs_info *c)
|
||||
{
|
||||
int max_xattrs = (c->leb_size / 2) / UBIFS_INO_NODE_SZ;
|
||||
|
||||
ubifs_assert(c, max_xattrs < c->max_orphans);
|
||||
return max_xattrs;
|
||||
}
|
||||
|
||||
const char *ubifs_assert_action_name(struct ubifs_info *c);
|
||||
|
||||
#endif /* __UBIFS_MISC_H__ */
|
||||
|
@ -54,30 +54,24 @@
|
||||
|
||||
static int dbg_check_orphans(struct ubifs_info *c);
|
||||
|
||||
/**
|
||||
* ubifs_add_orphan - add an orphan.
|
||||
* @c: UBIFS file-system description object
|
||||
* @inum: orphan inode number
|
||||
*
|
||||
* Add an orphan. This function is called when an inodes link count drops to
|
||||
* zero.
|
||||
*/
|
||||
int ubifs_add_orphan(struct ubifs_info *c, ino_t inum)
|
||||
static struct ubifs_orphan *orphan_add(struct ubifs_info *c, ino_t inum,
|
||||
struct ubifs_orphan *parent_orphan)
|
||||
{
|
||||
struct ubifs_orphan *orphan, *o;
|
||||
struct rb_node **p, *parent = NULL;
|
||||
|
||||
orphan = kzalloc(sizeof(struct ubifs_orphan), GFP_NOFS);
|
||||
if (!orphan)
|
||||
return -ENOMEM;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
orphan->inum = inum;
|
||||
orphan->new = 1;
|
||||
INIT_LIST_HEAD(&orphan->child_list);
|
||||
|
||||
spin_lock(&c->orphan_lock);
|
||||
if (c->tot_orphans >= c->max_orphans) {
|
||||
spin_unlock(&c->orphan_lock);
|
||||
kfree(orphan);
|
||||
return -ENFILE;
|
||||
return ERR_PTR(-ENFILE);
|
||||
}
|
||||
p = &c->orph_tree.rb_node;
|
||||
while (*p) {
|
||||
@ -91,7 +85,7 @@ int ubifs_add_orphan(struct ubifs_info *c, ino_t inum)
|
||||
ubifs_err(c, "orphaned twice");
|
||||
spin_unlock(&c->orphan_lock);
|
||||
kfree(orphan);
|
||||
return 0;
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
}
|
||||
c->tot_orphans += 1;
|
||||
@ -100,8 +94,135 @@ int ubifs_add_orphan(struct ubifs_info *c, ino_t inum)
|
||||
rb_insert_color(&orphan->rb, &c->orph_tree);
|
||||
list_add_tail(&orphan->list, &c->orph_list);
|
||||
list_add_tail(&orphan->new_list, &c->orph_new);
|
||||
|
||||
if (parent_orphan) {
|
||||
list_add_tail(&orphan->child_list,
|
||||
&parent_orphan->child_list);
|
||||
}
|
||||
|
||||
spin_unlock(&c->orphan_lock);
|
||||
dbg_gen("ino %lu", (unsigned long)inum);
|
||||
return orphan;
|
||||
}
|
||||
|
||||
static struct ubifs_orphan *lookup_orphan(struct ubifs_info *c, ino_t inum)
|
||||
{
|
||||
struct ubifs_orphan *o;
|
||||
struct rb_node *p;
|
||||
|
||||
p = c->orph_tree.rb_node;
|
||||
while (p) {
|
||||
o = rb_entry(p, struct ubifs_orphan, rb);
|
||||
if (inum < o->inum)
|
||||
p = p->rb_left;
|
||||
else if (inum > o->inum)
|
||||
p = p->rb_right;
|
||||
else {
|
||||
return o;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void __orphan_drop(struct ubifs_info *c, struct ubifs_orphan *o)
|
||||
{
|
||||
rb_erase(&o->rb, &c->orph_tree);
|
||||
list_del(&o->list);
|
||||
c->tot_orphans -= 1;
|
||||
|
||||
if (o->new) {
|
||||
list_del(&o->new_list);
|
||||
c->new_orphans -= 1;
|
||||
}
|
||||
|
||||
kfree(o);
|
||||
}
|
||||
|
||||
static void orphan_delete(struct ubifs_info *c, ino_t inum)
|
||||
{
|
||||
struct ubifs_orphan *orph, *child_orph, *tmp_o;
|
||||
|
||||
spin_lock(&c->orphan_lock);
|
||||
|
||||
orph = lookup_orphan(c, inum);
|
||||
if (!orph) {
|
||||
spin_unlock(&c->orphan_lock);
|
||||
ubifs_err(c, "missing orphan ino %lu", (unsigned long)inum);
|
||||
dump_stack();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (orph->del) {
|
||||
spin_unlock(&c->orphan_lock);
|
||||
dbg_gen("deleted twice ino %lu",
|
||||
(unsigned long)inum);
|
||||
return;
|
||||
}
|
||||
|
||||
if (orph->cmt) {
|
||||
orph->del = 1;
|
||||
orph->dnext = c->orph_dnext;
|
||||
c->orph_dnext = orph;
|
||||
spin_unlock(&c->orphan_lock);
|
||||
dbg_gen("delete later ino %lu",
|
||||
(unsigned long)inum);
|
||||
return;
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(child_orph, tmp_o, &orph->child_list, child_list) {
|
||||
list_del(&child_orph->child_list);
|
||||
__orphan_drop(c, child_orph);
|
||||
}
|
||||
|
||||
__orphan_drop(c, orph);
|
||||
|
||||
spin_unlock(&c->orphan_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_add_orphan - add an orphan.
|
||||
* @c: UBIFS file-system description object
|
||||
* @inum: orphan inode number
|
||||
*
|
||||
* Add an orphan. This function is called when an inodes link count drops to
|
||||
* zero.
|
||||
*/
|
||||
int ubifs_add_orphan(struct ubifs_info *c, ino_t inum)
|
||||
{
|
||||
int err = 0;
|
||||
ino_t xattr_inum;
|
||||
union ubifs_key key;
|
||||
struct ubifs_dent_node *xent;
|
||||
struct fscrypt_name nm = {0};
|
||||
struct ubifs_orphan *xattr_orphan;
|
||||
struct ubifs_orphan *orphan;
|
||||
|
||||
orphan = orphan_add(c, inum, NULL);
|
||||
if (IS_ERR(orphan))
|
||||
return PTR_ERR(orphan);
|
||||
|
||||
lowest_xent_key(c, &key, inum);
|
||||
while (1) {
|
||||
xent = ubifs_tnc_next_ent(c, &key, &nm);
|
||||
if (IS_ERR(xent)) {
|
||||
err = PTR_ERR(xent);
|
||||
if (err == -ENOENT)
|
||||
break;
|
||||
return err;
|
||||
}
|
||||
|
||||
fname_name(&nm) = xent->name;
|
||||
fname_len(&nm) = le16_to_cpu(xent->nlen);
|
||||
xattr_inum = le64_to_cpu(xent->inum);
|
||||
|
||||
xattr_orphan = orphan_add(c, xattr_inum, orphan);
|
||||
if (IS_ERR(xattr_orphan))
|
||||
return PTR_ERR(xattr_orphan);
|
||||
|
||||
key_read(c, &xent->key, &key);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -114,49 +235,7 @@ int ubifs_add_orphan(struct ubifs_info *c, ino_t inum)
|
||||
*/
|
||||
void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum)
|
||||
{
|
||||
struct ubifs_orphan *o;
|
||||
struct rb_node *p;
|
||||
|
||||
spin_lock(&c->orphan_lock);
|
||||
p = c->orph_tree.rb_node;
|
||||
while (p) {
|
||||
o = rb_entry(p, struct ubifs_orphan, rb);
|
||||
if (inum < o->inum)
|
||||
p = p->rb_left;
|
||||
else if (inum > o->inum)
|
||||
p = p->rb_right;
|
||||
else {
|
||||
if (o->del) {
|
||||
spin_unlock(&c->orphan_lock);
|
||||
dbg_gen("deleted twice ino %lu",
|
||||
(unsigned long)inum);
|
||||
return;
|
||||
}
|
||||
if (o->cmt) {
|
||||
o->del = 1;
|
||||
o->dnext = c->orph_dnext;
|
||||
c->orph_dnext = o;
|
||||
spin_unlock(&c->orphan_lock);
|
||||
dbg_gen("delete later ino %lu",
|
||||
(unsigned long)inum);
|
||||
return;
|
||||
}
|
||||
rb_erase(p, &c->orph_tree);
|
||||
list_del(&o->list);
|
||||
c->tot_orphans -= 1;
|
||||
if (o->new) {
|
||||
list_del(&o->new_list);
|
||||
c->new_orphans -= 1;
|
||||
}
|
||||
spin_unlock(&c->orphan_lock);
|
||||
kfree(o);
|
||||
dbg_gen("inum %lu", (unsigned long)inum);
|
||||
return;
|
||||
}
|
||||
}
|
||||
spin_unlock(&c->orphan_lock);
|
||||
ubifs_err(c, "missing orphan ino %lu", (unsigned long)inum);
|
||||
dump_stack();
|
||||
orphan_delete(c, inum);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -611,10 +690,16 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
|
||||
|
||||
n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3;
|
||||
for (i = 0; i < n; i++) {
|
||||
union ubifs_key key1, key2;
|
||||
|
||||
inum = le64_to_cpu(orph->inos[i]);
|
||||
dbg_rcvry("deleting orphaned inode %lu",
|
||||
(unsigned long)inum);
|
||||
err = ubifs_tnc_remove_ino(c, inum);
|
||||
|
||||
lowest_ino_key(c, &key1, inum);
|
||||
highest_ino_key(c, &key2, inum);
|
||||
|
||||
err = ubifs_tnc_remove_range(c, &key1, &key2);
|
||||
if (err)
|
||||
return err;
|
||||
err = insert_dead_orphan(c, inum);
|
||||
@ -744,26 +829,15 @@ struct check_info {
|
||||
struct rb_root root;
|
||||
};
|
||||
|
||||
static int dbg_find_orphan(struct ubifs_info *c, ino_t inum)
|
||||
static bool dbg_find_orphan(struct ubifs_info *c, ino_t inum)
|
||||
{
|
||||
struct ubifs_orphan *o;
|
||||
struct rb_node *p;
|
||||
bool found = false;
|
||||
|
||||
spin_lock(&c->orphan_lock);
|
||||
p = c->orph_tree.rb_node;
|
||||
while (p) {
|
||||
o = rb_entry(p, struct ubifs_orphan, rb);
|
||||
if (inum < o->inum)
|
||||
p = p->rb_left;
|
||||
else if (inum > o->inum)
|
||||
p = p->rb_right;
|
||||
else {
|
||||
spin_unlock(&c->orphan_lock);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
found = !!lookup_orphan(c, inum);
|
||||
spin_unlock(&c->orphan_lock);
|
||||
return 0;
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static int dbg_ins_check_orphan(struct rb_root *root, ino_t inum)
|
||||
|
@ -748,14 +748,12 @@ int ubifs_read_superblock(struct ubifs_info *c)
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_FS_ENCRYPTION
|
||||
if (c->encrypted) {
|
||||
if (!IS_ENABLED(CONFIG_UBIFS_FS_ENCRYPTION) && c->encrypted) {
|
||||
ubifs_err(c, "file system contains encrypted files but UBIFS"
|
||||
" was built without crypto support.");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Automatically increase file system size to the maximum size */
|
||||
c->old_leb_cnt = c->leb_cnt;
|
||||
@ -943,6 +941,9 @@ int ubifs_enable_encryption(struct ubifs_info *c)
|
||||
int err;
|
||||
struct ubifs_sb_node *sup = c->sup_node;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_UBIFS_FS_ENCRYPTION))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (c->encrypted)
|
||||
return 0;
|
||||
|
||||
|
@ -129,9 +129,10 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
|
||||
goto out_ino;
|
||||
|
||||
inode->i_flags |= S_NOCMTIME;
|
||||
#ifndef CONFIG_UBIFS_ATIME_SUPPORT
|
||||
inode->i_flags |= S_NOATIME;
|
||||
#endif
|
||||
|
||||
if (!IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT))
|
||||
inode->i_flags |= S_NOATIME;
|
||||
|
||||
set_nlink(inode, le32_to_cpu(ino->nlink));
|
||||
i_uid_write(inode, le32_to_cpu(ino->uid));
|
||||
i_gid_write(inode, le32_to_cpu(ino->gid));
|
||||
@ -1545,6 +1546,8 @@ static int mount_ubifs(struct ubifs_info *c)
|
||||
c->bud_bytes, c->bud_bytes >> 10, c->bud_bytes >> 20);
|
||||
dbg_gen("max. seq. number: %llu", c->max_sqnum);
|
||||
dbg_gen("commit number: %llu", c->cmt_no);
|
||||
dbg_gen("max. xattrs per inode: %d", ubifs_xattr_max_cnt(c));
|
||||
dbg_gen("max orphans: %d", c->max_orphans);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -2141,9 +2144,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
#ifdef CONFIG_UBIFS_FS_XATTR
|
||||
sb->s_xattr = ubifs_xattr_handlers;
|
||||
#endif
|
||||
#ifdef CONFIG_FS_ENCRYPTION
|
||||
sb->s_cop = &ubifs_crypt_operations;
|
||||
#endif
|
||||
fscrypt_set_ops(sb, &ubifs_crypt_operations);
|
||||
|
||||
mutex_lock(&c->umount_mutex);
|
||||
err = mount_ubifs(c);
|
||||
@ -2245,11 +2246,10 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
|
||||
goto out_deact;
|
||||
/* We do not support atime */
|
||||
sb->s_flags |= SB_ACTIVE;
|
||||
#ifndef CONFIG_UBIFS_ATIME_SUPPORT
|
||||
sb->s_flags |= SB_NOATIME;
|
||||
#else
|
||||
ubifs_msg(c, "full atime support is enabled.");
|
||||
#endif
|
||||
if (IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT))
|
||||
ubifs_msg(c, "full atime support is enabled.");
|
||||
else
|
||||
sb->s_flags |= SB_NOATIME;
|
||||
}
|
||||
|
||||
/* 'fill_super()' opens ubi again so we must close it here */
|
||||
|
@ -479,14 +479,13 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
|
||||
if (node_len != len)
|
||||
return 0;
|
||||
|
||||
if (type == UBIFS_DATA_NODE && c->no_chk_data_crc && !c->mounting &&
|
||||
!c->remounting_rw)
|
||||
return 1;
|
||||
|
||||
crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
|
||||
node_crc = le32_to_cpu(ch->crc);
|
||||
if (crc != node_crc)
|
||||
return 0;
|
||||
if (type != UBIFS_DATA_NODE || !c->no_chk_data_crc || c->mounting ||
|
||||
c->remounting_rw) {
|
||||
crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
|
||||
node_crc = le32_to_cpu(ch->crc);
|
||||
if (crc != node_crc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = ubifs_node_check_hash(c, buf, zbr->hash);
|
||||
if (err) {
|
||||
|
@ -924,6 +924,8 @@ struct ubifs_budget_req {
|
||||
* @rb: rb-tree node of rb-tree of orphans sorted by inode number
|
||||
* @list: list head of list of orphans in order added
|
||||
* @new_list: list head of list of orphans added since the last commit
|
||||
* @child_list: list of xattr childs if this orphan hosts xattrs, list head
|
||||
* if this orphan is a xattr, not used otherwise.
|
||||
* @cnext: next orphan to commit
|
||||
* @dnext: next orphan to delete
|
||||
* @inum: inode number
|
||||
@ -935,6 +937,7 @@ struct ubifs_orphan {
|
||||
struct rb_node rb;
|
||||
struct list_head list;
|
||||
struct list_head new_list;
|
||||
struct list_head child_list;
|
||||
struct ubifs_orphan *cnext;
|
||||
struct ubifs_orphan *dnext;
|
||||
ino_t inum;
|
||||
@ -1996,9 +1999,7 @@ int ubifs_calc_dark(const struct ubifs_info *c, int spc);
|
||||
/* file.c */
|
||||
int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync);
|
||||
int ubifs_setattr(struct dentry *dentry, struct iattr *attr);
|
||||
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
|
||||
int ubifs_update_time(struct inode *inode, struct timespec64 *time, int flags);
|
||||
#endif
|
||||
|
||||
/* dir.c */
|
||||
struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
|
||||
@ -2014,6 +2015,7 @@ int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
|
||||
size_t size, int flags, bool check_lock);
|
||||
ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf,
|
||||
size_t size);
|
||||
int ubifs_purge_xattrs(struct inode *host);
|
||||
|
||||
#ifdef CONFIG_UBIFS_FS_XATTR
|
||||
void ubifs_evict_xattr_inode(struct ubifs_info *c, ino_t xattr_inum);
|
||||
|
@ -60,12 +60,6 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/xattr.h>
|
||||
|
||||
/*
|
||||
* Limit the number of extended attributes per inode so that the total size
|
||||
* (@xattr_size) is guaranteeded to fit in an 'unsigned int'.
|
||||
*/
|
||||
#define MAX_XATTRS_PER_INODE 65535
|
||||
|
||||
/*
|
||||
* Extended attribute type constants.
|
||||
*
|
||||
@ -106,7 +100,7 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
|
||||
.new_ino_d = ALIGN(size, 8), .dirtied_ino = 1,
|
||||
.dirtied_ino_d = ALIGN(host_ui->data_len, 8) };
|
||||
|
||||
if (host_ui->xattr_cnt >= MAX_XATTRS_PER_INODE) {
|
||||
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;
|
||||
@ -507,6 +501,69 @@ out_cancel:
|
||||
return err;
|
||||
}
|
||||
|
||||
int ubifs_purge_xattrs(struct inode *host)
|
||||
{
|
||||
union ubifs_key key;
|
||||
struct ubifs_info *c = host->i_sb->s_fs_info;
|
||||
struct ubifs_dent_node *xent, *pxent = NULL;
|
||||
struct inode *xino;
|
||||
struct fscrypt_name nm = {0};
|
||||
int err;
|
||||
|
||||
if (ubifs_inode(host)->xattr_cnt < ubifs_xattr_max_cnt(c))
|
||||
return 0;
|
||||
|
||||
ubifs_warn(c, "inode %lu has too many xattrs, doing a non-atomic deletion",
|
||||
host->i_ino);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
fname_name(&nm) = xent->name;
|
||||
fname_len(&nm) = le16_to_cpu(xent->nlen);
|
||||
|
||||
xino = ubifs_iget(c->vfs_sb, xent->inum);
|
||||
if (IS_ERR(xino)) {
|
||||
err = PTR_ERR(xino);
|
||||
ubifs_err(c, "dead directory entry '%s', error %d",
|
||||
xent->name, err);
|
||||
ubifs_ro_mode(c, err);
|
||||
kfree(pxent);
|
||||
return err;
|
||||
}
|
||||
|
||||
ubifs_assert(c, ubifs_inode(xino)->xattr);
|
||||
|
||||
clear_nlink(xino);
|
||||
err = remove_xattr(c, host, xino, &nm);
|
||||
if (err) {
|
||||
kfree(pxent);
|
||||
iput(xino);
|
||||
ubifs_err(c, "cannot remove xattr, error %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
iput(xino);
|
||||
|
||||
kfree(pxent);
|
||||
pxent = xent;
|
||||
key_read(c, &xent->key, &key);
|
||||
}
|
||||
|
||||
kfree(pxent);
|
||||
if (err != -ENOENT) {
|
||||
ubifs_err(c, "cannot find next direntry, error %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_evict_xattr_inode - Evict an xattr inode.
|
||||
* @c: UBIFS file-system description object
|
||||
|
@ -247,6 +247,11 @@ extern int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
|
||||
extern const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
|
||||
unsigned int max_size,
|
||||
struct delayed_call *done);
|
||||
static inline void fscrypt_set_ops(struct super_block *sb,
|
||||
const struct fscrypt_operations *s_cop)
|
||||
{
|
||||
sb->s_cop = s_cop;
|
||||
}
|
||||
#else /* !CONFIG_FS_ENCRYPTION */
|
||||
|
||||
static inline bool fscrypt_has_encryption_key(const struct inode *inode)
|
||||
@ -471,6 +476,12 @@ static inline const char *fscrypt_get_symlink(struct inode *inode,
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline void fscrypt_set_ops(struct super_block *sb,
|
||||
const struct fscrypt_operations *s_cop)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_FS_ENCRYPTION */
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user