Skip to content

Commit

Permalink
ubifs: journal: Handle xattrs like files
Browse files Browse the repository at this point in the history
If an inode hosts xattrs, create deletion entries for each
inode. That way we can make sure that upon journal replay UBIFS
can find find all xattr inodes.
Otherwise it can happen that GC consumed already a LEB which contained
parts of the TNC that pointed to the xattrs and we no longer
find all xattr inodes, which will confuse the LPT and cause
space allocation issues.

Reported-by: Stefan Agner <[email protected]>
Fixes: 1e51764 ("UBIFS: add new flash file system")
Signed-off-by: Richard Weinberger <[email protected]>
  • Loading branch information
richardweinberger committed May 7, 2019
1 parent 257bb92 commit 7959cf3
Showing 1 changed file with 49 additions and 11 deletions.
60 changes: 49 additions & 11 deletions fs/ubifs/journal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 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);
Expand All @@ -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;

Expand All @@ -883,12 +886,47 @@ 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;

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);
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)
Expand All @@ -903,7 +941,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;

Expand All @@ -917,7 +955,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:
Expand All @@ -926,7 +964,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
ubifs_ro_mode(c, err);
finish_reservation(c);
out_free:
kfree(ino);
kfree(ino_start);
return err;
}

Expand Down Expand Up @@ -966,8 +1004,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);
Expand Down

0 comments on commit 7959cf3

Please sign in to comment.