jffs2: add compr=lzo and compr=zlib options
..to allow forcing of either compression scheme. This will override compiled-in defaults. jffs2_compress is reworked a bit, as the lzo/zlib override shares lots of code w/ the PRIORITY mode. v2: update show_options accordingly. Signed-off-by: Andres Salomon <dilinger@queued.net> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@intel.com>
This commit is contained in:
parent
92abc475d8
commit
123005f3cc
3 changed files with 110 additions and 37 deletions
119
fs/jffs2/compr.c
119
fs/jffs2/compr.c
|
@ -53,6 +53,78 @@ static int jffs2_is_best_compression(struct jffs2_compressor *this,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* jffs2_selected_compress:
|
||||||
|
* @compr: Explicit compression type to use (ie, JFFS2_COMPR_ZLIB).
|
||||||
|
* If 0, just take the first available compression mode.
|
||||||
|
* @data_in: Pointer to uncompressed data
|
||||||
|
* @cpage_out: Pointer to returned pointer to buffer for compressed data
|
||||||
|
* @datalen: On entry, holds the amount of data available for compression.
|
||||||
|
* On exit, expected to hold the amount of data actually compressed.
|
||||||
|
* @cdatalen: On entry, holds the amount of space available for compressed
|
||||||
|
* data. On exit, expected to hold the actual size of the compressed
|
||||||
|
* data.
|
||||||
|
*
|
||||||
|
* Returns: the compression type used. Zero is used to show that the data
|
||||||
|
* could not be compressed; probably because we couldn't find the requested
|
||||||
|
* compression mode.
|
||||||
|
*/
|
||||||
|
static int jffs2_selected_compress(u8 compr, unsigned char *data_in,
|
||||||
|
unsigned char **cpage_out, u32 *datalen, u32 *cdatalen)
|
||||||
|
{
|
||||||
|
struct jffs2_compressor *this;
|
||||||
|
int err, ret = JFFS2_COMPR_NONE;
|
||||||
|
uint32_t orig_slen, orig_dlen;
|
||||||
|
char *output_buf;
|
||||||
|
|
||||||
|
output_buf = kmalloc(*cdatalen, GFP_KERNEL);
|
||||||
|
if (!output_buf) {
|
||||||
|
printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
orig_slen = *datalen;
|
||||||
|
orig_dlen = *cdatalen;
|
||||||
|
spin_lock(&jffs2_compressor_list_lock);
|
||||||
|
list_for_each_entry(this, &jffs2_compressor_list, list) {
|
||||||
|
/* Skip decompress-only and disabled modules */
|
||||||
|
if (!this->compress || this->disabled)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Skip if not the desired compression type */
|
||||||
|
if (compr && (compr != this->compr))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Either compression type was unspecified, or we found our
|
||||||
|
* compressor; either way, we're good to go.
|
||||||
|
*/
|
||||||
|
this->usecount++;
|
||||||
|
spin_unlock(&jffs2_compressor_list_lock);
|
||||||
|
|
||||||
|
*datalen = orig_slen;
|
||||||
|
*cdatalen = orig_dlen;
|
||||||
|
err = this->compress(data_in, output_buf, datalen, cdatalen);
|
||||||
|
|
||||||
|
spin_lock(&jffs2_compressor_list_lock);
|
||||||
|
this->usecount--;
|
||||||
|
if (!err) {
|
||||||
|
/* Success */
|
||||||
|
ret = this->compr;
|
||||||
|
this->stat_compr_blocks++;
|
||||||
|
this->stat_compr_orig_size += *datalen;
|
||||||
|
this->stat_compr_new_size += *cdatalen;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock(&jffs2_compressor_list_lock);
|
||||||
|
if (ret == JFFS2_COMPR_NONE)
|
||||||
|
kfree(output_buf);
|
||||||
|
else
|
||||||
|
*cpage_out = output_buf;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* jffs2_compress:
|
/* jffs2_compress:
|
||||||
* @data_in: Pointer to uncompressed data
|
* @data_in: Pointer to uncompressed data
|
||||||
* @cpage_out: Pointer to returned pointer to buffer for compressed data
|
* @cpage_out: Pointer to returned pointer to buffer for compressed data
|
||||||
|
@ -91,37 +163,8 @@ uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
|
||||||
case JFFS2_COMPR_MODE_NONE:
|
case JFFS2_COMPR_MODE_NONE:
|
||||||
break;
|
break;
|
||||||
case JFFS2_COMPR_MODE_PRIORITY:
|
case JFFS2_COMPR_MODE_PRIORITY:
|
||||||
output_buf = kmalloc(*cdatalen,GFP_KERNEL);
|
ret = jffs2_selected_compress(0, data_in, cpage_out, datalen,
|
||||||
if (!output_buf) {
|
cdatalen);
|
||||||
printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
orig_slen = *datalen;
|
|
||||||
orig_dlen = *cdatalen;
|
|
||||||
spin_lock(&jffs2_compressor_list_lock);
|
|
||||||
list_for_each_entry(this, &jffs2_compressor_list, list) {
|
|
||||||
/* Skip decompress-only backwards-compatibility and disabled modules */
|
|
||||||
if ((!this->compress)||(this->disabled))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
this->usecount++;
|
|
||||||
spin_unlock(&jffs2_compressor_list_lock);
|
|
||||||
*datalen = orig_slen;
|
|
||||||
*cdatalen = orig_dlen;
|
|
||||||
compr_ret = this->compress(data_in, output_buf, datalen, cdatalen);
|
|
||||||
spin_lock(&jffs2_compressor_list_lock);
|
|
||||||
this->usecount--;
|
|
||||||
if (!compr_ret) {
|
|
||||||
ret = this->compr;
|
|
||||||
this->stat_compr_blocks++;
|
|
||||||
this->stat_compr_orig_size += *datalen;
|
|
||||||
this->stat_compr_new_size += *cdatalen;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spin_unlock(&jffs2_compressor_list_lock);
|
|
||||||
if (ret == JFFS2_COMPR_NONE)
|
|
||||||
kfree(output_buf);
|
|
||||||
break;
|
break;
|
||||||
case JFFS2_COMPR_MODE_SIZE:
|
case JFFS2_COMPR_MODE_SIZE:
|
||||||
case JFFS2_COMPR_MODE_FAVOURLZO:
|
case JFFS2_COMPR_MODE_FAVOURLZO:
|
||||||
|
@ -179,22 +222,28 @@ uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
|
||||||
best->stat_compr_orig_size += best_slen;
|
best->stat_compr_orig_size += best_slen;
|
||||||
best->stat_compr_new_size += best_dlen;
|
best->stat_compr_new_size += best_dlen;
|
||||||
ret = best->compr;
|
ret = best->compr;
|
||||||
|
*cpage_out = output_buf;
|
||||||
}
|
}
|
||||||
spin_unlock(&jffs2_compressor_list_lock);
|
spin_unlock(&jffs2_compressor_list_lock);
|
||||||
break;
|
break;
|
||||||
|
case JFFS2_COMPR_MODE_FORCELZO:
|
||||||
|
ret = jffs2_selected_compress(JFFS2_COMPR_LZO, data_in,
|
||||||
|
cpage_out, datalen, cdatalen);
|
||||||
|
break;
|
||||||
|
case JFFS2_COMPR_MODE_FORCEZLIB:
|
||||||
|
ret = jffs2_selected_compress(JFFS2_COMPR_ZLIB, data_in,
|
||||||
|
cpage_out, datalen, cdatalen);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printk(KERN_ERR "JFFS2: unknown compression mode.\n");
|
printk(KERN_ERR "JFFS2: unknown compression mode.\n");
|
||||||
}
|
}
|
||||||
out:
|
|
||||||
if (ret == JFFS2_COMPR_NONE) {
|
if (ret == JFFS2_COMPR_NONE) {
|
||||||
*cpage_out = data_in;
|
*cpage_out = data_in;
|
||||||
*datalen = *cdatalen;
|
*datalen = *cdatalen;
|
||||||
none_stat_compr_blocks++;
|
none_stat_compr_blocks++;
|
||||||
none_stat_compr_size += *datalen;
|
none_stat_compr_size += *datalen;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
*cpage_out = output_buf;
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,8 @@
|
||||||
#define JFFS2_COMPR_MODE_PRIORITY 1
|
#define JFFS2_COMPR_MODE_PRIORITY 1
|
||||||
#define JFFS2_COMPR_MODE_SIZE 2
|
#define JFFS2_COMPR_MODE_SIZE 2
|
||||||
#define JFFS2_COMPR_MODE_FAVOURLZO 3
|
#define JFFS2_COMPR_MODE_FAVOURLZO 3
|
||||||
|
#define JFFS2_COMPR_MODE_FORCELZO 4
|
||||||
|
#define JFFS2_COMPR_MODE_FORCEZLIB 5
|
||||||
|
|
||||||
#define FAVOUR_LZO_PERCENT 80
|
#define FAVOUR_LZO_PERCENT 80
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,14 @@ static const char *jffs2_compr_name(unsigned int compr)
|
||||||
switch (compr) {
|
switch (compr) {
|
||||||
case JFFS2_COMPR_MODE_NONE:
|
case JFFS2_COMPR_MODE_NONE:
|
||||||
return "none";
|
return "none";
|
||||||
|
#ifdef CONFIG_JFFS2_LZO
|
||||||
|
case JFFS2_COMPR_MODE_FORCELZO:
|
||||||
|
return "lzo";
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_JFFS2_ZLIB
|
||||||
|
case JFFS2_COMPR_MODE_FORCEZLIB:
|
||||||
|
return "zlib";
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
/* should never happen; programmer error */
|
/* should never happen; programmer error */
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
|
@ -195,11 +203,25 @@ static int jffs2_parse_options(struct jffs2_sb_info *c, char *data)
|
||||||
|
|
||||||
if (!name)
|
if (!name)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
if (!strcmp(name, "none")) {
|
if (!strcmp(name, "none"))
|
||||||
c->mount_opts.compr = JFFS2_COMPR_MODE_NONE;
|
c->mount_opts.compr = JFFS2_COMPR_MODE_NONE;
|
||||||
c->mount_opts.override_compr = true;
|
#ifdef CONFIG_JFFS2_LZO
|
||||||
|
else if (!strcmp(name, "lzo"))
|
||||||
|
c->mount_opts.compr = JFFS2_COMPR_MODE_FORCELZO;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_JFFS2_ZLIB
|
||||||
|
else if (!strcmp(name, "zlib"))
|
||||||
|
c->mount_opts.compr =
|
||||||
|
JFFS2_COMPR_MODE_FORCEZLIB;
|
||||||
|
#endif
|
||||||
|
else {
|
||||||
|
printk(KERN_ERR "JFFS2 Error: unknown compressor \"%s\"",
|
||||||
|
name);
|
||||||
|
kfree(name);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
kfree(name);
|
kfree(name);
|
||||||
|
c->mount_opts.override_compr = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printk(KERN_ERR "JFFS2 Error: unrecognized mount option '%s' or missing value\n",
|
printk(KERN_ERR "JFFS2 Error: unrecognized mount option '%s' or missing value\n",
|
||||||
|
|
Loading…
Reference in a new issue