]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/md/dm-mpath.c
Pull cpuidle into release branch
[linux-2.6-omap-h63xx.git] / drivers / md / dm-mpath.c
index c0950a0b5312158909ed7662a308cae9a440d151..24b2b1e32faefc443bf102949a3674689e505b05 100644 (file)
@@ -10,6 +10,7 @@
 #include "dm-hw-handler.h"
 #include "dm-bio-list.h"
 #include "dm-bio-record.h"
+#include "dm-uevent.h"
 
 #include <linux/ctype.h>
 #include <linux/init.h>
@@ -75,6 +76,8 @@ struct multipath {
        unsigned queue_io;              /* Must we queue all I/O? */
        unsigned queue_if_no_path;      /* Queue I/O if last path fails? */
        unsigned saved_queue_if_no_path;/* Saved state during suspension */
+       unsigned pg_init_retries;       /* Number of times to retry pg_init */
+       unsigned pg_init_count;         /* Number of times pg_init called */
 
        struct work_struct process_queued_ios;
        struct bio_list queued_ios;
@@ -225,6 +228,8 @@ static void __switch_pg(struct multipath *m, struct pgpath *pgpath)
                m->pg_init_required = 0;
                m->queue_io = 0;
        }
+
+       m->pg_init_count = 0;
 }
 
 static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg)
@@ -390,11 +395,11 @@ static void dispatch_queued_ios(struct multipath *m)
 
                r = map_io(m, bio, mpio, 1);
                if (r < 0)
-                       bio_endio(bio, bio->bi_size, r);
+                       bio_endio(bio, r);
                else if (r == DM_MAPIO_REMAPPED)
                        generic_make_request(bio);
                else if (r == DM_MAPIO_REQUEUE)
-                       bio_endio(bio, bio->bi_size, -EIO);
+                       bio_endio(bio, -EIO);
 
                bio = next;
        }
