Merge branch 'linux-next' of git://git.infradead.org/ubifs-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 17 Jun 2009 16:46:33 +0000 (09:46 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 17 Jun 2009 16:46:33 +0000 (09:46 -0700)
* 'linux-next' of git://git.infradead.org/ubifs-2.6:
  UBIFS: start using hrtimers
  hrtimer: export ktime_add_safe
  UBIFS: do not forget to register BDI device
  UBIFS: allow sync option in rootflags
  UBIFS: remove dead code
  UBIFS: use anonymous device
  UBIFS: return proper error code if the compr is not present
  UBIFS: return error if link and unlink race
  UBIFS: reset no_space flag after inode deletion

1  2 
fs/ubifs/super.c
kernel/hrtimer.c

diff --combined fs/ubifs/super.c
@@@ -36,7 -36,6 +36,7 @@@
  #include <linux/mount.h>
  #include <linux/math64.h>
  #include <linux/writeback.h>
 +#include <linux/smp_lock.h>
  #include "ubifs.h"
  
  /*
@@@ -361,6 -360,11 +361,11 @@@ static void ubifs_delete_inode(struct i
  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);
  }
  
@@@ -448,6 -452,9 +453,6 @@@ static int ubifs_sync_fs(struct super_b
        if (!wait)
                return 0;
  
 -      if (sb->s_flags & MS_RDONLY)
 -              return 0;
 -
        /*
         * VFS calls '->sync_fs()' before synchronizing all dirty inodes and
         * pages, so synchronize them first, then commit the journal. Strictly
@@@ -792,7 -799,7 +797,7 @@@ static int alloc_wbufs(struct ubifs_inf
         * 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.softlimit = ktime_set(0, 0);
  
        return 0;
  }
@@@ -933,6 -940,27 +938,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
@@@ -1008,9 -1036,19 +1034,19 @@@ static int ubifs_parse_options(struct u
                        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;
+               }
                }
        }
  
@@@ -1180,6 -1218,7 +1216,7 @@@ static int mount_ubifs(struct ubifs_inf
        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;
        }
  
@@@ -1656,7 -1695,7 +1693,7 @@@ static void ubifs_remount_ro(struct ubi
  
        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,9 -1724,6 +1722,9 @@@ static void ubifs_put_super(struct supe
  
        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
                if (c->jheads)
                        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);
                        }
  
                /*
        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)
                return err;
        }
  
 +      lock_kernel();
        if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) {
                if (c->ro_media) {
                        ubifs_msg("cannot re-mount due to prior errors");
 +                      unlock_kernel();
                        return -EROFS;
                }
                err = ubifs_remount_rw(c);
 -              if (err)
 +              if (err) {
 +                      unlock_kernel();
                        return err;
 +              }
        } else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) {
                if (c->ro_media) {
                        ubifs_msg("cannot re-mount due to prior errors");
 +                      unlock_kernel();
                        return -EROFS;
                }
                ubifs_remount_ro(c);
        }
  
        ubifs_assert(c->lst.taken_empty_lebs > 0);
 +      unlock_kernel();
        return 0;
  }
  
@@@ -1911,6 -1939,7 +1948,7 @@@ static int ubifs_fill_super(struct supe
        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;
  
        if (err)
                goto out_bdi;
  
-       c->vfs_sb = sb;
        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;
@@@ -1996,16 -2022,9 +2031,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,
  
        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;
        return 0;
  
  out_deact:
 -      up_write(&sb->s_umount);
 -      deactivate_super(sb);
 +      deactivate_locked_super(sb);
  out_close:
        ubi_close_volume(ubi);
        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,
  };
  
  /*
diff --combined kernel/hrtimer.c
@@@ -43,8 -43,6 +43,8 @@@
  #include <linux/seq_file.h>
  #include <linux/err.h>
  #include <linux/debugobjects.h>
 +#include <linux/sched.h>
 +#include <linux/timer.h>
  
  #include <asm/uaccess.h>
  
@@@ -195,24 -193,12 +195,24 @@@ struct hrtimer_clock_base *lock_hrtimer
   * Switch the timer base to the current CPU when possible.
   */
  static inline struct hrtimer_clock_base *
 -switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base)
 +switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base,
 +                  int pinned)
  {
        struct hrtimer_clock_base *new_base;
        struct hrtimer_cpu_base *new_cpu_base;
 +      int cpu, preferred_cpu = -1;
 +
 +      cpu = smp_processor_id();
 +#if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP)
 +      if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu)) {
 +              preferred_cpu = get_nohz_load_balancer();
 +              if (preferred_cpu >= 0)
 +                      cpu = preferred_cpu;
 +      }
 +#endif
  
 -      new_cpu_base = &__get_cpu_var(hrtimer_bases);
 +again:
 +      new_cpu_base = &per_cpu(hrtimer_bases, cpu);
        new_base = &new_cpu_base->clock_base[base->index];
  
        if (base != new_base) {
                timer->base = NULL;
                spin_unlock(&base->cpu_base->lock);
                spin_lock(&new_base->cpu_base->lock);
 +
 +              /* Optimized away for NOHZ=n SMP=n */
 +              if (cpu == preferred_cpu) {
 +                      /* Calculate clock monotonic expiry time */
 +#ifdef CONFIG_HIGH_RES_TIMERS
 +                      ktime_t expires = ktime_sub(hrtimer_get_expires(timer),
 +                                                      new_base->offset);
 +#else
 +                      ktime_t expires = hrtimer_get_expires(timer);
 +#endif
 +
 +                      /*
 +                       * Get the next event on target cpu from the
 +                       * clock events layer.
 +                       * This covers the highres=off nohz=on case as well.
 +                       */
 +                      ktime_t next = clockevents_get_next_event(cpu);
 +
 +                      ktime_t delta = ktime_sub(expires, next);
 +
 +                      /*
 +                       * We do not migrate the timer when it is expiring
 +                       * before the next event on the target cpu because
 +                       * we cannot reprogram the target cpu hardware and
 +                       * we would cause it to fire late.
 +                       */
 +                      if (delta.tv64 < 0) {
 +                              cpu = smp_processor_id();
 +                              spin_unlock(&new_base->cpu_base->lock);
 +                              spin_lock(&base->cpu_base->lock);
 +                              timer->base = base;
 +                              goto again;
 +                      }
 +              }
                timer->base = new_base;
        }
        return new_base;
@@@ -283,7 -235,7 +283,7 @@@ lock_hrtimer_base(const struct hrtimer 
        return base;
  }
  
 -# define switch_hrtimer_base(t, b)    (b)
 +# define switch_hrtimer_base(t, b, p) (b)
  
  #endif        /* !CONFIG_SMP */
  
@@@ -380,6 -332,8 +380,8 @@@ ktime_t ktime_add_safe(const ktime_t lh
        return res;
  }
  
+ EXPORT_SYMBOL_GPL(ktime_add_safe);
  #ifdef CONFIG_DEBUG_OBJECTS_TIMERS
  
  static struct debug_obj_descr hrtimer_debug_descr;
@@@ -955,9 -909,9 +957,9 @@@ int __hrtimer_start_range_ns(struct hrt
        ret = remove_hrtimer(timer, base);
  
        /* Switch the timer base, if necessary: */
 -      new_base = switch_hrtimer_base(timer, base);
 +      new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED);
  
 -      if (mode == HRTIMER_MODE_REL) {
 +      if (mode & HRTIMER_MODE_REL) {
                tim = ktime_add_safe(tim, new_base->get_time());
                /*
                 * CONFIG_TIME_LOW_RES is a temporary way for architectures