* @entry: deleting entry
  * @turn_off_scanning: Check if a scanning flag should be turned off
  */
-static inline void __efi_pstore_scan_sysfs_exit(struct efivar_entry *entry,
+static inline int __efi_pstore_scan_sysfs_exit(struct efivar_entry *entry,
                                                bool turn_off_scanning)
 {
        if (entry->deleting) {
                list_del(&entry->list);
                efivar_entry_iter_end();
                efivar_unregister(entry);
-               efivar_entry_iter_begin();
+               if (efivar_entry_iter_begin())
+                       return -EINTR;
        } else if (turn_off_scanning)
                entry->scanning = false;
+
+       return 0;
 }
 
 /**
  * @head: list head
  * @stop: a flag checking if scanning will stop
  */
-static void efi_pstore_scan_sysfs_exit(struct efivar_entry *pos,
+static int efi_pstore_scan_sysfs_exit(struct efivar_entry *pos,
                                       struct efivar_entry *next,
                                       struct list_head *head, bool stop)
 {
-       __efi_pstore_scan_sysfs_exit(pos, true);
+       int ret = __efi_pstore_scan_sysfs_exit(pos, true);
+
+       if (ret)
+               return ret;
+
        if (stop)
-               __efi_pstore_scan_sysfs_exit(next, &next->list != head);
+               ret = __efi_pstore_scan_sysfs_exit(next, &next->list != head);
+       return ret;
 }
 
 /**
        struct efivar_entry *entry, *n;
        struct list_head *head = &efivar_sysfs_list;
        int size = 0;
+       int ret;
 
        if (!*pos) {
                list_for_each_entry_safe(entry, n, head, list) {
                        efi_pstore_scan_sysfs_enter(entry, n, head);
 
                        size = efi_pstore_read_func(entry, data);
-                       efi_pstore_scan_sysfs_exit(entry, n, head, size < 0);
+                       ret = efi_pstore_scan_sysfs_exit(entry, n, head,
+                                                        size < 0);
+                       if (ret)
+                               return ret;
                        if (size)
                                break;
                }
                efi_pstore_scan_sysfs_enter((*pos), n, head);
 
                size = efi_pstore_read_func((*pos), data);
-               efi_pstore_scan_sysfs_exit((*pos), n, head, size < 0);
+               ret = efi_pstore_scan_sysfs_exit((*pos), n, head, size < 0);
+               if (ret)
+                       return ret;
                if (size)
                        break;
        }
        if (!*data.buf)
                return -ENOMEM;
 
-       efivar_entry_iter_begin();
+       if (efivar_entry_iter_begin()) {
+               kfree(*data.buf);
+               return -EINTR;
+       }
        size = efi_pstore_sysfs_entry_iter(&data,
                                           (struct efivar_entry **)&psi->data);
        efivar_entry_iter_end();
        edata.time = time;
        edata.name = efi_name;
 
-       efivar_entry_iter_begin();
+       if (efivar_entry_iter_begin())
+               return -EINTR;
        found = __efivar_entry_iter(efi_pstore_erase_func, &efivar_sysfs_list, &edata, &entry);
 
        if (found && !entry->scanning) {
 
  * 2) ->ops calls
  * 3) (un)registration of __efivars
  */
-static DEFINE_SPINLOCK(efivars_lock);
+static DEFINE_SEMAPHORE(efivars_lock);
 
 static bool efivar_wq_enabled = true;
 DECLARE_WORK(efivar_work, NULL);
                return -ENOMEM;
        }
 
-       spin_lock_irq(&efivars_lock);
+       if (down_interruptible(&efivars_lock)) {
+               err = -EINTR;
+               goto free;
+       }
 
        /*
         * Per EFI spec, the maximum storage allocated for both
                switch (status) {
                case EFI_SUCCESS:
                        if (duplicates)
-                               spin_unlock_irq(&efivars_lock);
+                               up(&efivars_lock);
 
                        variable_name_size = var_name_strnsize(variable_name,
                                                               variable_name_size);
                                        status = EFI_NOT_FOUND;
                        }
 
-                       if (duplicates)
-                               spin_lock_irq(&efivars_lock);
+                       if (duplicates) {
+                               if (down_interruptible(&efivars_lock)) {
+                                       err = -EINTR;
+                                       goto free;
+                               }
+                       }
 
                        break;
                case EFI_NOT_FOUND:
 
        } while (status != EFI_NOT_FOUND);
 
-       spin_unlock_irq(&efivars_lock);
-
+       up(&efivars_lock);
+free:
        kfree(variable_name);
 
        return err;
  * efivar_entry_add - add entry to variable list
  * @entry: entry to add to list
  * @head: list head
+ *
+ * Returns 0 on success, or a kernel error code on failure.
  */
-void efivar_entry_add(struct efivar_entry *entry, struct list_head *head)
+int efivar_entry_add(struct efivar_entry *entry, struct list_head *head)
 {
-       spin_lock_irq(&efivars_lock);
+       if (down_interruptible(&efivars_lock))
+               return -EINTR;
        list_add(&entry->list, head);
-       spin_unlock_irq(&efivars_lock);
+       up(&efivars_lock);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(efivar_entry_add);
 
 /**
  * efivar_entry_remove - remove entry from variable list
  * @entry: entry to remove from list
+ *
+ * Returns 0 on success, or a kernel error code on failure.
  */
-void efivar_entry_remove(struct efivar_entry *entry)
+int efivar_entry_remove(struct efivar_entry *entry)
 {
-       spin_lock_irq(&efivars_lock);
+       if (down_interruptible(&efivars_lock))
+               return -EINTR;
        list_del(&entry->list);
-       spin_unlock_irq(&efivars_lock);
+       up(&efivars_lock);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(efivar_entry_remove);
 
  */
 static void efivar_entry_list_del_unlock(struct efivar_entry *entry)
 {
-       lockdep_assert_held(&efivars_lock);
-
        list_del(&entry->list);
-       spin_unlock_irq(&efivars_lock);
+       up(&efivars_lock);
 }
 
 /**
        const struct efivar_operations *ops = __efivars->ops;
        efi_status_t status;
 
-       lockdep_assert_held(&efivars_lock);
-
        status = ops->set_variable(entry->var.VariableName,
                                   &entry->var.VendorGuid,
                                   0, 0, NULL);
  * variable list. It is the caller's responsibility to free @entry
  * once we return.
  *
- * Returns 0 on success, or a converted EFI status code if
- * set_variable() fails.
+ * Returns 0 on success, -EINTR if we can't grab the semaphore,
+ * converted EFI status code if set_variable() fails.
  */
 int efivar_entry_delete(struct efivar_entry *entry)
 {
        const struct efivar_operations *ops = __efivars->ops;
        efi_status_t status;
 
-       spin_lock_irq(&efivars_lock);
+       if (down_interruptible(&efivars_lock))
+               return -EINTR;
+
        status = ops->set_variable(entry->var.VariableName,
                                   &entry->var.VendorGuid,
                                   0, 0, NULL);
        if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) {
-               spin_unlock_irq(&efivars_lock);
+               up(&efivars_lock);
                return efi_status_to_err(status);
        }
 
  * If @head is not NULL a lookup is performed to determine whether
  * the entry is already on the list.
  *
- * Returns 0 on success, -EEXIST if a lookup is performed and the entry
- * already exists on the list, or a converted EFI status code if
- * set_variable() fails.
+ * Returns 0 on success, -EINTR if we can't grab the semaphore,
+ * -EEXIST if a lookup is performed and the entry already exists on
+ * the list, or a converted EFI status code if set_variable() fails.
  */
 int efivar_entry_set(struct efivar_entry *entry, u32 attributes,
                     unsigned long size, void *data, struct list_head *head)
        efi_char16_t *name = entry->var.VariableName;
        efi_guid_t vendor = entry->var.VendorGuid;
 
-       spin_lock_irq(&efivars_lock);
-
+       if (down_interruptible(&efivars_lock))
+               return -EINTR;
        if (head && efivar_entry_find(name, vendor, head, false)) {
-               spin_unlock_irq(&efivars_lock);
+               up(&efivars_lock);
                return -EEXIST;
        }
 
                status = ops->set_variable(name, &vendor,
                                           attributes, size, data);
 
-       spin_unlock_irq(&efivars_lock);
+       up(&efivars_lock);
 
        return efi_status_to_err(status);
 
                             u32 attributes, unsigned long size, void *data)
 {
        const struct efivar_operations *ops = __efivars->ops;
-       unsigned long flags;
        efi_status_t status;
 
-       if (!spin_trylock_irqsave(&efivars_lock, flags))
+       if (down_trylock(&efivars_lock))
                return -EBUSY;
 
        status = check_var_size_nonblocking(attributes,
                                            size + ucs2_strsize(name, 1024));
        if (status != EFI_SUCCESS) {
-               spin_unlock_irqrestore(&efivars_lock, flags);
+               up(&efivars_lock);
                return -ENOSPC;
        }
 
        status = ops->set_variable_nonblocking(name, &vendor, attributes,
                                               size, data);
 
-       spin_unlock_irqrestore(&efivars_lock, flags);
+       up(&efivars_lock);
        return efi_status_to_err(status);
 }
 
                          bool block, unsigned long size, void *data)
 {
        const struct efivar_operations *ops = __efivars->ops;
-       unsigned long flags;
        efi_status_t status;
 
        if (!ops->query_variable_store)
                                                    size, data);
 
        if (!block) {
-               if (!spin_trylock_irqsave(&efivars_lock, flags))
+               if (down_trylock(&efivars_lock))
                        return -EBUSY;
        } else {
-               spin_lock_irqsave(&efivars_lock, flags);
+               if (down_interruptible(&efivars_lock))
+                       return -EINTR;
        }
 
        status = check_var_size(attributes, size + ucs2_strsize(name, 1024));
        if (status != EFI_SUCCESS) {
-               spin_unlock_irqrestore(&efivars_lock, flags);
+               up(&efivars_lock);
                return -ENOSPC;
        }
 
        status = ops->set_variable(name, &vendor, attributes, size, data);
 
-       spin_unlock_irqrestore(&efivars_lock, flags);
+       up(&efivars_lock);
 
        return efi_status_to_err(status);
 }
        int strsize1, strsize2;
        bool found = false;
 
