]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/exofs/super.c
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux...
[mv-sheeva.git] / fs / exofs / super.c
index 8c6c4669b381699d78b52e541c7ad59fd82a9c1b..06065bd37fc339070948a141cd8063c9d39af8ad 100644 (file)
@@ -48,6 +48,7 @@
  * struct to hold what we get from mount options
  */
 struct exofs_mountopt {
+       bool is_osdname;
        const char *dev_name;
        uint64_t pid;
        int timeout;
@@ -56,7 +57,7 @@ struct exofs_mountopt {
 /*
  * exofs-specific mount-time options.
  */
-enum { Opt_pid, Opt_to, Opt_mkfs, Opt_format, Opt_err };
+enum { Opt_name, Opt_pid, Opt_to, Opt_err };
 
 /*
  * Our mount-time options.  These should ideally be 64-bit unsigned, but the
@@ -64,6 +65,7 @@ enum { Opt_pid, Opt_to, Opt_mkfs, Opt_format, Opt_err };
  * sufficient for most applications now.
  */
 static match_table_t tokens = {
+       {Opt_name, "osdname=%s"},
        {Opt_pid, "pid=%u"},
        {Opt_to, "to=%u"},
        {Opt_err, NULL}
@@ -94,6 +96,14 @@ static int parse_options(char *options, struct exofs_mountopt *opts)
 
                token = match_token(p, tokens, args);
                switch (token) {
+               case Opt_name:
+                       opts->dev_name = match_strdup(&args[0]);
+                       if (unlikely(!opts->dev_name)) {
+                               EXOFS_ERR("Error allocating dev_name");
+                               return -ENOMEM;
+                       }
+                       opts->is_osdname = true;
+                       break;
                case Opt_pid:
                        if (0 == match_strlcpy(str, &args[0], sizeof(str)))
                                return -EINVAL;
@@ -203,6 +213,101 @@ static void destroy_inodecache(void)
 static const struct super_operations exofs_sops;
 static const struct export_operations exofs_export_ops;
 
+static const struct osd_attr g_attr_sb_stats = ATTR_DEF(
+       EXOFS_APAGE_SB_DATA,
+       EXOFS_ATTR_SB_STATS,
+       sizeof(struct exofs_sb_stats));
+
+static int __sbi_read_stats(struct exofs_sb_info *sbi)
+{
+       struct osd_attr attrs[] = {
+               [0] = g_attr_sb_stats,
+       };
+       struct exofs_io_state *ios;
+       int ret;
+
+       ret = exofs_get_io_state(&sbi->layout, &ios);
+       if (unlikely(ret)) {
+               EXOFS_ERR("%s: exofs_get_io_state failed.\n", __func__);
+               return ret;
+       }
+
+       ios->cred = sbi->s_cred;
+
+       ios->in_attr = attrs;
+       ios->in_attr_len = ARRAY_SIZE(attrs);
+
+       ret = exofs_sbi_read(ios);
+       if (unlikely(ret)) {
+               EXOFS_ERR("Error reading super_block stats => %d\n", ret);
+               goto out;
+       }
+
+       ret = extract_attr_from_ios(ios, &attrs[0]);
+       if (ret) {
+               EXOFS_ERR("%s: extract_attr of sb_stats failed\n", __func__);
+               goto out;
+       }
+       if (attrs[0].len) {
+               struct exofs_sb_stats *ess;
+
+               if (unlikely(attrs[0].len != sizeof(*ess))) {
+                       EXOFS_ERR("%s: Wrong version of exofs_sb_stats "
+                                 "size(%d) != expected(%zd)\n",
+                                 __func__, attrs[0].len, sizeof(*ess));
+                       goto out;
+               }
+
+               ess = attrs[0].val_ptr;
+               sbi->s_nextid = le64_to_cpu(ess->s_nextid);
+               sbi->s_numfiles = le32_to_cpu(ess->s_numfiles);
+       }
+
+out:
+       exofs_put_io_state(ios);
+       return ret;
+}
+
+static void stats_done(struct exofs_io_state *ios, void *p)
+{
+       exofs_put_io_state(ios);
+       /* Good thanks nothing to do anymore */
+}
+
+/* Asynchronously write the stats attribute */
+int exofs_sbi_write_stats(struct exofs_sb_info *sbi)
+{
+       struct osd_attr attrs[] = {
+               [0] = g_attr_sb_stats,
+       };
+       struct exofs_io_state *ios;
+       int ret;
+
+       ret = exofs_get_io_state(&sbi->layout, &ios);
+       if (unlikely(ret)) {
+               EXOFS_ERR("%s: exofs_get_io_state failed.\n", __func__);
+               return ret;
+       }
+
+       sbi->s_ess.s_nextid   = cpu_to_le64(sbi->s_nextid);
+       sbi->s_ess.s_numfiles = cpu_to_le64(sbi->s_numfiles);
+       attrs[0].val_ptr = &sbi->s_ess;
+
+       ios->cred = sbi->s_cred;
+       ios->done = stats_done;
+       ios->private = sbi;
+       ios->out_attr = attrs;
+       ios->out_attr_len = ARRAY_SIZE(attrs);
+
+       ret = exofs_sbi_write(ios);
+       if (unlikely(ret)) {
+               EXOFS_ERR("%s: exofs_sbi_write failed.\n", __func__);
+               exofs_put_io_state(ios);
+       }
+
+       return ret;
+}
+
 /*
  * Write the superblock to the OSD
  */
@@ -213,18 +318,25 @@ int exofs_sync_fs(struct super_block *sb, int wait)
        struct exofs_io_state *ios;
        int ret = -ENOMEM;
 
-       lock_super(sb);
+       fscb = kmalloc(sizeof(*fscb), GFP_KERNEL);
+       if (unlikely(!fscb))
+               return -ENOMEM;
+
        sbi = sb->s_fs_info;
-       fscb = &sbi->s_fscb;
 
+       /* NOTE: We no longer dirty the super_block anywhere in exofs. The
+        * reason we write the fscb here on unmount is so we can stay backwards
+        * compatible with fscb->s_version == 1. (What we are not compatible
+        * with is if a new version FS crashed and then we try to mount an old
+        * version). Otherwise the exofs_fscb is read-only from mkfs time. All
+        * the writeable info is set in exofs_sbi_write_stats() above.
+        */
        ret = exofs_get_io_state(&sbi->layout, &ios);
-       if (ret)
+       if (unlikely(ret))
                goto out;
 
-       /* Note: We only write the changing part of the fscb. .i.e upto the
-        *       the fscb->s_dev_table_oid member. There is no read-modify-write
-        *       here.
-        */
+       lock_super(sb);
+
        ios->length = offsetof(struct exofs_fscb, s_dev_table_oid);
        memset(fscb, 0, ios->length);
        fscb->s_nextid = cpu_to_le64(sbi->s_nextid);
@@ -239,16 +351,17 @@ int exofs_sync_fs(struct super_block *sb, int wait)
        ios->cred = sbi->s_cred;
 
        ret = exofs_sbi_write(ios);
-       if (unlikely(ret)) {
+       if (unlikely(ret))
                EXOFS_ERR("%s: exofs_sbi_write failed.\n", __func__);
-               goto out;
-       }
-       sb->s_dirt = 0;
+       else
+               sb->s_dirt = 0;
+
 
+       unlock_super(sb);
 out:
        EXOFS_DBGMSG("s_nextid=0x%llx ret=%d\n", _LLU(sbi->s_nextid), ret);
        exofs_put_io_state(ios);
-       unlock_super(sb);
+       kfree(fscb);
        return ret;
 }
 
@@ -292,13 +405,14 @@ static void exofs_put_super(struct super_block *sb)
        int num_pend;
        struct exofs_sb_info *sbi = sb->s_fs_info;
 
-       if (sb->s_dirt)
-               exofs_write_super(sb);
-
        /* make sure there are no pending commands */
        for (num_pend = atomic_read(&sbi->s_curr_pending); num_pend > 0;
             num_pend = atomic_read(&sbi->s_curr_pending)) {
                wait_queue_head_t wq;
+
+               printk(KERN_NOTICE "%s: !!Pending operations in flight. "
+                      "This is a BUG. please report to osd-dev@open-osd.org\n",
+                      __func__);
                init_waitqueue_head(&wq);
                wait_event_timeout(wq,
                                  (atomic_read(&sbi->s_curr_pending) == 0),
@@ -390,6 +504,23 @@ static int _read_and_match_data_map(struct exofs_sb_info *sbi, unsigned numdevs,
        return 0;
 }
 
+static unsigned __ra_pages(struct exofs_layout *layout)
+{
+       const unsigned _MIN_RA = 32; /* min 128K read-ahead */
+       unsigned ra_pages = layout->group_width * layout->stripe_unit /
+                               PAGE_SIZE;
+       unsigned max_io_pages = exofs_max_io_pages(layout, ~0);
+
+       ra_pages *= 2; /* two stripes */
+       if (ra_pages < _MIN_RA)
+               ra_pages = roundup(_MIN_RA, ra_pages / 2);
+
+       if (ra_pages > max_io_pages)
+               ra_pages = max_io_pages;
+
+       return ra_pages;
+}
+
 /* @odi is valid only as long as @fscb_dev is valid */
 static int exofs_devs_2_odi(struct exofs_dt_device_info *dt_dev,
                             struct osd_dev_info *odi)
@@ -495,7 +626,7 @@ static int exofs_read_lookup_dev_table(struct exofs_sb_info **psbi,
                }
 
                od = osduld_info_lookup(&odi);
-               if (unlikely(IS_ERR(od))) {
+               if (IS_ERR(od)) {
                        ret = PTR_ERR(od);
                        EXOFS_ERR("ERROR: device requested is not found "
                                  "osd_name-%s =>%d\n", odi.osdname, ret);
@@ -558,9 +689,17 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
                goto free_bdi;
 
        /* use mount options to fill superblock */
-       od = osduld_path_lookup(opts->dev_name);
+       if (opts->is_osdname) {
+               struct osd_dev_info odi = {.systemid_len = 0};
+
+               odi.osdname_len = strlen(opts->dev_name);
+               odi.osdname = (u8 *)opts->dev_name;
+               od = osduld_info_lookup(&odi);
+       } else {
+               od = osduld_path_lookup(opts->dev_name);
+       }
        if (IS_ERR(od)) {
-               ret = PTR_ERR(od);
+               ret = -EINVAL;
                goto free_sbi;
        }
 
@@ -594,6 +733,7 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
                goto free_sbi;
 
        sb->s_magic = le16_to_cpu(fscb.s_magic);
+       /* NOTE: we read below to be backward compatible with old versions */
        sbi->s_nextid = le64_to_cpu(fscb.s_nextid);
        sbi->s_numfiles = le32_to_cpu(fscb.s_numfiles);
 
@@ -604,7 +744,7 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
                ret = -EINVAL;
                goto free_sbi;
        }
-       if (le32_to_cpu(fscb.s_version) != EXOFS_FSCB_VER) {
+       if (le32_to_cpu(fscb.s_version) > EXOFS_FSCB_VER) {
                EXOFS_ERR("ERROR: Bad FSCB version expected-%d got-%d\n",
                          EXOFS_FSCB_VER, le32_to_cpu(fscb.s_version));
                ret = -EINVAL;
@@ -622,7 +762,10 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
                        goto free_sbi;
        }
 
+       __sbi_read_stats(sbi);
+
        /* set up operation vectors */
+       sbi->bdi.ra_pages = __ra_pages(&sbi->layout);
        sb->s_bdi = &sbi->bdi;
        sb->s_fs_info = sbi;
        sb->s_op = &exofs_sops;
@@ -652,6 +795,8 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
 
        _exofs_print_device("Mounting", opts->dev_name, sbi->layout.s_ods[0],
                            sbi->layout.s_pid);
+       if (opts->is_osdname)
+               kfree(opts->dev_name);
        return 0;
 
 free_sbi:
@@ -660,6 +805,8 @@ free_bdi:
        EXOFS_ERR("Unable to mount exofs on %s pid=0x%llx err=%d\n",
                  opts->dev_name, sbi->layout.s_pid, ret);
        exofs_free_sbi(sbi);
+       if (opts->is_osdname)
+               kfree(opts->dev_name);
        return ret;
 }
 
@@ -677,7 +824,8 @@ static struct dentry *exofs_mount(struct file_system_type *type,
        if (ret)
                return ERR_PTR(ret);
 
-       opts.dev_name = dev_name;
+       if (!opts.dev_name)
+               opts.dev_name = dev_name;
        return mount_nodev(type, flags, &opts, exofs_fill_super);
 }