} else {
ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), name,
false, BTRFS_I(inode)->dir_index);
- if (unlikely(ret)) {
+ if (ret == -ENOMEM) {
+ /*
+ * Orphan the new inode instead of aborting. The inode
+ * item was already written with nlink 1, and discard's
+ * eviction won't delete a bad inode, so nlink 0 must be
+ * persisted here or orphan cleanup would see nlink > 0,
+ * drop the orphan item, and leak the inode.
+ */
+ clear_nlink(inode);
+ /* btrfs_orphan_add() aborts the transaction on failure. */
+ ret = btrfs_orphan_add(trans, BTRFS_I(inode));
+ if (ret)
+ goto discard;
+ ret = btrfs_update_inode(trans, BTRFS_I(inode));
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ goto discard;
+ }
+ ret = -ENOMEM;
+ goto discard;
+ } else if (unlikely(ret)) {
btrfs_abort_transaction(trans, ret);
goto discard;
}
ret = btrfs_insert_dir_item(trans, name, parent_inode, &key,
btrfs_inode_type(inode), index, NULL);
- if (ret == -EEXIST || ret == -EOVERFLOW)
+ if (ret == -EEXIST || ret == -EOVERFLOW || ret == -ENOMEM)
goto fail_dir_item;
else if (unlikely(ret)) {
btrfs_abort_transaction(trans, ret);