struct key_type *keytype;
 };
 
+enum key_state {
+       KEY_IS_UNINSTANTIATED,
+       KEY_IS_POSITIVE,                /* Positively instantiated */
+};
+
 /*****************************************************************************/
 /*
  * authentication token / access credential / keyring
                                                 * - may not match RCU dereferenced payload
                                                 * - payload should contain own length
                                                 */
+       short                   state;          /* Key state (+) or rejection error (-) */
 
 #ifdef KEY_DEBUGGING
        unsigned                magic;
 #endif
 
        unsigned long           flags;          /* status flags (change with bitops) */
-#define KEY_FLAG_INSTANTIATED  0       /* set if key has been instantiated */
-#define KEY_FLAG_DEAD          1       /* set if key type has been deleted */
-#define KEY_FLAG_REVOKED       2       /* set if key had been revoked */
-#define KEY_FLAG_IN_QUOTA      3       /* set if key consumes quota */
-#define KEY_FLAG_USER_CONSTRUCT        4       /* set if key is being constructed in userspace */
-#define KEY_FLAG_NEGATIVE      5       /* set if key is negative */
-#define KEY_FLAG_ROOT_CAN_CLEAR        6       /* set if key can be cleared by root without permission */
-#define KEY_FLAG_INVALIDATED   7       /* set if key has been invalidated */
-#define KEY_FLAG_BUILTIN       8       /* set if key is built in to the kernel */
-#define KEY_FLAG_ROOT_CAN_INVAL        9       /* set if key can be invalidated by root without permission */
-#define KEY_FLAG_KEEP          10      /* set if key should not be removed */
-#define KEY_FLAG_UID_KEYRING   11      /* set if key is a user or user session keyring */
+#define KEY_FLAG_DEAD          0       /* set if key type has been deleted */
+#define KEY_FLAG_REVOKED       1       /* set if key had been revoked */
+#define KEY_FLAG_IN_QUOTA      2       /* set if key consumes quota */
+#define KEY_FLAG_USER_CONSTRUCT        3       /* set if key is being constructed in userspace */
+#define KEY_FLAG_ROOT_CAN_CLEAR        4       /* set if key can be cleared by root without permission */
+#define KEY_FLAG_INVALIDATED   5       /* set if key has been invalidated */
+#define KEY_FLAG_BUILTIN       6       /* set if key is built in to the kernel */
+#define KEY_FLAG_ROOT_CAN_INVAL        7       /* set if key can be invalidated by root without permission */
+#define KEY_FLAG_KEEP          8       /* set if key should not be removed */
+#define KEY_FLAG_UID_KEYRING   9       /* set if key is a user or user session keyring */
 
        /* the key type and key description string
         * - the desc is used to match a key against search criteria
                        struct list_head name_link;
                        struct assoc_array keys;
                };
-               int reject_error;
        };
 
        /* This is set on a keyring to restrict the addition of a link to a key
 #define        KEY_NEED_SETATTR 0x20   /* Require permission to change attributes */
 #define        KEY_NEED_ALL    0x3f    /* All the above permissions */
 
+static inline short key_read_state(const struct key *key)
+{
+       /* Barrier versus mark_key_instantiated(). */
+       return smp_load_acquire(&key->state);
+}
+
 /**
- * key_is_instantiated - Determine if a key has been positively instantiated
+ * key_is_positive - Determine if a key has been positively instantiated
  * @key: The key to check.
  *
  * Return true if the specified key has been positively instantiated, false
  * otherwise.
  */
