xfs: fix internal error from AGFL exhaustion
[platform/kernel/linux-starfive.git] / lib / debugobjects.c
index 984985c..c90834a 100644 (file)
@@ -498,6 +498,15 @@ static void debug_print_object(struct debug_obj *obj, char *msg)
        const struct debug_obj_descr *descr = obj->descr;
        static int limit;
 
+       /*
+        * Don't report if lookup_object_or_alloc() by the current thread
+        * failed because lookup_object_or_alloc()/debug_objects_oom() by a
+        * concurrent thread turned off debug_objects_enabled and cleared
+        * the hash buckets.
+        */
+       if (!debug_objects_enabled)
+               return;
+
        if (limit < 5 && descr != descr_test) {
                void *hint = descr->debug_hint ?
                        descr->debug_hint(obj->object) : NULL;
@@ -611,9 +620,8 @@ static void debug_objects_fill_pool(void)
 static void
 __debug_object_init(void *addr, const struct debug_obj_descr *descr, int onstack)
 {
-       enum debug_obj_state state;
+       struct debug_obj *obj, o;
        struct debug_bucket *db;
-       struct debug_obj *obj;
        unsigned long flags;
 
        debug_objects_fill_pool();
@@ -634,24 +642,18 @@ __debug_object_init(void *addr, const struct debug_obj_descr *descr, int onstack
        case ODEBUG_STATE_INIT:
        case ODEBUG_STATE_INACTIVE:
                obj->state = ODEBUG_STATE_INIT;
-               break;
-
-       case ODEBUG_STATE_ACTIVE:
-               state = obj->state;
-               raw_spin_unlock_irqrestore(&db->lock, flags);
-               debug_print_object(obj, "init");
-               debug_object_fixup(descr->fixup_init, addr, state);
-               return;
-
-       case ODEBUG_STATE_DESTROYED:
                raw_spin_unlock_irqrestore(&db->lock, flags);
-               debug_print_object(obj, "init");
                return;
        default:
                break;
        }
 
+       o = *obj;
        raw_spin_unlock_irqrestore(&db->lock, flags);
+       debug_print_object(&o, "init");
+
+       if (o.state == ODEBUG_STATE_ACTIVE)
+               debug_object_fixup(descr->fixup_init, addr, o.state);
 }
 
 /**
@@ -692,11 +694,9 @@ EXPORT_SYMBOL_GPL(debug_object_init_on_stack);
 int debug_object_activate(void *addr, const struct debug_obj_descr *descr)
 {
        struct debug_obj o = { .object = addr, .state = ODEBUG_STATE_NOTAVAILABLE, .descr = descr };
-       enum debug_obj_state state;
        struct debug_bucket *db;
        struct debug_obj *obj;
        unsigned long flags;
-       int ret;
 
        if (!debug_objects_enabled)
                return 0;
@@ -708,49 +708,38 @@ int debug_object_activate(void *addr, const struct debug_obj_descr *descr)
        raw_spin_lock_irqsave(&db->lock, flags);
 
        obj = lookup_object_or_alloc(addr, db, descr, false, true);
-       if (likely(!IS_ERR_OR_NULL(obj))) {
-               bool print_object = false;
-
+       if (unlikely(!obj)) {
+               raw_spin_unlock_irqrestore(&db->lock, flags);
+               debug_objects_oom();
+               return 0;
+       } else if (likely(!IS_ERR(obj))) {
                switch (obj->state) {
-               case ODEBUG_STATE_INIT:
-               case ODEBUG_STATE_INACTIVE:
-                       obj->state = ODEBUG_STATE_ACTIVE;
-                       ret = 0;
-                       break;
-
                case ODEBUG_STATE_ACTIVE:
-                       state = obj->state;
-                       raw_spin_unlock_irqrestore(&db->lock, flags);
-                       debug_print_object(obj, "activate");
-                       ret = debug_object_fixup(descr->fixup_activate, addr, state);
-                       return ret ? 0 : -EINVAL;
-
                case ODEBUG_STATE_DESTROYED:
-                       print_object = true;
-                       ret = -EINVAL;
+                       o = *obj;
                        break;
+               case ODEBUG_STATE_INIT:
+               case ODEBUG_STATE_INACTIVE:
+                       obj->state = ODEBUG_STATE_ACTIVE;
+                       fallthrough;
                default:
-                       ret = 0;
-                       break;
+                       raw_spin_unlock_irqrestore(&db->lock, flags);
+                       return 0;
                }
-               raw_spin_unlock_irqrestore(&db->lock, flags);
-               if (print_object)
-                       debug_print_object(obj, "activate");
-               return ret;
        }
 
        raw_spin_unlock_irqrestore(&db->lock, flags);
+       debug_print_object(&o, "activate");
 
-       /* If NULL the allocation has hit OOM */
-       if (!obj) {
-               debug_objects_oom();
-               return 0;
+       switch (o.state) {
+       case ODEBUG_STATE_ACTIVE:
+       case ODEBUG_STATE_NOTAVAILABLE:
+               if (debug_object_fixup(descr->fixup_activate, addr, o.state))
+                       return 0;
+               fallthrough;
+       default:
+               return -EINVAL;
        }
-
-       /* Object is neither static nor tracked. It's not initialized */
-       debug_print_object(&o, "activate");
-       ret = debug_object_fixup(descr->fixup_activate, addr, ODEBUG_STATE_NOTAVAILABLE);
-       return ret ? 0 : -EINVAL;
 }
 EXPORT_SYMBOL_GPL(debug_object_activate);
 
@@ -761,10 +750,10 @@ EXPORT_SYMBOL_GPL(debug_object_activate);
  */
 void debug_object_deactivate(void *addr, const struct debug_obj_descr *descr)
 {
+       struct debug_obj o = { .object = addr, .state = ODEBUG_STATE_NOTAVAILABLE, .descr = descr };
        struct debug_bucket *db;
        struct debug_obj *obj;
        unsigned long flags;
-       bool print_object = false;
 
        if (!debug_objects_enabled)
                return;
@@ -776,33 +765,24 @@ void debug_object_deactivate(void *addr, const struct debug_obj_descr *descr)
        obj = lookup_object(addr, db);
        if (obj) {
                switch (obj->state) {
+               case ODEBUG_STATE_DESTROYED:
+                       break;
                case ODEBUG_STATE_INIT:
                case ODEBUG_STATE_INACTIVE:
                case ODEBUG_STATE_ACTIVE:
-                       if (!obj->astate)
-                               obj->state = ODEBUG_STATE_INACTIVE;
-                       else
-                               print_object = true;
-                       break;
-
-               case ODEBUG_STATE_DESTROYED:
-                       print_object = true;
-                       break;
+                       if (obj->astate)
+                               break;
+                       obj->state = ODEBUG_STATE_INACTIVE;
+                       fallthrough;
                default:
-                       break;
+                       raw_spin_unlock_irqrestore(&db->lock, flags);
+                       return;
                }
+               o = *obj;
        }
 
        raw_spin_unlock_irqrestore(&db->lock, flags);
-       if (!obj) {
-               struct debug_obj o = { .object = addr,
-                                      .state = ODEBUG_STATE_NOTAVAILABLE,
-                                      .descr = descr };
-
-               debug_print_object(&o, "deactivate");
-       } else if (print_object) {
-               debug_print_object(obj, "deactivate");
-       }
+       debug_print_object(&o, "deactivate");
 }
 EXPORT_SYMBOL_GPL(debug_object_deactivate);
 
@@ -813,11 +793,9 @@ EXPORT_SYMBOL_GPL(debug_object_deactivate);
  */
 void debug_object_destroy(void *addr, const struct debug_obj_descr *descr)
 {
-       enum debug_obj_state state;
+       struct debug_obj *obj, o;
        struct debug_bucket *db;
-       struct debug_obj *obj;
        unsigned long flags;
-       bool print_object = false;
 
        if (!debug_objects_enabled)
                return;
@@ -827,32 +805,31 @@ void debug_object_destroy(void *addr, const struct debug_obj_descr *descr)
        raw_spin_lock_irqsave(&db->lock, flags);
 
        obj = lookup_object(addr, db);
-       if (!obj)
-               goto out_unlock;
+       if (!obj) {
+               raw_spin_unlock_irqrestore(&db->lock, flags);
+               return;
+       }
 
        switch (obj->state) {
+       case ODEBUG_STATE_ACTIVE:
+       case ODEBUG_STATE_DESTROYED:
+               break;
        case ODEBUG_STATE_NONE:
        case ODEBUG_STATE_INIT:
        case ODEBUG_STATE_INACTIVE:
                obj->state = ODEBUG_STATE_DESTROYED;
-               break;
-       case ODEBUG_STATE_ACTIVE:
-               state = obj->state;
+               fallthrough;
+       default:
                raw_spin_unlock_irqrestore(&db->lock, flags);
-               debug_print_object(obj, "destroy");
-               debug_object_fixup(descr->fixup_destroy, addr, state);
                return;
-
-       case ODEBUG_STATE_DESTROYED:
-               print_object = true;
-               break;
-       default:
-               break;
        }
-out_unlock:
+
+       o = *obj;
        raw_spin_unlock_irqrestore(&db->lock, flags);
-       if (print_object)
-               debug_print_object(obj, "destroy");
+       debug_print_object(&o, "destroy");
+
+       if (o.state == ODEBUG_STATE_ACTIVE)
+               debug_object_fixup(descr->fixup_destroy, addr, o.state);
 }
 EXPORT_SYMBOL_GPL(debug_object_destroy);
 
@@ -863,9 +840,8 @@ EXPORT_SYMBOL_GPL(debug_object_destroy);
  */
 void debug_object_free(void *addr, const struct debug_obj_descr *descr)
 {
-       enum debug_obj_state state;
+       struct debug_obj *obj, o;
        struct debug_bucket *db;
-       struct debug_obj *obj;
        unsigned long flags;
 
        if (!debug_objects_enabled)
@@ -876,24 +852,26 @@ void debug_object_free(void *addr, const struct debug_obj_descr *descr)
        raw_spin_lock_irqsave(&db->lock, flags);
 
        obj = lookup_object(addr, db);
-       if (!obj)
-               goto out_unlock;
+       if (!obj) {
+               raw_spin_unlock_irqrestore(&db->lock, flags);
+               return;
+       }
 
        switch (obj->state) {
        case ODEBUG_STATE_ACTIVE:
-               state = obj->state;
-               raw_spin_unlock_irqrestore(&db->lock, flags);
-               debug_print_object(obj, "free");
-               debug_object_fixup(descr->fixup_free, addr, state);
-               return;
+               break;
        default:
                hlist_del(&obj->node);
                raw_spin_unlock_irqrestore(&db->lock, flags);
                free_object(obj);
                return;
        }
-out_unlock:
+
+       o = *obj;
        raw_spin_unlock_irqrestore(&db->lock, flags);
+       debug_print_object(&o, "free");
+
+       debug_object_fixup(descr->fixup_free, addr, o.state);
 }
 EXPORT_SYMBOL_GPL(debug_object_free);
 
@@ -945,10 +923,10 @@ void
 debug_object_active_state(void *addr, const struct debug_obj_descr *descr,
                          unsigned int expect, unsigned int next)
 {
+       struct debug_obj o = { .object = addr, .state = ODEBUG_STATE_NOTAVAILABLE, .descr = descr };
        struct debug_bucket *db;
        struct debug_obj *obj;
        unsigned long flags;
-       bool print_object = false;
 
        if (!debug_objects_enabled)
                return;
@@ -961,28 +939,19 @@ debug_object_active_state(void *addr, const struct debug_obj_descr *descr,
        if (obj) {
                switch (obj->state) {
                case ODEBUG_STATE_ACTIVE:
-                       if (obj->astate == expect)
-                               obj->astate = next;
-                       else
-                               print_object = true;
-                       break;
-
+                       if (obj->astate != expect)
+                               break;
+                       obj->astate = next;
+                       raw_spin_unlock_irqrestore(&db->lock, flags);
+                       return;
                default:
-                       print_object = true;
                        break;
                }
+               o = *obj;
        }
 
        raw_spin_unlock_irqrestore(&db->lock, flags);
-       if (!obj) {
-               struct debug_obj o = { .object = addr,
-                                      .state = ODEBUG_STATE_NOTAVAILABLE,
-                                      .descr = descr };
-
-               debug_print_object(&o, "active_state");
-       } else if (print_object) {
-               debug_print_object(obj, "active_state");
-       }
+       debug_print_object(&o, "active_state");
 }
 EXPORT_SYMBOL_GPL(debug_object_active_state);
 
@@ -990,12 +959,10 @@ EXPORT_SYMBOL_GPL(debug_object_active_state);
 static void __debug_check_no_obj_freed(const void *address, unsigned long size)
 {
        unsigned long flags, oaddr, saddr, eaddr, paddr, chunks;
-       const struct debug_obj_descr *descr;
-       enum debug_obj_state state;
+       int cnt, objs_checked = 0;
+       struct debug_obj *obj, o;
        struct debug_bucket *db;
        struct hlist_node *tmp;
-       struct debug_obj *obj;
-       int cnt, objs_checked = 0;
 
        saddr = (unsigned long) address;
        eaddr = saddr + size;
@@ -1017,12 +984,10 @@ repeat:
 
                        switch (obj->state) {
                        case ODEBUG_STATE_ACTIVE:
-                               descr = obj->descr;
-                               state = obj->state;
+                               o = *obj;
                                raw_spin_unlock_irqrestore(&db->lock, flags);
-                               debug_print_object(obj, "free");
-                               debug_object_fixup(descr->fixup_free,
-                                                  (void *) oaddr, state);
+                               debug_print_object(&o, "free");
+                               debug_object_fixup(o.descr->fixup_free, (void *)oaddr, o.state);
                                goto repeat;
                        default:
                                hlist_del(&obj->node);