Commit caffe745 authored by Richard Weinberger's avatar Richard Weinberger Committed by Greg Kroah-Hartman

ubifs: Correctly evict xattr inodes

commit 272eda82 upstream.

UBIFS handles extended attributes just like files, as consequence of
that, they also have inodes.
Therefore UBIFS does all the inode machinery also for xattrs. Since new
inodes have i_nlink of 1, a file or xattr inode will be evicted
if i_nlink goes down to 0 after an unlink. UBIFS assumes this model also
for xattrs, which is not correct.
One can create a file "foo" with xattr "user.test". By reading
"user.test" an inode will be created, and by deleting "user.test" it
will get evicted later. The assumption breaks if the file "foo", which
hosts the xattrs, will be removed. VFS nor UBIFS does not remove each
xattr via ubifs_xattr_remove(), it just removes the host inode from
the TNC and all underlying xattr nodes too and the inode will remain
in the cache and wastes memory.

To solve this problem, remove xattr inodes from the VFS inode cache in
ubifs_xattr_remove() to make sure that they get evicted.

Fixes: 1e51764a ("UBIFS: add new flash file system")
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 012e56c5
...@@ -2802,6 +2802,8 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum) ...@@ -2802,6 +2802,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);
......
...@@ -1757,6 +1757,7 @@ int ubifs_xattr_set(struct inode *host, const char *name, const void *value, ...@@ -1757,6 +1757,7 @@ int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
size_t size, int flags); size_t size, int flags);
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,
......
...@@ -513,6 +513,28 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host, ...@@ -513,6 +513,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;
......
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