summaryrefslogtreecommitdiff
path: root/fs/ubifs/super.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-10-28 18:26:12 +0300
committerIngo Molnar <mingo@elte.hu>2008-10-28 18:26:12 +0300
commit7a9787e1eba95a166265e6a260cf30af04ef0a99 (patch)
treee730a4565e0318140d2fbd2f0415d18a339d7336 /fs/ubifs/super.c
parent41b9eb264c8407655db57b60b4457fe1b2ec9977 (diff)
parent0173a3265b228da319ceb9c1ec6a5682fd1b2d92 (diff)
downloadlinux-7a9787e1eba95a166265e6a260cf30af04ef0a99.tar.xz
Merge commit 'v2.6.28-rc2' into x86/pci-ioapic-boot-irq-quirks
Diffstat (limited to 'fs/ubifs/super.c')
-rw-r--r--fs/ubifs/super.c186
1 files changed, 135 insertions, 51 deletions
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 00eb9c68ad03..8780efbf40ac 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -30,7 +30,6 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/ctype.h>
-#include <linux/random.h>
#include <linux/kthread.h>
#include <linux/parser.h>
#include <linux/seq_file.h>
@@ -149,7 +148,7 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
if (err)
goto out_invalid;
- /* Disable readahead */
+ /* Disable read-ahead */
inode->i_mapping->backing_dev_info = &c->bdi;
switch (inode->i_mode & S_IFMT) {
@@ -278,7 +277,7 @@ static void ubifs_destroy_inode(struct inode *inode)
*/
static int ubifs_write_inode(struct inode *inode, int wait)
{
- int err;
+ int err = 0;
struct ubifs_info *c = inode->i_sb->s_fs_info;
struct ubifs_inode *ui = ubifs_inode(inode);
@@ -299,10 +298,18 @@ static int ubifs_write_inode(struct inode *inode, int wait)
return 0;
}
- dbg_gen("inode %lu", inode->i_ino);
- err = ubifs_jnl_write_inode(c, inode, 0);
- if (err)
- ubifs_err("can't write inode %lu, error %d", inode->i_ino, err);
+ /*
+ * As an optimization, do not write orphan inodes to the media just
+ * because this is not needed.
+ */
+ dbg_gen("inode %lu, mode %#x, nlink %u",
+ inode->i_ino, (int)inode->i_mode, inode->i_nlink);
+ if (inode->i_nlink) {
+ err = ubifs_jnl_write_inode(c, inode);
+ if (err)
+ ubifs_err("can't write inode %lu, error %d",
+ inode->i_ino, err);
+ }
ui->dirty = 0;
mutex_unlock(&ui->ui_mutex);
@@ -314,8 +321,9 @@ static void ubifs_delete_inode(struct inode *inode)
{
int err;
struct ubifs_info *c = inode->i_sb->s_fs_info;
+ struct ubifs_inode *ui = ubifs_inode(inode);
- if (ubifs_inode(inode)->xattr)
+ if (ui->xattr)
/*
* Extended attribute inode deletions are fully handled in
* 'ubifs_removexattr()'. These inodes are special and have
@@ -323,7 +331,7 @@ static void ubifs_delete_inode(struct inode *inode)
*/
goto out;
- dbg_gen("inode %lu", inode->i_ino);
+ dbg_gen("inode %lu, mode %#x", inode->i_ino, (int)inode->i_mode);
ubifs_assert(!atomic_read(&inode->i_count));
ubifs_assert(inode->i_nlink == 0);
@@ -331,15 +339,19 @@ static void ubifs_delete_inode(struct inode *inode)
if (is_bad_inode(inode))
goto out;
- ubifs_inode(inode)->ui_size = inode->i_size = 0;
- err = ubifs_jnl_write_inode(c, inode, 1);
+ ui->ui_size = inode->i_size = 0;
+ err = ubifs_jnl_delete_inode(c, inode);
if (err)
/*
* Worst case we have a lost orphan inode wasting space, so a
- * simple error message is ok here.
+ * simple error message is OK here.
*/
- ubifs_err("can't write inode %lu, error %d", inode->i_ino, err);
+ ubifs_err("can't delete inode %lu, error %d",
+ inode->i_ino, err);
+
out:
+ if (ui->dirty)
+ ubifs_release_dirty_inode_budget(c, ui);
clear_inode(inode);
}
@@ -358,8 +370,9 @@ static int ubifs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct ubifs_info *c = dentry->d_sb->s_fs_info;
unsigned long long free;
+ __le32 *uuid = (__le32 *)c->uuid;
- free = ubifs_budg_get_free_space(c);
+ free = ubifs_get_free_space(c);
dbg_gen("free space %lld bytes (%lld blocks)",
free, free >> UBIFS_BLOCK_SHIFT);
@@ -374,7 +387,8 @@ static int ubifs_statfs(struct dentry *dentry, struct kstatfs *buf)
buf->f_files = 0;
buf->f_ffree = 0;
buf->f_namelen = UBIFS_MAX_NLEN;
-
+ buf->f_fsid.val[0] = le32_to_cpu(uuid[0]) ^ le32_to_cpu(uuid[2]);
+ buf->f_fsid.val[1] = le32_to_cpu(uuid[1]) ^ le32_to_cpu(uuid[3]);
return 0;
}
@@ -387,6 +401,16 @@ static int ubifs_show_options(struct seq_file *s, struct vfsmount *mnt)
else if (c->mount_opts.unmount_mode == 1)
seq_printf(s, ",norm_unmount");
+ if (c->mount_opts.bulk_read == 2)
+ seq_printf(s, ",bulk_read");
+ else if (c->mount_opts.bulk_read == 1)
+ seq_printf(s, ",no_bulk_read");
+
+ if (c->mount_opts.chk_data_crc == 2)
+ seq_printf(s, ",chk_data_crc");
+ else if (c->mount_opts.chk_data_crc == 1)
+ seq_printf(s, ",no_chk_data_crc");
+
return 0;
}
@@ -394,13 +418,26 @@ static int ubifs_sync_fs(struct super_block *sb, int wait)
{
struct ubifs_info *c = sb->s_fs_info;
int i, ret = 0, err;
+ long long bud_bytes;
- if (c->jheads)
+ if (c->jheads) {
for (i = 0; i < c->jhead_cnt; i++) {
err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
if (err && !ret)
ret = err;
}
+
+ /* 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;
+ }
+ }
+
/*
* 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
@@ -518,6 +555,24 @@ static int init_constants_early(struct ubifs_info *c)
c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size);
c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size);
+ /*
+ * Calculate how many bytes would be wasted at the end of LEB if it was
+ * fully filled with data nodes of maximum size. This is used in
+ * calculations when reporting free space.
+ */
+ c->leb_overhead = c->leb_size % UBIFS_MAX_DATA_NODE_SZ;
+ /* Buffer size for bulk-reads */
+ c->bulk_read_buf_size = UBIFS_MAX_BULK_READ * UBIFS_MAX_DATA_NODE_SZ;
+ if (c->bulk_read_buf_size > c->leb_size)
+ c->bulk_read_buf_size = c->leb_size;
+ if (c->bulk_read_buf_size > 128 * 1024) {
+ /* Check if we can kmalloc more than 128KiB */
+ void *try = kmalloc(c->bulk_read_buf_size, GFP_KERNEL);
+
+ kfree(try);
+ if (!try)
+ c->bulk_read_buf_size = 128 * 1024;
+ }
return 0;
}
@@ -635,13 +690,11 @@ static int init_constants_late(struct ubifs_info *c)
* internally because it does not make much sense for UBIFS, but it is
* necessary to report something for the 'statfs()' call.
*
- * Subtract the LEB reserved for GC and the LEB which is reserved for
- * deletions.
- *
- * Review 'ubifs_calc_available()' if changing this calculation.
+ * Subtract the LEB reserved for GC, the LEB which is reserved for
+ * deletions, and assume only one journal head is available.
*/
- tmp64 = c->main_lebs - 2;
- tmp64 *= (uint64_t)c->leb_size - c->dark_wm;
+ tmp64 = c->main_lebs - 2 - c->jhead_cnt + 1;
+ tmp64 *= (uint64_t)c->leb_size - c->leb_overhead;
tmp64 = ubifs_reported_space(c, tmp64);
c->block_cnt = tmp64 >> UBIFS_BLOCK_SHIFT;
@@ -822,17 +875,29 @@ static int check_volume_empty(struct ubifs_info *c)
*
* Opt_fast_unmount: do not run a journal commit before un-mounting
* Opt_norm_unmount: run a journal commit before un-mounting
+ * Opt_bulk_read: enable bulk-reads
+ * 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_err: just end of array marker
*/
enum {
Opt_fast_unmount,
Opt_norm_unmount,
+ Opt_bulk_read,
+ Opt_no_bulk_read,
+ Opt_chk_data_crc,
+ Opt_no_chk_data_crc,
Opt_err,
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_fast_unmount, "fast_unmount"},
{Opt_norm_unmount, "norm_unmount"},
+ {Opt_bulk_read, "bulk_read"},
+ {Opt_no_bulk_read, "no_bulk_read"},
+ {Opt_chk_data_crc, "chk_data_crc"},
+ {Opt_no_chk_data_crc, "no_chk_data_crc"},
{Opt_err, NULL},
};
@@ -870,6 +935,22 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
c->mount_opts.unmount_mode = 1;
c->fast_unmount = 0;
break;
+ case Opt_bulk_read:
+ c->mount_opts.bulk_read = 2;
+ c->bulk_read = 1;
+ break;
+ case Opt_no_bulk_read:
+ c->mount_opts.bulk_read = 1;
+ c->bulk_read = 0;
+ break;
+ case Opt_chk_data_crc:
+ c->mount_opts.chk_data_crc = 2;
+ c->no_chk_data_crc = 0;
+ break;
+ case Opt_no_chk_data_crc:
+ c->mount_opts.chk_data_crc = 1;
+ c->no_chk_data_crc = 1;
+ break;
default:
ubifs_err("unrecognized mount option \"%s\" "
"or missing value", p);
@@ -978,6 +1059,8 @@ static int mount_ubifs(struct ubifs_info *c)
goto out_free;
}
+ c->always_chk_crc = 1;
+
err = ubifs_read_superblock(c);
if (err)
goto out_free;
@@ -1006,17 +1089,14 @@ static int mount_ubifs(struct ubifs_info *c)
goto out_dereg;
}
+ sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id);
if (!mounted_read_only) {
err = alloc_wbufs(c);
if (err)
goto out_cbuf;
/* Create background thread */
- sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num,
- c->vi.vol_id);
c->bgt = kthread_create(ubifs_bg_thread, c, c->bgt_name);
- if (!c->bgt)
- c->bgt = ERR_PTR(-EINVAL);
if (IS_ERR(c->bgt)) {
err = PTR_ERR(c->bgt);
c->bgt = NULL;
@@ -1122,24 +1202,28 @@ static int mount_ubifs(struct ubifs_info *c)
if (err)
goto out_infos;
- ubifs_msg("mounted UBI device %d, volume %d", c->vi.ubi_num,
- c->vi.vol_id);
+ c->always_chk_crc = 0;
+
+ ubifs_msg("mounted UBI device %d, volume %d, name \"%s\"",
+ c->vi.ubi_num, c->vi.vol_id, c->vi.name);
if (mounted_read_only)
ubifs_msg("mounted read-only");
x = (long long)c->main_lebs * c->leb_size;
- ubifs_msg("file system size: %lld bytes (%lld KiB, %lld MiB, %d LEBs)",
- x, x >> 10, x >> 20, c->main_lebs);
+ ubifs_msg("file system size: %lld bytes (%lld KiB, %lld MiB, %d "
+ "LEBs)", x, x >> 10, x >> 20, c->main_lebs);
x = (long long)c->log_lebs * c->leb_size + c->max_bud_bytes;
- ubifs_msg("journal size: %lld bytes (%lld KiB, %lld MiB, %d LEBs)",
- x, x >> 10, x >> 20, c->log_lebs + c->max_bud_cnt);
- ubifs_msg("default compressor: %s", ubifs_compr_name(c->default_compr));
- ubifs_msg("media format %d, latest format %d",
+ ubifs_msg("journal size: %lld bytes (%lld KiB, %lld MiB, %d "
+ "LEBs)", x, x >> 10, x >> 20, c->log_lebs + c->max_bud_cnt);
+ ubifs_msg("media format: %d (latest is %d)",
c->fmt_version, UBIFS_FORMAT_VERSION);
+ ubifs_msg("default compressor: %s", ubifs_compr_name(c->default_compr));
+ ubifs_msg("reserved for root: %llu bytes (%llu KiB)",
+ c->report_rp_size, c->report_rp_size >> 10);
dbg_msg("compiled on: " __DATE__ " at " __TIME__);
dbg_msg("min. I/O unit size: %d bytes", c->min_io_size);
dbg_msg("LEB size: %d bytes (%d KiB)",
- c->leb_size, c->leb_size / 1024);
+ c->leb_size, c->leb_size >> 10);
dbg_msg("data journal heads: %d",
c->jhead_cnt - NONDATA_JHEADS_CNT);
dbg_msg("UUID: %02X%02X%02X%02X-%02X%02X"
@@ -1265,6 +1349,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)
mutex_lock(&c->umount_mutex);
c->remounting_rw = 1;
+ c->always_chk_crc = 1;
/* Check for enough free space */
if (ubifs_calc_available(c, c->min_idx_lebs) <= 0) {
@@ -1328,20 +1413,20 @@ static int ubifs_remount_rw(struct ubifs_info *c)
/* Create background thread */
c->bgt = kthread_create(ubifs_bg_thread, c, c->bgt_name);
- if (!c->bgt)
- c->bgt = ERR_PTR(-EINVAL);
if (IS_ERR(c->bgt)) {
err = PTR_ERR(c->bgt);
c->bgt = NULL;
ubifs_err("cannot spawn \"%s\", error %d",
c->bgt_name, err);
- return err;
+ goto out;
}
wake_up_process(c->bgt);
c->orph_buf = vmalloc(c->leb_size);
- if (!c->orph_buf)
- return -ENOMEM;
+ if (!c->orph_buf) {
+ err = -ENOMEM;
+ goto out;
+ }
/* Check for enough log space */
lnum = c->lhead_lnum + 1;
@@ -1368,6 +1453,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)
dbg_gen("re-mounted read-write");
c->vfs_sb->s_flags &= ~MS_RDONLY;
c->remounting_rw = 0;
+ c->always_chk_crc = 0;
mutex_unlock(&c->umount_mutex);
return 0;
@@ -1383,6 +1469,7 @@ 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;
}
@@ -1391,12 +1478,9 @@ out:
* commit_on_unmount - commit the journal when un-mounting.
* @c: UBIFS file-system description object
*
- * This function is called during un-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.
- *
- * Sometimes recovery requires the journal to be committed at least once, and
- * this function takes care about this.
+ * 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.
*/
static void commit_on_unmount(struct ubifs_info *c)
{
@@ -1469,6 +1553,7 @@ static void ubifs_put_super(struct super_block *sb)
*/
ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0);
ubifs_assert(c->budg_idx_growth == 0);
+ ubifs_assert(c->budg_dd_growth == 0);
ubifs_assert(c->budg_data_growth == 0);
/*
@@ -1657,7 +1742,6 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
INIT_LIST_HEAD(&c->orph_new);
c->highest_inum = UBIFS_FIRST_INO;
- get_random_bytes(&c->vfs_gen, sizeof(int));
c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM;
ubi_get_volume_info(ubi, &c->vi);
@@ -1671,10 +1755,10 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
}
/*
- * UBIFS provids 'backing_dev_info' in order to disable readahead. For
+ * UBIFS provides 'backing_dev_info' in order to disable read-ahead. For
* UBIFS, I/O is not deferred, it is done immediately in readpage,
* which means the user would have to wait not just for their own I/O
- * but the readahead I/O as well i.e. completely pointless.
+ * but the read-ahead I/O as well i.e. completely pointless.
*
* Read-ahead will be disabled because @c->bdi.ra_pages is 0.
*/
@@ -1841,7 +1925,7 @@ static struct file_system_type ubifs_fs_type = {
/*
* Inode slab cache constructor.
*/
-static void inode_slab_ctor(struct kmem_cache *cachep, void *obj)
+static void inode_slab_ctor(void *obj)
{
struct ubifs_inode *ui = obj;
inode_init_once(&ui->vfs_inode);