@@ -424,6 +429,7 @@ static void process_queued_ios(struct work_struct *work)
                must_queue = 0;
 
        if (m->pg_init_required && !m->pg_init_in_progress) {
+               m->pg_init_count++;
                m->pg_init_required = 0;
                m->pg_init_in_progress = 1;
                init_required = 1;
@@ -689,9 +695,11 @@ static int parse_features(struct arg_set *as, struct multipath *m)
        int r;
        unsigned argc;
        struct dm_target *ti = m->ti;
+       const char *param_name;
 
        static struct param _params[] = {
-               {0, 1, "invalid number of feature args"},
+               {0, 3, "invalid number of feature args"},
+               {1, 50, "pg_init_retries must be between 1 and 50"},
        };
 
        r = read_param(_params, shift(as), &argc, &ti->error);
@@ -701,12 +709,28 @@ static int parse_features(struct arg_set *as, struct multipath *m)
        if (!argc)
                return 0;
 
-       if (!strnicmp(shift(as), MESG_STR("queue_if_no_path")))
-               return queue_if_no_path(m, 1, 0);
-       else {
+       do {
+               param_name = shift(as);
+               argc--;
+
+               if (!strnicmp(param_name, MESG_STR("queue_if_no_path"))) {
+                       r = queue_if_no_path(m, 1, 0);
+                       continue;
+               }
+
+               if (!strnicmp(param_name, MESG_STR("pg_init_retries")) &&
+                   (argc >= 1)) {
+                       r = read_param(_params + 1, shift(as),
+                                      &m->pg_init_retries, &ti->error);
+                       argc--;
+                       continue;
+               }
+
                ti->error = "Unrecognised multipath feature request";
-               return -EINVAL;
-       }
+               r = -EINVAL;
+       } while (argc && !r);
+
+       return r;
 }
 
 static int multipath_ctr(struct dm_target *ti, unsigned int argc,
@@ -798,9 +822,6 @@ static int multipath_map(struct dm_target *ti, struct bio *bio,
        struct dm_mpath_io *mpio;
        struct multipath *m = (struct multipath *) ti->private;
 
-       if (bio_barrier(bio))
-               return -EOPNOTSUPP;
-
        mpio = mempool_alloc(m->mpio_pool, GFP_NOIO);
        dm_bio_record(&mpio->details, bio);
 
@@ -837,6 +858,9 @@ static int fail_path(struct pgpath *pgpath)
        if (pgpath == m->current_pgpath)
                m->current_pgpath = NULL;
 
+       dm_path_uevent(DM_UEVENT_PATH_FAILED, m->ti,
+                     pgpath->path.dev->name, m->nr_valid_paths);
+
        queue_work(kmultipathd, &m->trigger_event);
 
 out:
@@ -876,6 +900,9 @@ static int reinstate_path(struct pgpath *pgpath)
        if (!m->nr_valid_paths++ && m->queue_size)
                queue_work(kmultipathd, &m->process_queued_ios);
 
+       dm_path_uevent(DM_UEVENT_PATH_REINSTATED, m->ti,
+                     pgpath->path.dev->name, m->nr_valid_paths);
+
        queue_work(kmultipathd, &m->trigger_event);
 
 out:
@@ -978,6 +1005,26 @@ static int bypass_pg_num(struct multipath *m, const char *pgstr, int bypassed)
        return 0;
 }
 
+/*
+ * Should we retry pg_init immediately?
+ */
+static int pg_init_limit_reached(struct multipath *m, struct pgpath *pgpath)
+{
+       unsigned long flags;
+       int limit_reached = 0;
+
+       spin_lock_irqsave(&m->lock, flags);
+
+       if (m->pg_init_count <= m->pg_init_retries)
+               m->pg_init_required = 1;
+       else
+               limit_reached = 1;
+
+       spin_unlock_irqrestore(&m->lock, flags);
+
+       return limit_reached;
+}
+
 /*
  * pg_init must call this when it has completed its initialisation
  */
@@ -988,8 +1035,14 @@ void dm_pg_init_complete(struct dm_path *path, unsigned err_flags)
        struct multipath *m = pg->m;
        unsigned long flags;
 
-       /* We insist on failing the path if the PG is already bypassed. */
-       if (err_flags && pg->bypassed)
+       /*
+        * If requested, retry pg_init until maximum number of retries exceeded.
+        * If retry not requested and PG already bypassed, always fail the path.
+        */
+       if (err_flags & MP_RETRY) {
+               if (pg_init_limit_reached(m, pgpath))
+                       err_flags |= MP_FAIL_PATH;
+       } else if (err_flags && pg->bypassed)
                err_flags |= MP_FAIL_PATH;
 
        if (err_flags & MP_FAIL_PATH)
@@ -999,7 +1052,7 @@ void dm_pg_init_complete(struct dm_path *path, unsigned err_flags)
                bypass_pg(m, pg, 1);
 
        spin_lock_irqsave(&m->lock, flags);
-       if (err_flags) {
+       if (err_flags & ~MP_RETRY) {
                m->current_pgpath = NULL;
                m->current_pg = NULL;
        } else if (!m->pg_init_required)
@@ -1151,11 +1204,15 @@ static int multipath_status(struct dm_target *ti, status_type_t type,
 
        /* Features */
        if (type == STATUSTYPE_INFO)
-               DMEMIT("1 %u ", m->queue_size);
-       else if (m->queue_if_no_path)
-               DMEMIT("1 queue_if_no_path ");
-       else
-               DMEMIT("0 ");
+               DMEMIT("2 %u %u ", m->queue_size, m->pg_init_count);
+       else {
+               DMEMIT("%u ", m->queue_if_no_path +
+                             (m->pg_init_retries > 0) * 2);
+               if (m->queue_if_no_path)
+                       DMEMIT("queue_if_no_path ");
+               if (m->pg_init_retries)
+                       DMEMIT("pg_init_retries %u ", m->pg_init_retries);
+       }
 
        if (hwh->type && hwh->type->status)
                sz += hwh->type->status(hwh, type, result + sz, maxlen - sz);
@@ -1352,15 +1409,14 @@ static int __init dm_multipath_init(void)
 
        r = dm_register_target(&multipath_target);
        if (r < 0) {
-               DMERR("%s: register failed %d", multipath_target.name, r);
+               DMERR("register failed %d", r);
                kmem_cache_destroy(_mpio_cache);
                return -EINVAL;
        }
 
        kmultipathd = create_workqueue("kmpathd");
        if (!kmultipathd) {
-               DMERR("%s: failed to create workqueue kmpathd",
-                               multipath_target.name);
+               DMERR("failed to create workqueue kmpathd");
                dm_unregister_target(&multipath_target);
                kmem_cache_destroy(_mpio_cache);
                return -ENOMEM;
@@ -1381,8 +1437,7 @@ static void __exit dm_multipath_exit(void)
 
        r = dm_unregister_target(&multipath_target);
        if (r < 0)
-               DMERR("%s: target unregister failed %d",
-                     multipath_target.name, r);
+               DMERR("target unregister failed %d", r);
        kmem_cache_destroy(_mpio_cache);
 }