hfsplus: prevent btree data loss on ENOSPC
[linux] / fs / hfsplus / catalog.c
index a196369..35472cb 100644 (file)
@@ -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);