Commit 966859b9 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'upstream-4.13-rc1' of git://git.infradead.org/linux-ubifs

Pull UBIFS updates from Richard Weinberger:

 - Updates and fixes for the file encryption mode

 - Minor improvements

 - Random fixes

* tag 'upstream-4.13-rc1' of git://git.infradead.org/linux-ubifs:
  ubifs: Set double hash cookie also for RENAME_EXCHANGE
  ubifs: Massage assert in ubifs_xattr_set() wrt. init_xattrs
  ubifs: Don't leak kernel memory to the MTD
  ubifs: Change gfp flags in page allocation for bulk read
  ubifs: Fix oops when remounting with no_bulk_read.
  ubifs: Fail commit if TNC is obviously inconsistent
  ubifs: allow userspace to map mounts to volumes
  ubifs: Wire-up statx() support
  ubifs: Remove dead code from ubifs_get_link()
  ubifs: Massage debug prints wrt. fscrypt
  ubifs: Add assert to dent_key_init()
  ubifs: Fix unlink code wrt. double hash lookups
  ubifs: Fix data node size for truncating uncompressed nodes
  ubifs: Don't encrypt special files on creation
  ubifs: Fix memory leak in RENAME_WHITEOUT error path in do_rename
  ubifs: Fix inode data budget in ubifs_mknod
  ubifs: Correctly evict xattr inodes
  ubifs: Unexport ubifs_inode_slab
  ubifs: don't bother checking for encryption key in ->mmap()
  ubifs: require key for truncate(2) of encrypted file
