|
@@ -37,6 +37,14 @@
|
|
/* Private pointer to registered efivars */
|
|
/* Private pointer to registered efivars */
|
|
static struct efivars *__efivars;
|
|
static struct efivars *__efivars;
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * efivars_lock protects three things:
|
|
|
|
+ * 1) efivarfs_list and efivars_sysfs_list
|
|
|
|
+ * 2) ->ops calls
|
|
|
|
+ * 3) (un)registration of __efivars
|
|
|
|
+ */
|
|
|
|
+static DEFINE_SEMAPHORE(efivars_lock);
|
|
|
|
+
|
|
static bool efivar_wq_enabled = true;
|
|
static bool efivar_wq_enabled = true;
|
|
DECLARE_WORK(efivar_work, NULL);
|
|
DECLARE_WORK(efivar_work, NULL);
|
|
EXPORT_SYMBOL_GPL(efivar_work);
|
|
EXPORT_SYMBOL_GPL(efivar_work);
|
|
@@ -434,7 +442,10 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
|
|
return -ENOMEM;
|
|
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
|
|
* Per EFI spec, the maximum storage allocated for both
|
|
@@ -450,7 +461,7 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
|
|
switch (status) {
|
|
switch (status) {
|
|
case EFI_SUCCESS:
|
|
case EFI_SUCCESS:
|
|
if (duplicates)
|
|
if (duplicates)
|
|
- spin_unlock_irq(&__efivars->lock);
|
|
|
|
|
|
+ up(&efivars_lock);
|
|
|
|
|
|
variable_name_size = var_name_strnsize(variable_name,
|
|
variable_name_size = var_name_strnsize(variable_name,
|
|
variable_name_size);
|
|
variable_name_size);
|
|
@@ -476,8 +487,12 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
|
|
status = EFI_NOT_FOUND;
|
|
status = EFI_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
|
|
- if (duplicates)
|
|
|
|
- spin_lock_irq(&__efivars->lock);
|
|
|
|
|
|
+ if (duplicates) {
|
|
|
|
+ if (down_interruptible(&efivars_lock)) {
|
|
|
|
+ err = -EINTR;
|
|
|
|
+ goto free;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
break;
|
|
break;
|
|
case EFI_NOT_FOUND:
|
|
case EFI_NOT_FOUND:
|
|
@@ -491,8 +506,8 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
|
|
|
|
|
|
} while (status != EFI_NOT_FOUND);
|
|
} while (status != EFI_NOT_FOUND);
|
|
|
|
|
|
- spin_unlock_irq(&__efivars->lock);
|
|
|
|
-
|
|
|
|
|
|
+ up(&efivars_lock);
|
|
|
|
+free:
|
|
kfree(variable_name);
|
|
kfree(variable_name);
|
|
|
|
|
|
return err;
|
|
return err;
|
|
@@ -503,24 +518,34 @@ EXPORT_SYMBOL_GPL(efivar_init);
|
|
* efivar_entry_add - add entry to variable list
|
|
* efivar_entry_add - add entry to variable list
|
|
* @entry: entry to add to list
|
|
* @entry: entry to add to list
|
|
* @head: list head
|
|
* @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);
|
|
list_add(&entry->list, head);
|
|
- spin_unlock_irq(&__efivars->lock);
|
|
|
|
|
|
+ up(&efivars_lock);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(efivar_entry_add);
|
|
EXPORT_SYMBOL_GPL(efivar_entry_add);
|
|
|
|
|
|
/**
|
|
/**
|
|
* efivar_entry_remove - remove entry from variable list
|
|
* efivar_entry_remove - remove entry from variable list
|
|
* @entry: entry to remove from 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);
|
|
list_del(&entry->list);
|
|
- spin_unlock_irq(&__efivars->lock);
|
|
|
|
|
|
+ up(&efivars_lock);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(efivar_entry_remove);
|
|
EXPORT_SYMBOL_GPL(efivar_entry_remove);
|
|
|
|
|
|
@@ -537,10 +562,8 @@ EXPORT_SYMBOL_GPL(efivar_entry_remove);
|
|
*/
|
|
*/
|
|
static void efivar_entry_list_del_unlock(struct efivar_entry *entry)
|
|
static void efivar_entry_list_del_unlock(struct efivar_entry *entry)
|
|
{
|
|
{
|
|
- lockdep_assert_held(&__efivars->lock);
|
|
|
|
-
|
|
|
|
list_del(&entry->list);
|
|
list_del(&entry->list);
|
|
- spin_unlock_irq(&__efivars->lock);
|
|
|
|
|
|
+ up(&efivars_lock);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -563,8 +586,6 @@ int __efivar_entry_delete(struct efivar_entry *entry)
|
|
const struct efivar_operations *ops = __efivars->ops;
|
|
const struct efivar_operations *ops = __efivars->ops;
|
|
efi_status_t status;
|
|
efi_status_t status;
|
|
|
|
|
|
- lockdep_assert_held(&__efivars->lock);
|
|
|
|
-
|
|
|
|
status = ops->set_variable(entry->var.VariableName,
|
|
status = ops->set_variable(entry->var.VariableName,
|
|
&entry->var.VendorGuid,
|
|
&entry->var.VendorGuid,
|
|
0, 0, NULL);
|
|
0, 0, NULL);
|
|
@@ -581,20 +602,22 @@ EXPORT_SYMBOL_GPL(__efivar_entry_delete);
|
|
* variable list. It is the caller's responsibility to free @entry
|
|
* variable list. It is the caller's responsibility to free @entry
|
|
* once we return.
|
|
* 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)
|
|
int efivar_entry_delete(struct efivar_entry *entry)
|
|
{
|
|
{
|
|
const struct efivar_operations *ops = __efivars->ops;
|
|
const struct efivar_operations *ops = __efivars->ops;
|
|
efi_status_t status;
|
|
efi_status_t status;
|
|
|
|
|
|
- spin_lock_irq(&__efivars->lock);
|
|
|
|
|
|
+ if (down_interruptible(&efivars_lock))
|
|
|
|
+ return -EINTR;
|
|
|
|
+
|
|
status = ops->set_variable(entry->var.VariableName,
|
|
status = ops->set_variable(entry->var.VariableName,
|
|
&entry->var.VendorGuid,
|
|
&entry->var.VendorGuid,
|
|
0, 0, NULL);
|
|
0, 0, NULL);
|
|
if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) {
|
|
if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) {
|
|
- spin_unlock_irq(&__efivars->lock);
|
|
|
|
|
|
+ up(&efivars_lock);
|
|
return efi_status_to_err(status);
|
|
return efi_status_to_err(status);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -620,9 +643,9 @@ EXPORT_SYMBOL_GPL(efivar_entry_delete);
|
|
* If @head is not NULL a lookup is performed to determine whether
|
|
* If @head is not NULL a lookup is performed to determine whether
|
|
* the entry is already on the list.
|
|
* 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,
|
|
int efivar_entry_set(struct efivar_entry *entry, u32 attributes,
|
|
unsigned long size, void *data, struct list_head *head)
|
|
unsigned long size, void *data, struct list_head *head)
|
|
@@ -632,10 +655,10 @@ int efivar_entry_set(struct efivar_entry *entry, u32 attributes,
|
|
efi_char16_t *name = entry->var.VariableName;
|
|
efi_char16_t *name = entry->var.VariableName;
|
|
efi_guid_t vendor = entry->var.VendorGuid;
|
|
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)) {
|
|
if (head && efivar_entry_find(name, vendor, head, false)) {
|
|
- spin_unlock_irq(&__efivars->lock);
|
|
|
|
|
|
+ up(&efivars_lock);
|
|
return -EEXIST;
|
|
return -EEXIST;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -644,7 +667,7 @@ int efivar_entry_set(struct efivar_entry *entry, u32 attributes,
|
|
status = ops->set_variable(name, &vendor,
|
|
status = ops->set_variable(name, &vendor,
|
|
attributes, size, data);
|
|
attributes, size, data);
|
|
|
|
|
|
- spin_unlock_irq(&__efivars->lock);
|
|
|
|
|
|
+ up(&efivars_lock);
|
|
|
|
|
|
return efi_status_to_err(status);
|
|
return efi_status_to_err(status);
|
|
|
|
|
|
@@ -658,30 +681,29 @@ EXPORT_SYMBOL_GPL(efivar_entry_set);
|
|
* from crash/panic handlers.
|
|
* from crash/panic handlers.
|
|
*
|
|
*
|
|
* Crucially, this function will not block if it cannot acquire
|
|
* Crucially, this function will not block if it cannot acquire
|
|
- * __efivars->lock. Instead, it returns -EBUSY.
|
|
|
|
|
|
+ * efivars_lock. Instead, it returns -EBUSY.
|
|
*/
|
|
*/
|
|
static int
|
|
static int
|
|
efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor,
|
|
efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor,
|
|
u32 attributes, unsigned long size, void *data)
|
|
u32 attributes, unsigned long size, void *data)
|
|
{
|
|
{
|
|
const struct efivar_operations *ops = __efivars->ops;
|
|
const struct efivar_operations *ops = __efivars->ops;
|
|
- unsigned long flags;
|
|
|
|
efi_status_t status;
|
|
efi_status_t status;
|
|
|
|
|
|
- if (!spin_trylock_irqsave(&__efivars->lock, flags))
|
|
|
|
|
|
+ if (down_trylock(&efivars_lock))
|
|
return -EBUSY;
|
|
return -EBUSY;
|
|
|
|
|
|
status = check_var_size_nonblocking(attributes,
|
|
status = check_var_size_nonblocking(attributes,
|
|
size + ucs2_strsize(name, 1024));
|
|
size + ucs2_strsize(name, 1024));
|
|
if (status != EFI_SUCCESS) {
|
|
if (status != EFI_SUCCESS) {
|
|
- spin_unlock_irqrestore(&__efivars->lock, flags);
|
|
|
|
|
|
+ up(&efivars_lock);
|
|
return -ENOSPC;
|
|
return -ENOSPC;
|
|
}
|
|
}
|
|
|
|
|
|
status = ops->set_variable_nonblocking(name, &vendor, attributes,
|
|
status = ops->set_variable_nonblocking(name, &vendor, attributes,
|
|
size, data);
|
|
size, data);
|
|
|
|
|
|
- spin_unlock_irqrestore(&__efivars->lock, flags);
|
|
|
|
|
|
+ up(&efivars_lock);
|
|
return efi_status_to_err(status);
|
|
return efi_status_to_err(status);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -706,7 +728,6 @@ int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes,
|
|
bool block, unsigned long size, void *data)
|
|
bool block, unsigned long size, void *data)
|
|
{
|
|
{
|
|
const struct efivar_operations *ops = __efivars->ops;
|
|
const struct efivar_operations *ops = __efivars->ops;
|
|
- unsigned long flags;
|
|
|
|
efi_status_t status;
|
|
efi_status_t status;
|
|
|
|
|
|
if (!ops->query_variable_store)
|
|
if (!ops->query_variable_store)
|
|
@@ -727,21 +748,22 @@ int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes,
|
|
size, data);
|
|
size, data);
|
|
|
|
|
|
if (!block) {
|
|
if (!block) {
|
|
- if (!spin_trylock_irqsave(&__efivars->lock, flags))
|
|
|
|
|
|
+ if (down_trylock(&efivars_lock))
|
|
return -EBUSY;
|
|
return -EBUSY;
|
|
} else {
|
|
} else {
|
|
- spin_lock_irqsave(&__efivars->lock, flags);
|
|
|
|
|
|
+ if (down_interruptible(&efivars_lock))
|
|
|
|
+ return -EINTR;
|
|
}
|
|
}
|
|
|
|
|
|
status = check_var_size(attributes, size + ucs2_strsize(name, 1024));
|
|
status = check_var_size(attributes, size + ucs2_strsize(name, 1024));
|
|
if (status != EFI_SUCCESS) {
|
|
if (status != EFI_SUCCESS) {
|
|
- spin_unlock_irqrestore(&__efivars->lock, flags);
|
|
|
|
|
|
+ up(&efivars_lock);
|
|
return -ENOSPC;
|
|
return -ENOSPC;
|
|
}
|
|
}
|
|
|
|
|
|
status = ops->set_variable(name, &vendor, attributes, size, data);
|
|
status = ops->set_variable(name, &vendor, attributes, size, data);
|
|
|
|
|
|
- spin_unlock_irqrestore(&__efivars->lock, flags);
|
|
|
|
|
|
+ up(&efivars_lock);
|
|
|
|
|
|
return efi_status_to_err(status);
|
|
return efi_status_to_err(status);
|
|
}
|
|
}
|
|
@@ -771,8 +793,6 @@ struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid,
|
|
int strsize1, strsize2;
|
|
int strsize1, strsize2;
|
|
bool found = false;
|
|
bool found = false;
|
|
|
|
|
|
- lockdep_assert_held(&__efivars->lock);
|
|
|
|
-
|
|
|
|
list_for_each_entry_safe(entry, n, head, list) {
|
|
list_for_each_entry_safe(entry, n, head, list) {
|
|
strsize1 = ucs2_strsize(name, 1024);
|
|
strsize1 = ucs2_strsize(name, 1024);
|
|
strsize2 = ucs2_strsize(entry->var.VariableName, 1024);
|
|
strsize2 = ucs2_strsize(entry->var.VariableName, 1024);
|
|
@@ -814,10 +834,11 @@ int efivar_entry_size(struct efivar_entry *entry, unsigned long *size)
|
|
|
|
|
|
*size = 0;
|
|
*size = 0;
|
|
|
|
|
|
- spin_lock_irq(&__efivars->lock);
|
|
|
|
|
|
+ if (down_interruptible(&efivars_lock))
|
|
|
|
+ return -EINTR;
|
|
status = ops->get_variable(entry->var.VariableName,
|
|
status = ops->get_variable(entry->var.VariableName,
|
|
&entry->var.VendorGuid, NULL, size, NULL);
|
|
&entry->var.VendorGuid, NULL, size, NULL);
|
|
- spin_unlock_irq(&__efivars->lock);
|
|
|
|
|
|
+ up(&efivars_lock);
|
|
|
|
|
|
if (status != EFI_BUFFER_TOO_SMALL)
|
|
if (status != EFI_BUFFER_TOO_SMALL)
|
|
return efi_status_to_err(status);
|
|
return efi_status_to_err(status);
|
|
@@ -843,8 +864,6 @@ int __efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
|
|
const struct efivar_operations *ops = __efivars->ops;
|
|
const struct efivar_operations *ops = __efivars->ops;
|
|
efi_status_t status;
|
|
efi_status_t status;
|
|
|
|
|
|
- lockdep_assert_held(&__efivars->lock);
|
|
|
|
-
|
|
|
|
status = ops->get_variable(entry->var.VariableName,
|
|
status = ops->get_variable(entry->var.VariableName,
|
|
&entry->var.VendorGuid,
|
|
&entry->var.VendorGuid,
|
|
attributes, size, data);
|
|
attributes, size, data);
|
|
@@ -866,11 +885,12 @@ int efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
|
|
const struct efivar_operations *ops = __efivars->ops;
|
|
const struct efivar_operations *ops = __efivars->ops;
|
|
efi_status_t status;
|
|
efi_status_t status;
|
|
|
|
|
|
- spin_lock_irq(&__efivars->lock);
|
|
|
|
|
|
+ if (down_interruptible(&efivars_lock))
|
|
|
|
+ return -EINTR;
|
|
status = ops->get_variable(entry->var.VariableName,
|
|
status = ops->get_variable(entry->var.VariableName,
|
|
&entry->var.VendorGuid,
|
|
&entry->var.VendorGuid,
|
|
attributes, size, data);
|
|
attributes, size, data);
|
|
- spin_unlock_irq(&__efivars->lock);
|
|
|
|
|
|
+ up(&efivars_lock);
|
|
|
|
|
|
return efi_status_to_err(status);
|
|
return efi_status_to_err(status);
|
|
}
|
|
}
|
|
@@ -917,7 +937,8 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
|
|
* set_variable call, and removal of the variable from the efivars
|
|
* set_variable call, and removal of the variable from the efivars
|
|
* list (in the case of an authenticated delete).
|
|
* 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
|
|
* Ensure that the available space hasn't shrunk below the safe level
|
|
@@ -957,7 +978,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
|
|
if (status == EFI_NOT_FOUND)
|
|
if (status == EFI_NOT_FOUND)
|
|
efivar_entry_list_del_unlock(entry);
|
|
efivar_entry_list_del_unlock(entry);
|
|
else
|
|
else
|
|
- spin_unlock_irq(&__efivars->lock);
|
|
|
|
|
|
+ up(&efivars_lock);
|
|
|
|
|
|
if (status && status != EFI_BUFFER_TOO_SMALL)
|
|
if (status && status != EFI_BUFFER_TOO_SMALL)
|
|
return efi_status_to_err(status);
|
|
return efi_status_to_err(status);
|
|
@@ -965,7 +986,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
out:
|
|
out:
|
|
- spin_unlock_irq(&__efivars->lock);
|
|
|
|
|
|
+ up(&efivars_lock);
|
|
return err;
|
|
return err;
|
|
|
|
|
|
}
|
|
}
|
|
@@ -978,9 +999,9 @@ EXPORT_SYMBOL_GPL(efivar_entry_set_get_size);
|
|
* efivar_entry_iter_end() is called. This function is usually used in
|
|
* efivar_entry_iter_end() is called. This function is usually used in
|
|
* conjunction with __efivar_entry_iter() or efivar_entry_iter().
|
|
* 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);
|
|
EXPORT_SYMBOL_GPL(efivar_entry_iter_begin);
|
|
|
|
|
|
@@ -991,7 +1012,7 @@ EXPORT_SYMBOL_GPL(efivar_entry_iter_begin);
|
|
*/
|
|
*/
|
|
void efivar_entry_iter_end(void)
|
|
void efivar_entry_iter_end(void)
|
|
{
|
|
{
|
|
- spin_unlock_irq(&__efivars->lock);
|
|
|
|
|
|
+ up(&efivars_lock);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(efivar_entry_iter_end);
|
|
EXPORT_SYMBOL_GPL(efivar_entry_iter_end);
|
|
|
|
|
|
@@ -1067,7 +1088,9 @@ int efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
|
|
{
|
|
{
|
|
int err = 0;
|
|
int err = 0;
|
|
|
|
|
|
- efivar_entry_iter_begin();
|
|
|
|
|
|
+ err = efivar_entry_iter_begin();
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
err = __efivar_entry_iter(func, head, data, NULL);
|
|
err = __efivar_entry_iter(func, head, data, NULL);
|
|
efivar_entry_iter_end();
|
|
efivar_entry_iter_end();
|
|
|
|
|
|
@@ -1112,12 +1135,18 @@ int efivars_register(struct efivars *efivars,
|
|
const struct efivar_operations *ops,
|
|
const struct efivar_operations *ops,
|
|
struct kobject *kobject)
|
|
struct kobject *kobject)
|
|
{
|
|
{
|
|
- spin_lock_init(&efivars->lock);
|
|
|
|
|
|
+ if (down_interruptible(&efivars_lock))
|
|
|
|
+ return -EINTR;
|
|
|
|
+
|
|
efivars->ops = ops;
|
|
efivars->ops = ops;
|
|
efivars->kobject = kobject;
|
|
efivars->kobject = kobject;
|
|
|
|
|
|
__efivars = efivars;
|
|
__efivars = efivars;
|
|
|
|
|
|
|
|
+ pr_info("Registered efivars operations\n");
|
|
|
|
+
|
|
|
|
+ up(&efivars_lock);
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(efivars_register);
|
|
EXPORT_SYMBOL_GPL(efivars_register);
|
|
@@ -1133,6 +1162,9 @@ int efivars_unregister(struct efivars *efivars)
|
|
{
|
|
{
|
|
int rv;
|
|
int rv;
|
|
|
|
|
|
|
|
+ if (down_interruptible(&efivars_lock))
|
|
|
|
+ return -EINTR;
|
|
|
|
+
|
|
if (!__efivars) {
|
|
if (!__efivars) {
|
|
printk(KERN_ERR "efivars not registered\n");
|
|
printk(KERN_ERR "efivars not registered\n");
|
|
rv = -EINVAL;
|
|
rv = -EINVAL;
|
|
@@ -1144,10 +1176,12 @@ int efivars_unregister(struct efivars *efivars)
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ pr_info("Unregistered efivars operations\n");
|
|
__efivars = NULL;
|
|
__efivars = NULL;
|
|
|
|
|
|
rv = 0;
|
|
rv = 0;
|
|
out:
|
|
out:
|
|
|
|
+ up(&efivars_lock);
|
|
return rv;
|
|
return rv;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(efivars_unregister);
|
|
EXPORT_SYMBOL_GPL(efivars_unregister);
|