-       lockdep_assert_held(&efivars_lock);
-
        list_for_each_entry_safe(entry, n, head, list) {
                strsize1 = ucs2_strsize(name, 1024);
                strsize2 = ucs2_strsize(entry->var.VariableName, 1024);
 
        *size = 0;
 
-       spin_lock_irq(&efivars_lock);
+       if (down_interruptible(&efivars_lock))
+               return -EINTR;
        status = ops->get_variable(entry->var.VariableName,
                                   &entry->var.VendorGuid, NULL, size, NULL);
-       spin_unlock_irq(&efivars_lock);
+       up(&efivars_lock);
 
        if (status != EFI_BUFFER_TOO_SMALL)
                return efi_status_to_err(status);
        const struct efivar_operations *ops = __efivars->ops;
        efi_status_t status;
 
-       lockdep_assert_held(&efivars_lock);
-
        status = ops->get_variable(entry->var.VariableName,
                                   &entry->var.VendorGuid,
                                   attributes, size, data);
        const struct efivar_operations *ops = __efivars->ops;
        efi_status_t status;
 
-       spin_lock_irq(&efivars_lock);
+       if (down_interruptible(&efivars_lock))
+               return -EINTR;
        status = ops->get_variable(entry->var.VariableName,
                                   &entry->var.VendorGuid,
                                   attributes, size, data);
-       spin_unlock_irq(&efivars_lock);
+       up(&efivars_lock);
 
        return efi_status_to_err(status);
 }
         * set_variable call, and removal of the variable from the efivars
         * list (in the case of an authenticated delete).
         */
