From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.223.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AB3823AD50A for ; Thu, 19 Mar 2026 21:05:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=195.135.223.131 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773954333; cv=none; b=TsRLn0jfAQlrQRFXD1jCUTbCZg9pgl1G7jgw2unxqRJetCdkyvsf4VKLRCnRVKgkfm8XSN4YzC6k/ZAd+JfX6GXB3RikXwkzcOjQHxht0x0UOiI/4VWQxo5J6/udRwXfhSSdhdfJhgWxR520eMXsXvFl3PB/3ST5vje8NQYZS5Q= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773954333; c=relaxed/simple; bh=IGn8mnO/IR7t8VbALT7l4mpdPuRBV+6NbOQqQkiBdOQ=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jdRDF3AHZnGOixFDzvxqM7A7P41spX8hjgazPqgyp4adARfgXk4iynVqkH8SiveH+ymwqv+7y2CTFigd++efrV2MWA8RIg/yORcMNdjilRMImzNsQiNpPnjvlUCddUBFavxipH8yemOR/sR4WbQGsHM/2jVODQV0zhfF9y+3hCk= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=suse.com; spf=pass smtp.mailfrom=suse.com; dkim=pass (1024-bit key) header.d=suse.com header.i=@suse.com header.b=ejGSVGcy; dkim=pass (1024-bit key) header.d=suse.com header.i=@suse.com header.b=ejGSVGcy; arc=none smtp.client-ip=195.135.223.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=suse.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=suse.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=suse.com header.i=@suse.com header.b="ejGSVGcy"; dkim=pass (1024-bit key) header.d=suse.com header.i=@suse.com header.b="ejGSVGcy" Received: from imap1.dmz-prg2.suse.org (unknown [10.150.64.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id CB8DB5BDDC for ; Thu, 19 Mar 2026 21:05:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1773954317; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=He9X0e4758FC1Hpl0DxQup63e8zlZIPzxHFMHQRP3Po=; b=ejGSVGcyiLx1a/BmHP52Cv/gJ5tkeW1Ge1ZbhXttrTEyGGO6f8d26UjxD1z+JvCRtqyWNo xFWbQ68vqQzR9EhNuOYx09rPgMnk3Uz+6qhYtSLhoSnew+Yey8uuGNARK9PsQESQZCY0qL sNkkE7uvONXwJhxwz8xbccxkyk1m+cA= Authentication-Results: smtp-out2.suse.de; none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1773954317; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=He9X0e4758FC1Hpl0DxQup63e8zlZIPzxHFMHQRP3Po=; b=ejGSVGcyiLx1a/BmHP52Cv/gJ5tkeW1Ge1ZbhXttrTEyGGO6f8d26UjxD1z+JvCRtqyWNo xFWbQ68vqQzR9EhNuOYx09rPgMnk3Uz+6qhYtSLhoSnew+Yey8uuGNARK9PsQESQZCY0qL sNkkE7uvONXwJhxwz8xbccxkyk1m+cA= Received: from imap1.dmz-prg2.suse.org (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by imap1.dmz-prg2.suse.org (Postfix) with ESMTPS id CC6A34273B for ; Thu, 19 Mar 2026 21:05:16 +0000 (UTC) Received: from dovecot-director2.suse.de ([2a07:de40:b281:106:10:150:64:167]) by imap1.dmz-prg2.suse.org with ESMTPSA id MBKVHgxlvGk5FAAAD6G6ig (envelope-from ) for ; Thu, 19 Mar 2026 21:05:16 +0000 From: Qu Wenruo To: linux-btrfs@vger.kernel.org Subject: [PATCH 5/6] btrfs: implement uncompressed fallback for delayed bbio Date: Fri, 20 Mar 2026 07:34:49 +1030 Message-ID: <71a51e57630e5728da660e29eab1450f34f03e7a.1773953307.git.wqu@suse.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-btrfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Score: -2.80 X-Spam-Level: X-Spamd-Result: default: False [-2.80 / 50.00]; BAYES_HAM(-3.00)[100.00%]; NEURAL_HAM_LONG(-1.00)[-1.000]; MID_CONTAINS_FROM(1.00)[]; R_MISSING_CHARSET(0.50)[]; NEURAL_HAM_SHORT(-0.20)[-1.000]; MIME_GOOD(-0.10)[text/plain]; FUZZY_RATELIMITED(0.00)[rspamd.com]; RCVD_VIA_SMTP_AUTH(0.00)[]; RCPT_COUNT_ONE(0.00)[1]; ARC_NA(0.00)[]; DKIM_SIGNED(0.00)[suse.com:s=susede1]; DBL_BLOCKED_OPENRESOLVER(0.00)[imap1.dmz-prg2.suse.org:helo,suse.com:mid,suse.com:email]; FROM_EQ_ENVFROM(0.00)[]; FROM_HAS_DN(0.00)[]; MIME_TRACE(0.00)[0:+]; RCVD_COUNT_TWO(0.00)[2]; TO_MATCH_ENVRCPT_ALL(0.00)[]; TO_DN_NONE(0.00)[]; PREVIOUSLY_DELIVERED(0.00)[linux-btrfs@vger.kernel.org]; RCVD_TLS_ALL(0.00)[] X-Spam-Flag: NO When the compression failed (either bad ratio, fragmented free space, or writeback path choose to submit the bio early), we have to fall back to uncompressed writes. The uncompressed fallback is mostly the same as cow_file_range() but with some changes: - Endio function is slightly different from the compressed path Only in the folio freeing handling. - Uncompressed fallback error handling Since at the stage, the folios already have WRITEBACK flag set, we do not need to do the usual page unlock/end writeback, but just free the reserved space and call it a day. Signed-off-by: Qu Wenruo --- fs/btrfs/inode.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 147 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index ef1f5efb68ca..183fb3c83c10 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -7768,10 +7768,144 @@ static bool try_submit_compressed(struct btrfs_bio *parent) return false; } +static void end_bbio_delayed_uncompressed(struct btrfs_bio *bbio) +{ + struct delayed_bio_private *dbp = bbio->private; + struct btrfs_bio *parent = dbp->delayed_bbio; + struct folio_iter fi; + + bio_for_each_folio_all(fi, &bbio->bio) + folio_put(fi.folio); + bio_put(&bbio->bio); + + cmpxchg(&parent->status, BLK_STS_OK, bbio->status); + if (atomic_dec_and_test(&dbp->pending_ios)) + btrfs_bio_end_io(parent, parent->status); +} + +static struct btrfs_bio *child_bbio_from_page_cache(struct btrfs_bio *parent, + u64 fileoff, u32 len) +{ + struct btrfs_inode *inode = parent->inode; + struct address_space *mapping = inode->vfs_inode.i_mapping; + struct btrfs_bio *bbio; + struct folio_iter fi; + u64 cur = fileoff; + int ret; + + bbio = btrfs_bio_alloc(round_up(len, PAGE_SIZE) >> PAGE_SHIFT, REQ_OP_WRITE, + inode, fileoff, end_bbio_delayed_uncompressed, + parent->private); + + while (cur < fileoff + len) { + struct folio *folio; + u32 cur_len; + + folio = filemap_get_folio(mapping, cur >> PAGE_SHIFT); + if (IS_ERR(folio)) { + ret = PTR_ERR(folio); + goto error; + } + cur_len = min_t(u64, folio_next_pos(folio), fileoff + len) - cur; + ret = bio_add_folio(&bbio->bio, folio, cur_len, + offset_in_folio(folio, cur)); + ASSERT(ret); + cur += cur_len; + } + + return bbio; +error: + bio_for_each_folio_all(fi, &bbio->bio) + folio_put(fi.folio); + bio_put(&bbio->bio); + return ERR_PTR(ret); +} + +static int submit_one_uncompressed_range(struct btrfs_bio *parent, struct btrfs_key *ins, + struct extent_state **cached, u64 file_offset, + u32 num_bytes, u64 alloc_hint, u32 *ret_alloc_size) +{ + struct btrfs_inode *inode = parent->inode; + struct delayed_bio_private *dbp = parent->private; + struct btrfs_root *root = inode->root; + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_ordered_extent *ordered; + struct btrfs_file_extent file_extent; + struct btrfs_bio *child; + struct extent_map *em; + u64 cur_end; + u32 cur_len = 0; + int ret; + + ret = btrfs_reserve_extent(root, num_bytes, num_bytes, fs_info->sectorsize, + 0, alloc_hint, ins, true, true); + if (ret < 0) + return ret; + + cur_len = ins->offset; + cur_end = file_offset + cur_len - 1; + + file_extent.disk_bytenr = ins->objectid; + file_extent.disk_num_bytes = ins->offset; + file_extent.num_bytes = ins->offset; + file_extent.ram_bytes = ins->offset; + file_extent.offset = 0; + file_extent.compression = BTRFS_COMPRESS_NONE; + + btrfs_lock_extent(&inode->io_tree, file_offset, cur_end, cached); + em = btrfs_create_io_em(inode, file_offset, &file_extent, BTRFS_ORDERED_REGULAR); + if (IS_ERR(em)) { + ret = PTR_ERR(em); + btrfs_unlock_extent(&inode->io_tree, file_offset, cur_end, cached); + goto free_reserved; + } + btrfs_free_extent_map(em); + ordered = btrfs_alloc_ordered_extent(inode, file_offset, &file_extent, + 1U << BTRFS_ORDERED_REGULAR); + if (IS_ERR(ordered)) { + btrfs_drop_extent_map_range(inode, file_offset, cur_end, false); + btrfs_unlock_extent(&inode->io_tree, file_offset, cur_end, cached); + ret = PTR_ERR(ordered); + goto free_reserved; + } + btrfs_dec_block_group_reservations(fs_info, ins->objectid); + btrfs_unlock_extent(&inode->io_tree, file_offset, cur_end, cached); + child = child_bbio_from_page_cache(parent, file_offset, cur_len); + if (IS_ERR(child)) { + btrfs_put_ordered_extent(ordered); + btrfs_drop_extent_map_range(inode, file_offset, cur_end, false); + ret = PTR_ERR(ordered); + goto free_reserved; + } + child->ordered = ordered; + child->private = parent->private; + child->end_io = end_bbio_delayed_uncompressed; + child->bio.bi_iter.bi_sector = ins->objectid >> SECTOR_SHIFT; + atomic_inc(&dbp->pending_ios); + btrfs_submit_bbio(child, 0); + *ret_alloc_size = cur_len; + return 0; + +free_reserved: + btrfs_qgroup_free_data(inode, NULL, file_offset, cur_len, NULL); + btrfs_dec_block_group_reservations(fs_info, ins->objectid); + btrfs_free_reserved_extent(fs_info, ins->objectid, ins->offset, true); + ASSERT(ret != -EAGAIN); + return ret; +} + static void run_delayed_bbio(struct work_struct *work) { struct delayed_bio_private *dbp = container_of(work, struct delayed_bio_private, work); struct btrfs_bio *parent = dbp->delayed_bbio; + struct btrfs_key ins; + struct extent_state *cached = NULL; + const u32 uncompressed_size = bio_get_size(&parent->bio); + const u64 start = parent->file_offset; + const u64 end = start + uncompressed_size - 1; + u64 cur = start; + u64 alloc_hint; + int ret = 0; /* * Increase the pending_ios so that parent bbio won't end @@ -7781,8 +7915,19 @@ static void run_delayed_bbio(struct work_struct *work) if (try_submit_compressed(parent)) goto finish; - /* Uncompressed fallback is not yet implemented. */ - ASSERT(0); + alloc_hint = btrfs_get_extent_allocation_hint(parent->inode, start, + uncompressed_size); + while (cur < end) { + u32 cur_len; + + ret = submit_one_uncompressed_range(parent, &ins, &cached, + cur, end + 1 - cur, + alloc_hint, &cur_len); + if (ret < 0) + goto finish; + cur += cur_len; + alloc_hint += cur_len; + } finish: if (atomic_dec_and_test(&dbp->pending_ios)) -- 2.53.0