JFS: Free sbi memory in error path
[safe/jmp/linux-2.6] / fs / ubifs / super.c
index 522c3fd..4d2f215 100644 (file)
@@ -283,7 +283,7 @@ static void ubifs_destroy_inode(struct inode *inode)
 /*
  * Note, Linux write-back code calls this without 'i_mutex'.
  */
-static int ubifs_write_inode(struct inode *inode, int wait)
+static int ubifs_write_inode(struct inode *inode, struct writeback_control *wbc)
 {
        int err = 0;
        struct ubifs_info *c = inode->i_sb->s_fs_info;
@@ -317,6 +317,8 @@ static int ubifs_write_inode(struct inode *inode, int wait)
                if (err)
                        ubifs_err("can't write inode %lu, error %d",
                                  inode->i_ino, err);
+               else
+                       err = dbg_check_inode_size(c, inode, ui->ui_size);
        }
 
        ui->dirty = 0;
@@ -360,6 +362,11 @@ static void ubifs_delete_inode(struct inode *inode)
 out:
        if (ui->dirty)
                ubifs_release_dirty_inode_budget(c, ui);
+       else {
+               /* We've deleted something - clean the "no space" flags */
+               c->nospace = c->nospace_rp = 0;
+               smp_wmb();
+       }
        clear_inode(inode);
 }
 
@@ -432,12 +439,6 @@ static int ubifs_sync_fs(struct super_block *sb, int wait)
 {
        int i, err;
        struct ubifs_info *c = sb->s_fs_info;
-       struct writeback_control wbc = {
-               .sync_mode   = WB_SYNC_ALL,
-               .range_start = 0,
-               .range_end   = LLONG_MAX,
-               .nr_to_write = LONG_MAX,
-       };
 
        /*
         * Zero @wait is just an advisory thing to help the file system shove
@@ -448,17 +449,6 @@ static int ubifs_sync_fs(struct super_block *sb, int wait)
                return 0;
 
        /*
-        * 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.
-        */
-       generic_sync_sb_inodes(sb, &wbc);
-
-       /*
         * Synchronize write buffers, because 'ubifs_run_commit()' does not
         * do this if it waits for an already running commit.
         */
@@ -468,6 +458,13 @@ static int ubifs_sync_fs(struct super_block *sb, int wait)
                        return err;
        }
 
+       /*
+        * 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.
+        */
        err = ubifs_run_commit(c);
        if (err)
                return err;
@@ -791,7 +788,7 @@ static int alloc_wbufs(struct ubifs_info *c)
         * does not need to be synchronized by timer.
         */
        c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM;
-       c->jheads[GCHD].wbuf.timeout = 0;
+       c->jheads[GCHD].wbuf.no_timer = 1;
 
        return 0;
 }
@@ -932,6 +929,27 @@ static const match_table_t tokens = {
 };
 
 /**
+ * parse_standard_option - parse a standard mount option.
+ * @option: the option to parse
+ *
+ * Normally, standard mount options like "sync" are passed to file-systems as
+ * flags. However, when a "rootflags=" kernel boot parameter is used, they may
+ * be present in the options string. This function tries to deal with this
+ * situation and parse standard options. Returns 0 if the option was not
+ * recognized, and the corresponding integer flag if it was.
+ *
+ * UBIFS is only interested in the "sync" option, so do not check for anything
+ * else.
+ */
+static int parse_standard_option(const char *option)
+{
+       ubifs_msg("parse %s", option);
+       if (!strcmp(option, "sync"))
+               return MS_SYNCHRONOUS;
+       return 0;
+}
+
+/**
  * ubifs_parse_options - parse mount parameters.
  * @c: UBIFS file-system description object
  * @options: parameters to parse
@@ -959,7 +977,7 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
                switch (token) {
                /*
                 * %Opt_fast_unmount and %Opt_norm_unmount options are ignored.
-                * We accepte them in order to be backware-compatible. But this
+                * We accept them in order to be backward-compatible. But this
                 * should be removed at some point.
                 */
                case Opt_fast_unmount:
@@ -1007,9 +1025,19 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
                        break;
                }
                default:
