summaryrefslogtreecommitdiffstats
path: root/fs/jffs2/compr.c
blob: 1c5a7d9137e2b7c4b3764183fb23fc455155fad8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*
 * JFFS2 -- Journalling Flash File System, Version 2.
 *
 * Copyright © 2001-2007 Red Hat, Inc.
 * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
 * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
 *		    University of Szeged, Hungary
 *
 * Created by Arjan van de Ven <arjan@infradead.org>
 *
 * For licensing information, see the file 'LICENCE' in this directory.
 *
 */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <common.h>
#include "compr.h"

/* Available compressors are on this list */
static LIST_HEAD(jffs2_compressor_list);

/* Statistics for blocks stored without compression */
static uint32_t none_stat_decompr_blocks=0;

/*
 * Return 1 to use this compression
 */
int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
		     uint16_t comprtype, unsigned char *cdata_in,
		     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
{
	struct jffs2_compressor *this;
	int ret;

	/* Older code had a bug where it would write non-zero 'usercompr'
	   fields. Deal with it. */
	if ((comprtype & 0xff) <= JFFS2_COMPR_ZLIB)
		comprtype &= 0xff;

	switch (comprtype & 0xff) {
	case JFFS2_COMPR_NONE:
		/* This should be special-cased elsewhere, but we might as well deal with it */
		memcpy(data_out, cdata_in, datalen);
		none_stat_decompr_blocks++;
		break;
	case JFFS2_COMPR_ZERO:
		memset(data_out, 0, datalen);
		break;
	default:
		list_for_each_entry(this, &jffs2_compressor_list, list) {
			if (comprtype == this->compr) {
				this->usecount++;
				ret = this->decompress(cdata_in, data_out, cdatalen, datalen);
				if (ret) {
					pr_warn("Decompressor \"%s\" returned %d\n",
						this->name, ret);
				}
				else {
					this->stat_decompr_blocks++;
				}
				this->usecount--;
				return ret;
			}
		}
		pr_warn("compression type 0x%02x not available\n", comprtype);
		return -EIO;
	}
	return 0;
}

int jffs2_register_compressor(struct jffs2_compressor *comp)
{
	struct jffs2_compressor *this;

	if (!comp->name) {
		pr_warn("NULL compressor name at registering JFFS2 compressor. Failed.\n");
		return -1;
	}
	comp->compr_buf_size=0;
	comp->compr_buf=NULL;
	comp->usecount=0;
	comp->stat_compr_orig_size=0;
	comp->stat_compr_new_size=0;
	comp->stat_compr_blocks=0;
	comp->stat_decompr_blocks=0;
	jffs2_dbg(1, "Registering JFFS2 compressor \"%s\"\n", comp->name);

	list_for_each_entry(this, &jffs2_compressor_list, list) {
		if (this->priority < comp->priority) {
			list_add(&comp->list, this->list.prev);
			goto out;
		}
	}
	list_add_tail(&comp->list, &jffs2_compressor_list);
out:
	D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
		printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
	})


	return 0;
}

int jffs2_unregister_compressor(struct jffs2_compressor *comp)
{
	D2(struct jffs2_compressor *this);

	jffs2_dbg(1, "Unregistering JFFS2 compressor \"%s\"\n", comp->name);

	if (comp->usecount) {
		pr_warn("Compressor module is in use. Unregister failed.\n");
		return -1;
	}
	list_del(&comp->list);

	D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
		printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
	})
	return 0;
}

int __init jffs2_compressors_init(void)
{
/* Registering compressors */
#ifdef CONFIG_FS_JFFS2_COMPRESSION_ZLIB
	jffs2_zlib_init();
#endif
#ifdef CONFIG_FS_JFFS2_COMPRESSION_LZO
	jffs2_lzo_init();
#endif
#ifdef CONFIG_FS_JFFS2_COMPRESSION_RTIME
	jffs2_rtime_init();
#endif
#ifdef CONFIG_FS_JFFS2_COMPRESSION_RUBIN
	jffs2_dynrubin_init();
#endif
/* Setting default compression mode */
	return 0;
}

int jffs2_compressors_exit(void)
{
#ifdef CONFIG_FS_JFFS2_COMPRESSION_ZLIB
	jffs2_zlib_exit();
#endif
#ifdef CONFIG_FS_JFFS2_COMPRESSION_LZO
	jffs2_lzo_exit();
#endif
#ifdef CONFIG_FS_JFFS2_COMPRESSION_RTIME
	jffs2_rtime_exit();
#endif
#ifdef CONFIG_FS_JFFS2_COMPRESSION_RUBIN
	jffs2_dynrubin_exit();
#endif
	return 0;
}