fs/erofs/decompressor_zstd.c

Source file repositories/reference/linux-study-clean/fs/erofs/decompressor_zstd.c

File Facts

System
Linux kernel
Corpus path
fs/erofs/decompressor_zstd.c
Extension
.c
Size
5939 bytes
Lines
221
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 z_erofs_zstd {
	struct z_erofs_zstd *next;
	u8 bounce[PAGE_SIZE];
	void *wksp;
	unsigned int wkspsz;
};

static DEFINE_SPINLOCK(z_erofs_zstd_lock);
static unsigned int z_erofs_zstd_max_dictsize;
static unsigned int z_erofs_zstd_nstrms, z_erofs_zstd_avail_strms;
static struct z_erofs_zstd *z_erofs_zstd_head;
static DECLARE_WAIT_QUEUE_HEAD(z_erofs_zstd_wq);

module_param_named(zstd_streams, z_erofs_zstd_nstrms, uint, 0444);

static struct z_erofs_zstd *z_erofs_isolate_strms(bool all)
{
	struct z_erofs_zstd *strm;

again:
	spin_lock(&z_erofs_zstd_lock);
	strm = z_erofs_zstd_head;
	if (!strm) {
		spin_unlock(&z_erofs_zstd_lock);
		wait_event(z_erofs_zstd_wq, READ_ONCE(z_erofs_zstd_head));
		goto again;
	}
	z_erofs_zstd_head = all ? NULL : strm->next;
	spin_unlock(&z_erofs_zstd_lock);
	return strm;
}

static void z_erofs_zstd_exit(void)
{
	while (z_erofs_zstd_avail_strms) {
		struct z_erofs_zstd *strm, *n;

		for (strm = z_erofs_isolate_strms(true); strm; strm = n) {
			n = strm->next;

			kvfree(strm->wksp);
			kfree(strm);
			--z_erofs_zstd_avail_strms;
		}
	}
}

static int __init z_erofs_zstd_init(void)
{
	/* by default, use # of possible CPUs instead */
	if (!z_erofs_zstd_nstrms)
		z_erofs_zstd_nstrms = num_possible_cpus();

	for (; z_erofs_zstd_avail_strms < z_erofs_zstd_nstrms;
	     ++z_erofs_zstd_avail_strms) {
		struct z_erofs_zstd *strm;

		strm = kzalloc_obj(*strm);
		if (!strm) {
			z_erofs_zstd_exit();
			return -ENOMEM;
		}
		spin_lock(&z_erofs_zstd_lock);
		strm->next = z_erofs_zstd_head;
		z_erofs_zstd_head = strm;
		spin_unlock(&z_erofs_zstd_lock);
	}
	return 0;
}

static int z_erofs_load_zstd_config(struct super_block *sb,
			struct erofs_super_block *dsb, void *data, int size)
{
	static DEFINE_MUTEX(zstd_resize_mutex);
	struct z_erofs_zstd_cfgs *zstd = data;
	unsigned int dict_size, wkspsz;
	struct z_erofs_zstd *strm, *head = NULL;
	void *wksp;

	if (!zstd || size < sizeof(struct z_erofs_zstd_cfgs) || zstd->format) {
		erofs_err(sb, "unsupported zstd format, size=%u", size);
		return -EINVAL;
	}

	if (zstd->windowlog > ilog2(Z_EROFS_ZSTD_MAX_DICT_SIZE) - 10) {
		erofs_err(sb, "unsupported zstd window log %u", zstd->windowlog);
		return -EINVAL;
	}
	dict_size = 1U << (zstd->windowlog + 10);

Annotation

Implementation Notes