[S390] cio: device scan oom fallback.
authorSebastian Ott <sebott@linux.vnet.ibm.com>
Thu, 26 Mar 2009 14:24:11 +0000 (15:24 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Thu, 26 Mar 2009 14:24:14 +0000 (15:24 +0100)
Since some callers rely on for_each_subchannel_staged to not fail,
fall back to brute force scanning using get_subchannel_by_schid in
case of a oom situation.

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/cio/css.c

index a5fc56371ba85a822b8078b04b248e2df6b83ff4..1f2e424596af282b4937fd93fa30407930d5f2b4 100644 (file)
@@ -83,6 +83,25 @@ static int call_fn_unknown_sch(struct subchannel_id schid, void *data)
        return rc;
 }
 
+static int call_fn_all_sch(struct subchannel_id schid, void *data)
+{
+       struct cb_data *cb = data;
+       struct subchannel *sch;
+       int rc = 0;
+
+       sch = get_subchannel_by_schid(schid);
+       if (sch) {
+               if (cb->fn_known_sch)
+                       rc = cb->fn_known_sch(sch, cb->data);
+               put_device(&sch->dev);
+       } else {
+               if (cb->fn_unknown_sch)
+                       rc = cb->fn_unknown_sch(schid, cb->data);
+       }
+
+       return rc;
+}
+
 int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
                               int (*fn_unknown)(struct subchannel_id,
                               void *), void *data)
@@ -90,13 +109,17 @@ int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
        struct cb_data cb;
        int rc;
 
-       cb.set = idset_sch_new();
-       if (!cb.set)
-               return -ENOMEM;
-       idset_fill(cb.set);
        cb.data = data;
        cb.fn_known_sch = fn_known;
        cb.fn_unknown_sch = fn_unknown;
+
+       cb.set = idset_sch_new();
+       if (!cb.set)
+               /* fall back to brute force scanning in case of oom */
+               return for_each_subchannel(call_fn_all_sch, &cb);
+
+       idset_fill(cb.set);
+
        /* Process registered subchannels. */
        rc = bus_for_each_dev(&css_bus_type, NULL, &cb, call_fn_known_sch);
        if (rc)