get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/811897/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 811897,
    "url": "http://patchwork.ozlabs.org/api/patches/811897/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/ubuntu-kernel/patch/20170909002556.23382-3-cascardo@canonical.com/",
    "project": {
        "id": 15,
        "url": "http://patchwork.ozlabs.org/api/projects/15/?format=api",
        "name": "Ubuntu Kernel",
        "link_name": "ubuntu-kernel",
        "list_id": "kernel-team.lists.ubuntu.com",
        "list_email": "kernel-team@lists.ubuntu.com",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20170909002556.23382-3-cascardo@canonical.com>",
    "list_archive_url": null,
    "date": "2017-09-09T00:25:55",
    "name": "[xenial,CVE-2015-8952,2/3] ext2: convert to mbcache2",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "a91287f2db24f2926eccbbf02841aa32462e213c",
    "submitter": {
        "id": 70574,
        "url": "http://patchwork.ozlabs.org/api/people/70574/?format=api",
        "name": "Thadeu Lima de Souza Cascardo",
        "email": "cascardo@canonical.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/ubuntu-kernel/patch/20170909002556.23382-3-cascardo@canonical.com/mbox/",
    "series": [
        {
            "id": 2317,
            "url": "http://patchwork.ozlabs.org/api/series/2317/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/ubuntu-kernel/list/?series=2317",
            "date": "2017-09-09T00:25:53",
            "name": "replace mbcache with mbcache2 for ext2/ext4",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/2317/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/811897/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/811897/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<kernel-team-bounces@lists.ubuntu.com>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org",
        "Authentication-Results": "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=lists.ubuntu.com\n\t(client-ip=91.189.94.19; helo=huckleberry.canonical.com;\n\tenvelope-from=kernel-team-bounces@lists.ubuntu.com;\n\treceiver=<UNKNOWN>)",
        "Received": [
            "from huckleberry.canonical.com (huckleberry.canonical.com\n\t[91.189.94.19])\n\tby ozlabs.org (Postfix) with ESMTP id 3xpw4x0pDzz9t2c;\n\tSat,  9 Sep 2017 10:27:45 +1000 (AEST)",
            "from localhost ([127.0.0.1] helo=huckleberry.canonical.com)\n\tby huckleberry.canonical.com with esmtp (Exim 4.86_2)\n\t(envelope-from <kernel-team-bounces@lists.ubuntu.com>)\n\tid 1dqTcc-0004kn-52; Sat, 09 Sep 2017 00:27:42 +0000",
            "from youngberry.canonical.com ([91.189.89.112])\n\tby huckleberry.canonical.com with esmtps\n\t(TLS1.0:DHE_RSA_AES_128_CBC_SHA1:128)\n\t(Exim 4.86_2) (envelope-from <cascardo@canonical.com>)\n\tid 1dqTcY-0004j4-CI\n\tfor kernel-team@lists.ubuntu.com; Sat, 09 Sep 2017 00:27:38 +0000",
            "from 1.general.cascardo.us.vpn ([10.172.70.58]\n\thelo=localhost.localdomain)\n\tby youngberry.canonical.com with esmtpsa\n\t(TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32)\n\t(Exim 4.76) (envelope-from <cascardo@canonical.com>)\n\tid 1dqTcX-0008Qv-M0\n\tfor kernel-team@lists.ubuntu.com; Sat, 09 Sep 2017 00:27:38 +0000"
        ],
        "From": "Thadeu Lima de Souza Cascardo <cascardo@canonical.com>",
        "To": "kernel-team@lists.ubuntu.com",
        "Subject": "[xenial CVE-2015-8952 2/3] ext2: convert to mbcache2",
        "Date": "Fri,  8 Sep 2017 21:25:55 -0300",
        "Message-Id": "<20170909002556.23382-3-cascardo@canonical.com>",
        "X-Mailer": "git-send-email 2.11.0",
        "In-Reply-To": "<20170909002556.23382-1-cascardo@canonical.com>",
        "References": "<20170909002556.23382-1-cascardo@canonical.com>",
        "X-BeenThere": "kernel-team@lists.ubuntu.com",
        "X-Mailman-Version": "2.1.20",
        "Precedence": "list",
        "List-Id": "Kernel team discussions <kernel-team.lists.ubuntu.com>",
        "List-Unsubscribe": "<https://lists.ubuntu.com/mailman/options/kernel-team>,\n\t<mailto:kernel-team-request@lists.ubuntu.com?subject=unsubscribe>",
        "List-Archive": "<https://lists.ubuntu.com/archives/kernel-team>",
        "List-Post": "<mailto:kernel-team@lists.ubuntu.com>",
        "List-Help": "<mailto:kernel-team-request@lists.ubuntu.com?subject=help>",
        "List-Subscribe": "<https://lists.ubuntu.com/mailman/listinfo/kernel-team>,\n\t<mailto:kernel-team-request@lists.ubuntu.com?subject=subscribe>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "base64",
        "Errors-To": "kernel-team-bounces@lists.ubuntu.com",
        "Sender": "\"kernel-team\" <kernel-team-bounces@lists.ubuntu.com>"
    },
    "content": "From: Jan Kara <jack@suse.cz>\n\nThe conversion is generally straightforward. We convert filesystem from\na global cache to per-fs one. Similarly to ext4 the tricky part is that\nxattr block corresponding to found mbcache entry can get freed before we\nget buffer lock for that block. So we have to check whether the entry is\nstill valid after getting the buffer lock.\n\nSigned-off-by: Jan Kara <jack@suse.cz>\nSigned-off-by: Theodore Ts'o <tytso@mit.edu>\n(cherry picked from commit be0726d33cb8f411945884664924bed3cb8c70ee)\nCVE-2015-8952\nSigned-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>\n---\n fs/ext2/ext2.h  |   3 ++\n fs/ext2/super.c |  25 ++++++----\n fs/ext2/xattr.c | 143 ++++++++++++++++++++++++++------------------------------\n fs/ext2/xattr.h |  21 ++-------\n 4 files changed, 92 insertions(+), 100 deletions(-)",
    "diff": "diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h\nindex 4c69c94cafd8..f98ce7e60a0f 100644\n--- a/fs/ext2/ext2.h\n+++ b/fs/ext2/ext2.h\n@@ -61,6 +61,8 @@ struct ext2_block_alloc_info {\n #define rsv_start rsv_window._rsv_start\n #define rsv_end rsv_window._rsv_end\n \n+struct mb2_cache;\n+\n /*\n  * second extended-fs super-block data in memory\n  */\n@@ -111,6 +113,7 @@ struct ext2_sb_info {\n \t * of the mount options.\n \t */\n \tspinlock_t s_lock;\n+\tstruct mb2_cache *s_mb_cache;\n };\n \n static inline spinlock_t *\ndiff --git a/fs/ext2/super.c b/fs/ext2/super.c\nindex 748d35afc902..111a31761ffa 100644\n--- a/fs/ext2/super.c\n+++ b/fs/ext2/super.c\n@@ -131,7 +131,10 @@ static void ext2_put_super (struct super_block * sb)\n \n \tdquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);\n \n-\text2_xattr_put_super(sb);\n+\tif (sbi->s_mb_cache) {\n+\t\text2_xattr_destroy_cache(sbi->s_mb_cache);\n+\t\tsbi->s_mb_cache = NULL;\n+\t}\n \tif (!(sb->s_flags & MS_RDONLY)) {\n \t\tstruct ext2_super_block *es = sbi->s_es;\n \n@@ -1104,6 +1107,14 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)\n \t\text2_msg(sb, KERN_ERR, \"error: insufficient memory\");\n \t\tgoto failed_mount3;\n \t}\n+\n+#ifdef CONFIG_EXT2_FS_XATTR\n+\tsbi->s_mb_cache = ext2_xattr_create_cache();\n+\tif (!sbi->s_mb_cache) {\n+\t\text2_msg(sb, KERN_ERR, \"Failed to create an mb_cache\");\n+\t\tgoto failed_mount3;\n+\t}\n+#endif\n \t/*\n \t * set up enough so that it can read an inode\n \t */\n@@ -1149,6 +1160,8 @@ cantfind_ext2:\n \t\t\tsb->s_id);\n \tgoto failed_mount;\n failed_mount3:\n+\tif (sbi->s_mb_cache)\n+\t\text2_xattr_destroy_cache(sbi->s_mb_cache);\n \tpercpu_counter_destroy(&sbi->s_freeblocks_counter);\n \tpercpu_counter_destroy(&sbi->s_freeinodes_counter);\n \tpercpu_counter_destroy(&sbi->s_dirs_counter);\n@@ -1555,20 +1568,17 @@ MODULE_ALIAS_FS(\"ext2\");\n \n static int __init init_ext2_fs(void)\n {\n-\tint err = init_ext2_xattr();\n-\tif (err)\n-\t\treturn err;\n+\tint err;\n+\n \terr = init_inodecache();\n \tif (err)\n-\t\tgoto out1;\n+\t\treturn err;\n         err = register_filesystem(&ext2_fs_type);\n \tif (err)\n \t\tgoto out;\n \treturn 0;\n out:\n \tdestroy_inodecache();\n-out1:\n-\texit_ext2_xattr();\n \treturn err;\n }\n \n@@ -1576,7 +1586,6 @@ static void __exit exit_ext2_fs(void)\n {\n \tunregister_filesystem(&ext2_fs_type);\n \tdestroy_inodecache();\n-\texit_ext2_xattr();\n }\n \n MODULE_AUTHOR(\"Remy Card and others\");\ndiff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c\nindex fa70848afa8f..24736c8b3d51 100644\n--- a/fs/ext2/xattr.c\n+++ b/fs/ext2/xattr.c\n@@ -56,7 +56,7 @@\n #include <linux/buffer_head.h>\n #include <linux/init.h>\n #include <linux/slab.h>\n-#include <linux/mbcache.h>\n+#include <linux/mbcache2.h>\n #include <linux/quotaops.h>\n #include <linux/rwsem.h>\n #include <linux/security.h>\n@@ -92,14 +92,12 @@\n static int ext2_xattr_set2(struct inode *, struct buffer_head *,\n \t\t\t   struct ext2_xattr_header *);\n \n-static int ext2_xattr_cache_insert(struct buffer_head *);\n+static int ext2_xattr_cache_insert(struct mb2_cache *, struct buffer_head *);\n static struct buffer_head *ext2_xattr_cache_find(struct inode *,\n \t\t\t\t\t\t struct ext2_xattr_header *);\n static void ext2_xattr_rehash(struct ext2_xattr_header *,\n \t\t\t      struct ext2_xattr_entry *);\n \n-static struct mb_cache *ext2_xattr_cache;\n-\n static const struct xattr_handler *ext2_xattr_handler_map[] = {\n \t[EXT2_XATTR_INDEX_USER]\t\t     = &ext2_xattr_user_handler,\n #ifdef CONFIG_EXT2_FS_POSIX_ACL\n@@ -154,6 +152,7 @@ ext2_xattr_get(struct inode *inode, int name_index, const char *name,\n \tsize_t name_len, size;\n \tchar *end;\n \tint error;\n+\tstruct mb2_cache *ext2_mb_cache = EXT2_SB(inode->i_sb)->s_mb_cache;\n \n \tea_idebug(inode, \"name=%d.%s, buffer=%p, buffer_size=%ld\",\n \t\t  name_index, name, buffer, (long)buffer_size);\n@@ -198,7 +197,7 @@ bad_block:\text2_error(inode->i_sb, \"ext2_xattr_get\",\n \t\t\tgoto found;\n \t\tentry = next;\n \t}\n-\tif (ext2_xattr_cache_insert(bh))\n+\tif (ext2_xattr_cache_insert(ext2_mb_cache, bh))\n \t\tea_idebug(inode, \"cache insert failed\");\n \terror = -ENODATA;\n \tgoto cleanup;\n@@ -211,7 +210,7 @@ found:\n \t    le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize)\n \t\tgoto bad_block;\n \n-\tif (ext2_xattr_cache_insert(bh))\n+\tif (ext2_xattr_cache_insert(ext2_mb_cache, bh))\n \t\tea_idebug(inode, \"cache insert failed\");\n \tif (buffer) {\n \t\terror = -ERANGE;\n@@ -249,6 +248,7 @@ ext2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)\n \tchar *end;\n \tsize_t rest = buffer_size;\n \tint error;\n+\tstruct mb2_cache *ext2_mb_cache = EXT2_SB(inode->i_sb)->s_mb_cache;\n \n \tea_idebug(inode, \"buffer=%p, buffer_size=%ld\",\n \t\t  buffer, (long)buffer_size);\n@@ -283,7 +283,7 @@ bad_block:\text2_error(inode->i_sb, \"ext2_xattr_list\",\n \t\t\tgoto bad_block;\n \t\tentry = next;\n \t}\n-\tif (ext2_xattr_cache_insert(bh))\n+\tif (ext2_xattr_cache_insert(ext2_mb_cache, bh))\n \t\tea_idebug(inode, \"cache insert failed\");\n \n \t/* list the attribute names */\n@@ -480,22 +480,23 @@ bad_block:\t\text2_error(sb, \"ext2_xattr_set\",\n \t/* Here we know that we can set the new attribute. */\n \n \tif (header) {\n-\t\tstruct mb_cache_entry *ce;\n-\n \t\t/* assert(header == HDR(bh)); */\n-\t\tce = mb_cache_entry_get(ext2_xattr_cache, bh->b_bdev,\n-\t\t\t\t\tbh->b_blocknr);\n \t\tlock_buffer(bh);\n \t\tif (header->h_refcount == cpu_to_le32(1)) {\n+\t\t\t__u32 hash = le32_to_cpu(header->h_hash);\n+\n \t\t\tea_bdebug(bh, \"modifying in-place\");\n-\t\t\tif (ce)\n-\t\t\t\tmb_cache_entry_free(ce);\n+\t\t\t/*\n+\t\t\t * This must happen under buffer lock for\n+\t\t\t * ext2_xattr_set2() to reliably detect modified block\n+\t\t\t */\n+\t\t\tmb2_cache_entry_delete_block(EXT2_SB(sb)->s_mb_cache,\n+\t\t\t\t\t\t     hash, bh->b_blocknr);\n+\n \t\t\t/* keep the buffer locked while modifying it. */\n \t\t} else {\n \t\t\tint offset;\n \n-\t\t\tif (ce)\n-\t\t\t\tmb_cache_entry_release(ce);\n \t\t\tunlock_buffer(bh);\n \t\t\tea_bdebug(bh, \"cloning\");\n \t\t\theader = kmalloc(bh->b_size, GFP_KERNEL);\n@@ -623,6 +624,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,\n \tstruct super_block *sb = inode->i_sb;\n \tstruct buffer_head *new_bh = NULL;\n \tint error;\n+\tstruct mb2_cache *ext2_mb_cache = EXT2_SB(sb)->s_mb_cache;\n \n \tif (header) {\n \t\tnew_bh = ext2_xattr_cache_find(inode, header);\n@@ -650,7 +652,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,\n \t\t\t   don't need to change the reference count. */\n \t\t\tnew_bh = old_bh;\n \t\t\tget_bh(new_bh);\n-\t\t\text2_xattr_cache_insert(new_bh);\n+\t\t\text2_xattr_cache_insert(ext2_mb_cache, new_bh);\n \t\t} else {\n \t\t\t/* We need to allocate a new block */\n \t\t\text2_fsblk_t goal = ext2_group_first_block_no(sb,\n@@ -671,7 +673,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,\n \t\t\tmemcpy(new_bh->b_data, header, new_bh->b_size);\n \t\t\tset_buffer_uptodate(new_bh);\n \t\t\tunlock_buffer(new_bh);\n-\t\t\text2_xattr_cache_insert(new_bh);\n+\t\t\text2_xattr_cache_insert(ext2_mb_cache, new_bh);\n \t\t\t\n \t\t\text2_xattr_update_super_block(sb);\n \t\t}\n@@ -704,19 +706,21 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,\n \n \terror = 0;\n \tif (old_bh && old_bh != new_bh) {\n-\t\tstruct mb_cache_entry *ce;\n-\n \t\t/*\n \t\t * If there was an old block and we are no longer using it,\n \t\t * release the old block.\n \t\t */\n-\t\tce = mb_cache_entry_get(ext2_xattr_cache, old_bh->b_bdev,\n-\t\t\t\t\told_bh->b_blocknr);\n \t\tlock_buffer(old_bh);\n \t\tif (HDR(old_bh)->h_refcount == cpu_to_le32(1)) {\n+\t\t\t__u32 hash = le32_to_cpu(HDR(old_bh)->h_hash);\n+\n+\t\t\t/*\n+\t\t\t * This must happen under buffer lock for\n+\t\t\t * ext2_xattr_set2() to reliably detect freed block\n+\t\t\t */\n+\t\t\tmb2_cache_entry_delete_block(ext2_mb_cache,\n+\t\t\t\t\t\t     hash, old_bh->b_blocknr);\n \t\t\t/* Free the old block. */\n-\t\t\tif (ce)\n-\t\t\t\tmb_cache_entry_free(ce);\n \t\t\tea_bdebug(old_bh, \"freeing\");\n \t\t\text2_free_blocks(inode, old_bh->b_blocknr, 1);\n \t\t\tmark_inode_dirty(inode);\n@@ -727,8 +731,6 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,\n \t\t} else {\n \t\t\t/* Decrement the refcount only. */\n \t\t\tle32_add_cpu(&HDR(old_bh)->h_refcount, -1);\n-\t\t\tif (ce)\n-\t\t\t\tmb_cache_entry_release(ce);\n \t\t\tdquot_free_block_nodirty(inode, 1);\n \t\t\tmark_inode_dirty(inode);\n \t\t\tmark_buffer_dirty(old_bh);\n@@ -754,7 +756,6 @@ void\n ext2_xattr_delete_inode(struct inode *inode)\n {\n \tstruct buffer_head *bh = NULL;\n-\tstruct mb_cache_entry *ce;\n \n \tdown_write(&EXT2_I(inode)->xattr_sem);\n \tif (!EXT2_I(inode)->i_file_acl)\n@@ -774,19 +775,22 @@ ext2_xattr_delete_inode(struct inode *inode)\n \t\t\tEXT2_I(inode)->i_file_acl);\n \t\tgoto cleanup;\n \t}\n-\tce = mb_cache_entry_get(ext2_xattr_cache, bh->b_bdev, bh->b_blocknr);\n \tlock_buffer(bh);\n \tif (HDR(bh)->h_refcount == cpu_to_le32(1)) {\n-\t\tif (ce)\n-\t\t\tmb_cache_entry_free(ce);\n+\t\t__u32 hash = le32_to_cpu(HDR(bh)->h_hash);\n+\n+\t\t/*\n+\t\t * This must happen under buffer lock for ext2_xattr_set2() to\n+\t\t * reliably detect freed block\n+\t\t */\n+\t\tmb2_cache_entry_delete_block(EXT2_SB(inode->i_sb)->s_mb_cache,\n+\t\t\t\t\t     hash, bh->b_blocknr);\n \t\text2_free_blocks(inode, EXT2_I(inode)->i_file_acl, 1);\n \t\tget_bh(bh);\n \t\tbforget(bh);\n \t\tunlock_buffer(bh);\n \t} else {\n \t\tle32_add_cpu(&HDR(bh)->h_refcount, -1);\n-\t\tif (ce)\n-\t\t\tmb_cache_entry_release(ce);\n \t\tea_bdebug(bh, \"refcount now=%d\",\n \t\t\tle32_to_cpu(HDR(bh)->h_refcount));\n \t\tunlock_buffer(bh);\n@@ -803,18 +807,6 @@ cleanup:\n }\n \n /*\n- * ext2_xattr_put_super()\n- *\n- * This is called when a file system is unmounted.\n- */\n-void\n-ext2_xattr_put_super(struct super_block *sb)\n-{\n-\tmb_cache_shrink(sb->s_bdev);\n-}\n-\n-\n-/*\n  * ext2_xattr_cache_insert()\n  *\n  * Create a new entry in the extended attribute cache, and insert\n@@ -823,28 +815,20 @@ ext2_xattr_put_super(struct super_block *sb)\n  * Returns 0, or a negative error number on failure.\n  */\n static int\n-ext2_xattr_cache_insert(struct buffer_head *bh)\n+ext2_xattr_cache_insert(struct mb2_cache *cache, struct buffer_head *bh)\n {\n \t__u32 hash = le32_to_cpu(HDR(bh)->h_hash);\n-\tstruct mb_cache_entry *ce;\n \tint error;\n \n-\tce = mb_cache_entry_alloc(ext2_xattr_cache, GFP_NOFS);\n-\tif (!ce)\n-\t\treturn -ENOMEM;\n-\terror = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, hash);\n+\terror = mb2_cache_entry_create(cache, GFP_NOFS, hash, bh->b_blocknr);\n \tif (error) {\n-\t\tmb_cache_entry_free(ce);\n \t\tif (error == -EBUSY) {\n \t\t\tea_bdebug(bh, \"already in cache (%d cache entries)\",\n \t\t\t\tatomic_read(&ext2_xattr_cache->c_entry_count));\n \t\t\terror = 0;\n \t\t}\n-\t} else {\n-\t\tea_bdebug(bh, \"inserting [%x] (%d cache entries)\", (int)hash,\n-\t\t\t  atomic_read(&ext2_xattr_cache->c_entry_count));\n-\t\tmb_cache_entry_release(ce);\n-\t}\n+\t} else\n+\t\tea_bdebug(bh, \"inserting [%x]\", (int)hash);\n \treturn error;\n }\n \n@@ -900,23 +884,17 @@ static struct buffer_head *\n ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header)\n {\n \t__u32 hash = le32_to_cpu(header->h_hash);\n-\tstruct mb_cache_entry *ce;\n+\tstruct mb2_cache_entry *ce;\n+\tstruct mb2_cache *ext2_mb_cache = EXT2_SB(inode->i_sb)->s_mb_cache;\n \n \tif (!header->h_hash)\n \t\treturn NULL;  /* never share */\n \tea_idebug(inode, \"looking for cached blocks [%x]\", (int)hash);\n again:\n-\tce = mb_cache_entry_find_first(ext2_xattr_cache, inode->i_sb->s_bdev,\n-\t\t\t\t       hash);\n+\tce = mb2_cache_entry_find_first(ext2_mb_cache, hash);\n \twhile (ce) {\n \t\tstruct buffer_head *bh;\n \n-\t\tif (IS_ERR(ce)) {\n-\t\t\tif (PTR_ERR(ce) == -EAGAIN)\n-\t\t\t\tgoto again;\n-\t\t\tbreak;\n-\t\t}\n-\n \t\tbh = sb_bread(inode->i_sb, ce->e_block);\n \t\tif (!bh) {\n \t\t\text2_error(inode->i_sb, \"ext2_xattr_cache_find\",\n@@ -924,7 +902,21 @@ again:\n \t\t\t\tinode->i_ino, (unsigned long) ce->e_block);\n \t\t} else {\n \t\t\tlock_buffer(bh);\n-\t\t\tif (le32_to_cpu(HDR(bh)->h_refcount) >\n+\t\t\t/*\n+\t\t\t * We have to be careful about races with freeing or\n+\t\t\t * rehashing of xattr block. Once we hold buffer lock\n+\t\t\t * xattr block's state is stable so we can check\n+\t\t\t * whether the block got freed / rehashed or not.\n+\t\t\t * Since we unhash mbcache entry under buffer lock when\n+\t\t\t * freeing / rehashing xattr block, checking whether\n+\t\t\t * entry is still hashed is reliable.\n+\t\t\t */\n+\t\t\tif (hlist_bl_unhashed(&ce->e_hash_list)) {\n+\t\t\t\tmb2_cache_entry_put(ext2_mb_cache, ce);\n+\t\t\t\tunlock_buffer(bh);\n+\t\t\t\tbrelse(bh);\n+\t\t\t\tgoto again;\n+\t\t\t} else if (le32_to_cpu(HDR(bh)->h_refcount) >\n \t\t\t\t   EXT2_XATTR_REFCOUNT_MAX) {\n \t\t\t\tea_idebug(inode, \"block %ld refcount %d>%d\",\n \t\t\t\t\t  (unsigned long) ce->e_block,\n@@ -933,13 +925,14 @@ again:\n \t\t\t} else if (!ext2_xattr_cmp(header, HDR(bh))) {\n \t\t\t\tea_bdebug(bh, \"b_count=%d\",\n \t\t\t\t\t  atomic_read(&(bh->b_count)));\n-\t\t\t\tmb_cache_entry_release(ce);\n+\t\t\t\tmb2_cache_entry_touch(ext2_mb_cache, ce);\n+\t\t\t\tmb2_cache_entry_put(ext2_mb_cache, ce);\n \t\t\t\treturn bh;\n \t\t\t}\n \t\t\tunlock_buffer(bh);\n \t\t\tbrelse(bh);\n \t\t}\n-\t\tce = mb_cache_entry_find_next(ce, inode->i_sb->s_bdev, hash);\n+\t\tce = mb2_cache_entry_find_next(ext2_mb_cache, ce);\n \t}\n \treturn NULL;\n }\n@@ -1012,17 +1005,15 @@ static void ext2_xattr_rehash(struct ext2_xattr_header *header,\n \n #undef BLOCK_HASH_SHIFT\n \n-int __init\n-init_ext2_xattr(void)\n+#define HASH_BUCKET_BITS 10\n+\n+struct mb2_cache *ext2_xattr_create_cache(void)\n {\n-\text2_xattr_cache = mb_cache_create(\"ext2_xattr\", 6);\n-\tif (!ext2_xattr_cache)\n-\t\treturn -ENOMEM;\n-\treturn 0;\n+\treturn mb2_cache_create(HASH_BUCKET_BITS);\n }\n \n-void\n-exit_ext2_xattr(void)\n+void ext2_xattr_destroy_cache(struct mb2_cache *cache)\n {\n-\tmb_cache_destroy(ext2_xattr_cache);\n+\tif (cache)\n+\t\tmb2_cache_destroy(cache);\n }\ndiff --git a/fs/ext2/xattr.h b/fs/ext2/xattr.h\nindex 60edf298644e..6ea38aa9563a 100644\n--- a/fs/ext2/xattr.h\n+++ b/fs/ext2/xattr.h\n@@ -53,6 +53,8 @@ struct ext2_xattr_entry {\n #define EXT2_XATTR_SIZE(size) \\\n \t(((size) + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND)\n \n+struct mb2_cache;\n+\n # ifdef CONFIG_EXT2_FS_XATTR\n \n extern const struct xattr_handler ext2_xattr_user_handler;\n@@ -65,10 +67,9 @@ extern int ext2_xattr_get(struct inode *, int, const char *, void *, size_t);\n extern int ext2_xattr_set(struct inode *, int, const char *, const void *, size_t, int);\n \n extern void ext2_xattr_delete_inode(struct inode *);\n-extern void ext2_xattr_put_super(struct super_block *);\n \n-extern int init_ext2_xattr(void);\n-extern void exit_ext2_xattr(void);\n+extern struct mb2_cache *ext2_xattr_create_cache(void);\n+extern void ext2_xattr_destroy_cache(struct mb2_cache *cache);\n \n extern const struct xattr_handler *ext2_xattr_handlers[];\n \n@@ -93,19 +94,7 @@ ext2_xattr_delete_inode(struct inode *inode)\n {\n }\n \n-static inline void\n-ext2_xattr_put_super(struct super_block *sb)\n-{\n-}\n-\n-static inline int\n-init_ext2_xattr(void)\n-{\n-\treturn 0;\n-}\n-\n-static inline void\n-exit_ext2_xattr(void)\n+static inline void ext2_xattr_destroy_cache(struct mb2_cache *cache)\n {\n }\n \n",
    "prefixes": [
        "xenial",
        "CVE-2015-8952",
        "2/3"
    ]
}