From 18d1d7fbcc260e67d249bf90b454d8cf34288453 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Mon, 17 Jan 2011 22:27:56 +0200 Subject: UBIFS: introduce mounting flag This is a preparational patch which removes the 'c->always_chk_crc' which was set during mounting and remounting to R/W mode and introduces 'c->mounting' flag which is set when mounting. Now the 'c->always_chk_crc' flag is the same as 'c->remounting_rw && c->mounting'. This patch is a preparation for the next one which will need to know when we are mounting and remounting to R/W mode, which is exactly what 'c->always_chk_crc' effectively is, but its name does not suite the next patch. The other possibility would be to just re-name it, but then we'd end up with less logical flags coverage. Signed-off-by: Artem Bityutskiy --- fs/ubifs/super.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'fs/ubifs/super.c') diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 91fac54c70e3..703a62109cf2 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -1194,11 +1194,7 @@ static int mount_ubifs(struct ubifs_info *c) if (c->bulk_read == 1) bu_init(c); - /* - * We have to check all CRCs, even for data nodes, when we mount the FS - * (specifically, when we are replaying). - */ - c->always_chk_crc = 1; + c->mounting = 1; err = ubifs_read_superblock(c); if (err) @@ -1374,7 +1370,7 @@ static int mount_ubifs(struct ubifs_info *c) if (err) goto out_infos; - c->always_chk_crc = 0; + c->mounting = 0; ubifs_msg("mounted UBI device %d, volume %d, name \"%s\"", c->vi.ubi_num, c->vi.vol_id, c->vi.name); @@ -1535,7 +1531,6 @@ static int ubifs_remount_rw(struct ubifs_info *c) mutex_lock(&c->umount_mutex); dbg_save_space_info(c); c->remounting_rw = 1; - c->always_chk_crc = 1; err = check_free_space(c); if (err) @@ -1642,7 +1637,6 @@ static int ubifs_remount_rw(struct ubifs_info *c) dbg_gen("re-mounted read-write"); c->ro_mount = 0; c->remounting_rw = 0; - c->always_chk_crc = 0; err = dbg_check_space_info(c); mutex_unlock(&c->umount_mutex); return err; @@ -1659,7 +1653,6 @@ out: c->ileb_buf = NULL; ubifs_lpt_free(c, 1); c->remounting_rw = 0; - c->always_chk_crc = 0; mutex_unlock(&c->umount_mutex); return err; } -- cgit v1.2.3 From 3e8e2e0c8da1f1701a8014543c951c41751791cc Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Sun, 30 Jan 2011 18:58:32 +0200 Subject: UBIFS: incorporate maximum write size Incorporate maximum write size into the UBIFS description data structure. This patch just introduces new 'c->max_write_size' and 'c->max_write_shift' fields as a preparation for the following patches. Signed-off-by: Artem Bityutskiy --- fs/ubifs/super.c | 19 +++++++++++++++++++ fs/ubifs/ubifs.h | 5 +++++ 2 files changed, 24 insertions(+) (limited to 'fs/ubifs/super.c') diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 703a62109cf2..efc327b92f98 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -507,6 +507,8 @@ static int init_constants_early(struct ubifs_info *c) c->half_leb_size = c->leb_size / 2; c->min_io_size = c->di.min_io_size; c->min_io_shift = fls(c->min_io_size) - 1; + c->max_write_size = c->di.max_write_size; + c->max_write_shift = fls(c->max_write_size) - 1; if (c->leb_size < UBIFS_MIN_LEB_SZ) { ubifs_err("too small LEBs (%d bytes), min. is %d bytes", @@ -525,6 +527,18 @@ static int init_constants_early(struct ubifs_info *c) return -EINVAL; } + /* + * Maximum write size has to be greater or equivalent to min. I/O + * size, and be multiple of min. I/O size. + */ + if (c->max_write_size < c->min_io_size || + c->max_write_size % c->min_io_size || + !is_power_of_2(c->max_write_size)) { + ubifs_err("bad write buffer size %d for %d min. I/O unit", + c->max_write_size, c->min_io_size); + return -EINVAL; + } + /* * UBIFS aligns all node to 8-byte boundary, so to make function in * io.c simpler, assume minimum I/O unit size to be 8 bytes if it is @@ -533,6 +547,10 @@ static int init_constants_early(struct ubifs_info *c) if (c->min_io_size < 8) { c->min_io_size = 8; c->min_io_shift = 3; + if (c->max_write_size < c->min_io_size) { + c->max_write_size = c->min_io_size; + c->max_write_shift = c->min_io_shift; + } } c->ref_node_alsz = ALIGN(UBIFS_REF_NODE_SZ, c->min_io_size); @@ -1391,6 +1409,7 @@ static int mount_ubifs(struct ubifs_info *c) dbg_msg("compiled on: " __DATE__ " at " __TIME__); dbg_msg("min. I/O unit size: %d bytes", c->min_io_size); + dbg_msg("max. write size: %d bytes", c->max_write_size); dbg_msg("LEB size: %d bytes (%d KiB)", c->leb_size, c->leb_size >> 10); dbg_msg("data journal heads: %d", diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index d1823541f987..8b519499f14a 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -1024,6 +1024,9 @@ struct ubifs_debug_info; * * @min_io_size: minimal input/output unit size * @min_io_shift: number of bits in @min_io_size minus one + * @max_write_size: maximum amount of bytes the underlying flash can write at a + * time (MTD write buffer size) + * @max_write_shift: number of bits in @max_write_size minus one * @leb_size: logical eraseblock size in bytes * @half_leb_size: half LEB size * @idx_leb_size: how many bytes of an LEB are effectively available when it is @@ -1270,6 +1273,8 @@ struct ubifs_info { int min_io_size; int min_io_shift; + int max_write_size; + int max_write_shift; int leb_size; int half_leb_size; int idx_leb_size; -- cgit v1.2.3 From ca2ec61d157f23ec24aaa200f8016ea0a8aeb617 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Mon, 14 Feb 2011 15:17:55 +0200 Subject: UBI: incorporate LEB offset information Incorporate the LEB offset information into UBIFS. We'll use this information in one of the next patches to figure out what are the max. write size offsets relative to the PEB. So this patch is just a preparation. Signed-off-by: Artem Bityutskiy --- fs/ubifs/super.c | 1 + fs/ubifs/ubifs.h | 3 +++ 2 files changed, 4 insertions(+) (limited to 'fs/ubifs/super.c') diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index efc327b92f98..d4b4cb4596e2 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -504,6 +504,7 @@ static int init_constants_early(struct ubifs_info *c) c->leb_cnt = c->vi.size; c->leb_size = c->vi.usable_leb_size; + c->leb_start = c->di.leb_start; c->half_leb_size = c->leb_size / 2; c->min_io_size = c->di.min_io_size; c->min_io_shift = fls(c->min_io_size) - 1; diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 8b519499f14a..942c1d3cb0db 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -1028,6 +1028,8 @@ struct ubifs_debug_info; * time (MTD write buffer size) * @max_write_shift: number of bits in @max_write_size minus one * @leb_size: logical eraseblock size in bytes + * @leb_start: starting offset of logical eraseblocks within physical + * eraseblocks * @half_leb_size: half LEB size * @idx_leb_size: how many bytes of an LEB are effectively available when it is * used to store indexing nodes (@leb_size - @max_idx_node_sz) @@ -1276,6 +1278,7 @@ struct ubifs_info { int max_write_size; int max_write_shift; int leb_size; + int leb_start; int half_leb_size; int idx_leb_size; int leb_cnt; -- cgit v1.2.3 From d882962f6af2b484b62a7fb05ef959e1bf355fc4 Mon Sep 17 00:00:00 2001 From: "Matthew L. Creech" Date: Fri, 4 Mar 2011 17:55:02 -0500 Subject: UBIFS: handle allocation failures in UBIFS write path Running kernel 2.6.37, my PPC-based device occasionally gets an order-2 allocation failure in UBIFS, which causes the root FS to become unwritable: kswapd0: page allocation failure. order:2, mode:0x4050 Call Trace: [c787dc30] [c00085b8] show_stack+0x7c/0x194 (unreliable) [c787dc70] [c0061aec] __alloc_pages_nodemask+0x4f0/0x57c [c787dd00] [c0061b98] __get_free_pages+0x20/0x50 [c787dd10] [c00e4f88] ubifs_jnl_write_data+0x54/0x200 [c787dd50] [c00e82d4] do_writepage+0x94/0x198 [c787dd90] [c00675e4] shrink_page_list+0x40c/0x77c [c787de40] [c0067de0] shrink_inactive_list+0x1e0/0x370 [c787de90] [c0068224] shrink_zone+0x2b4/0x2b8 [c787df00] [c0068854] kswapd+0x408/0x5d4 [c787dfb0] [c0037bcc] kthread+0x80/0x84 [c787dff0] [c000ef44] kernel_thread+0x4c/0x68 Similar problems were encountered last April by Tomasz Stanislawski: http://patchwork.ozlabs.org/patch/50965/ This patch implements Artem's suggested fix: fall back to a mutex-protected static buffer, allocated at mount time. I tested it by forcing execution down the failure path, and didn't see any ill effects. Artem: massaged the patch a little, improved it so that we'd not allocate the write reserve buffer when we are in R/O mode. Signed-off-by: Matthew L. Creech Signed-off-by: Artem Bityutskiy --- fs/ubifs/journal.c | 28 ++++++++++++++++++++++------ fs/ubifs/super.c | 18 ++++++++++++++++++ fs/ubifs/ubifs.h | 14 ++++++++++++++ 3 files changed, 54 insertions(+), 6 deletions(-) (limited to 'fs/ubifs/super.c') diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c index 914f1bd89e57..aed25e864227 100644 --- a/fs/ubifs/journal.c +++ b/fs/ubifs/journal.c @@ -690,7 +690,7 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, { struct ubifs_data_node *data; int err, lnum, offs, compr_type, out_len; - int dlen = UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR; + int dlen = COMPRESSED_DATA_NODE_BUF_SZ, allocated = 1; struct ubifs_inode *ui = ubifs_inode(inode); dbg_jnl("ino %lu, blk %u, len %d, key %s", @@ -698,9 +698,19 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, DBGKEY(key)); ubifs_assert(len <= UBIFS_BLOCK_SIZE); - data = kmalloc(dlen, GFP_NOFS); - if (!data) - return -ENOMEM; + data = kmalloc(dlen, GFP_NOFS | __GFP_NOWARN); + if (!data) { + /* + * Fall-back to the write reserve buffer. Note, we might be + * currently on the memory reclaim path, when the kernel is + * trying to free some memory by writing out dirty pages. The + * write reserve buffer helps us to guarantee that we are + * always able to write the data. + */ + allocated = 0; + mutex_lock(&c->write_reserve_mutex); + data = c->write_reserve_buf; + } data->ch.node_type = UBIFS_DATA_NODE; key_write(c, key, &data->key); @@ -736,7 +746,10 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, goto out_ro; finish_reservation(c); - kfree(data); + if (!allocated) + mutex_unlock(&c->write_reserve_mutex); + else + kfree(data); return 0; out_release: @@ -745,7 +758,10 @@ out_ro: ubifs_ro_mode(c, err); finish_reservation(c); out_free: - kfree(data); + if (!allocated) + mutex_unlock(&c->write_reserve_mutex); + else + kfree(data); return err; } diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index d4b4cb4596e2..e360c7a71f9e 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -1213,6 +1213,13 @@ static int mount_ubifs(struct ubifs_info *c) if (c->bulk_read == 1) bu_init(c); + if (!c->ro_mount) { + c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ, + GFP_KERNEL); + if (!c->write_reserve_buf) + goto out_free; + } + c->mounting = 1; err = ubifs_read_superblock(c); @@ -1482,6 +1489,7 @@ out_wbufs: out_cbuf: kfree(c->cbuf); out_free: + kfree(c->write_reserve_buf); kfree(c->bu.buf); vfree(c->ileb_buf); vfree(c->sbuf); @@ -1520,6 +1528,7 @@ static void ubifs_umount(struct ubifs_info *c) kfree(c->cbuf); kfree(c->rcvrd_mst_node); kfree(c->mst_node); + kfree(c->write_reserve_buf); kfree(c->bu.buf); vfree(c->ileb_buf); vfree(c->sbuf); @@ -1605,6 +1614,10 @@ static int ubifs_remount_rw(struct ubifs_info *c) goto out; } + c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ, GFP_KERNEL); + if (!c->write_reserve_buf) + goto out; + err = ubifs_lpt_init(c, 0, 1); if (err) goto out; @@ -1669,6 +1682,8 @@ out: c->bgt = NULL; } free_wbufs(c); + kfree(c->write_reserve_buf); + c->write_reserve_buf = NULL; vfree(c->ileb_buf); c->ileb_buf = NULL; ubifs_lpt_free(c, 1); @@ -1712,6 +1727,8 @@ static void ubifs_remount_ro(struct ubifs_info *c) free_wbufs(c); vfree(c->orph_buf); c->orph_buf = NULL; + kfree(c->write_reserve_buf); + c->write_reserve_buf = NULL; vfree(c->ileb_buf); c->ileb_buf = NULL; ubifs_lpt_free(c, 1); @@ -1942,6 +1959,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) mutex_init(&c->mst_mutex); mutex_init(&c->umount_mutex); mutex_init(&c->bu_mutex); + mutex_init(&c->write_reserve_mutex); init_waitqueue_head(&c->cmt_wq); c->buds = RB_ROOT; c->old_idx = RB_ROOT; diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 362495078489..8c40ad3c6721 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -151,6 +151,12 @@ */ #define WORST_COMPR_FACTOR 2 +/* + * How much memory is needed for a buffer where we comress a data node. + */ +#define COMPRESSED_DATA_NODE_BUF_SZ \ + (UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR) + /* Maximum expected tree height for use by bottom_up_buf */ #define BOTTOM_UP_HEIGHT 64 @@ -1005,6 +1011,11 @@ struct ubifs_debug_info; * @bu_mutex: protects the pre-allocated bulk-read buffer and @c->bu * @bu: pre-allocated bulk-read information * + * @write_reserve_mutex: protects @write_reserve_buf + * @write_reserve_buf: on the write path we allocate memory, which might + * sometimes be unavailable, in which case we use this + * write reserve buffer + * * @log_lebs: number of logical eraseblocks in the log * @log_bytes: log size in bytes * @log_last: last LEB of the log @@ -1256,6 +1267,9 @@ struct ubifs_info { struct mutex bu_mutex; struct bu_info bu; + struct mutex write_reserve_mutex; + void *write_reserve_buf; + int log_lebs; long long log_bytes; int log_last; -- cgit v1.2.3 From 6342aaebda9b94e3cd101ba13eee690ac6577124 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Tue, 8 Mar 2011 14:26:47 +0200 Subject: UBIFS: print max. index node size Improve debugging messages by printing the maximum index node size on mount. Signed-off-by: Artem Bityutskiy --- fs/ubifs/super.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/ubifs/super.c') diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index e360c7a71f9e..e9585ad90f5e 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -1447,9 +1447,9 @@ static int mount_ubifs(struct ubifs_info *c) 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", + dbg_msg("max. node sizes: data %zu, inode %zu dentry %zu, idx %d", UBIFS_MAX_DATA_NODE_SZ, UBIFS_MAX_INO_NODE_SZ, - UBIFS_MAX_DENT_NODE_SZ); + UBIFS_MAX_DENT_NODE_SZ, ubifs_idx_node_sz(c, c->fanout)); dbg_msg("dead watermark: %d", c->dead_wm); dbg_msg("dark watermark: %d", c->dark_wm); dbg_msg("LEB overhead: %d", c->leb_overhead); -- cgit v1.2.3 From 2bcf002159c2aedd5c0ab5a21c3ea73fec87ff8d Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 10 Mar 2011 16:26:32 +0200 Subject: UBIFS: do not check data crc by default Change the default UBIFS behavior WRT data CRC checking. Currently, UBIFS checks data CRC when reading, which slows it down quite a bit, and this is the default option. However, it looks like in average user does not need this feature and would prefer faster read speed over extra reliability. And this seems to be de-facto standard that file-systems do not check data CRC every time they read from the media. Thus, make UBIFS default behavior so that it does not check data CRC. This corresponds to the no_chk_data_crc mount option. Those users who need extra protection can always enable it using the chk_data_crc option. Please, read more information about this feature here: http://www.linux-mtd.infradead.org/doc/ubifs.html#L_checksumming Signed-off-by: Artem Bityutskiy --- Documentation/filesystems/ubifs.txt | 4 ++-- fs/ubifs/super.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'fs/ubifs/super.c') diff --git a/Documentation/filesystems/ubifs.txt b/Documentation/filesystems/ubifs.txt index 12fedb7834c6..d7b13b01e980 100644 --- a/Documentation/filesystems/ubifs.txt +++ b/Documentation/filesystems/ubifs.txt @@ -82,12 +82,12 @@ Mount options bulk_read read more in one go to take advantage of flash media that read faster sequentially no_bulk_read (*) do not bulk-read -no_chk_data_crc skip checking of CRCs on data nodes in order to +no_chk_data_crc (*) skip checking of CRCs on data nodes in order to improve read performance. Use this option only if the flash media is highly reliable. The effect of this option is that corruption of the contents of a file can go unnoticed. -chk_data_crc (*) do not skip checking CRCs on data nodes +chk_data_crc do not skip checking CRCs on data nodes compr=none override default compressor and set it to "none" compr=lzo override default compressor and set it to "lzo" compr=zlib override default compressor and set it to "zlib" diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index e9585ad90f5e..1da5155a1bea 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -1977,6 +1977,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) INIT_LIST_HEAD(&c->old_buds); INIT_LIST_HEAD(&c->orph_list); INIT_LIST_HEAD(&c->orph_new); + c->no_chk_data_crc = 1; c->vfs_sb = sb; c->highest_inum = UBIFS_FIRST_INO; -- cgit v1.2.3