fs/btrfs/subpage.c

Source file repositories/reference/linux-study-clean/fs/btrfs/subpage.c

File Facts

System
Linux kernel
Corpus path
fs/btrfs/subpage.c
Extension
.c
Size
24949 bytes
Lines
767
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0

#include <linux/slab.h>
#include "messages.h"
#include "subpage.h"
#include "btrfs_inode.h"

/*
 * Subpage (block size < folio size) support overview:
 *
 * Limitations:
 *
 * - Metadata must be fully aligned to node size
 *   So when nodesize <= page size, the metadata can never cross folio boundaries.
 *
 * - Only support blocks per folio <= min(BTRFS_MAX_FOLIO_SIZE / fs block size,
 *					  BTRFS_MAX_BLOCKS_PER_FOLIO)
 *   This is to ensure we can afford an on-stack bitmap, without the need to allocate
 *   bitmap memory at runtime.
 *
 * Implementation:
 *
 * - Common
 *   Both metadata and data will use a new structure, btrfs_folio_state, to
 *   record the status of each sector inside a page.  This provides the extra
 *   granularity needed.
 *
 * - Metadata
 *   Since we have multiple tree blocks inside one page, we can't rely on page
 *   locking anymore, or we will have greatly reduced concurrency or even
 *   deadlocks (hold one tree lock while trying to lock another tree lock in
 *   the same page).
 *
 *   Thus for metadata locking, subpage support relies on io_tree locking only.
 *   This means a slightly higher tree locking latency.
 */

int btrfs_attach_folio_state(const struct btrfs_fs_info *fs_info,
			     struct folio *folio, enum btrfs_folio_type type)
{
	struct btrfs_folio_state *bfs;

	/* For metadata we don't support large folio yet. */
	if (type == BTRFS_SUBPAGE_METADATA)
		ASSERT(!folio_test_large(folio));

	/*
	 * We have cases like a dummy extent buffer page, which is not mapped
	 * and doesn't need to be locked.
	 */
	if (folio->mapping)
		ASSERT(folio_test_locked(folio));

	/* Either not subpage, or the folio already has private attached. */
	if (folio_test_private(folio))
		return 0;
	if (type == BTRFS_SUBPAGE_METADATA && !btrfs_meta_is_subpage(fs_info))
		return 0;
	if (type == BTRFS_SUBPAGE_DATA && !btrfs_is_subpage(fs_info, folio))
		return 0;

	bfs = btrfs_alloc_folio_state(fs_info, folio_size(folio), type);
	if (IS_ERR(bfs))
		return PTR_ERR(bfs);

	folio_attach_private(folio, bfs);
	return 0;
}

void btrfs_detach_folio_state(const struct btrfs_fs_info *fs_info, struct folio *folio,
			      enum btrfs_folio_type type)
{
	struct btrfs_folio_state *bfs;

	/* Either not subpage, or the folio already has private attached. */
	if (!folio_test_private(folio))
		return;
	if (type == BTRFS_SUBPAGE_METADATA && !btrfs_meta_is_subpage(fs_info))
		return;
	if (type == BTRFS_SUBPAGE_DATA && !btrfs_is_subpage(fs_info, folio))
		return;

	bfs = folio_detach_private(folio);
	ASSERT(bfs);
	btrfs_free_folio_state(bfs);
}

struct btrfs_folio_state *btrfs_alloc_folio_state(const struct btrfs_fs_info *fs_info,
						  size_t fsize, enum btrfs_folio_type type)
{

Annotation

Implementation Notes