From: Matt Domsch <Matt_Domsch@Dell.com>
To: linux-ia64@vger.kernel.org
Subject: [Linux-ia64] [PATCH] efivars.c locking fixes
Date: Fri, 13 Dec 2002 23:31:03 +0000 [thread overview]
Message-ID: <marc-linux-ia64-105590709805563@msgid-missing> (raw)
With thanks to Peter Chubb and his preempt work, here's a patch for
efivars.c that applies to both 2.4.x and 2.5.x to clean up the SMP
locking issues discovered there. The efivar_lock was being held
across calls to create_proc_entry(), and worse, kmalloc(). I believe
this fixes those.
This has been tested on a Big Sur on 2.5.50 and seems to work
correctly. This hasn't been tested on 2.4.20 (though it patches,
compiles and builds properly, and I expect it works fine), something
immediately after efivars_init() finishes crashes and I haven't been
able to track it down yet, though I'm pretty certain it's not
something in efivars.c.
Thanks,
Matt
--
Matt Domsch
Sr. Software Engineer, Lead Engineer, Architect
Dell Linux Solutions www.dell.com/linux
Linux on Dell mailing lists @ http://lists.us.dell.com
--- linux-2.5-ia64/arch/ia64/kernel/efivars.c Fri Dec 13 17:22:01 2002
+++ linux-2.5-ia64-test/arch/ia64/kernel/efivars.c Fri Dec 13 10:33:51 2002
@@ -29,6 +29,9 @@
*
* Changelog:
*
+ * 10 Dec 2002 - Matt Domsch <Matt_Domsch@dell.com>
+ * fix locking per Peter Chubb's findings
+ *
* 25 Mar 2002 - Matt Domsch <Matt_Domsch@dell.com>
* move uuid_unparse() to include/asm-ia64/efi.h:efi_guid_unparse()
*
@@ -73,7 +76,7 @@ MODULE_AUTHOR("Matt Domsch <Matt_Domsch@
MODULE_DESCRIPTION("/proc interface to EFI Variables");
MODULE_LICENSE("GPL");
-#define EFIVARS_VERSION "0.05 2002-Mar-26"
+#define EFIVARS_VERSION "0.06 2002-Dec-10"
static int
efivar_read(char *page, char **start, off_t off,
@@ -106,6 +109,14 @@ typedef struct _efivar_entry_t {
struct list_head list;
} efivar_entry_t;
+/*
+ efivars_lock protects two things:
+ 1) efivar_list - adds, removals, reads, writes
+ 2) efi.[gs]et_variable() calls.
+ It must not be held when creating proc entries or calling kmalloc.
+ efi.get_next_variable() is only called from efivars_init(),
+ which is protected by the BKL, so that path is safe.
+*/
static spinlock_t efivars_lock = SPIN_LOCK_UNLOCKED;
static LIST_HEAD(efivar_list);
static struct proc_dir_entry *efi_vars_dir = NULL;
@@ -150,6 +161,7 @@ proc_calc_metrics(char *page, char **sta
* variable_name_size = number of bytes required to hold
* variable_name (not counting the NULL
* character at the end.
+ * efivars_lock is not held on entry or exit.
* Returns 1 on failure, 0 on success
*/
static int
@@ -160,10 +172,12 @@ efivar_create_proc_entry(unsigned long v
int i, short_name_size = variable_name_size /
sizeof(efi_char16_t) + 38;
- char *short_name = kmalloc(short_name_size+1,
- GFP_KERNEL);
- efivar_entry_t *new_efivar = kmalloc(sizeof(efivar_entry_t),
- GFP_KERNEL);
+ char *short_name;
+ efivar_entry_t *new_efivar;
+
+ short_name = kmalloc(short_name_size+1, GFP_KERNEL);
+ new_efivar = kmalloc(sizeof(efivar_entry_t), GFP_KERNEL);
+
if (!short_name || !new_efivar) {
if (short_name) kfree(short_name);
if (new_efivar) kfree(new_efivar);
@@ -188,19 +202,18 @@ efivar_create_proc_entry(unsigned long v
*(short_name + strlen(short_name)) = '-';
efi_guid_unparse(vendor_guid, short_name + strlen(short_name));
-
/* Create the entry in proc */
new_efivar->entry = create_proc_entry(short_name, 0600, efi_vars_dir);
kfree(short_name); short_name = NULL;
if (!new_efivar->entry) return 1;
-
new_efivar->entry->data = new_efivar;
new_efivar->entry->read_proc = efivar_read;
new_efivar->entry->write_proc = efivar_write;
+ spin_lock(&efivars_lock);
list_add(&new_efivar->list, &efivar_list);
-
+ spin_unlock(&efivars_lock);
return 0;
}
@@ -326,6 +339,8 @@ efivar_write(struct file *file, const ch
kfree(efivar);
}
+ spin_unlock(&efivars_lock);
+
/* If this is a new variable, set up the proc entry for it. */
if (!found) {
efivar_create_proc_entry(utf8_strsize(var_data->VariableName,
@@ -336,7 +351,6 @@ efivar_write(struct file *file, const ch
kfree(var_data);
MOD_DEC_USE_COUNT;
- spin_unlock(&efivars_lock);
return size;
}
@@ -351,8 +365,6 @@ efivars_init(void)
efi_char16_t *variable_name = kmalloc(1024, GFP_KERNEL);
unsigned long variable_name_size = 1024;
- spin_lock(&efivars_lock);
-
printk(KERN_INFO "EFI Variables Facility v%s\n", EFIVARS_VERSION);
/* Since efi.c happens before procfs is available,
@@ -365,8 +377,6 @@ efivars_init(void)
efi_vars_dir = proc_mkdir("vars", efi_dir);
-
-
/* Per EFI spec, the maximum storage allocated for both
the variable name and variable data is 1024 bytes.
*/
@@ -398,7 +408,6 @@ efivars_init(void)
} while (status != EFI_NOT_FOUND);
kfree(variable_name);
- spin_unlock(&efivars_lock);
return 0;
}
@@ -408,17 +417,16 @@ efivars_exit(void)
struct list_head *pos, *n;
efivar_entry_t *efivar;
- spin_lock(&efivars_lock);
-
+ spin_lock(&efivars_lock);
list_for_each_safe(pos, n, &efivar_list) {
efivar = efivar_entry(pos);
remove_proc_entry(efivar->entry->name, efi_vars_dir);
list_del(&efivar->list);
kfree(efivar);
}
- remove_proc_entry(efi_vars_dir->name, efi_dir);
spin_unlock(&efivars_lock);
+ remove_proc_entry(efi_vars_dir->name, efi_dir);
}
module_init(efivars_init);
reply other threads:[~2002-12-13 23:31 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=marc-linux-ia64-105590709805563@msgid-missing \
--to=matt_domsch@dell.com \
--cc=linux-ia64@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.