-                       ubifs_err("unrecognized mount option \"%s\" "
-                                 "or missing value", p);
-                       return -EINVAL;
+               {
+                       unsigned long flag;
+                       struct super_block *sb = c->vfs_sb;
+
+                       flag = parse_standard_option(p);
+                       if (!flag) {
+                               ubifs_err("unrecognized mount option \"%s\" "
+                                         "or missing value", p);
+                               return -EINVAL;
+                       }
+                       sb->s_flags |= flag;
+                       break;
+               }
                }
        }
 
@@ -1179,6 +1207,7 @@ static int mount_ubifs(struct ubifs_info *c)
        if (!ubifs_compr_present(c->default_compr)) {
                ubifs_err("'compressor \"%s\" is not compiled in",
                          ubifs_compr_name(c->default_compr));
+               err = -ENOTSUPP;
                goto out_free;
        }
 
@@ -1249,6 +1278,9 @@ static int mount_ubifs(struct ubifs_info *c)
        if (err)
                goto out_journal;
 
+       /* Calculate 'min_idx_lebs' after journal replay */
+       c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+
        err = ubifs_mount_orphans(c, c->need_recovery, mounted_read_only);
        if (err)
                goto out_orphans;
@@ -1361,12 +1393,7 @@ static int mount_ubifs(struct ubifs_info *c)
                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"
-              "-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
-              c->uuid[0], c->uuid[1], c->uuid[2], c->uuid[3],
-              c->uuid[4], c->uuid[5], c->uuid[6], c->uuid[7],
-              c->uuid[8], c->uuid[9], c->uuid[10], c->uuid[11],
-              c->uuid[12], c->uuid[13], c->uuid[14], c->uuid[15]);
+       dbg_msg("UUID:                %pUB", c->uuid);
        dbg_msg("big_lpt              %d", c->big_lpt);
        dbg_msg("log LEBs:            %d (%d - %d)",
                c->log_lebs, UBIFS_LOG_LNUM, c->log_last);
@@ -1655,7 +1682,7 @@ static void ubifs_remount_ro(struct ubifs_info *c)
 
        for (i = 0; i < c->jhead_cnt; i++) {
                ubifs_wbuf_sync(&c->jheads[i].wbuf);
-               del_timer_sync(&c->jheads[i].wbuf.timer);
+               hrtimer_cancel(&c->jheads[i].wbuf.timer);
        }
 
        c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY);
@@ -1685,8 +1712,6 @@ static void ubifs_put_super(struct super_block *sb)
        ubifs_msg("un-mount UBI device %d, volume %d", c->vi.ubi_num,
                  c->vi.vol_id);
 
-       lock_kernel();
-
        /*
         * The following asserts are only valid if there has not been a failure
         * of the media. For example, there will be dirty inodes if we failed
@@ -1716,10 +1741,8 @@ static void ubifs_put_super(struct super_block *sb)
 
                /* Synchronize write-buffers */
                if (c->jheads)
