fs/btrfs/lzo.c

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

File Facts

System
Linux kernel
Corpus path
fs/btrfs/lzo.c
Extension
.c
Size
17960 bytes
Lines
595
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

struct workspace {
	void *mem;
	void *buf;	/* where decompressed data goes */
	void *cbuf;	/* where compressed data goes */
	struct list_head list;
};

static u32 workspace_buf_length(const struct btrfs_fs_info *fs_info)
{
	return lzo1x_worst_compress(fs_info->sectorsize);
}
static u32 workspace_cbuf_length(const struct btrfs_fs_info *fs_info)
{
	return lzo1x_worst_compress(fs_info->sectorsize);
}

void lzo_free_workspace(struct list_head *ws)
{
	struct workspace *workspace = list_entry(ws, struct workspace, list);

	kvfree(workspace->buf);
	kvfree(workspace->cbuf);
	kvfree(workspace->mem);
	kfree(workspace);
}

struct list_head *lzo_alloc_workspace(struct btrfs_fs_info *fs_info)
{
	struct workspace *workspace;

	workspace = kzalloc_obj(*workspace);
	if (!workspace)
		return ERR_PTR(-ENOMEM);

	workspace->mem = kvmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL | __GFP_NOWARN);
	workspace->buf = kvmalloc(workspace_buf_length(fs_info), GFP_KERNEL | __GFP_NOWARN);
	workspace->cbuf = kvmalloc(workspace_cbuf_length(fs_info), GFP_KERNEL | __GFP_NOWARN);
	if (!workspace->mem || !workspace->buf || !workspace->cbuf)
		goto fail;

	INIT_LIST_HEAD(&workspace->list);

	return &workspace->list;
fail:
	lzo_free_workspace(&workspace->list);
	return ERR_PTR(-ENOMEM);
}

/*
 * Write data into @out_folio and queue it into @out_bio.
 *
 * Return 0 if everything is fine and @total_out will be increased.
 * Return <0 for error.
 *
 * The @out_folio can be NULL after a full folio is queued.
 * Thus the caller should check and allocate a new folio when needed.
 */
static int write_and_queue_folio(struct bio *out_bio, struct folio **out_folio,
				 u32 *total_out, u32 write_len)
{
	const u32 fsize = folio_size(*out_folio);
	const u32 foffset = offset_in_folio(*out_folio, *total_out);

	ASSERT(out_folio && *out_folio);
	/* Should not cross folio boundary. */
	ASSERT(foffset + write_len <= fsize);

	/* We can not use bio_add_folio_nofail() which doesn't do any merge. */
	if (!bio_add_folio(out_bio, *out_folio, write_len, foffset)) {
		/*
		 * We have allocated a bio that havs BTRFS_MAX_COMPRESSED_PAGES
		 * vecs, and all ranges inside the same folio should have been
		 * merged.  If bio_add_folio() still failed, that means we have
		 * reached the bvec limits.
		 *
		 * This should only happen at the beginning of a folio, and
		 * caller is responsible for releasing the folio, since it's
		 * not yet queued into the bio.
		 */
		ASSERT(IS_ALIGNED(*total_out, fsize));
		return -E2BIG;
	}

	*total_out += write_len;
	/*
	 * The full folio has been filled and queued, reset @out_folio to NULL,
	 * so that error handling is fully handled by the bio.
	 */
	if (IS_ALIGNED(*total_out, fsize))
		*out_folio = NULL;

Annotation

Implementation Notes