|
@@ -34,6 +34,8 @@
|
|
|
#include <linux/parser.h>
|
|
|
#include <linux/seq_file.h>
|
|
|
#include <linux/mount.h>
|
|
|
+#include <linux/math64.h>
|
|
|
+#include <linux/writeback.h>
|
|
|
#include "ubifs.h"
|
|
|
|
|
|
/*
|
|
@@ -417,39 +419,54 @@ static int ubifs_show_options(struct seq_file *s, struct vfsmount *mnt)
|
|
|
else if (c->mount_opts.chk_data_crc == 1)
|
|
|
seq_printf(s, ",no_chk_data_crc");
|
|
|
|
|
|
+ if (c->mount_opts.override_compr) {
|
|
|
+ seq_printf(s, ",compr=");
|
|
|
+ seq_printf(s, ubifs_compr_name(c->mount_opts.compr_type));
|
|
|
+ }
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static int ubifs_sync_fs(struct super_block *sb, int wait)
|
|
|
{
|
|
|
+ int i, err;
|
|
|
struct ubifs_info *c = sb->s_fs_info;
|
|
|
- int i, ret = 0, err;
|
|
|
- long long bud_bytes;
|
|
|
-
|
|
|
- if (c->jheads) {
|
|
|
- for (i = 0; i < c->jhead_cnt; i++) {
|
|
|
- err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
|
|
|
- if (err && !ret)
|
|
|
- ret = err;
|
|
|
- }
|
|
|
+ struct writeback_control wbc = {
|
|
|
+ .sync_mode = wait ? WB_SYNC_ALL : WB_SYNC_HOLD,
|
|
|
+ .range_start = 0,
|
|
|
+ .range_end = LLONG_MAX,
|
|
|
+ .nr_to_write = LONG_MAX,
|
|
|
+ };
|
|
|
+
|
|
|
+ if (sb->s_flags & MS_RDONLY)
|
|
|
+ return 0;
|
|
|
|
|
|
- /* Commit the journal unless it has too little data */
|
|
|
- spin_lock(&c->buds_lock);
|
|
|
- bud_bytes = c->bud_bytes;
|
|
|
- spin_unlock(&c->buds_lock);
|
|
|
- if (bud_bytes > c->leb_size) {
|
|
|
- err = ubifs_run_commit(c);
|
|
|
- if (err)
|
|
|
- return err;
|
|
|
- }
|
|
|
+ /*
|
|
|
+ * Synchronize write buffers, because 'ubifs_run_commit()' does not
|
|
|
+ * do this if it waits for an already running commit.
|
|
|
+ */
|
|
|
+ for (i = 0; i < c->jhead_cnt; i++) {
|
|
|
+ err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * We ought to call sync for c->ubi but it does not have one. If it had
|
|
|
- * it would in turn call mtd->sync, however mtd operations are
|
|
|
- * synchronous anyway, so we don't lose any sleep here.
|
|
|
+ * VFS calls '->sync_fs()' before synchronizing all dirty inodes and
|
|
|
+ * pages, so synchronize them first, then commit the journal. Strictly
|
|
|
+ * speaking, it is not necessary to commit the journal here,
|
|
|
+ * synchronizing write-buffers would be enough. But committing makes
|
|
|
+ * UBIFS free space predictions much more accurate, so we want to let
|
|
|
+ * the user be able to get more accurate results of 'statfs()' after
|
|
|
+ * they synchronize the file system.
|
|
|
*/
|
|
|
- return ret;
|
|
|
+ generic_sync_sb_inodes(sb, &wbc);
|
|
|
+
|
|
|
+ err = ubifs_run_commit(c);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ return ubi_sync(c->vi.ubi_num);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -596,7 +613,7 @@ static int bud_wbuf_callback(struct ubifs_info *c, int lnum, int free, int pad)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * init_constants_late - initialize UBIFS constants.
|
|
|
+ * init_constants_sb - initialize UBIFS constants.
|
|
|
* @c: UBIFS file-system description object
|
|
|
*
|
|
|
* This is a helper function which initializes various UBIFS constants after
|
|
@@ -604,10 +621,10 @@ static int bud_wbuf_callback(struct ubifs_info *c, int lnum, int free, int pad)
|
|
|
* makes sure they are all right. Returns zero in case of success and a
|
|
|
* negative error code in case of failure.
|
|
|
*/
|
|
|
-static int init_constants_late(struct ubifs_info *c)
|
|
|
+static int init_constants_sb(struct ubifs_info *c)
|
|
|
{
|
|
|
int tmp, err;
|
|
|
- uint64_t tmp64;
|
|
|
+ long long tmp64;
|
|
|
|
|
|
c->main_bytes = (long long)c->main_lebs * c->leb_size;
|
|
|
c->max_znode_sz = sizeof(struct ubifs_znode) +
|
|
@@ -634,9 +651,8 @@ static int init_constants_late(struct ubifs_info *c)
|
|
|
* Make sure that the log is large enough to fit reference nodes for
|
|
|
* all buds plus one reserved LEB.
|
|
|
*/
|
|
|
- tmp64 = c->max_bud_bytes;
|
|
|
- tmp = do_div(tmp64, c->leb_size);
|
|
|
- c->max_bud_cnt = tmp64 + !!tmp;
|
|
|
+ tmp64 = c->max_bud_bytes + c->leb_size - 1;
|
|
|
+ c->max_bud_cnt = div_u64(tmp64, c->leb_size);
|
|
|
tmp = (c->ref_node_alsz * c->max_bud_cnt + c->leb_size - 1);
|
|
|
tmp /= c->leb_size;
|
|
|
tmp += 1;
|
|
@@ -672,7 +688,7 @@ static int init_constants_late(struct ubifs_info *c)
|
|
|
* Consequently, if the journal is too small, UBIFS will treat it as
|
|
|
* always full.
|
|
|
*/
|
|
|
- tmp64 = (uint64_t)(c->jhead_cnt + 1) * c->leb_size + 1;
|
|
|
+ tmp64 = (long long)(c->jhead_cnt + 1) * c->leb_size + 1;
|
|
|
if (c->bg_bud_bytes < tmp64)
|
|
|
c->bg_bud_bytes = tmp64;
|
|
|
if (c->max_bud_bytes < tmp64 + c->leb_size)
|
|
@@ -682,6 +698,21 @@ static int init_constants_late(struct ubifs_info *c)
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * init_constants_master - initialize UBIFS constants.
|
|
|
+ * @c: UBIFS file-system description object
|
|
|
+ *
|
|
|
+ * This is a helper function which initializes various UBIFS constants after
|
|
|
+ * the master node has been read. It also checks various UBIFS parameters and
|
|
|
+ * makes sure they are all right.
|
|
|
+ */
|
|
|
+static void init_constants_master(struct ubifs_info *c)
|
|
|
+{
|
|
|
+ long long tmp64;
|
|
|
+
|
|
|
c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
|
|
|
|
|
|
/*
|
|
@@ -690,14 +721,13 @@ static int init_constants_late(struct ubifs_info *c)
|
|
|
* necessary to report something for the 'statfs()' call.
|
|
|
*
|
|
|
* Subtract the LEB reserved for GC, the LEB which is reserved for
|
|
|
- * deletions, and assume only one journal head is available.
|
|
|
+ * deletions, minimum LEBs for the index, and assume only one journal
|
|
|
+ * head is available.
|
|
|
*/
|
|
|
- tmp64 = c->main_lebs - 2 - c->jhead_cnt + 1;
|
|
|
- tmp64 *= (uint64_t)c->leb_size - c->leb_overhead;
|
|
|
+ tmp64 = c->main_lebs - 1 - 1 - MIN_INDEX_LEBS - c->jhead_cnt + 1;
|
|
|
+ tmp64 *= (long long)c->leb_size - c->leb_overhead;
|
|
|
tmp64 = ubifs_reported_space(c, tmp64);
|
|
|
c->block_cnt = tmp64 >> UBIFS_BLOCK_SHIFT;
|
|
|
-
|
|
|
- return 0;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -878,6 +908,7 @@ static int check_volume_empty(struct ubifs_info *c)
|
|
|
* Opt_no_bulk_read: disable bulk-reads
|
|
|
* Opt_chk_data_crc: check CRCs when reading data nodes
|
|
|
* Opt_no_chk_data_crc: do not check CRCs when reading data nodes
|
|
|
+ * Opt_override_compr: override default compressor
|
|
|
* Opt_err: just end of array marker
|
|
|
*/
|
|
|
enum {
|
|
@@ -887,6 +918,7 @@ enum {
|
|
|
Opt_no_bulk_read,
|
|
|
Opt_chk_data_crc,
|
|
|
Opt_no_chk_data_crc,
|
|
|
+ Opt_override_compr,
|
|
|
Opt_err,
|
|
|
};
|
|
|
|
|
@@ -897,6 +929,7 @@ static const match_table_t tokens = {
|
|
|
{Opt_no_bulk_read, "no_bulk_read"},
|
|
|
{Opt_chk_data_crc, "chk_data_crc"},
|
|
|
{Opt_no_chk_data_crc, "no_chk_data_crc"},
|
|
|
+ {Opt_override_compr, "compr=%s"},
|
|
|
{Opt_err, NULL},
|
|
|
};
|
|
|
|
|
@@ -950,6 +983,28 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
|
|
|
c->mount_opts.chk_data_crc = 1;
|
|
|
c->no_chk_data_crc = 1;
|
|
|
break;
|
|
|
+ case Opt_override_compr:
|
|
|
+ {
|
|
|
+ char *name = match_strdup(&args[0]);
|
|
|
+
|
|
|
+ if (!name)
|
|
|
+ return -ENOMEM;
|
|
|
+ if (!strcmp(name, "none"))
|
|
|
+ c->mount_opts.compr_type = UBIFS_COMPR_NONE;
|
|
|
+ else if (!strcmp(name, "lzo"))
|
|
|
+ c->mount_opts.compr_type = UBIFS_COMPR_LZO;
|
|
|
+ else if (!strcmp(name, "zlib"))
|
|
|
+ c->mount_opts.compr_type = UBIFS_COMPR_ZLIB;
|
|
|
+ else {
|
|
|
+ ubifs_err("unknown compressor \"%s\"", name);
|
|
|
+ kfree(name);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ kfree(name);
|
|
|
+ c->mount_opts.override_compr = 1;
|
|
|
+ c->default_compr = c->mount_opts.compr_type;
|
|
|
+ break;
|
|
|
+ }
|
|
|
default:
|
|
|
ubifs_err("unrecognized mount option \"%s\" "
|
|
|
"or missing value", p);
|
|
@@ -1018,6 +1073,30 @@ again:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * check_free_space - check if there is enough free space to mount.
|
|
|
+ * @c: UBIFS file-system description object
|
|
|
+ *
|
|
|
+ * This function makes sure UBIFS has enough free space to be mounted in
|
|
|
+ * read/write mode. UBIFS must always have some free space to allow deletions.
|
|
|
+ */
|
|
|
+static int check_free_space(struct ubifs_info *c)
|
|
|
+{
|
|
|
+ ubifs_assert(c->dark_wm > 0);
|
|
|
+ if (c->lst.total_free + c->lst.total_dirty < c->dark_wm) {
|
|
|
+ ubifs_err("insufficient free space to mount in read/write mode");
|
|
|
+ dbg_dump_budg(c);
|
|
|
+ dbg_dump_lprops(c);
|
|
|
+ /*
|
|
|
+ * We return %-EINVAL instead of %-ENOSPC because it seems to
|
|
|
+ * be the closest error code mentioned in the mount function
|
|
|
+ * documentation.
|
|
|
+ */
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* mount_ubifs - mount UBIFS file-system.
|
|
|
* @c: UBIFS file-system description object
|
|
@@ -1039,11 +1118,9 @@ static int mount_ubifs(struct ubifs_info *c)
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
|
-#ifdef CONFIG_UBIFS_FS_DEBUG
|
|
|
- c->dbg_buf = vmalloc(c->leb_size);
|
|
|
- if (!c->dbg_buf)
|
|
|
- return -ENOMEM;
|
|
|
-#endif
|
|
|
+ err = ubifs_debugging_init(c);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
|
|
|
err = check_volume_empty(c);
|
|
|
if (err)
|
|
@@ -1100,27 +1177,25 @@ static int mount_ubifs(struct ubifs_info *c)
|
|
|
goto out_free;
|
|
|
|
|
|
/*
|
|
|
- * Make sure the compressor which is set as the default on in the
|
|
|
- * superblock was actually compiled in.
|
|
|
+ * Make sure the compressor which is set as default in the superblock
|
|
|
+ * or overridden by mount options is actually compiled in.
|
|
|
*/
|
|
|
if (!ubifs_compr_present(c->default_compr)) {
|
|
|
- ubifs_warn("'%s' compressor is set by superblock, but not "
|
|
|
- "compiled in", ubifs_compr_name(c->default_compr));
|
|
|
- c->default_compr = UBIFS_COMPR_NONE;
|
|
|
+ ubifs_err("'compressor \"%s\" is not compiled in",
|
|
|
+ ubifs_compr_name(c->default_compr));
|
|
|
+ goto out_free;
|
|
|
}
|
|
|
|
|
|
- dbg_failure_mode_registration(c);
|
|
|
-
|
|
|
- err = init_constants_late(c);
|
|
|
+ err = init_constants_sb(c);
|
|
|
if (err)
|
|
|
- goto out_dereg;
|
|
|
+ goto out_free;
|
|
|
|
|
|
sz = ALIGN(c->max_idx_node_sz, c->min_io_size);
|
|
|
sz = ALIGN(sz + c->max_idx_node_sz, c->min_io_size);
|
|
|
c->cbuf = kmalloc(sz, GFP_NOFS);
|
|
|
if (!c->cbuf) {
|
|
|
err = -ENOMEM;
|
|
|
- goto out_dereg;
|
|
|
+ goto out_free;
|
|
|
}
|
|
|
|
|
|
sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id);
|
|
@@ -1145,6 +1220,8 @@ static int mount_ubifs(struct ubifs_info *c)
|
|
|
if (err)
|
|
|
goto out_master;
|
|
|
|
|
|
+ init_constants_master(c);
|
|
|
+
|
|
|
if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) {
|
|
|
ubifs_msg("recovery needed");
|
|
|
c->need_recovery = 1;
|
|
@@ -1183,12 +1260,9 @@ static int mount_ubifs(struct ubifs_info *c)
|
|
|
if (!mounted_read_only) {
|
|
|
int lnum;
|
|
|
|
|
|
- /* Check for enough free space */
|
|
|
- if (ubifs_calc_available(c, c->min_idx_lebs) <= 0) {
|
|
|
- ubifs_err("insufficient available space");
|
|
|
- err = -EINVAL;
|
|
|
+ err = check_free_space(c);
|
|
|
+ if (err)
|
|
|
goto out_orphans;
|
|
|
- }
|
|
|
|
|
|
/* Check for enough log space */
|
|
|
lnum = c->lhead_lnum + 1;
|
|
@@ -1232,6 +1306,10 @@ static int mount_ubifs(struct ubifs_info *c)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ err = dbg_debugfs_init_fs(c);
|
|
|
+ if (err)
|
|
|
+ goto out_infos;
|
|
|
+
|
|
|
err = dbg_check_filesystem(c);
|
|
|
if (err)
|
|
|
goto out_infos;
|
|
@@ -1283,8 +1361,20 @@ static int mount_ubifs(struct ubifs_info *c)
|
|
|
dbg_msg("tree fanout: %d", c->fanout);
|
|
|
dbg_msg("reserved GC LEB: %d", c->gc_lnum);
|
|
|
dbg_msg("first main LEB: %d", c->main_first);
|
|
|
+ dbg_msg("max. znode size %d", c->max_znode_sz);
|
|
|
+ dbg_msg("max. index node size %d", c->max_idx_node_sz);
|
|
|
+ dbg_msg("node sizes: data %zu, inode %zu, dentry %zu",
|
|
|
+ UBIFS_DATA_NODE_SZ, UBIFS_INO_NODE_SZ, UBIFS_DENT_NODE_SZ);
|
|
|
+ dbg_msg("node sizes: trun %zu, sb %zu, master %zu",
|
|
|
+ UBIFS_TRUN_NODE_SZ, UBIFS_SB_NODE_SZ, UBIFS_MST_NODE_SZ);
|
|
|
+ dbg_msg("node sizes: ref %zu, cmt. start %zu, orph %zu",
|
|
|
+ UBIFS_REF_NODE_SZ, UBIFS_CS_NODE_SZ, UBIFS_ORPH_NODE_SZ);
|
|
|
+ dbg_msg("max. node sizes: data %zu, inode %zu dentry %zu",
|
|
|
+ UBIFS_MAX_DATA_NODE_SZ, UBIFS_MAX_INO_NODE_SZ,
|
|
|
+ UBIFS_MAX_DENT_NODE_SZ);
|
|
|
dbg_msg("dead watermark: %d", c->dead_wm);
|
|
|
dbg_msg("dark watermark: %d", c->dark_wm);
|
|
|
+ dbg_msg("LEB overhead: %d", c->leb_overhead);
|
|
|
x = (long long)c->main_lebs * c->dark_wm;
|
|
|
dbg_msg("max. dark space: %lld (%lld KiB, %lld MiB)",
|
|
|
x, x >> 10, x >> 20);
|
|
@@ -1320,14 +1410,12 @@ out_wbufs:
|
|
|
free_wbufs(c);
|
|
|
out_cbuf:
|
|
|
kfree(c->cbuf);
|
|
|
-out_dereg:
|
|
|
- dbg_failure_mode_deregistration(c);
|
|
|
out_free:
|
|
|
kfree(c->bu.buf);
|
|
|
vfree(c->ileb_buf);
|
|
|
vfree(c->sbuf);
|
|
|
kfree(c->bottom_up_buf);
|
|
|
- UBIFS_DBG(vfree(c->dbg_buf));
|
|
|
+ ubifs_debugging_exit(c);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -1345,6 +1433,7 @@ static void ubifs_umount(struct ubifs_info *c)
|
|
|
dbg_gen("un-mounting UBI device %d, volume %d", c->vi.ubi_num,
|
|
|
c->vi.vol_id);
|
|
|
|
|
|
+ dbg_debugfs_exit_fs(c);
|
|
|
spin_lock(&ubifs_infos_lock);
|
|
|
list_del(&c->infos_list);
|
|
|
spin_unlock(&ubifs_infos_lock);
|
|
@@ -1364,8 +1453,7 @@ static void ubifs_umount(struct ubifs_info *c)
|
|
|
vfree(c->ileb_buf);
|
|
|
vfree(c->sbuf);
|
|
|
kfree(c->bottom_up_buf);
|
|
|
- UBIFS_DBG(vfree(c->dbg_buf));
|
|
|
- dbg_failure_mode_deregistration(c);
|
|
|
+ ubifs_debugging_exit(c);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1387,12 +1475,9 @@ static int ubifs_remount_rw(struct ubifs_info *c)
|
|
|
c->remounting_rw = 1;
|
|
|
c->always_chk_crc = 1;
|
|
|
|
|
|
- /* Check for enough free space */
|
|
|
- if (ubifs_calc_available(c, c->min_idx_lebs) <= 0) {
|
|
|
- ubifs_err("insufficient available space");
|
|
|
- err = -EINVAL;
|
|
|
+ err = check_free_space(c);
|
|
|
+ if (err)
|
|
|
goto out;
|
|
|
- }
|
|
|
|
|
|
if (c->old_leb_cnt != c->leb_cnt) {
|
|
|
struct ubifs_sb_node *sup;
|
|
@@ -1515,20 +1600,24 @@ out:
|
|
|
* @c: UBIFS file-system description object
|
|
|
*
|
|
|
* This function is called during un-mounting and re-mounting, and it commits
|
|
|
- * the journal unless the "fast unmount" mode is enabled. It also avoids
|
|
|
- * committing the journal if it contains too few data.
|
|
|
+ * the journal unless the "fast unmount" mode is enabled.
|
|
|
*/
|
|
|
static void commit_on_unmount(struct ubifs_info *c)
|
|
|
{
|
|
|
- if (!c->fast_unmount) {
|
|
|
- long long bud_bytes;
|
|
|
+ struct super_block *sb = c->vfs_sb;
|
|
|
+ long long bud_bytes;
|
|
|
|
|
|
- spin_lock(&c->buds_lock);
|
|
|
- bud_bytes = c->bud_bytes;
|
|
|
- spin_unlock(&c->buds_lock);
|
|
|
- if (bud_bytes > c->leb_size)
|
|
|
- ubifs_run_commit(c);
|
|
|
- }
|
|
|
+ /*
|
|
|
+ * This function is called before the background thread is stopped, so
|
|
|
+ * we may race with ongoing commit, which means we have to take
|
|
|
+ * @c->bud_lock to access @c->bud_bytes.
|
|
|
+ */
|
|
|
+ spin_lock(&c->buds_lock);
|
|
|
+ bud_bytes = c->bud_bytes;
|
|
|
+ spin_unlock(&c->buds_lock);
|
|
|
+
|
|
|
+ if (!c->fast_unmount && !(sb->s_flags & MS_RDONLY) && bud_bytes)
|
|
|
+ ubifs_run_commit(c);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1849,7 +1938,6 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
|
|
|
goto out_iput;
|
|
|
|
|
|
mutex_unlock(&c->umount_mutex);
|
|
|
-
|
|
|
return 0;
|
|
|
|
|
|
out_iput:
|
|
@@ -1955,7 +2043,7 @@ static void ubifs_kill_sb(struct super_block *sb)
|
|
|
* We do 'commit_on_unmount()' here instead of 'ubifs_put_super()'
|
|
|
* in order to be outside BKL.
|
|
|
*/
|
|
|
- if (sb->s_root && !(sb->s_flags & MS_RDONLY))
|
|
|
+ if (sb->s_root)
|
|
|
commit_on_unmount(c);
|
|
|
/* The un-mount routine is actually done in put_super() */
|
|
|
generic_shutdown_super(sb);
|
|
@@ -2020,6 +2108,14 @@ static int __init ubifs_init(void)
|
|
|
BUILD_BUG_ON(UBIFS_INO_NODE_SZ != 160);
|
|
|
BUILD_BUG_ON(UBIFS_REF_NODE_SZ != 64);
|
|
|
|
|
|
+ /*
|
|
|
+ * We use 2 bit wide bit-fields to store compression type, which should
|
|
|
+ * be amended if more compressors are added. The bit-fields are:
|
|
|
+ * @compr_type in 'struct ubifs_inode', @default_compr in
|
|
|
+ * 'struct ubifs_info' and @compr_type in 'struct ubifs_mount_opts'.
|
|
|
+ */
|
|
|
+ BUILD_BUG_ON(UBIFS_COMPR_TYPES_CNT > 4);
|
|
|
+
|
|
|
/*
|
|
|
* We require that PAGE_CACHE_SIZE is greater-than-or-equal-to
|
|
|
* UBIFS_BLOCK_SIZE. It is assumed that both are powers of 2.
|
|
@@ -2048,12 +2144,18 @@ static int __init ubifs_init(void)
|
|
|
register_shrinker(&ubifs_shrinker_info);
|
|
|
|
|
|
err = ubifs_compressors_init();
|
|
|
+ if (err)
|
|
|
+ goto out_shrinker;
|
|
|
+
|
|
|
+ err = dbg_debugfs_init();
|
|
|
if (err)
|
|
|
goto out_compr;
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
out_compr:
|
|
|
+ ubifs_compressors_exit();
|
|
|
+out_shrinker:
|
|
|
unregister_shrinker(&ubifs_shrinker_info);
|
|
|
kmem_cache_destroy(ubifs_inode_slab);
|
|
|
out_reg:
|
|
@@ -2068,6 +2170,7 @@ static void __exit ubifs_exit(void)
|
|
|
ubifs_assert(list_empty(&ubifs_infos));
|
|
|
ubifs_assert(atomic_long_read(&ubifs_clean_zn_cnt) == 0);
|
|
|
|
|
|
+ dbg_debugfs_exit();
|
|
|
ubifs_compressors_exit();
|
|
|
unregister_shrinker(&ubifs_shrinker_info);
|
|
|
kmem_cache_destroy(ubifs_inode_slab);
|