-       spin_lock_irq(&efivars_lock);
+       if (down_interruptible(&efivars_lock))
+               return -EINTR;
 
        /*
         * Ensure that the available space hasn't shrunk below the safe level
        if (status == EFI_NOT_FOUND)
                efivar_entry_list_del_unlock(entry);
        else
-               spin_unlock_irq(&efivars_lock);
+               up(&efivars_lock);
 
        if (status && status != EFI_BUFFER_TOO_SMALL)
                return efi_status_to_err(status);
        return 0;
 
 out:
-       spin_unlock_irq(&efivars_lock);
+       up(&efivars_lock);
        return err;
 
 }
  * efivar_entry_iter_end() is called. This function is usually used in
  * conjunction with __efivar_entry_iter() or efivar_entry_iter().
  */
-void efivar_entry_iter_begin(void)
+int efivar_entry_iter_begin(void)
 {
-       spin_lock_irq(&efivars_lock);
+       return down_interruptible(&efivars_lock);
 }
 EXPORT_SYMBOL_GPL(efivar_entry_iter_begin);
 
  */
 void efivar_entry_iter_end(void)
 {
-       spin_unlock_irq(&efivars_lock);
+       up(&efivars_lock);
 }
 EXPORT_SYMBOL_GPL(efivar_entry_iter_end);
 
 {
        int err = 0;
 
-       efivar_entry_iter_begin();
+       err = efivar_entry_iter_begin();
+       if (err)
+               return err;
        err = __efivar_entry_iter(func, head, data, NULL);
        efivar_entry_iter_end();
 
                     const struct efivar_operations *ops,
                     struct kobject *kobject)
 {
-       spin_lock_irq(&efivars_lock);
+       if (down_interruptible(&efivars_lock))
+               return -EINTR;
+
        efivars->ops = ops;
        efivars->kobject = kobject;
 
        __efivars = efivars;
-       spin_unlock_irq(&efivars_lock);
+
+       pr_info("Registered efivars operations\n");
+
+       up(&efivars_lock);
 
        return 0;
 }
 {
        int rv;
 
-       spin_lock_irq(&efivars_lock);
+       if (down_interruptible(&efivars_lock))
+               return -EINTR;
+
        if (!__efivars) {
                printk(KERN_ERR "efivars not registered\n");
                rv = -EINVAL;
                goto out;
        }
 
+       pr_info("Unregistered efivars operations\n");
        __efivars = NULL;
 
        rv = 0;
 out:
-       spin_unlock_irq(&efivars_lock);
+       up(&efivars_lock);
        return rv;
 }
 EXPORT_SYMBOL_GPL(efivars_unregister);