From patchwork Sun Sep 9 22:46:35 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Ernesto_A=2E_Fern=C3=A1ndez?= X-Patchwork-Id: 10593537 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 25E22920 for ; Mon, 10 Sep 2018 03:11:14 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0FFD328D7B for ; Mon, 10 Sep 2018 03:11:14 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 03A9E28E5E; Mon, 10 Sep 2018 03:11:14 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3E00628D7B for ; Mon, 10 Sep 2018 03:11:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726106AbeIJIDA (ORCPT ); Mon, 10 Sep 2018 04:03:00 -0400 Received: from mail-qt0-f194.google.com ([209.85.216.194]:33892 "EHLO mail-qt0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726024AbeIJIDA (ORCPT ); Mon, 10 Sep 2018 04:03:00 -0400 Received: by mail-qt0-f194.google.com with SMTP id m13-v6so22674766qth.1 for ; Sun, 09 Sep 2018 20:11:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:to:cc:subject:message-id:mime-version:content-disposition :content-transfer-encoding; bh=go7YxnkYx7F2DELMVSaddZeuWuHsRIA4c2qoBMEsIko=; b=pZnFPW/gEDhn+NzSRlSL1tXmRarQe624E3CIPbUcDEe28XcWqgOvtGtWyEuyUrzmRZ 6ZLBGlZRzXZw1HUIOW9OvXIFRhdn1AjxH8gb3Kcn0NZmV2SfhJ3DYGBaouQ4Q8XPbmjq swkld9uSkqIeJEclkAjnPmqsymD+Q17IkorvGMMDmw1cgCKWgQJz1vxZNFoATDs+F3L5 5ZduSccr5nQ0Hmw2PqUOpvo8J9Ya8tGqE4oP2crH+fQkKhF8zLCtjgyROh5Abtsg7pjo ZpsYJk8c9dr1xdCHhhcV0qnykh3d0+J0eOYYKza673tltSm7yqns32lSTG0CNU+qv8lL qpaQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:mime-version :content-disposition:content-transfer-encoding; bh=go7YxnkYx7F2DELMVSaddZeuWuHsRIA4c2qoBMEsIko=; b=fWELMtbkNgxbRNXipEQrzWRo520fx5L90zTHKbjOoIEpH5tbId6y8qW+uLeKb7cQZq 192HpXt8EVDMuVoygjoAXarnB39EITe8mdYJE9S8Q3p7cuguEEzsm7pfw754demhAqOR 2UnC8W1/KVYe9pRdiZf5EXNn1kf/EPA/lgtLz7IJ6NedI6P9MXAiV6o0voQWObNYszo0 ioWHKy/Yol+tmT3QWSwbXtTnAMykSRDF9JIBdtS+ByFDjl3hoX52c6V76XYkZyo+Nyxe sWf2FvwQfqwppXWXa2Ql0iw2r6KSR5H80rKBDv5uclPGTijI4YTSHOykIZduNL0mTGvv zgNw== X-Gm-Message-State: APzg51CpWo/uRkh3RMwBxfS4vKBMb9qwKYXZZN9R5eRkCdaXC1nqM6Mq RNsHWqcoL/vVmOyfRMR0wtoGd+of X-Google-Smtp-Source: ANB0VdZDsOpw/bfxKsz8McQeRUfzVzrYkUS5SKa14Mras9Q4r2guUKK/pv887v0SiURFELEo9V1x7Q== X-Received: by 2002:a0c:93c9:: with SMTP id g9-v6mr12784780qvg.14.1536533200783; Sun, 09 Sep 2018 15:46:40 -0700 (PDT) Received: from eaf ([181.47.179.0]) by smtp.gmail.com with ESMTPSA id t11-v6sm9035828qkt.28.2018.09.09.15.46.39 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sun, 09 Sep 2018 15:46:40 -0700 (PDT) Date: Sun, 9 Sep 2018 19:46:35 -0300 From: Ernesto =?utf-8?q?A=2E_Fern=C3=A1ndez?= To: linux-fsdevel@vger.kernel.org Cc: Andrew Morton Subject: [PATCH v2 1/2] hfsplus: prevent btree data loss on ENOSPC Message-ID: <4596eef22fbda137b4ffa0272d92f0da15364421.1536269129.git.ernesto.mnd.fernandez@gmail.com> MIME-Version: 1.0 Content-Disposition: inline Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Inserting or deleting a record in a btree may require splitting several of its nodes. If we hit ENOSPC halfway through, the new nodes will be left orphaned and their records will be lost. This could mean lost inodes, extents or xattrs. From now on, check the available disk space before making any changes. This still leaves the potential problem of corruption on ENOMEM. The patch can be tested with xfstests generic/027. Signed-off-by: Ernesto A. Fernández --- Changes in v2: Increase the free node count after each loop in hfs_bmap_reserve(), instead of resetting it. fs/hfsplus/attributes.c | 10 ++++++++++ fs/hfsplus/btree.c | 44 ++++++++++++++++++++++++++++---------------- fs/hfsplus/catalog.c | 24 ++++++++++++++++++++++++ fs/hfsplus/extents.c | 4 ++++ fs/hfsplus/hfsplus_fs.h | 2 ++ 5 files changed, 68 insertions(+), 16 deletions(-) diff --git a/fs/hfsplus/attributes.c b/fs/hfsplus/attributes.c index 2bab6b3cdba4..e6d554476db4 100644 --- a/fs/hfsplus/attributes.c +++ b/fs/hfsplus/attributes.c @@ -217,6 +217,11 @@ int hfsplus_create_attr(struct inode *inode, if (err) goto failed_init_create_attr; + /* Fail early and avoid ENOSPC during the btree operation */ + err = hfs_bmap_reserve(fd.tree, fd.tree->depth + 1); + if (err) + goto failed_create_attr; + if (name) { err = hfsplus_attr_build_key(sb, fd.search_key, inode->i_ino, name); @@ -313,6 +318,11 @@ int hfsplus_delete_attr(struct inode *inode, const char *name) if (err) return err; + /* Fail early and avoid ENOSPC during the btree operation */ + err = hfs_bmap_reserve(fd.tree, fd.tree->depth); + if (err) + goto out; + if (name) { err = hfsplus_attr_build_key(sb, fd.search_key, inode->i_ino, name); diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c index de14b2b6881b..236efe51eca6 100644 --- a/fs/hfsplus/btree.c +++ b/fs/hfsplus/btree.c @@ -342,26 +342,21 @@ static struct hfs_bnode *hfs_bmap_new_bmap(struct hfs_bnode *prev, u32 idx) return node; } -struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree) +/* Make sure @tree has enough space for the @rsvd_nodes */ +int hfs_bmap_reserve(struct hfs_btree *tree, int rsvd_nodes) { - struct hfs_bnode *node, *next_node; - struct page **pagep; - u32 nidx, idx; - unsigned off; - u16 off16; - u16 len; - u8 *data, byte, m; - int i; + struct inode *inode = tree->inode; + struct hfsplus_inode_info *hip = HFSPLUS_I(inode); + u32 count; + int res; - while (!tree->free_nodes) { - struct inode *inode = tree->inode; - struct hfsplus_inode_info *hip = HFSPLUS_I(inode); - u32 count; - int res; + if (rsvd_nodes <= 0) + return 0; + while (tree->free_nodes < rsvd_nodes) { res = hfsplus_file_extend(inode, hfs_bnode_need_zeroout(tree)); if (res) - return ERR_PTR(res); + return res; hip->phys_size = inode->i_size = (loff_t)hip->alloc_blocks << HFSPLUS_SB(tree->sb)->alloc_blksz_shift; @@ -369,9 +364,26 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree) hip->alloc_blocks << HFSPLUS_SB(tree->sb)->fs_shift; inode_set_bytes(inode, inode->i_size); count = inode->i_size >> tree->node_size_shift; - tree->free_nodes = count - tree->node_count; + tree->free_nodes += count - tree->node_count; tree->node_count = count; } + return 0; +} + +struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree) +{ + struct hfs_bnode *node, *next_node; + struct page **pagep; + u32 nidx, idx; + unsigned off; + u16 off16; + u16 len; + u8 *data, byte, m; + int i, res; + + res = hfs_bmap_reserve(tree, 1); + if (res) + return ERR_PTR(res); nidx = 0; node = hfs_bnode_find(tree, nidx); diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c index a196369ba779..35472cba750e 100644 --- a/fs/hfsplus/catalog.c +++ b/fs/hfsplus/catalog.c @@ -265,6 +265,14 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, if (err) return err; + /* + * Fail early and avoid ENOSPC during the btree operations. We may + * have to split the root node at most once. + */ + err = hfs_bmap_reserve(fd.tree, 2 * fd.tree->depth); + if (err) + goto err2; + hfsplus_cat_build_key_with_cnid(sb, fd.search_key, cnid); entry_size = hfsplus_fill_cat_thread(sb, &entry, S_ISDIR(inode->i_mode) ? @@ -333,6 +341,14 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, const struct qstr *str) if (err) return err; + /* + * Fail early and avoid ENOSPC during the btree operations. We may + * have to split the root node at most once. + */ + err = hfs_bmap_reserve(fd.tree, 2 * (int)fd.tree->depth - 2); + if (err) + goto out; + if (!str) { int len; @@ -433,6 +449,14 @@ int hfsplus_rename_cat(u32 cnid, return err; dst_fd = src_fd; + /* + * Fail early and avoid ENOSPC during the btree operations. We may + * have to split the root node at most twice. + */ + err = hfs_bmap_reserve(src_fd.tree, 4 * (int)src_fd.tree->depth - 1); + if (err) + goto out; + /* find the old dir entry and read the data */ err = hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c index 8e0f59767694..8a8893d522ef 100644 --- a/fs/hfsplus/extents.c +++ b/fs/hfsplus/extents.c @@ -100,6 +100,10 @@ static int __hfsplus_ext_write_extent(struct inode *inode, if (hip->extent_state & HFSPLUS_EXT_NEW) { if (res != -ENOENT) return res; + /* Fail early and avoid ENOSPC during the btree operation */ + res = hfs_bmap_reserve(fd->tree, fd->tree->depth + 1); + if (res) + return res; hfs_brec_insert(fd, hip->cached_extents, sizeof(hfsplus_extent_rec)); hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW); diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 8e039435958a..dd7ad9f13e3a 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h @@ -311,6 +311,7 @@ static inline unsigned short hfsplus_min_io_size(struct super_block *sb) #define hfs_btree_open hfsplus_btree_open #define hfs_btree_close hfsplus_btree_close #define hfs_btree_write hfsplus_btree_write +#define hfs_bmap_reserve hfsplus_bmap_reserve #define hfs_bmap_alloc hfsplus_bmap_alloc #define hfs_bmap_free hfsplus_bmap_free #define hfs_bnode_read hfsplus_bnode_read @@ -395,6 +396,7 @@ u32 hfsplus_calc_btree_clump_size(u32 block_size, u32 node_size, u64 sectors, struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id); void hfs_btree_close(struct hfs_btree *tree); int hfs_btree_write(struct hfs_btree *tree); +int hfs_bmap_reserve(struct hfs_btree *tree, int rsvd_nodes); struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree); void hfs_bmap_free(struct hfs_bnode *node); From patchwork Sun Sep 9 22:47:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Ernesto_A=2E_Fern=C3=A1ndez?= X-Patchwork-Id: 10593513 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 355CF3E9D for ; Mon, 10 Sep 2018 02:47:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D4FDC28DED for ; Mon, 10 Sep 2018 02:47:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C92DE28DF8; Mon, 10 Sep 2018 02:47:29 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 43DF328DED for ; Mon, 10 Sep 2018 02:47:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726024AbeIJHjL (ORCPT ); Mon, 10 Sep 2018 03:39:11 -0400 Received: from mail-qt0-f193.google.com ([209.85.216.193]:34708 "EHLO mail-qt0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725957AbeIJHjL (ORCPT ); Mon, 10 Sep 2018 03:39:11 -0400 Received: by mail-qt0-f193.google.com with SMTP id m13-v6so22635329qth.1 for ; Sun, 09 Sep 2018 19:47:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:content-transfer-encoding:in-reply-to; bh=Wssb4F95QYHkwKsdXLyIedLaZuxelA4nrCv12CaDhTc=; b=ckQ2zrYfvKgv8OYpebqlVs9Yq8m6yf64xkxTvL1O7pCmLf6EihgpSvZBKk8SLbQs1K 9OszpBc9lUSOjei5cQXFZ83C80oB4KpgUz4YuEj9pQyhJgZiIl5R7PvyLiifPObVYwYy hQ80EEWNxDC4GzPsOVITxO7a/0xqwC8KMiAstCyhhGeKOH9vRancHA4R8UceHk3Srojj aUDNgrvBsrRHIX2mf8KB3dQ7MJQ5fzt5TzKkG3ItdLOZbK9DYx1cH56QN10MNUskBmwJ Y6bRu/sHVuKD4KWbru+zt6Z88GZ5/0eIyzU2BbBOI9boJEXoqurbTLpyjIck8w2/9v12 BbHQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:content-transfer-encoding :in-reply-to; bh=Wssb4F95QYHkwKsdXLyIedLaZuxelA4nrCv12CaDhTc=; b=Cb2hVjqyt+zg054GgKQZpK05s644jo99eDylL0B5zW/OHwmyU8WXJIO/BquhggJ057 bFpvWsogli8h7+b8zbK8pLj1ENQnytf9ig2fsxxRy6Ur1OyCNEjGB0U6Chpzp8GRCCC9 VukN9KVPgRs59l1bmeE5RBeBTOuKkVzxegmFrwTZ4tm3XIuZPqKq4H4hD4jpS9qeyayv s2q5ZOAFJdSISFNoWvo9Z4clDWA4AmfUh1jNaCjyrzSD16p2YS8hQKRUMS/sTy7vnXt6 90CxBuvyEm6OsvmvOMegjq6ZANsvVfOGnvCV2+HPWhW/Cua8ZxbPvXQBuDhgmDCj73oD eIbw== X-Gm-Message-State: APzg51DU0RNngBsdvwR6DyALUkHbKwvdpnpn8dj/1ZBB6XgEfi50Fdjc ZZOuakGB+y6Pi02jscSmJRYqDUk8 X-Google-Smtp-Source: ANB0VdawZAFO0yuB5Y6votCNWfCIPaKgUza8XmKVwfQIpZYHKkJWmNriEznheVnIqdfYw7z4plc6Ag== X-Received: by 2002:ac8:24e1:: with SMTP id t30-v6mr14280787qtt.208.1536533249235; Sun, 09 Sep 2018 15:47:29 -0700 (PDT) Received: from eaf ([181.47.179.0]) by smtp.gmail.com with ESMTPSA id 60-v6sm7906654qte.29.2018.09.09.15.47.27 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sun, 09 Sep 2018 15:47:28 -0700 (PDT) Date: Sun, 9 Sep 2018 19:47:25 -0300 From: Ernesto =?utf-8?q?A=2E_Fern=C3=A1ndez?= To: linux-fsdevel@vger.kernel.org Cc: Andrew Morton Subject: [PATCH v2 2/2] hfs: prevent btree data loss on ENOSPC Message-ID: References: <4596eef22fbda137b4ffa0272d92f0da15364421.1536269129.git.ernesto.mnd.fernandez@gmail.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <4596eef22fbda137b4ffa0272d92f0da15364421.1536269129.git.ernesto.mnd.fernandez@gmail.com> Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Inserting a new record in a btree may require splitting several of its nodes. If we hit ENOSPC halfway through, the new nodes will be left orphaned and their records will be lost. This could mean lost inodes or extents. From now on, check the available disk space before making any changes. This still leaves the potential problem of corruption on ENOMEM. There is no need to reserve space before deleting a catalog record, as we do for hfsplus. This difference is because hfs index nodes have fixed length keys. Signed-off-by: Ernesto A. Fernández --- Changes in v2: Increase the free node count after each loop in hfs_bmap_reserve(), instead of resetting it. fs/hfs/btree.c | 41 +++++++++++++++++++++++++---------------- fs/hfs/btree.h | 1 + fs/hfs/catalog.c | 16 ++++++++++++++++ fs/hfs/extent.c | 4 ++++ 4 files changed, 46 insertions(+), 16 deletions(-) diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c index 374b5688e29e..98b96ffb95ed 100644 --- a/fs/hfs/btree.c +++ b/fs/hfs/btree.c @@ -220,25 +220,17 @@ static struct hfs_bnode *hfs_bmap_new_bmap(struct hfs_bnode *prev, u32 idx) return node; } -struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree) +/* Make sure @tree has enough space for the @rsvd_nodes */ +int hfs_bmap_reserve(struct hfs_btree *tree, int rsvd_nodes) { - struct hfs_bnode *node, *next_node; - struct page **pagep; - u32 nidx, idx; - unsigned off; - u16 off16; - u16 len; - u8 *data, byte, m; - int i; - - while (!tree->free_nodes) { - struct inode *inode = tree->inode; - u32 count; - int res; + struct inode *inode = tree->inode; + u32 count; + int res; + while (tree->free_nodes < rsvd_nodes) { res = hfs_extend_file(inode); if (res) - return ERR_PTR(res); + return res; HFS_I(inode)->phys_size = inode->i_size = (loff_t)HFS_I(inode)->alloc_blocks * HFS_SB(tree->sb)->alloc_blksz; @@ -246,9 +238,26 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree) tree->sb->s_blocksize_bits; inode_set_bytes(inode, inode->i_size); count = inode->i_size >> tree->node_size_shift; - tree->free_nodes = count - tree->node_count; + tree->free_nodes += count - tree->node_count; tree->node_count = count; } + return 0; +} + +struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree) +{ + struct hfs_bnode *node, *next_node; + struct page **pagep; + u32 nidx, idx; + unsigned off; + u16 off16; + u16 len; + u8 *data, byte, m; + int i, res; + + res = hfs_bmap_reserve(tree, 1); + if (res) + return ERR_PTR(res); nidx = 0; node = hfs_bnode_find(tree, nidx); diff --git a/fs/hfs/btree.h b/fs/hfs/btree.h index c8b252dbb26c..dcc2aab1b2c4 100644 --- a/fs/hfs/btree.h +++ b/fs/hfs/btree.h @@ -82,6 +82,7 @@ struct hfs_find_data { extern struct hfs_btree *hfs_btree_open(struct super_block *, u32, btree_keycmp); extern void hfs_btree_close(struct hfs_btree *); extern void hfs_btree_write(struct hfs_btree *); +extern int hfs_bmap_reserve(struct hfs_btree *, int); extern struct hfs_bnode * hfs_bmap_alloc(struct hfs_btree *); extern void hfs_bmap_free(struct hfs_bnode *node); diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c index 8a66405b0f8b..d365bf0b8c77 100644 --- a/fs/hfs/catalog.c +++ b/fs/hfs/catalog.c @@ -97,6 +97,14 @@ int hfs_cat_create(u32 cnid, struct inode *dir, const struct qstr *str, struct i if (err) return err; + /* + * Fail early and avoid ENOSPC during the btree operations. We may + * have to split the root node at most once. + */ + err = hfs_bmap_reserve(fd.tree, 2 * fd.tree->depth); + if (err) + goto err2; + hfs_cat_build_key(sb, fd.search_key, cnid, NULL); entry_size = hfs_cat_build_thread(sb, &entry, S_ISDIR(inode->i_mode) ? HFS_CDR_THD : HFS_CDR_FTH, @@ -295,6 +303,14 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, const struct qstr *src_name, return err; dst_fd = src_fd; + /* + * Fail early and avoid ENOSPC during the btree operations. We may + * have to split the root node at most once. + */ + err = hfs_bmap_reserve(src_fd.tree, 2 * src_fd.tree->depth); + if (err) + goto out; + /* find the old dir entry and read the data */ hfs_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); err = hfs_brec_find(&src_fd); diff --git a/fs/hfs/extent.c b/fs/hfs/extent.c index 5d0182654580..0c638c612152 100644 --- a/fs/hfs/extent.c +++ b/fs/hfs/extent.c @@ -117,6 +117,10 @@ static int __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) if (HFS_I(inode)->flags & HFS_FLG_EXT_NEW) { if (res != -ENOENT) return res; + /* Fail early and avoid ENOSPC during the btree operation */ + res = hfs_bmap_reserve(fd->tree, fd->tree->depth + 1); + if (res) + return res; hfs_brec_insert(fd, HFS_I(inode)->cached_extents, sizeof(hfs_extent_rec)); HFS_I(inode)->flags &= ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW); } else {