-                       for (i = 0; i < c->jhead_cnt; i++) {
+                       for (i = 0; i < c->jhead_cnt; i++)
                                ubifs_wbuf_sync(&c->jheads[i].wbuf);
-                               del_timer_sync(&c->jheads[i].wbuf.timer);
-                       }
 
                /*
                 * On fatal errors c->ro_media is set to 1, in which case we do
@@ -1753,8 +1776,6 @@ static void ubifs_put_super(struct super_block *sb)
        ubi_close_volume(c->ubi);
        mutex_unlock(&c->umount_mutex);
        kfree(c);
-
-       unlock_kernel();
 }
 
 static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
@@ -1816,22 +1837,32 @@ const struct super_operations ubifs_super_operations = {
  * @name: UBI volume name
  * @mode: UBI volume open mode
  *
- * There are several ways to specify UBI volumes when mounting UBIFS:
- * o ubiX_Y    - UBI device number X, volume Y;
- * o ubiY      - UBI device number 0, volume Y;
+ * The primary method of mounting UBIFS is by specifying the UBI volume
+ * character device node path. However, UBIFS may also be mounted withoug any
+ * character device node using one of the following methods:
+ *
+ * o ubiX_Y    - mount UBI device number X, volume Y;
+ * o ubiY      - mount UBI device number 0, volume Y;
  * o ubiX:NAME - mount UBI device X, volume with name NAME;
  * o ubi:NAME  - mount UBI device 0, volume with name NAME.
  *
  * Alternative '!' separator may be used instead of ':' (because some shells
  * like busybox may interpret ':' as an NFS host name separator). This function
- * returns ubi volume object in case of success and a negative error code in
- * case of failure.
+ * returns UBI volume description object in case of success and a negative
+ * error code in case of failure.
  */
 static struct ubi_volume_desc *open_ubi(const char *name, int mode)
 {
+       struct ubi_volume_desc *ubi;
        int dev, vol;
        char *endptr;
 
+       /* First, try to open using the device node path method */
+       ubi = ubi_open_volume_path(name, mode);
+       if (!IS_ERR(ubi))
+               return ubi;
+
+       /* Try the "nodev" method */
        if (name[0] != 'u' || name[1] != 'b' || name[2] != 'i')
                return ERR_PTR(-EINVAL);
 
@@ -1904,6 +1935,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
        INIT_LIST_HEAD(&c->orph_list);
        INIT_LIST_HEAD(&c->orph_new);
 
+       c->vfs_sb = sb;
        c->highest_inum = UBIFS_FIRST_INO;
        c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM;
 
@@ -1925,23 +1957,26 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
         *
         * Read-ahead will be disabled because @c->bdi.ra_pages is 0.
         */
+       c->bdi.name = "ubifs",
        c->bdi.capabilities = BDI_CAP_MAP_COPY;
        c->bdi.unplug_io_fn = default_unplug_io_fn;
        err  = bdi_init(&c->bdi);
        if (err)
                goto out_close;
+       err = bdi_register(&c->bdi, NULL, "ubifs_%d_%d",
+                          c->vi.ubi_num, c->vi.vol_id);
+       if (err)
+               goto out_bdi;
 
        err = ubifs_parse_options(c, data, 0);
        if (err)
                goto out_bdi;
 
-       c->vfs_sb = sb;
-
+       sb->s_bdi = &c->bdi;
        sb->s_fs_info = c;
        sb->s_magic = UBIFS_SUPER_MAGIC;
        sb->s_blocksize = UBIFS_BLOCK_SIZE;
        sb->s_blocksize_bits = UBIFS_BLOCK_SHIFT;
-       sb->s_dev = c->vi.cdev;
        sb->s_maxbytes = c->max_inode_sz = key_max_inode_size(c);
        if (c->max_inode_sz > MAX_LFS_FILESIZE)
                sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE;
@@ -1986,16 +2021,9 @@ out_free:
 static int sb_test(struct super_block *sb, void *data)
 {
        dev_t *dev = data;
+       struct ubifs_info *c = sb->s_fs_info;
 
-       return sb->s_dev == *dev;
-}
-
-static int sb_set(struct super_block *sb, void *data)
-{
-       dev_t *dev = data;
-
-       sb->s_dev = *dev;
-       return 0;
+       return c->vi.cdev == *dev;
 }
 
 static int ubifs_get_sb(struct file_system_type *fs_type, int flags,
@@ -2023,7 +2051,7 @@ static int ubifs_get_sb(struct file_system_type *fs_type, int flags,
 
        dbg_gen("opened ubi%d_%d", vi.ubi_num, vi.vol_id);
 
-       sb = sget(fs_type, &sb_test, &sb_set, &vi.cdev);
+       sb = sget(fs_type, &sb_test, &set_anon_super, &vi.cdev);
        if (IS_ERR(sb)) {
                err = PTR_ERR(sb);
                goto out_close;
@@ -2063,16 +2091,11 @@ out_close:
        return err;
 }
 
-static void ubifs_kill_sb(struct super_block *sb)
-{
-       generic_shutdown_super(sb);
-}
-
 static struct file_system_type ubifs_fs_type = {
        .name    = "ubifs",
        .owner   = THIS_MODULE,
        .get_sb  = ubifs_get_sb,
-       .kill_sb = ubifs_kill_sb
+       .kill_sb = kill_anon_super,
 };
 
 /*