]> git.hungrycats.org Git - linux/commitdiff
ubifs: Correctly evict xattr inodes
authorRichard Weinberger <richard@nod.at>
Tue, 16 May 2017 22:20:27 +0000 (00:20 +0200)
committerBen Hutchings <ben@decadent.org.uk>
Thu, 12 Oct 2017 14:27:16 +0000 (15:27 +0100)
commit 272eda8298dc82eb411ece82bbb2c62911087b24 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: 1e51764a3c2ac05a ("UBIFS: add new flash file system")
Signed-off-by: Richard Weinberger <richard@nod.at>
[bwh: Backported to 3.2:
 - xattr support is optional, so add an #ifdef around the call
 - Adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
fs/ubifs/tnc.c
fs/ubifs/ubifs.h
fs/ubifs/xattr.c

index f996cb52442b55c4d3301f1331fd6e9d98b95fb6..e1498cc5cc8d275e8632b7ae184ab455ebd6064b 100644 (file)
@@ -2730,6 +2730,10 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
                dbg_tnc("xent '%s', ino %lu", xent->name,
                        (unsigned long)xattr_inum);
 
+#ifdef CONFIG_UBIFS_FS_XATTR
+               ubifs_evict_xattr_inode(c, xattr_inum);
+#endif
+
                nm.name = xent->name;
                nm.len = le16_to_cpu(xent->nlen);
                err = ubifs_tnc_remove_nm(c, &key1, &nm);
index 223dd4294d06bc821c4d9860789e12088de6ba21..30a9b5cf37295bfb7e74822e927d9b3afc1d73a0 100644 (file)
@@ -1748,6 +1748,7 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
                       size_t size);
 ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
 int ubifs_removexattr(struct dentry *dentry, const char *name);
+void ubifs_evict_xattr_inode(struct ubifs_info *c, ino_t xattr_inum);
 
 /* super.c */
 struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
index 28b7ebf5d0d93b9060394d2e6a2caa44fbbdc621..3962fa3be94802c8b8a0fb1e442a35315d5c7900 100644 (file)
@@ -483,6 +483,28 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
        return written;
 }
 
+/**
+ * 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 remove_xattr(struct ubifs_info *c, struct inode *host,
                        struct inode *inode, const struct qstr *nm)
 {