Commit d7a02fa0 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 4dbf09fe 04d37e5a
...@@ -1475,7 +1475,7 @@ static bool scrub_possible(struct ubi_device *ubi, struct ubi_wl_entry *e) ...@@ -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 ubi_bitflip_check(struct ubi_device *ubi, int pnum, int force)
{ {
int err; int err = 0;
struct ubi_wl_entry *e; struct ubi_wl_entry *e;
if (pnum < 0 || pnum >= ubi->peb_count) { 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, ...@@ -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, int ubifs_prepare_auth_node(struct ubifs_info *c, void *node,
struct shash_desc *inhash) struct shash_desc *inhash)
{ {
SHASH_DESC_ON_STACK(hash_desc, c->hash_tfm);
struct ubifs_auth_node *auth = node; struct ubifs_auth_node *auth = node;
u8 *hash; u8 *hash;
int err; int err;
...@@ -85,12 +84,16 @@ int ubifs_prepare_auth_node(struct ubifs_info *c, void *node, ...@@ -85,12 +84,16 @@ int ubifs_prepare_auth_node(struct ubifs_info *c, void *node,
if (!hash) if (!hash)
return -ENOMEM; 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); hash_desc->tfm = c->hash_tfm;
if (err) ubifs_shash_copy_state(c, inhash, hash_desc);
goto out;
err = crypto_shash_final(hash_desc, hash);
if (err)
goto out;
}
err = ubifs_hash_calc_hmac(c, hash, auth->hmac); err = ubifs_hash_calc_hmac(c, hash, auth->hmac);
if (err) if (err)
...@@ -142,24 +145,6 @@ struct shash_desc *__ubifs_hash_get_desc(const struct ubifs_info *c) ...@@ -142,24 +145,6 @@ struct shash_desc *__ubifs_hash_get_desc(const struct ubifs_info *c)
return ubifs_get_desc(c, c->hash_tfm); 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 * ubifs_bad_hash - Report hash mismatches
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
......
...@@ -1603,7 +1603,6 @@ int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb, ...@@ -1603,7 +1603,6 @@ int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb,
err = PTR_ERR(child); err = PTR_ERR(child);
goto out_unlock; goto out_unlock;
} }
zbr->znode = child;
} }
znode = child; znode = child;
......
...@@ -790,16 +790,14 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -790,16 +790,14 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
dentry, inode->i_ino, dentry, inode->i_ino,
inode->i_nlink, dir->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); err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm);
if (err) if (err)
return err; return err;
err = ubifs_purge_xattrs(inode);
if (err)
return err;
sz_change = CALC_DENT_SIZE(fname_len(&nm)); sz_change = CALC_DENT_SIZE(fname_len(&nm));
ubifs_assert(c, inode_is_locked(dir)); ubifs_assert(c, inode_is_locked(dir));
...@@ -900,16 +898,14 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -900,16 +898,14 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
if (err) if (err)
return 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); err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm);
if (err) if (err)
return err; return err;
err = ubifs_purge_xattrs(inode);
if (err)
return err;
sz_change = CALC_DENT_SIZE(fname_len(&nm)); sz_change = CALC_DENT_SIZE(fname_len(&nm));
err = ubifs_budget_space(c, &req); err = ubifs_budget_space(c, &req);
...@@ -1292,9 +1288,14 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -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, old_dentry, old_inode->i_ino, old_dir->i_ino,
new_dentry, new_dir->i_ino, flags); new_dentry, new_dir->i_ino, flags);
if (unlink) if (unlink) {
ubifs_assert(c, inode_is_locked(new_inode)); ubifs_assert(c, inode_is_locked(new_inode));
err = ubifs_purge_xattrs(new_inode);
if (err)
return err;
}
if (unlink && is_dir) { if (unlink && is_dir) {
err = ubifs_check_dir_empty(new_inode); err = ubifs_check_dir_empty(new_inode);
if (err) if (err)
...@@ -1650,9 +1651,7 @@ const struct inode_operations ubifs_dir_inode_operations = { ...@@ -1650,9 +1651,7 @@ const struct inode_operations ubifs_dir_inode_operations = {
#ifdef CONFIG_UBIFS_FS_XATTR #ifdef CONFIG_UBIFS_FS_XATTR
.listxattr = ubifs_listxattr, .listxattr = ubifs_listxattr,
#endif #endif
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
.update_time = ubifs_update_time, .update_time = ubifs_update_time,
#endif
.tmpfile = ubifs_tmpfile, .tmpfile = ubifs_tmpfile,
}; };
......
...@@ -1375,7 +1375,6 @@ static inline int mctime_update_needed(const struct inode *inode, ...@@ -1375,7 +1375,6 @@ static inline int mctime_update_needed(const struct inode *inode,
return 0; return 0;
} }
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
/** /**
* ubifs_update_time - update time of inode. * ubifs_update_time - update time of inode.
* @inode: inode to update * @inode: inode to update
...@@ -1392,6 +1391,9 @@ int ubifs_update_time(struct inode *inode, struct timespec64 *time, ...@@ -1392,6 +1391,9 @@ int ubifs_update_time(struct inode *inode, struct timespec64 *time,
int iflags = I_DIRTY_TIME; int iflags = I_DIRTY_TIME;
int err, release; int err, release;
if (!IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT))
return generic_update_time(inode, time, flags);
err = ubifs_budget_space(c, &req); err = ubifs_budget_space(c, &req);
if (err) if (err)
return err; return err;
...@@ -1414,7 +1416,6 @@ int ubifs_update_time(struct inode *inode, struct timespec64 *time, ...@@ -1414,7 +1416,6 @@ int ubifs_update_time(struct inode *inode, struct timespec64 *time,
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
return 0; return 0;
} }
#endif
/** /**
* update_mctime - update mtime and ctime of an inode. * 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) ...@@ -1623,9 +1624,10 @@ static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
if (err) if (err)
return err; return err;
vma->vm_ops = &ubifs_file_vm_ops; vma->vm_ops = &ubifs_file_vm_ops;
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
file_accessed(file); if (IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT))
#endif file_accessed(file);
return 0; return 0;
} }
...@@ -1663,9 +1665,7 @@ const struct inode_operations ubifs_file_inode_operations = { ...@@ -1663,9 +1665,7 @@ const struct inode_operations ubifs_file_inode_operations = {
#ifdef CONFIG_UBIFS_FS_XATTR #ifdef CONFIG_UBIFS_FS_XATTR
.listxattr = ubifs_listxattr, .listxattr = ubifs_listxattr,
#endif #endif
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
.update_time = ubifs_update_time, .update_time = ubifs_update_time,
#endif
}; };
const struct inode_operations ubifs_symlink_inode_operations = { const struct inode_operations ubifs_symlink_inode_operations = {
...@@ -1675,9 +1675,7 @@ 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 #ifdef CONFIG_UBIFS_FS_XATTR
.listxattr = ubifs_listxattr, .listxattr = ubifs_listxattr,
#endif #endif
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
.update_time = ubifs_update_time, .update_time = ubifs_update_time,
#endif
}; };
const struct file_operations ubifs_file_operations = { const struct file_operations ubifs_file_operations = {
......
...@@ -747,12 +747,6 @@ static int cmp_dirty_idx(const struct ubifs_lprops **a, ...@@ -747,12 +747,6 @@ static int cmp_dirty_idx(const struct ubifs_lprops **a,
return lpa->dirty + lpa->free - lpb->dirty - lpb->free; 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. * ubifs_save_dirty_idx_lnums - save an array of the most dirty index LEB nos.
* @c: the UBIFS file-system description object * @c: the UBIFS file-system description object
...@@ -772,8 +766,7 @@ int ubifs_save_dirty_idx_lnums(struct ubifs_info *c) ...@@ -772,8 +766,7 @@ int ubifs_save_dirty_idx_lnums(struct ubifs_info *c)
sizeof(void *) * c->dirty_idx.cnt); sizeof(void *) * c->dirty_idx.cnt);
/* Sort it so that the dirtiest is now at the end */ /* Sort it so that the dirtiest is now at the end */
sort(c->dirty_idx.arr, c->dirty_idx.cnt, sizeof(void *), sort(c->dirty_idx.arr, c->dirty_idx.cnt, sizeof(void *),
(int (*)(const void *, const void *))cmp_dirty_idx, (int (*)(const void *, const void *))cmp_dirty_idx, NULL);
(void (*)(void *, void *, int))swap_dirty_idx);
dbg_find("found %d dirty index LEBs", c->dirty_idx.cnt); dbg_find("found %d dirty index LEBs", c->dirty_idx.cnt);
if (c->dirty_idx.cnt) if (c->dirty_idx.cnt)
dbg_find("dirtiest index LEB is %d with dirty %d and free %d", 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) ...@@ -193,7 +193,6 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return err; return err;
} }
case FS_IOC_SET_ENCRYPTION_POLICY: { case FS_IOC_SET_ENCRYPTION_POLICY: {
#ifdef CONFIG_FS_ENCRYPTION
struct ubifs_info *c = inode->i_sb->s_fs_info; struct ubifs_info *c = inode->i_sb->s_fs_info;
err = ubifs_enable_encryption(c); err = ubifs_enable_encryption(c);
...@@ -201,17 +200,9 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -201,17 +200,9 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return err; return err;
return fscrypt_ioctl_set_policy(file, (const void __user *)arg); return fscrypt_ioctl_set_policy(file, (const void __user *)arg);
#else
return -EOPNOTSUPP;
#endif
} }
case FS_IOC_GET_ENCRYPTION_POLICY: { case FS_IOC_GET_ENCRYPTION_POLICY:
#ifdef CONFIG_FS_ENCRYPTION
return fscrypt_ioctl_get_policy(file, (void __user *)arg); return fscrypt_ioctl_get_policy(file, (void __user *)arg);
#else
return -EOPNOTSUPP;
#endif
}
default: default:
return -ENOTTY; return -ENOTTY;
......
...@@ -852,10 +852,11 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, ...@@ -852,10 +852,11 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode) int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
{ {
int err, lnum, offs; int err, lnum, offs;
struct ubifs_ino_node *ino; struct ubifs_ino_node *ino, *ino_start;
struct ubifs_inode *ui = ubifs_inode(inode); 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 last_reference = !inode->i_nlink;
int kill_xattrs = ui->xattr_cnt && last_reference;
u8 hash[UBIFS_HASH_ARR_SZ]; u8 hash[UBIFS_HASH_ARR_SZ];
dbg_jnl("ino %lu, nlink %u", inode->i_ino, inode->i_nlink); 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) ...@@ -867,14 +868,16 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
if (!last_reference) { if (!last_reference) {
ilen += ui->data_len; ilen += ui->data_len;
sync = IS_SYNC(inode); sync = IS_SYNC(inode);
} else if (kill_xattrs) {
write_len += UBIFS_INO_NODE_SZ * ui->xattr_cnt;
} }
if (ubifs_authenticated(c)) 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 else
write_len = ilen; write_len += ilen;
ino = kmalloc(write_len, GFP_NOFS); ino_start = ino = kmalloc(write_len, GFP_NOFS);
if (!ino) if (!ino)
return -ENOMEM; return -ENOMEM;
...@@ -883,12 +886,59 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode) ...@@ -883,12 +886,59 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
if (err) if (err)
goto out_free; 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); pack_inode(c, ino, inode, 1);
err = ubifs_node_calc_hash(c, ino, hash); err = ubifs_node_calc_hash(c, ino, hash);
if (err) if (err)
goto out_release; 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) if (err)
goto out_release; goto out_release;
if (!sync) if (!sync)
...@@ -903,7 +953,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode) ...@@ -903,7 +953,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
if (err) if (err)
goto out_ro; goto out_ro;
ubifs_delete_orphan(c, inode->i_ino); ubifs_delete_orphan(c, inode->i_ino);
err = ubifs_add_dirt(c, lnum, ilen); err = ubifs_add_dirt(c, lnum, write_len);
} else { } else {
union ubifs_key key; union ubifs_key key;
...@@ -917,7 +967,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode) ...@@ -917,7 +967,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
spin_lock(&ui->ui_lock); spin_lock(&ui->ui_lock);
ui->synced_i_size = ui->ui_size; ui->synced_i_size = ui->ui_size;
spin_unlock(&ui->ui_lock); spin_unlock(&ui->ui_lock);
kfree(ino); kfree(ino_start);
return 0; return 0;
out_release: out_release:
...@@ -926,7 +976,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode) ...@@ -926,7 +976,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
ubifs_ro_mode(c, err); ubifs_ro_mode(c, err);
finish_reservation(c); finish_reservation(c);
out_free: out_free:
kfree(ino); kfree(ino_start);
return err; return err;
} }
...@@ -966,8 +1016,8 @@ int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode) ...@@ -966,8 +1016,8 @@ int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode)
ubifs_assert(c, inode->i_nlink == 0); ubifs_assert(c, inode->i_nlink == 0);
if (ui->del_cmtno != c->cmt_no) if (ui->xattr_cnt || ui->del_cmtno != c->cmt_no)
/* A commit happened for sure */ /* A commit happened for sure or inode hosts xattrs */
return ubifs_jnl_write_inode(c, inode); return ubifs_jnl_write_inode(c, inode);
down_read(&c->commit_sem); down_read(&c->commit_sem);
......
...@@ -288,6 +288,14 @@ static inline int ubifs_next_log_lnum(const struct ubifs_info *c, int lnum) ...@@ -288,6 +288,14 @@ static inline int ubifs_next_log_lnum(const struct ubifs_info *c, int lnum)
return 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); const char *ubifs_assert_action_name(struct ubifs_info *c);
#endif /* __UBIFS_MISC_H__ */ #endif /* __UBIFS_MISC_H__ */
...@@ -54,30 +54,24 @@ ...@@ -54,30 +54,24 @@
static int dbg_check_orphans(struct ubifs_info *c); static int dbg_check_orphans(struct ubifs_info *c);
/** static struct ubifs_orphan *orphan_add(struct ubifs_info *c, ino_t inum,
* ubifs_add_orphan - add an orphan. struct ubifs_orphan *parent_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)
{ {
struct ubifs_orphan *orphan, *o; struct ubifs_orphan *orphan, *o;
struct rb_node **p, *parent = NULL; struct rb_node **p, *parent = NULL;
orphan = kzalloc(sizeof(struct ubifs_orphan), GFP_NOFS); orphan = kzalloc(sizeof(struct ubifs_orphan), GFP_NOFS);
if (!orphan) if (!orphan)
return -ENOMEM; return ERR_PTR(-ENOMEM);
orphan->inum = inum; orphan->inum = inum;
orphan->new = 1; orphan->new = 1;
INIT_LIST_HEAD(&orphan->child_list);
spin_lock(&c->orphan_lock); spin_lock(&c->orphan_lock);
if (c->tot_orphans >= c->max_orphans) { if (c->tot_orphans >= c->max_orphans) {
spin_unlock(&c->orphan_lock); spin_unlock(&c->orphan_lock);
kfree(orphan); kfree(orphan);
return -ENFILE; return ERR_PTR(-ENFILE);
} }
p = &c->orph_tree.rb_node; p = &c->orph_tree.rb_node;
while (*p) { while (*p) {
...@@ -91,7 +85,7 @@ int ubifs_add_orphan(struct ubifs_info *c, ino_t inum) ...@@ -91,7 +85,7 @@ int ubifs_add_orphan(struct ubifs_info *c, ino_t inum)
ubifs_err(c, "orphaned twice"); ubifs_err(c, "orphaned twice");
spin_unlock(&c->orphan_lock); spin_unlock(&c->orphan_lock);
kfree(orphan); kfree(orphan);
return 0; return ERR_PTR(-EINVAL);
} }
} }
c->tot_orphans += 1; c->tot_orphans += 1;
...@@ -100,24 +94,22 @@ int ubifs_add_orphan(struct ubifs_info *c, ino_t inum) ...@@ -100,24 +94,22 @@ int ubifs_add_orphan(struct ubifs_info *c, ino_t inum)
rb_insert_color(&orphan->rb, &c->orph_tree); rb_insert_color(&orphan->rb, &c->orph_tree);
list_add_tail(&orphan->list, &c->orph_list); list_add_tail(&orphan->list, &c->orph_list);
list_add_tail(&orphan->new_list, &c->orph_new); 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); spin_unlock(&c->orphan_lock);
dbg_gen("ino %lu", (unsigned long)inum); dbg_gen("ino %lu", (unsigned long)inum);
return 0; return orphan;
} }
/** static struct ubifs_orphan *lookup_orphan(struct ubifs_info *c, ino_t inum)
* ubifs_delete_orphan - delete an orphan.
* @c: UBIFS file-system description object
* @inum: orphan inode number
*
* Delete an orphan. This function is called when an inode is deleted.
*/
void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum)
{ {
struct ubifs_orphan *o; struct ubifs_orphan *o;
struct rb_node *p; struct rb_node *p;
spin_lock(&c->orphan_lock);
p = c->orph_tree.rb_node; p = c->orph_tree.rb_node;
while (p) { while (p) {
o = rb_entry(p, struct ubifs_orphan, rb); o = rb_entry(p, struct ubifs_orphan, rb);
...@@ -126,37 +118,124 @@ void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum) ...@@ -126,37 +118,124 @@ void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum)
else if (inum > o->inum) else if (inum > o->inum)
p = p->rb_right; p = p->rb_right;
else { else {
if (o->del) { return o;
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;
} }
} }
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); spin_unlock(&c->orphan_lock);
ubifs_err(c, "missing orphan ino %lu", (unsigned long)inum); }
dump_stack();
/**
* 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;
}
/**
* ubifs_delete_orphan - delete an orphan.
* @c: UBIFS file-system description object
* @inum: orphan inode number
*
* Delete an orphan. This function is called when an inode is deleted.
*/
void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum)
{
orphan_delete(c, inum);
} }
/** /**
...@@ -611,10 +690,16 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb, ...@@ -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; n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
union ubifs_key key1, key2;
inum = le64_to_cpu(orph->inos[i]); inum = le64_to_cpu(orph->inos[i]);
dbg_rcvry("deleting orphaned inode %lu", dbg_rcvry("deleting orphaned inode %lu",
(unsigned long)inum); (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) if (err)
return err; return err;
err = insert_dead_orphan(c, inum); err = insert_dead_orphan(c, inum);
...@@ -744,26 +829,15 @@ struct check_info { ...@@ -744,26 +829,15 @@ struct check_info {
struct rb_root root; 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; bool found = false;
struct rb_node *p;
spin_lock(&c->orphan_lock); spin_lock(&c->orphan_lock);
p = c->orph_tree.rb_node; found = !!lookup_orphan(c, inum);
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;
}
}
spin_unlock(&c->orphan_lock); spin_unlock(&c->orphan_lock);
return 0;
return found;
} }
static int dbg_ins_check_orphan(struct rb_root *root, ino_t inum) 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) ...@@ -748,14 +748,12 @@ int ubifs_read_superblock(struct ubifs_info *c)
goto out; goto out;
} }
#ifndef CONFIG_FS_ENCRYPTION if (!IS_ENABLED(CONFIG_UBIFS_FS_ENCRYPTION) && c->encrypted) {
if (c->encrypted) {
ubifs_err(c, "file system contains encrypted files but UBIFS" ubifs_err(c, "file system contains encrypted files but UBIFS"
" was built without crypto support."); " was built without crypto support.");
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
#endif
/* Automatically increase file system size to the maximum size */ /* Automatically increase file system size to the maximum size */
c->old_leb_cnt = c->leb_cnt; c->old_leb_cnt = c->leb_cnt;
...@@ -943,6 +941,9 @@ int ubifs_enable_encryption(struct ubifs_info *c) ...@@ -943,6 +941,9 @@ int ubifs_enable_encryption(struct ubifs_info *c)
int err; int err;
struct ubifs_sb_node *sup = c->sup_node; struct ubifs_sb_node *sup = c->sup_node;
if (!IS_ENABLED(CONFIG_UBIFS_FS_ENCRYPTION))
return -EOPNOTSUPP;
if (c->encrypted) if (c->encrypted)
return 0; return 0;
......
...@@ -129,9 +129,10 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum) ...@@ -129,9 +129,10 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
goto out_ino; goto out_ino;
inode->i_flags |= S_NOCMTIME; inode->i_flags |= S_NOCMTIME;
#ifndef CONFIG_UBIFS_ATIME_SUPPORT
inode->i_flags |= S_NOATIME; if (!IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT))
#endif inode->i_flags |= S_NOATIME;
set_nlink(inode, le32_to_cpu(ino->nlink)); set_nlink(inode, le32_to_cpu(ino->nlink));
i_uid_write(inode, le32_to_cpu(ino->uid)); i_uid_write(inode, le32_to_cpu(ino->uid));
i_gid_write(inode, le32_to_cpu(ino->gid)); i_gid_write(inode, le32_to_cpu(ino->gid));
...@@ -1545,6 +1546,8 @@ static int mount_ubifs(struct ubifs_info *c) ...@@ -1545,6 +1546,8 @@ static int mount_ubifs(struct ubifs_info *c)
c->bud_bytes, c->bud_bytes >> 10, c->bud_bytes >> 20); c->bud_bytes, c->bud_bytes >> 10, c->bud_bytes >> 20);
dbg_gen("max. seq. number: %llu", c->max_sqnum); dbg_gen("max. seq. number: %llu", c->max_sqnum);
dbg_gen("commit number: %llu", c->cmt_no); 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; return 0;
...@@ -2141,9 +2144,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -2141,9 +2144,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
#ifdef CONFIG_UBIFS_FS_XATTR #ifdef CONFIG_UBIFS_FS_XATTR
sb->s_xattr = ubifs_xattr_handlers; sb->s_xattr = ubifs_xattr_handlers;
#endif #endif
#ifdef CONFIG_FS_ENCRYPTION fscrypt_set_ops(sb, &ubifs_crypt_operations);
sb->s_cop = &ubifs_crypt_operations;
#endif
mutex_lock(&c->umount_mutex); mutex_lock(&c->umount_mutex);
err = mount_ubifs(c); err = mount_ubifs(c);
...@@ -2245,11 +2246,10 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags, ...@@ -2245,11 +2246,10 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
goto out_deact; goto out_deact;
/* We do not support atime */ /* We do not support atime */
sb->s_flags |= SB_ACTIVE; sb->s_flags |= SB_ACTIVE;
#ifndef CONFIG_UBIFS_ATIME_SUPPORT if (IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT))
sb->s_flags |= SB_NOATIME; ubifs_msg(c, "full atime support is enabled.");
#else else
ubifs_msg(c, "full atime support is enabled."); sb->s_flags |= SB_NOATIME;
#endif
} }
/* 'fill_super()' opens ubi again so we must close it here */ /* '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, ...@@ -479,14 +479,13 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
if (node_len != len) if (node_len != len)
return 0; return 0;
if (type == UBIFS_DATA_NODE && c->no_chk_data_crc && !c->mounting && if (type != UBIFS_DATA_NODE || !c->no_chk_data_crc || c->mounting ||
!c->remounting_rw) c->remounting_rw) {
return 1; crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
node_crc = le32_to_cpu(ch->crc);
crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8); if (crc != node_crc)
node_crc = le32_to_cpu(ch->crc); return 0;
if (crc != node_crc) }
return 0;
err = ubifs_node_check_hash(c, buf, zbr->hash); err = ubifs_node_check_hash(c, buf, zbr->hash);
if (err) { if (err) {
......
...@@ -924,6 +924,8 @@ struct ubifs_budget_req { ...@@ -924,6 +924,8 @@ struct ubifs_budget_req {
* @rb: rb-tree node of rb-tree of orphans sorted by inode number * @rb: rb-tree node of rb-tree of orphans sorted by inode number
* @list: list head of list of orphans in order added * @list: list head of list of orphans in order added
* @new_list: list head of list of orphans added since the last commit * @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 * @cnext: next orphan to commit
* @dnext: next orphan to delete * @dnext: next orphan to delete
* @inum: inode number * @inum: inode number
...@@ -935,6 +937,7 @@ struct ubifs_orphan { ...@@ -935,6 +937,7 @@ struct ubifs_orphan {
struct rb_node rb; struct rb_node rb;
struct list_head list; struct list_head list;
struct list_head new_list; struct list_head new_list;
struct list_head child_list;
struct ubifs_orphan *cnext; struct ubifs_orphan *cnext;
struct ubifs_orphan *dnext; struct ubifs_orphan *dnext;
ino_t inum; ino_t inum;
...@@ -1996,9 +1999,7 @@ int ubifs_calc_dark(const struct ubifs_info *c, int spc); ...@@ -1996,9 +1999,7 @@ int ubifs_calc_dark(const struct ubifs_info *c, int spc);
/* file.c */ /* file.c */
int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync); int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync);
int ubifs_setattr(struct dentry *dentry, struct iattr *attr); 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); int ubifs_update_time(struct inode *inode, struct timespec64 *time, int flags);
#endif
/* dir.c */ /* dir.c */
struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir, 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, ...@@ -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); size_t size, int flags, bool check_lock);
ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf, ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf,
size_t size); size_t size);
int ubifs_purge_xattrs(struct inode *host);
#ifdef CONFIG_UBIFS_FS_XATTR #ifdef CONFIG_UBIFS_FS_XATTR
void ubifs_evict_xattr_inode(struct ubifs_info *c, ino_t xattr_inum); void ubifs_evict_xattr_inode(struct ubifs_info *c, ino_t xattr_inum);
......
...@@ -60,12 +60,6 @@ ...@@ -60,12 +60,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/xattr.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. * Extended attribute type constants.
* *
...@@ -106,7 +100,7 @@ static int create_xattr(struct ubifs_info *c, struct inode *host, ...@@ -106,7 +100,7 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
.new_ino_d = ALIGN(size, 8), .dirtied_ino = 1, .new_ino_d = ALIGN(size, 8), .dirtied_ino = 1,
.dirtied_ino_d = ALIGN(host_ui->data_len, 8) }; .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", ubifs_err(c, "inode %lu already has too many xattrs (%d), cannot create more",
host->i_ino, host_ui->xattr_cnt); host->i_ino, host_ui->xattr_cnt);
return -ENOSPC; return -ENOSPC;
...@@ -507,6 +501,69 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host, ...@@ -507,6 +501,69 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host,
return err; 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. * ubifs_evict_xattr_inode - Evict an xattr inode.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
......
...@@ -247,6 +247,11 @@ extern int __fscrypt_encrypt_symlink(struct inode *inode, const char *target, ...@@ -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, extern const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
unsigned int max_size, unsigned int max_size,
struct delayed_call *done); 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 */ #else /* !CONFIG_FS_ENCRYPTION */
static inline bool fscrypt_has_encryption_key(const struct inode *inode) 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, ...@@ -471,6 +476,12 @@ static inline const char *fscrypt_get_symlink(struct inode *inode,
{ {
return ERR_PTR(-EOPNOTSUPP); return ERR_PTR(-EOPNOTSUPP);
} }
static inline void fscrypt_set_ops(struct super_block *sb,
const struct fscrypt_operations *s_cop)
{
}
#endif /* !CONFIG_FS_ENCRYPTION */ #endif /* !CONFIG_FS_ENCRYPTION */
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment