return zstrm;
}
-bool zcomp_available_algorithm(const char *comp)
-{
- int i = 0;
-
- while (backends[i]) {
- if (sysfs_streq(comp, backends[i]))
- return true;
- i++;
- }
-
- /*
- * Crypto does not ignore a trailing new line symbol,
- * so make sure you don't supply a string containing
- * one.
- * This also means that we permit zcomp initialisation
- * with any compressing algorithm known to crypto api.
- */
- return crypto_has_comp(comp, 0, 0) == 1;
-}
-
/* show available compressors */
ssize_t zcomp_available_show(const char *comp, char *buf)
{
return -ENOMEM;
}
-void zcomp_destroy(struct zcomp *comp)
+static void zcomp_destroy(struct zcomp *comp)
{
unsigned long cpu;
kfree(comp);
}
+void zcomp_reset(struct list_head *blist)
+{
+ struct list_head *curr, *next;
+ struct zcomp *comp;
+ int i;
+
+ list_for_each_safe(curr, next, blist) {
+ comp = list_entry(curr, struct zcomp, list);
+ list_del(&comp->list);
+
+ for (i = 0; backends[i]; i++) {
+ if (sysfs_streq(comp->name, backends[i]))
+ break;
+ }
+
+ if (!backends[i])
+ kfree(comp->name);
+
+ zcomp_destroy(comp);
+ }
+}
+
/*
- * search available compressors for requested algorithm.
* allocate new zcomp and initialize it. return compressing
* backend pointer or ERR_PTR if things went bad. ERR_PTR(-EINVAL)
* if requested algorithm is not supported, ERR_PTR(-ENOMEM) in
* case of allocation error, or any other error potentially
* returned by zcomp_init().
*/
-struct zcomp *zcomp_create(const char *compress)
+static struct zcomp *zcomp_create(const char *compress)
{
struct zcomp *comp;
int error;
- if (!zcomp_available_algorithm(compress))
- return ERR_PTR(-EINVAL);
-
comp = kzalloc(sizeof(struct zcomp), GFP_KERNEL);
if (!comp)
return ERR_PTR(-ENOMEM);
}
return comp;
}
+
+struct zcomp *zcomp_get_instance(struct list_head *blist, const char *name)
+{
+ struct zcomp *comp;
+ const char *comp_name = NULL;
+ int i;
+
+ list_for_each_entry(comp, blist, list)
+ if (sysfs_streq(name, comp->name))
+ return comp;
+
+ for (i = 0; backends[i]; i++) {
+ if (sysfs_streq(name, backends[i])) {
+ comp_name = backends[i];
+ break;
+ }
+ }
+
+ if (!comp_name) {
+ /*
+ * Crypto does not ignore a trailing new line symbol,
+ * so make sure you don't supply a string containing
+ * one.
+ * This also means that we permit zcomp initialisation
+ * with any compressing algorithm known to crypto api.
+ */
+ if (crypto_has_comp(name, 0, 0) == 1)
+ comp_name = kstrdup(name, GFP_KERNEL);
+ else
+ return ERR_PTR(-ENOENT);
+ }
+
+ comp = zcomp_create(comp_name);
+ if (IS_ERR(comp)) {
+ pr_err("Cannot initialise %s compressing backend\n", name);
+ if (!backends[i])
+ kfree(comp_name);
+ return comp;
+ }
+
+ list_add(&comp->list, blist);
+
+ return comp;
+}
struct device_attribute *attr, const char *buf, size_t len)
{
struct zram *zram = dev_to_zram(dev);
+ struct zcomp *comp;
char compressor[CRYPTO_MAX_ALG_NAME];
size_t sz;
if (sz > 0 && compressor[sz - 1] == '\n')
compressor[sz - 1] = 0x00;
- if (!zcomp_available_algorithm(compressor))
+ comp = zcomp_get_instance(&zram->backend_list, compressor);
+ if (IS_ERR_OR_NULL(comp))
return -EINVAL;
down_write(&zram->init_lock);
- if (init_done(zram)) {
- up_write(&zram->init_lock);
- pr_info("Can't change algorithm for initialized device\n");
- return -EBUSY;
- }
-
+ zram->comp = comp;
strlcpy(zram->compressor, compressor, sizeof(compressor));
up_write(&zram->init_lock);
return len;
int ret = 0;
unsigned char *cmem;
struct zram_meta *meta = zram->meta;
+ struct zcomp *comp;
unsigned long handle;
unsigned int size;
bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
handle = meta->table[index].handle;
size = zram_get_obj_size(meta, index);
+ comp = meta->table[index].comp;
if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) {
bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
if (size == PAGE_SIZE) {
memcpy(mem, cmem, PAGE_SIZE);
} else {
- struct zcomp_strm *zstrm = zcomp_stream_get(zram->comp);
+ struct zcomp_strm *zstrm = zcomp_stream_get(comp);
ret = zcomp_decompress(zstrm, cmem, size, mem);
- zcomp_stream_put(zram->comp);
+ zcomp_stream_put(comp);
}
zs_unmap_object(meta->mem_pool, handle);
bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
unsigned long handle = 0;
struct page *page;
unsigned char *user_mem, *cmem, *src, *uncmem = NULL;
+ struct zcomp *comp;
struct zram_meta *meta = zram->meta;
struct zcomp_strm *zstrm = NULL;
unsigned long alloced_pages;
goto out;
}
- zstrm = zcomp_stream_get(zram->comp);
+ comp = zram->comp;
+ zstrm = zcomp_stream_get(comp);
ret = zcomp_compress(zstrm, uncmem, &clen);
if (!is_partial_io(bvec)) {
kunmap_atomic(user_mem);
memcpy(cmem, src, clen);
}
- zcomp_stream_put(zram->comp);
+ zcomp_stream_put(comp);
zstrm = NULL;
zs_unmap_object(meta->mem_pool, handle);
zram_free_page(zram, index);
meta->table[index].handle = handle;
+ meta->table[index].comp = comp;
zram_set_obj_size(meta, index, clen);
bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
atomic64_inc(&zram->stats.pages_stored);
out:
if (zstrm)
- zcomp_stream_put(zram->comp);
+ zcomp_stream_put(comp);
if (is_partial_io(bvec))
kfree(uncmem);
return ret;
static void zram_reset_device(struct zram *zram)
{
struct zram_meta *meta;
- struct zcomp *comp;
u64 disksize;
down_write(&zram->init_lock);
}
meta = zram->meta;
- comp = zram->comp;
disksize = zram->disksize;
/*
* Refcount will go down to 0 eventually and r/w handler
up_write(&zram->init_lock);
/* I/O operation under all of CPU are done so let's free */
zram_meta_free(meta, disksize);
- zcomp_destroy(comp);
+
+ zram->comp = NULL;
+ zcomp_reset(&zram->backend_list);
}
static ssize_t disksize_store(struct device *dev,
struct zram *zram = dev_to_zram(dev);
int err;
+ down_write(&zram->init_lock);
+ if (init_done(zram)) {
+ pr_info("Cannot change disksize for initialized device\n");
+ up_write(&zram->init_lock);
+ return -EBUSY;
+ }
+ up_write(&zram->init_lock);
+
disksize = memparse(buf, NULL);
if (!disksize)
return -EINVAL;
if (!meta)
return -ENOMEM;
- comp = zcomp_create(zram->compressor);
- if (IS_ERR(comp)) {
- pr_err("Cannot initialise %s compressing backend\n",
- zram->compressor);
+ comp = zcomp_get_instance(&zram->backend_list, zram->compressor);
+ if (IS_ERR_OR_NULL(comp)) {
err = PTR_ERR(comp);
goto out_free_meta;
}
down_write(&zram->init_lock);
- if (init_done(zram)) {
- pr_info("Cannot change disksize for initialized device\n");
- err = -EBUSY;
- goto out_destroy_comp;
- }
-
init_waitqueue_head(&zram->io_done);
atomic_set(&zram->refcount, 1);
zram->meta = meta;
up_write(&zram->init_lock);
return len;
-
-out_destroy_comp:
- up_write(&zram->init_lock);
- zcomp_destroy(comp);
out_free_meta:
zram_meta_free(meta, disksize);
return err;
goto out_free_disk;
}
strlcpy(zram->compressor, default_compressor, sizeof(zram->compressor));
+ INIT_LIST_HEAD(&zram->backend_list);
+
zram->meta = NULL;
pr_info("Added device: %s\n", zram->disk->disk_name);