parents e37a07e0 a6664433
...@@ -9,8 +9,13 @@ static int ubifs_crypt_get_context(struct inode *inode, void *ctx, size_t len) ...@@ -9,8 +9,13 @@ static int ubifs_crypt_get_context(struct inode *inode, void *ctx, size_t len)
static int ubifs_crypt_set_context(struct inode *inode, const void *ctx, static int ubifs_crypt_set_context(struct inode *inode, const void *ctx,
size_t len, void *fs_data) size_t len, void *fs_data)
{ {
/*
* Creating an encryption context is done unlocked since we
* operate on a new inode which is not visible to other users
* at this point. So, no need to check whether inode is locked.
*/
return ubifs_xattr_set(inode, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT, return ubifs_xattr_set(inode, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT,
ctx, len, 0); ctx, len, 0, false);
} }
static bool ubifs_crypt_empty_dir(struct inode *inode) static bool ubifs_crypt_empty_dir(struct inode *inode)
......
...@@ -143,6 +143,7 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir, ...@@ -143,6 +143,7 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
case S_IFBLK: case S_IFBLK:
case S_IFCHR: case S_IFCHR:
inode->i_op = &ubifs_file_inode_operations; inode->i_op = &ubifs_file_inode_operations;
encrypted = false;
break; break;
default: default:
BUG(); BUG();
...@@ -1061,7 +1062,6 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -1061,7 +1062,6 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
int sz_change; int sz_change;
int err, devlen = 0; int err, devlen = 0;
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
.new_ino_d = ALIGN(devlen, 8),
.dirtied_ino = 1 }; .dirtied_ino = 1 };
struct fscrypt_name nm; struct fscrypt_name nm;
...@@ -1079,6 +1079,7 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -1079,6 +1079,7 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
devlen = ubifs_encode_dev(dev, rdev); devlen = ubifs_encode_dev(dev, rdev);
} }
req.new_ino_d = ALIGN(devlen, 8);
err = ubifs_budget_space(c, &req); err = ubifs_budget_space(c, &req);
if (err) { if (err) {
kfree(dev); kfree(dev);
...@@ -1396,17 +1397,14 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1396,17 +1397,14 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS);
if (!dev) { if (!dev) {
ubifs_release_budget(c, &req); err = -ENOMEM;
ubifs_release_budget(c, &ino_req); goto out_release;
return -ENOMEM;
} }
err = do_tmpfile(old_dir, old_dentry, S_IFCHR | WHITEOUT_MODE, &whiteout); err = do_tmpfile(old_dir, old_dentry, S_IFCHR | WHITEOUT_MODE, &whiteout);
if (err) { if (err) {
ubifs_release_budget(c, &req);
ubifs_release_budget(c, &ino_req);
kfree(dev); kfree(dev);
return err; goto out_release;
} }
whiteout->i_state |= I_LINKABLE; whiteout->i_state |= I_LINKABLE;
...@@ -1494,12 +1492,10 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1494,12 +1492,10 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
err = ubifs_budget_space(c, &wht_req); err = ubifs_budget_space(c, &wht_req);
if (err) { if (err) {
ubifs_release_budget(c, &req);
ubifs_release_budget(c, &ino_req);
kfree(whiteout_ui->data); kfree(whiteout_ui->data);
whiteout_ui->data_len = 0; whiteout_ui->data_len = 0;
iput(whiteout); iput(whiteout);
return err; goto out_release;
} }
inc_nlink(whiteout); inc_nlink(whiteout);
...@@ -1554,6 +1550,7 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1554,6 +1550,7 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
iput(whiteout); iput(whiteout);
} }
unlock_4_inodes(old_dir, new_dir, new_inode, whiteout); unlock_4_inodes(old_dir, new_dir, new_inode, whiteout);
out_release:
ubifs_release_budget(c, &ino_req); ubifs_release_budget(c, &ino_req);
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
fscrypt_free_filename(&old_nm); fscrypt_free_filename(&old_nm);
...@@ -1647,6 +1644,21 @@ int ubifs_getattr(const struct path *path, struct kstat *stat, ...@@ -1647,6 +1644,21 @@ int ubifs_getattr(const struct path *path, struct kstat *stat,
struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_inode *ui = ubifs_inode(inode);
mutex_lock(&ui->ui_mutex); mutex_lock(&ui->ui_mutex);
if (ui->flags & UBIFS_APPEND_FL)
stat->attributes |= STATX_ATTR_APPEND;
if (ui->flags & UBIFS_COMPR_FL)
stat->attributes |= STATX_ATTR_COMPRESSED;
if (ui->flags & UBIFS_CRYPT_FL)
stat->attributes |= STATX_ATTR_ENCRYPTED;
if (ui->flags & UBIFS_IMMUTABLE_FL)
stat->attributes |= STATX_ATTR_IMMUTABLE;
stat->attributes_mask |= (STATX_ATTR_APPEND |
STATX_ATTR_COMPRESSED |
STATX_ATTR_ENCRYPTED |
STATX_ATTR_IMMUTABLE);
generic_fillattr(inode, stat); generic_fillattr(inode, stat);
stat->blksize = UBIFS_BLOCK_SIZE; stat->blksize = UBIFS_BLOCK_SIZE;
stat->size = ui->ui_size; stat->size = ui->ui_size;
......
...@@ -735,6 +735,7 @@ static int ubifs_do_bulk_read(struct ubifs_info *c, struct bu_info *bu, ...@@ -735,6 +735,7 @@ static int ubifs_do_bulk_read(struct ubifs_info *c, struct bu_info *bu,
int err, page_idx, page_cnt, ret = 0, n = 0; int err, page_idx, page_cnt, ret = 0, n = 0;
int allocate = bu->buf ? 0 : 1; int allocate = bu->buf ? 0 : 1;
loff_t isize; loff_t isize;
gfp_t ra_gfp_mask = readahead_gfp_mask(mapping) & ~__GFP_FS;
err = ubifs_tnc_get_bu_keys(c, bu); err = ubifs_tnc_get_bu_keys(c, bu);
if (err) if (err)
...@@ -796,8 +797,7 @@ static int ubifs_do_bulk_read(struct ubifs_info *c, struct bu_info *bu, ...@@ -796,8 +797,7 @@ static int ubifs_do_bulk_read(struct ubifs_info *c, struct bu_info *bu,
if (page_offset > end_index) if (page_offset > end_index)
break; break;
page = find_or_create_page(mapping, page_offset, page = find_or_create_page(mapping, page_offset, ra_gfp_mask);
GFP_NOFS | __GFP_COLD);
if (!page) if (!page)
break; break;
if (!PageUptodate(page)) if (!PageUptodate(page))
...@@ -1284,6 +1284,14 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -1284,6 +1284,14 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr)
if (err) if (err)
return err; return err;
if (ubifs_crypt_is_encrypted(inode) && (attr->ia_valid & ATTR_SIZE)) {
err = fscrypt_get_encryption_info(inode);
if (err)
return err;
if (!fscrypt_has_encryption_key(inode))
return -ENOKEY;
}
if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size < inode->i_size) if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size < inode->i_size)
/* Truncation to a smaller size */ /* Truncation to a smaller size */
err = do_truncation(c, inode, attr); err = do_truncation(c, inode, attr);
...@@ -1607,15 +1615,6 @@ static const struct vm_operations_struct ubifs_file_vm_ops = { ...@@ -1607,15 +1615,6 @@ static const struct vm_operations_struct ubifs_file_vm_ops = {
static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma) static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
{ {
int err; int err;
struct inode *inode = file->f_mapping->host;
if (ubifs_crypt_is_encrypted(inode)) {
err = fscrypt_get_encryption_info(inode);
if (err)
return -EACCES;
if (!fscrypt_has_encryption_key(inode))
return -ENOKEY;
}
err = generic_file_mmap(file, vma); err = generic_file_mmap(file, vma);
if (err) if (err)
...@@ -1698,12 +1697,6 @@ static const char *ubifs_get_link(struct dentry *dentry, ...@@ -1698,12 +1697,6 @@ static const char *ubifs_get_link(struct dentry *dentry,
pstr.name[pstr.len] = '\0'; pstr.name[pstr.len] = '\0';
// XXX this probably won't happen anymore...
if (pstr.name[0] == '\0') {
fscrypt_fname_free_buffer(&pstr);
return ERR_PTR(-ENOENT);
}
set_delayed_call(done, kfree_link, pstr.name); set_delayed_call(done, kfree_link, pstr.name);
return pstr.name; return pstr.name;
} }
......
...@@ -549,8 +549,6 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, ...@@ -549,8 +549,6 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
struct ubifs_ino_node *ino; struct ubifs_ino_node *ino;
union ubifs_key dent_key, ino_key; union ubifs_key dent_key, ino_key;
//dbg_jnl("ino %lu, dent '%.*s', data len %d in dir ino %lu",
// inode->i_ino, nm->len, nm->name, ui->data_len, dir->i_ino);
ubifs_assert(mutex_is_locked(&host_ui->ui_mutex)); ubifs_assert(mutex_is_locked(&host_ui->ui_mutex));
dlen = UBIFS_DENT_NODE_SZ + fname_len(nm) + 1; dlen = UBIFS_DENT_NODE_SZ + fname_len(nm) + 1;
...@@ -574,7 +572,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, ...@@ -574,7 +572,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
/* Make sure to also account for extended attributes */ /* Make sure to also account for extended attributes */
len += host_ui->data_len; len += host_ui->data_len;
dent = kmalloc(len, GFP_NOFS); dent = kzalloc(len, GFP_NOFS);
if (!dent) if (!dent)
return -ENOMEM; return -ENOMEM;
...@@ -585,6 +583,9 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, ...@@ -585,6 +583,9 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
if (!xent) { if (!xent) {
dent->ch.node_type = UBIFS_DENT_NODE; dent->ch.node_type = UBIFS_DENT_NODE;
if (nm->hash)
dent_key_init_hash(c, &dent_key, dir->i_ino, nm->hash);
else
dent_key_init(c, &dent_key, dir->i_ino, nm); dent_key_init(c, &dent_key, dir->i_ino, nm);
} else { } else {
dent->ch.node_type = UBIFS_XENT_NODE; dent->ch.node_type = UBIFS_XENT_NODE;
...@@ -629,6 +630,9 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, ...@@ -629,6 +630,9 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
kfree(dent); kfree(dent);
if (deletion) { if (deletion) {
if (nm->hash)
err = ubifs_tnc_remove_dh(c, &dent_key, nm->minor_hash);
else
err = ubifs_tnc_remove_nm(c, &dent_key, nm); err = ubifs_tnc_remove_nm(c, &dent_key, nm);
if (err) if (err)
goto out_ro; goto out_ro;
...@@ -950,9 +954,6 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir, ...@@ -950,9 +954,6 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
int twoparents = (fst_dir != snd_dir); int twoparents = (fst_dir != snd_dir);
void *p; void *p;
//dbg_jnl("dent '%pd' in dir ino %lu between dent '%pd' in dir ino %lu",
// fst_dentry, fst_dir->i_ino, snd_dentry, snd_dir->i_ino);
ubifs_assert(ubifs_inode(fst_dir)->data_len == 0); ubifs_assert(ubifs_inode(fst_dir)->data_len == 0);
ubifs_assert(ubifs_inode(snd_dir)->data_len == 0); ubifs_assert(ubifs_inode(snd_dir)->data_len == 0);
ubifs_assert(mutex_is_locked(&ubifs_inode(fst_dir)->ui_mutex)); ubifs_assert(mutex_is_locked(&ubifs_inode(fst_dir)->ui_mutex));
...@@ -967,7 +968,7 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir, ...@@ -967,7 +968,7 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
if (twoparents) if (twoparents)
len += plen; len += plen;
dent1 = kmalloc(len, GFP_NOFS); dent1 = kzalloc(len, GFP_NOFS);
if (!dent1) if (!dent1)
return -ENOMEM; return -ENOMEM;
...@@ -984,6 +985,7 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir, ...@@ -984,6 +985,7 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
dent1->nlen = cpu_to_le16(fname_len(snd_nm)); dent1->nlen = cpu_to_le16(fname_len(snd_nm));
memcpy(dent1->name, fname_name(snd_nm), fname_len(snd_nm)); memcpy(dent1->name, fname_name(snd_nm), fname_len(snd_nm));
dent1->name[fname_len(snd_nm)] = '\0'; dent1->name[fname_len(snd_nm)] = '\0';
set_dent_cookie(c, dent1);
zero_dent_node_unused(dent1); zero_dent_node_unused(dent1);
ubifs_prep_grp_node(c, dent1, dlen1, 0); ubifs_prep_grp_node(c, dent1, dlen1, 0);
...@@ -996,6 +998,7 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir, ...@@ -996,6 +998,7 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
dent2->nlen = cpu_to_le16(fname_len(fst_nm)); dent2->nlen = cpu_to_le16(fname_len(fst_nm));
memcpy(dent2->name, fname_name(fst_nm), fname_len(fst_nm)); memcpy(dent2->name, fname_name(fst_nm), fname_len(fst_nm));
dent2->name[fname_len(fst_nm)] = '\0'; dent2->name[fname_len(fst_nm)] = '\0';
set_dent_cookie(c, dent2);
zero_dent_node_unused(dent2); zero_dent_node_unused(dent2);
ubifs_prep_grp_node(c, dent2, dlen2, 0); ubifs_prep_grp_node(c, dent2, dlen2, 0);
...@@ -1094,8 +1097,6 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, ...@@ -1094,8 +1097,6 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
int move = (old_dir != new_dir); int move = (old_dir != new_dir);
struct ubifs_inode *uninitialized_var(new_ui); struct ubifs_inode *uninitialized_var(new_ui);
//dbg_jnl("dent '%pd' in dir ino %lu to dent '%pd' in dir ino %lu",
// old_dentry, old_dir->i_ino, new_dentry, new_dir->i_ino);
ubifs_assert(ubifs_inode(old_dir)->data_len == 0); ubifs_assert(ubifs_inode(old_dir)->data_len == 0);
ubifs_assert(ubifs_inode(new_dir)->data_len == 0); ubifs_assert(ubifs_inode(new_dir)->data_len == 0);
ubifs_assert(mutex_is_locked(&ubifs_inode(old_dir)->ui_mutex)); ubifs_assert(mutex_is_locked(&ubifs_inode(old_dir)->ui_mutex));
...@@ -1117,7 +1118,7 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, ...@@ -1117,7 +1118,7 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
len = aligned_dlen1 + aligned_dlen2 + ALIGN(ilen, 8) + ALIGN(plen, 8); len = aligned_dlen1 + aligned_dlen2 + ALIGN(ilen, 8) + ALIGN(plen, 8);
if (move) if (move)
len += plen; len += plen;
dent = kmalloc(len, GFP_NOFS); dent = kzalloc(len, GFP_NOFS);
if (!dent) if (!dent)
return -ENOMEM; return -ENOMEM;
...@@ -1298,7 +1299,9 @@ static int truncate_data_node(const struct ubifs_info *c, const struct inode *in ...@@ -1298,7 +1299,9 @@ static int truncate_data_node(const struct ubifs_info *c, const struct inode *in
goto out; goto out;
} }
if (compr_type != UBIFS_COMPR_NONE) { if (compr_type == UBIFS_COMPR_NONE) {
out_len = *new_len;
} else {
err = ubifs_decompress(c, &dn->data, dlen, buf, &out_len, compr_type); err = ubifs_decompress(c, &dn->data, dlen, buf, &out_len, compr_type);
if (err) if (err)
goto out; goto out;
...@@ -1485,9 +1488,6 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host, ...@@ -1485,9 +1488,6 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
int sync = IS_DIRSYNC(host); int sync = IS_DIRSYNC(host);
struct ubifs_inode *host_ui = ubifs_inode(host); struct ubifs_inode *host_ui = ubifs_inode(host);
//dbg_jnl("host %lu, xattr ino %lu, name '%s', data len %d",
// host->i_ino, inode->i_ino, nm->name,
// ubifs_inode(inode)->data_len);
ubifs_assert(inode->i_nlink == 0); ubifs_assert(inode->i_nlink == 0);
ubifs_assert(mutex_is_locked(&host_ui->ui_mutex)); ubifs_assert(mutex_is_locked(&host_ui->ui_mutex));
...@@ -1500,7 +1500,7 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host, ...@@ -1500,7 +1500,7 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
hlen = host_ui->data_len + UBIFS_INO_NODE_SZ; hlen = host_ui->data_len + UBIFS_INO_NODE_SZ;
len = aligned_xlen + UBIFS_INO_NODE_SZ + ALIGN(hlen, 8); len = aligned_xlen + UBIFS_INO_NODE_SZ + ALIGN(hlen, 8);
xent = kmalloc(len, GFP_NOFS); xent = kzalloc(len, GFP_NOFS);
if (!xent) if (!xent)
return -ENOMEM; return -ENOMEM;
...@@ -1607,7 +1607,7 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode, ...@@ -1607,7 +1607,7 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode,
aligned_len1 = ALIGN(len1, 8); aligned_len1 = ALIGN(len1, 8);
aligned_len = aligned_len1 + ALIGN(len2, 8); aligned_len = aligned_len1 + ALIGN(len2, 8);
ino = kmalloc(aligned_len, GFP_NOFS); ino = kzalloc(aligned_len, GFP_NOFS);
if (!ino) if (!ino)
return -ENOMEM; return -ENOMEM;
......
...@@ -162,6 +162,7 @@ static inline void dent_key_init(const struct ubifs_info *c, ...@@ -162,6 +162,7 @@ static inline void dent_key_init(const struct ubifs_info *c,
uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm)); uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm));
ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK)); ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
ubifs_assert(!nm->hash && !nm->minor_hash);
key->u32[0] = inum; key->u32[0] = inum;
key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS); key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS);
} }
......
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
#define UBIFS_KMALLOC_OK (128*1024) #define UBIFS_KMALLOC_OK (128*1024)
/* Slab cache for UBIFS inodes */ /* Slab cache for UBIFS inodes */
struct kmem_cache *ubifs_inode_slab; static struct kmem_cache *ubifs_inode_slab;
/* UBIFS TNC shrinker description */ /* UBIFS TNC shrinker description */
static struct shrinker ubifs_shrinker_info = { static struct shrinker ubifs_shrinker_info = {
...@@ -446,6 +446,8 @@ static int ubifs_show_options(struct seq_file *s, struct dentry *root) ...@@ -446,6 +446,8 @@ static int ubifs_show_options(struct seq_file *s, struct dentry *root)
ubifs_compr_name(c->mount_opts.compr_type)); ubifs_compr_name(c->mount_opts.compr_type));
} }
seq_printf(s, ",ubi=%d,vol=%d", c->vi.ubi_num, c->vi.vol_id);
return 0; return 0;
} }
...@@ -931,6 +933,7 @@ enum { ...@@ -931,6 +933,7 @@ enum {
Opt_chk_data_crc, Opt_chk_data_crc,
Opt_no_chk_data_crc, Opt_no_chk_data_crc,
Opt_override_compr, Opt_override_compr,
Opt_ignore,
Opt_err, Opt_err,
}; };
...@@ -942,6 +945,8 @@ static const match_table_t tokens = { ...@@ -942,6 +945,8 @@ static const match_table_t tokens = {
{Opt_chk_data_crc, "chk_data_crc"}, {Opt_chk_data_crc, "chk_data_crc"},
{Opt_no_chk_data_crc, "no_chk_data_crc"}, {Opt_no_chk_data_crc, "no_chk_data_crc"},
{Opt_override_compr, "compr=%s"}, {Opt_override_compr, "compr=%s"},
{Opt_ignore, "ubi=%s"},
{Opt_ignore, "vol=%s"},
{Opt_err, NULL}, {Opt_err, NULL},
}; };
...@@ -1042,6 +1047,8 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options, ...@@ -1042,6 +1047,8 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
c->default_compr = c->mount_opts.compr_type; c->default_compr = c->mount_opts.compr_type;
break; break;
} }
case Opt_ignore:
break;
default: default:
{ {
unsigned long flag; unsigned long flag;
...@@ -1869,8 +1876,10 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) ...@@ -1869,8 +1876,10 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
bu_init(c); bu_init(c);
else { else {
dbg_gen("disable bulk-read"); dbg_gen("disable bulk-read");
mutex_lock(&c->bu_mutex);
kfree(c->bu.buf); kfree(c->bu.buf);
c->bu.buf = NULL; c->bu.buf = NULL;
mutex_unlock(&c->bu_mutex);
} }
ubifs_assert(c->lst.taken_empty_lebs > 0); ubifs_assert(c->lst.taken_empty_lebs > 0);
......
...@@ -1812,7 +1812,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, ...@@ -1812,7 +1812,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
int found, n, err; int found, n, err;
struct ubifs_znode *znode; struct ubifs_znode *znode;
//dbg_tnck(key, "name '%.*s' key ", nm->len, nm->name); dbg_tnck(key, "key ");
mutex_lock(&c->tnc_mutex); mutex_lock(&c->tnc_mutex);
found = ubifs_lookup_level0(c, key, &znode, &n); found = ubifs_lookup_level0(c, key, &znode, &n);
if (!found) { if (!found) {
...@@ -1880,47 +1880,64 @@ int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, ...@@ -1880,47 +1880,64 @@ int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
return do_lookup_nm(c, key, node, nm); return do_lookup_nm(c, key, node, nm);
} }
static int do_lookup_dh(struct ubifs_info *c, const union ubifs_key *key, static int search_dh_cookie(struct ubifs_info *c, const union ubifs_key *key,
struct ubifs_dent_node *dent, uint32_t cookie) struct ubifs_dent_node *dent, uint32_t cookie,
struct ubifs_znode **zn, int *n)
{ {
int n, err, type = key_type(c, key); int err;
struct ubifs_znode *znode; struct ubifs_znode *znode = *zn;
struct ubifs_zbranch *zbr; struct ubifs_zbranch *zbr;
union ubifs_key *dkey, start_key; union ubifs_key *dkey;
ubifs_assert(is_hash_key(c, key));
lowest_dent_key(c, &start_key, key_inum(c, key));
mutex_lock(&c->tnc_mutex);
err = ubifs_lookup_level0(c, &start_key, &znode, &n);
if (unlikely(err < 0))
goto out_unlock;
for (;;) { for (;;) {
if (!err) { if (!err) {
err = tnc_next(c, &znode, &n); err = tnc_next(c, &znode, n);
if (err) if (err)
goto out_unlock; goto out;
} }
zbr = &znode->zbranch[n]; zbr = &znode->zbranch[*n];
dkey = &zbr->key; dkey = &zbr->key;
if (key_inum(c, dkey) != key_inum(c, key) || if (key_inum(c, dkey) != key_inum(c, key) ||
key_type(c, dkey) != type) { key_type(c, dkey) != key_type(c, key)) {
err = -ENOENT; err = -ENOENT;
goto out_unlock; goto out;
} }
err = tnc_read_hashed_node(c, zbr, dent); err = tnc_read_hashed_node(c, zbr, dent);
if (err) if (err)
goto out_unlock; goto out;
if (key_hash(c, key) == key_hash(c, dkey) && if (key_hash(c, key) == key_hash(c, dkey) &&
le32_to_cpu(dent->cookie) == cookie) le32_to_cpu(dent->cookie) == cookie) {
goto out_unlock; *zn = znode;
goto out;
} }
}
out:
return err;
}
static int do_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
struct ubifs_dent_node *dent, uint32_t cookie)
{
int n, err;
struct ubifs_znode *znode;
union ubifs_key start_key;
ubifs_assert(is_hash_key(c, key));
lowest_dent_key(c, &start_key, key_inum(c, key));
mutex_lock(&c->tnc_mutex);
err = ubifs_lookup_level0(c, &start_key, &znode, &n);
if (unlikely(err < 0))
goto out_unlock;
err = search_dh_cookie(c, key, dent, cookie, &znode, &n);
out_unlock: out_unlock:
mutex_unlock(&c->tnc_mutex); mutex_unlock(&c->tnc_mutex);
...@@ -2393,8 +2410,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key, ...@@ -2393,8 +2410,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
struct ubifs_znode *znode; struct ubifs_znode *znode;
mutex_lock(&c->tnc_mutex); mutex_lock(&c->tnc_mutex);
//dbg_tnck(key, "LEB %d:%d, name '%.*s', key ", dbg_tnck(key, "LEB %d:%d, key ", lnum, offs);
// lnum, offs, nm->len, nm->name);
found = lookup_level0_dirty(c, key, &znode, &n); found = lookup_level0_dirty(c, key, &znode, &n);
if (found < 0) { if (found < 0) {
err = found; err = found;
...@@ -2628,7 +2644,7 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key, ...@@ -2628,7 +2644,7 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
struct ubifs_znode *znode; struct ubifs_znode *znode;
mutex_lock(&c->tnc_mutex); mutex_lock(&c->tnc_mutex);
//dbg_tnck(key, "%.*s, key ", nm->len, nm->name); dbg_tnck(key, "key ");
err = lookup_level0_dirty(c, key, &znode, &n); err = lookup_level0_dirty(c, key, &znode, &n);
if (err < 0) if (err < 0)
goto out_unlock; goto out_unlock;
...@@ -2662,6 +2678,74 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key, ...@@ -2662,6 +2678,74 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
return err; return err;
} }
/**
* ubifs_tnc_remove_dh - remove an index entry for a "double hashed" node.
* @c: UBIFS file-system description object
* @key: key of node
* @cookie: node cookie for collision resolution
*
* Returns %0 on success or negative error code on failure.
*/
int ubifs_tnc_remove_dh(struct ubifs_info *c, const union ubifs_key *key,
uint32_t cookie)
{
int n, err;
struct ubifs_znode *znode;
struct ubifs_dent_node *dent;
struct ubifs_zbranch *zbr;
if (!c->double_hash)
return -EOPNOTSUPP;
mutex_lock(&c->tnc_mutex);
err = lookup_level0_dirty(c, key, &znode, &n);
if (err <= 0)
goto out_unlock;
zbr = &znode->zbranch[n];
dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
if (!dent) {
err = -ENOMEM;
goto out_unlock;
}
err = tnc_read_hashed_node(c, zbr, dent);
if (err)
goto out_free;
/* If the cookie does not match, we're facing a hash collision. */
if (le32_to_cpu(dent->cookie) != cookie) {
union ubifs_key start_key;
lowest_dent_key(c, &start_key, key_inum(c, key));
err = ubifs_lookup_level0(c, &start_key, &znode, &n);
if (unlikely(err < 0))
goto out_free;
err = search_dh_cookie(c, key, dent, cookie, &znode, &n);
if (err)
goto out_free;
}
if (znode->cnext || !ubifs_zn_dirty(znode)) {
znode = dirty_cow_bottom_up(c, znode);
if (IS_ERR(znode)) {
err = PTR_ERR(znode);
goto out_free;
}
}
err = tnc_delete(c, znode, n);
out_free:
kfree(dent);
out_unlock:
if (!err)
err = dbg_check_tnc(c, 0);
mutex_unlock(&c->tnc_mutex);
return err;
}
/** /**
* key_in_range - determine if a key falls within a range of keys. * key_in_range - determine if a key falls within a range of keys.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
...@@ -2802,6 +2886,8 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum) ...@@ -2802,6 +2886,8 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
dbg_tnc("xent '%s', ino %lu", xent->name, dbg_tnc("xent '%s', ino %lu", xent->name,
(unsigned long)xattr_inum); (unsigned long)xattr_inum);
ubifs_evict_xattr_inode(c, xattr_inum);
fname_name(&nm) = xent->name; fname_name(&nm) = xent->name;
fname_len(&nm) = le16_to_cpu(xent->nlen); fname_len(&nm) = le16_to_cpu(xent->nlen);
err = ubifs_tnc_remove_nm(c, &key1, &nm); err = ubifs_tnc_remove_nm(c, &key1, &nm);
...@@ -2863,7 +2949,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c, ...@@ -2863,7 +2949,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
struct ubifs_zbranch *zbr; struct ubifs_zbranch *zbr;
union ubifs_key *dkey; union ubifs_key *dkey;
//dbg_tnck(key, "%s ", nm->name ? (char *)nm->name : "(lowest)"); dbg_tnck(key, "key ");
ubifs_assert(is_hash_key(c, key)); ubifs_assert(is_hash_key(c, key));
mutex_lock(&c->tnc_mutex); mutex_lock(&c->tnc_mutex);
......
...@@ -57,6 +57,8 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx, ...@@ -57,6 +57,8 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
ubifs_dump_znode(c, znode); ubifs_dump_znode(c, znode);
if (zbr->znode) if (zbr->znode)
ubifs_dump_znode(c, zbr->znode); ubifs_dump_znode(c, zbr->znode);
return -EINVAL;
} }
} }
ubifs_prepare_node(c, idx, len, 0); ubifs_prepare_node(c, idx, len, 0);
...@@ -859,6 +861,8 @@ static int write_index(struct ubifs_info *c) ...@@ -859,6 +861,8 @@ static int write_index(struct ubifs_info *c)
ubifs_dump_znode(c, znode); ubifs_dump_znode(c, znode);
if (zbr->znode) if (zbr->znode)
ubifs_dump_znode(c, zbr->znode); ubifs_dump_znode(c, zbr->znode);
return -EINVAL;
} }
} }
len = ubifs_idx_node_sz(c, znode->child_cnt); len = ubifs_idx_node_sz(c, znode->child_cnt);
......
...@@ -1451,7 +1451,6 @@ struct ubifs_info { ...@@ -1451,7 +1451,6 @@ struct ubifs_info {
extern struct list_head ubifs_infos; extern struct list_head ubifs_infos;
extern spinlock_t ubifs_infos_lock; extern spinlock_t ubifs_infos_lock;
extern atomic_long_t ubifs_clean_zn_cnt; extern atomic_long_t ubifs_clean_zn_cnt;
extern struct kmem_cache *ubifs_inode_slab;
extern const struct super_operations ubifs_super_operations; extern const struct super_operations ubifs_super_operations;
extern const struct address_space_operations ubifs_file_address_operations; extern const struct address_space_operations ubifs_file_address_operations;
extern const struct file_operations ubifs_file_operations; extern const struct file_operations ubifs_file_operations;
...@@ -1590,6 +1589,8 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key, ...@@ -1590,6 +1589,8 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key); int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key);
int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key, int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
const struct fscrypt_name *nm); const struct fscrypt_name *nm);
int ubifs_tnc_remove_dh(struct ubifs_info *c, const union ubifs_key *key,
uint32_t cookie);
int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key, int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
union ubifs_key *to_key); union ubifs_key *to_key);
int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum); int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum);
...@@ -1754,9 +1755,10 @@ int ubifs_check_dir_empty(struct inode *dir); ...@@ -1754,9 +1755,10 @@ int ubifs_check_dir_empty(struct inode *dir);
extern const struct xattr_handler *ubifs_xattr_handlers[]; extern const struct xattr_handler *ubifs_xattr_handlers[];
ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size); ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
int ubifs_xattr_set(struct inode *host, const char *name, const void *value, int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
size_t size, int flags); 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);
void ubifs_evict_xattr_inode(struct ubifs_info *c, ino_t xattr_inum);
#ifdef CONFIG_UBIFS_FS_SECURITY #ifdef CONFIG_UBIFS_FS_SECURITY
extern int ubifs_init_security(struct inode *dentry, struct inode *inode, extern int ubifs_init_security(struct inode *dentry, struct inode *inode,
......
...@@ -280,7 +280,7 @@ static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum) ...@@ -280,7 +280,7 @@ static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum)
} }
int ubifs_xattr_set(struct inode *host, const char *name, const void *value, int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
size_t size, int flags) size_t size, int flags, bool check_lock)
{ {
struct inode *inode; struct inode *inode;
struct ubifs_info *c = host->i_sb->s_fs_info; struct ubifs_info *c = host->i_sb->s_fs_info;
...@@ -289,12 +289,7 @@ int ubifs_xattr_set(struct inode *host, const char *name, const void *value, ...@@ -289,12 +289,7 @@ int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
union ubifs_key key; union ubifs_key key;
int err; int err;
/* if (check_lock)
* Creating an encryption context is done unlocked since we
* operate on a new inode which is not visible to other users
* at this point.
*/
if (strcmp(name, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) != 0)
ubifs_assert(inode_is_locked(host)); ubifs_assert(inode_is_locked(host));
if (size > UBIFS_MAX_INO_DATA) if (size > UBIFS_MAX_INO_DATA)
...@@ -513,6 +508,28 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host, ...@@ -513,6 +508,28 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host,
return err; return err;
} }
/**
* ubifs_evict_xattr_inode - Evict an xattr inode.
* @c: UBIFS file-system description object
* @xattr_inum: xattr inode number
*
* When an inode that hosts xattrs is being removed we have to make sure
* that cached inodes of the xattrs also get removed from the inode cache
* otherwise we'd waste memory. This function looks up an inode from the
* inode cache and clears the link counter such that iput() will evict
* the inode.
*/
void ubifs_evict_xattr_inode(struct ubifs_info *c, ino_t xattr_inum)
{
struct inode *inode;
inode = ilookup(c->vfs_sb, xattr_inum);
if (inode) {
clear_nlink(inode);
iput(inode);
}
}
static int ubifs_xattr_remove(struct inode *host, const char *name) static int ubifs_xattr_remove(struct inode *host, const char *name)
{ {
struct inode *inode; struct inode *inode;
...@@ -576,8 +593,12 @@ static int init_xattrs(struct inode *inode, const struct xattr *xattr_array, ...@@ -576,8 +593,12 @@ static int init_xattrs(struct inode *inode, const struct xattr *xattr_array,
} }
strcpy(name, XATTR_SECURITY_PREFIX); strcpy(name, XATTR_SECURITY_PREFIX);
strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name); strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name);
/*
* creating a new inode without holding the inode rwsem,
* no need to check whether inode is locked.
*/
err = ubifs_xattr_set(inode, name, xattr->value, err = ubifs_xattr_set(inode, name, xattr->value,
xattr->value_len, 0); xattr->value_len, 0, false);
kfree(name); kfree(name);
if (err < 0) if (err < 0)
break; break;
...@@ -624,7 +645,7 @@ static int xattr_set(const struct xattr_handler *handler, ...@@ -624,7 +645,7 @@ static int xattr_set(const struct xattr_handler *handler,
name = xattr_full_name(handler, name); name = xattr_full_name(handler, name);
if (value) if (value)
return ubifs_xattr_set(inode, name, value, size, flags); return ubifs_xattr_set(inode, name, value, size, flags, true);
else else
return ubifs_xattr_remove(inode, name); return ubifs_xattr_remove(inode, name);
} }
......
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