-static inline bool key_is_instantiated(const struct key *key)
+static inline bool key_is_positive(const struct key *key)
+{
+       return key_read_state(key) == KEY_IS_POSITIVE;
+}
+
+static inline bool key_is_negative(const struct key *key)
 {
-       return test_bit(KEY_FLAG_INSTANTIATED, &key->flags) &&
-               !test_bit(KEY_FLAG_NEGATIVE, &key->flags);
+       return key_read_state(key) < 0;
 }
 
 #define dereference_key_rcu(KEY)                                       \
 
 static void dns_resolver_describe(const struct key *key, struct seq_file *m)
 {
        seq_puts(m, key->description);
-       if (key_is_instantiated(key)) {
+       if (key_is_positive(key)) {
                int err = PTR_ERR(key->payload.data[dns_key_error]);
 
                if (err)
 
 
        /* clear the quota */
        key_payload_reserve(key, 0);
-       if (key_is_instantiated(key) &&
+       if (key_is_positive(key) &&
            (size_t)key->payload.data[big_key_len] > BIG_KEY_FILE_THRESHOLD)
                vfs_truncate(path, 0);
 }
 
        seq_puts(m, key->description);
 
-       if (key_is_instantiated(key))
+       if (key_is_positive(key))
                seq_printf(m, ": %zu [%s]",
                           datalen,
                           datalen > BIG_KEY_FILE_THRESHOLD ? "file" : "buff");
 
        size_t datalen = prep->datalen;
        int ret = 0;
 
-       if (test_bit(KEY_FLAG_NEGATIVE, &key->flags))
+       if (key_is_negative(key))
                return -ENOKEY;
        if (datalen <= 0 || datalen > 32767 || !prep->data)
                return -EINVAL;
 
        while (!list_empty(keys)) {
                struct key *key =
                        list_entry(keys->next, struct key, graveyard_link);
+               short state = key->state;
+
                list_del(&key->graveyard_link);
 
                kdebug("- %u", key->serial);
                key_check(key);
 
                /* Throw away the key data if the key is instantiated */
-               if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags) &&
-                   !test_bit(KEY_FLAG_NEGATIVE, &key->flags) &&
-                   key->type->destroy)
+               if (state == KEY_IS_POSITIVE && key->type->destroy)
                        key->type->destroy(key);
 
                security_key_free(key);
                }
 
                atomic_dec(&key->user->nkeys);
-               if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
+               if (state != KEY_IS_UNINSTANTIATED)
                        atomic_dec(&key->user->nikeys);
 
                key_user_put(key->user);
 
 }
 EXPORT_SYMBOL(key_payload_reserve);
 
+/*
+ * Change the key state to being instantiated.
+ */
+static void mark_key_instantiated(struct key *key, int reject_error)
+{
+       /* Commit the payload before setting the state; barrier versus
+        * key_read_state().
+        */
+       smp_store_release(&key->state,
+                         (reject_error < 0) ? reject_error : KEY_IS_POSITIVE);
+}
+
 /*
  * Instantiate a key and link it into the target keyring atomically.  Must be
  * called with the target keyring's semaphore writelocked.  The target key's
        mutex_lock(&key_construction_mutex);
 
        /* can't instantiate twice */
-       if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
+       if (key->state == KEY_IS_UNINSTANTIATED) {
                /* instantiate the key */
                ret = key->type->instantiate(key, prep);
 
                if (ret == 0) {
                        /* mark the key as being instantiated */
                        atomic_inc(&key->user->nikeys);
-                       set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
+                       mark_key_instantiated(key, 0);
 
                        if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
                                awaken = 1;
        mutex_lock(&key_construction_mutex);
 
        /* can't instantiate twice */
-       if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
+       if (key->state == KEY_IS_UNINSTANTIATED) {
                /* mark the key as being negatively instantiated */
                atomic_inc(&key->user->nikeys);
-               key->reject_error = -error;
-               smp_wmb();
-               set_bit(KEY_FLAG_NEGATIVE, &key->flags);
-               set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
+               mark_key_instantiated(key, -error);
                now = current_kernel_time();
                key->expiry = now.tv_sec + timeout;
                key_schedule_gc(key->expiry + key_gc_delay);
 
        ret = key->type->update(key, prep);
        if (ret == 0)
-               /* updating a negative key instantiates it */
-               clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
+               /* Updating a negative key positively instantiates it */
+               mark_key_instantiated(key, 0);
 
        up_write(&key->sem);
 
 
        ret = key->type->update(key, &prep);
        if (ret == 0)
-               /* updating a negative key instantiates it */
-               clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
+               /* Updating a negative key positively instantiates it */
+               mark_key_instantiated(key, 0);
 
        up_write(&key->sem);
 
 
 
        key = key_ref_to_ptr(key_ref);
 
-       if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
-               ret = -ENOKEY;
-               goto error2;
-       }
+       ret = key_read_state(key);
+       if (ret < 0)
+               goto error2; /* Negatively instantiated */
 
        /* see if we can read it directly */
        ret = key_permission(key_ref, KEY_NEED_READ);
                atomic_dec(&key->user->nkeys);
                atomic_inc(&newowner->nkeys);
 
-               if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
+               if (key->state != KEY_IS_UNINSTANTIATED) {
                        atomic_dec(&key->user->nikeys);
                        atomic_inc(&newowner->nikeys);
                }
 
        else
                seq_puts(m, "[anon]");
 
-       if (key_is_instantiated(keyring)) {
+       if (key_is_positive(keyring)) {
                if (keyring->keys.nr_leaves_on_tree != 0)
                        seq_printf(m, ": %lu", keyring->keys.nr_leaves_on_tree);
                else
 {
        struct keyring_search_context *ctx = iterator_data;
        const struct key *key = keyring_ptr_to_key(object);
-       unsigned long kflags = key->flags;
+       unsigned long kflags = READ_ONCE(key->flags);
+       short state = READ_ONCE(key->state);
 
        kenter("{%d}", key->serial);
 
 
        if (ctx->flags & KEYRING_SEARCH_DO_STATE_CHECK) {
                /* we set a different error code if we pass a negative key */
-               if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
-                       smp_rmb();
-                       ctx->result = ERR_PTR(key->reject_error);
+               if (state < 0) {
+                       ctx->result = ERR_PTR(state);
                        kleave(" = %d [neg]", ctx->skipped_ret);
                        goto skipped;
                }
 
        unsigned long timo;
        key_ref_t key_ref, skey_ref;
        char xbuf[16];
+       short state;
        int rc;
 
        struct keyring_search_context ctx = {
                        sprintf(xbuf, "%luw", timo / (60*60*24*7));
        }
 
+       state = key_read_state(key);
+
 #define showflag(KEY, LETTER, FLAG) \
        (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-')
 
        seq_printf(m, "%08x %c%c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ",
                   key->serial,
-                  showflag(key, 'I', KEY_FLAG_INSTANTIATED),
+                  state != KEY_IS_UNINSTANTIATED ? 'I' : '-',
                   showflag(key, 'R', KEY_FLAG_REVOKED),
                   showflag(key, 'D', KEY_FLAG_DEAD),
                   showflag(key, 'Q', KEY_FLAG_IN_QUOTA),
                   showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT),
-                  showflag(key, 'N', KEY_FLAG_NEGATIVE),
+                  state < 0 ? 'N' : '-',
                   showflag(key, 'i', KEY_FLAG_INVALIDATED),
                   refcount_read(&key->usage),
                   xbuf,
 
 
        ret = -EIO;
        if (!(lflags & KEY_LOOKUP_PARTIAL) &&
-           !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
+           key_read_state(key) == KEY_IS_UNINSTANTIATED)
                goto invalid_key;
 
        /* check the permissions */
 
                          intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
        if (ret)
                return -ERESTARTSYS;
-       if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
-               smp_rmb();
-               return key->reject_error;
-       }
+       ret = key_read_state(key);
+       if (ret < 0)
+               return ret;
        return key_validate(key);
 }
 EXPORT_SYMBOL(wait_for_key_construction);
 
 
        seq_puts(m, "key:");
        seq_puts(m, key->description);
-       if (key_is_instantiated(key))
+       if (key_is_positive(key))
                seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);
 }
 
 
        char *datablob;
        int ret = 0;
 
-       if (test_bit(KEY_FLAG_NEGATIVE, &key->flags))
+       if (key_is_negative(key))
                return -ENOKEY;
        p = key->payload.data[0];
        if (!p->migratable)
 
 
        /* attach the new data, displacing the old */
        key->expiry = prep->expiry;
-       if (!test_bit(KEY_FLAG_NEGATIVE, &key->flags))
+       if (key_is_positive(key))
                zap = dereference_key_locked(key);
        rcu_assign_keypointer(key, prep->payload.data[0]);
        prep->payload.data[0] = NULL;
 void user_describe(const struct key *key, struct seq_file *m)
 {
        seq_puts(m, key->description);
-       if (key_is_instantiated(key))
+       if (key_is_positive(key))
                seq_printf(m, ": %u", key->datalen);
 }