diff options
author | Mike Pagano <mpagano@gentoo.org> | 2016-03-16 15:40:25 -0400 |
---|---|---|
committer | Mike Pagano <mpagano@gentoo.org> | 2016-03-16 15:40:25 -0400 |
commit | deeb81d32b2d6b7408271c5d0483307f20262d08 (patch) | |
tree | 78cb64355456f6613b413ed5fcede3e54c4b8a09 | |
parent | Linux patch 3.10.100 (diff) | |
download | linux-patches-deeb81d32b2d6b7408271c5d0483307f20262d08.tar.gz linux-patches-deeb81d32b2d6b7408271c5d0483307f20262d08.tar.bz2 linux-patches-deeb81d32b2d6b7408271c5d0483307f20262d08.zip |
Linux patch 3.10.1013.10-106
-rw-r--r-- | 0000_README | 4 | ||||
-rw-r--r-- | 1100_linux-3.10.101.patch | 1493 |
2 files changed, 1497 insertions, 0 deletions
diff --git a/0000_README b/0000_README index bdc1498c..92f6908d 100644 --- a/0000_README +++ b/0000_README @@ -442,6 +442,10 @@ Patch: 1099_linux-3.10.100.patch From: http://www.kernel.org Desc: Linux 3.10.100 +Patch: 1100_linux-3.10.101.patch +From: http://www.kernel.org +Desc: Linux 3.10.101 + Patch: 1500_XATTR_USER_PREFIX.patch From: https://bugs.gentoo.org/show_bug.cgi?id=470644 Desc: Support for namespace user.pax.* on tmpfs. diff --git a/1100_linux-3.10.101.patch b/1100_linux-3.10.101.patch new file mode 100644 index 00000000..d9647df4 --- /dev/null +++ b/1100_linux-3.10.101.patch @@ -0,0 +1,1493 @@ +diff --git a/Documentation/filesystems/efivarfs.txt b/Documentation/filesystems/efivarfs.txt +index c477af086e65..686a64bba775 100644 +--- a/Documentation/filesystems/efivarfs.txt ++++ b/Documentation/filesystems/efivarfs.txt +@@ -14,3 +14,10 @@ filesystem. + efivarfs is typically mounted like this, + + mount -t efivarfs none /sys/firmware/efi/efivars ++ ++Due to the presence of numerous firmware bugs where removing non-standard ++UEFI variables causes the system firmware to fail to POST, efivarfs ++files that are not well-known standardized variables are created ++as immutable files. This doesn't prevent removal - "chattr -i" will work - ++but it does prevent this kind of failure from being accomplished ++accidentally. +diff --git a/Makefile b/Makefile +index 40d4d3bf52c3..4be9e643cef0 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 3 + PATCHLEVEL = 10 +-SUBLEVEL = 100 ++SUBLEVEL = 101 + EXTRAVERSION = + NAME = TOSSUG Baby Fish + +diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c +index 6ee59a0eb268..48b4cf6b2a24 100644 +--- a/arch/powerpc/kernel/module_64.c ++++ b/arch/powerpc/kernel/module_64.c +@@ -192,7 +192,7 @@ static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab) + if (syms[i].st_shndx == SHN_UNDEF) { + char *name = strtab + syms[i].st_name; + if (name[0] == '.') +- memmove(name, name+1, strlen(name)); ++ syms[i].st_name++; + } + } + } +diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c +index 04cc2fa7744f..335fe70967a8 100644 +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -1487,6 +1487,13 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr, + return; + } + break; ++ case MSR_IA32_PEBS_ENABLE: ++ /* PEBS needs a quiescent period after being disabled (to write ++ * a record). Disabling PEBS through VMX MSR swapping doesn't ++ * provide that period, so a CPU could write host's record into ++ * guest's memory. ++ */ ++ wrmsrl(MSR_IA32_PEBS_ENABLE, 0); + } + + for (i = 0; i < m->nr; ++i) +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index 41ba726c1ce2..7f2b6dec4b2b 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -1941,6 +1941,8 @@ static void accumulate_steal_time(struct kvm_vcpu *vcpu) + + static void record_steal_time(struct kvm_vcpu *vcpu) + { ++ accumulate_steal_time(vcpu); ++ + if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED)) + return; + +@@ -2074,12 +2076,6 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) + if (!(data & KVM_MSR_ENABLED)) + break; + +- vcpu->arch.st.last_steal = current->sched_info.run_delay; +- +- preempt_disable(); +- accumulate_steal_time(vcpu); +- preempt_enable(); +- + kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu); + + break; +@@ -2758,7 +2754,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) + vcpu->cpu = cpu; + } + +- accumulate_steal_time(vcpu); + kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu); + } + +diff --git a/crypto/af_alg.c b/crypto/af_alg.c +index 0ca108f3c840..1aaa555fab56 100644 +--- a/crypto/af_alg.c ++++ b/crypto/af_alg.c +@@ -125,23 +125,6 @@ int af_alg_release(struct socket *sock) + } + EXPORT_SYMBOL_GPL(af_alg_release); + +-void af_alg_release_parent(struct sock *sk) +-{ +- struct alg_sock *ask = alg_sk(sk); +- bool last; +- +- sk = ask->parent; +- ask = alg_sk(sk); +- +- lock_sock(sk); +- last = !--ask->refcnt; +- release_sock(sk); +- +- if (last) +- sock_put(sk); +-} +-EXPORT_SYMBOL_GPL(af_alg_release_parent); +- + static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) + { + struct sock *sk = sock->sk; +@@ -149,7 +132,6 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) + struct sockaddr_alg *sa = (void *)uaddr; + const struct af_alg_type *type; + void *private; +- int err; + + if (sock->state == SS_CONNECTED) + return -EINVAL; +@@ -175,22 +157,16 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) + return PTR_ERR(private); + } + +- err = -EBUSY; + lock_sock(sk); +- if (ask->refcnt) +- goto unlock; + + swap(ask->type, type); + swap(ask->private, private); + +- err = 0; +- +-unlock: + release_sock(sk); + + alg_do_release(type, private); + +- return err; ++ return 0; + } + + static int alg_setkey(struct sock *sk, char __user *ukey, +@@ -223,15 +199,11 @@ static int alg_setsockopt(struct socket *sock, int level, int optname, + struct sock *sk = sock->sk; + struct alg_sock *ask = alg_sk(sk); + const struct af_alg_type *type; +- int err = -EBUSY; ++ int err = -ENOPROTOOPT; + + lock_sock(sk); +- if (ask->refcnt) +- goto unlock; +- + type = ask->type; + +- err = -ENOPROTOOPT; + if (level != SOL_ALG || !type) + goto unlock; + +@@ -280,8 +252,7 @@ int af_alg_accept(struct sock *sk, struct socket *newsock) + + sk2->sk_family = PF_ALG; + +- if (!ask->refcnt++) +- sock_hold(sk); ++ sock_hold(sk); + alg_sk(sk2)->parent = sk; + alg_sk(sk2)->type = type; + +diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c +index 8bd1bb6dbe47..24ae2a694e9b 100644 +--- a/drivers/firmware/efi/efivars.c ++++ b/drivers/firmware/efi/efivars.c +@@ -219,7 +219,8 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) + } + + if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || +- efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { ++ efivar_validate(new_var->VendorGuid, new_var->VariableName, ++ new_var->Data, new_var->DataSize) == false) { + printk(KERN_ERR "efivars: Malformed variable content\n"); + return -EINVAL; + } +@@ -334,7 +335,8 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj, + return -EACCES; + + if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || +- efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { ++ efivar_validate(new_var->VendorGuid, new_var->VariableName, ++ new_var->Data, new_var->DataSize) == false) { + printk(KERN_ERR "efivars: Malformed variable content\n"); + return -EINVAL; + } +@@ -405,35 +407,27 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var) + { + int i, short_name_size; + char *short_name; +- unsigned long variable_name_size; +- efi_char16_t *variable_name; +- +- variable_name = new_var->var.VariableName; +- variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t); ++ unsigned long utf8_name_size; ++ efi_char16_t *variable_name = new_var->var.VariableName; + + /* +- * Length of the variable bytes in ASCII, plus the '-' separator, ++ * Length of the variable bytes in UTF8, plus the '-' separator, + * plus the GUID, plus trailing NUL + */ +- short_name_size = variable_name_size / sizeof(efi_char16_t) +- + 1 + EFI_VARIABLE_GUID_LEN + 1; +- +- short_name = kzalloc(short_name_size, GFP_KERNEL); ++ utf8_name_size = ucs2_utf8size(variable_name); ++ short_name_size = utf8_name_size + 1 + EFI_VARIABLE_GUID_LEN + 1; + ++ short_name = kmalloc(short_name_size, GFP_KERNEL); + if (!short_name) + return 1; + +- /* Convert Unicode to normal chars (assume top bits are 0), +- ala UTF-8 */ +- for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) { +- short_name[i] = variable_name[i] & 0xFF; +- } ++ ucs2_as_utf8(short_name, variable_name, short_name_size); ++ + /* This is ugly, but necessary to separate one vendor's + private variables from another's. */ +- +- *(short_name + strlen(short_name)) = '-'; ++ short_name[utf8_name_size] = '-'; + efi_guid_unparse(&new_var->var.VendorGuid, +- short_name + strlen(short_name)); ++ short_name + utf8_name_size + 1); + + new_var->kobj.kset = efivars_kset; + +diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c +index 7dbc319e1cf5..9f82b5545edd 100644 +--- a/drivers/firmware/efi/vars.c ++++ b/drivers/firmware/efi/vars.c +@@ -42,7 +42,7 @@ DECLARE_WORK(efivar_work, NULL); + EXPORT_SYMBOL_GPL(efivar_work); + + static bool +-validate_device_path(struct efi_variable *var, int match, u8 *buffer, ++validate_device_path(efi_char16_t *var_name, int match, u8 *buffer, + unsigned long len) + { + struct efi_generic_dev_path *node; +@@ -75,7 +75,7 @@ validate_device_path(struct efi_variable *var, int match, u8 *buffer, + } + + static bool +-validate_boot_order(struct efi_variable *var, int match, u8 *buffer, ++validate_boot_order(efi_char16_t *var_name, int match, u8 *buffer, + unsigned long len) + { + /* An array of 16-bit integers */ +@@ -86,18 +86,18 @@ validate_boot_order(struct efi_variable *var, int match, u8 *buffer, + } + + static bool +-validate_load_option(struct efi_variable *var, int match, u8 *buffer, ++validate_load_option(efi_char16_t *var_name, int match, u8 *buffer, + unsigned long len) + { + u16 filepathlength; + int i, desclength = 0, namelen; + +- namelen = ucs2_strnlen(var->VariableName, sizeof(var->VariableName)); ++ namelen = ucs2_strnlen(var_name, EFI_VAR_NAME_LEN); + + /* Either "Boot" or "Driver" followed by four digits of hex */ + for (i = match; i < match+4; i++) { +- if (var->VariableName[i] > 127 || +- hex_to_bin(var->VariableName[i] & 0xff) < 0) ++ if (var_name[i] > 127 || ++ hex_to_bin(var_name[i] & 0xff) < 0) + return true; + } + +@@ -132,12 +132,12 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer, + /* + * And, finally, check the filepath + */ +- return validate_device_path(var, match, buffer + desclength + 6, ++ return validate_device_path(var_name, match, buffer + desclength + 6, + filepathlength); + } + + static bool +-validate_uint16(struct efi_variable *var, int match, u8 *buffer, ++validate_uint16(efi_char16_t *var_name, int match, u8 *buffer, + unsigned long len) + { + /* A single 16-bit integer */ +@@ -148,7 +148,7 @@ validate_uint16(struct efi_variable *var, int match, u8 *buffer, + } + + static bool +-validate_ascii_string(struct efi_variable *var, int match, u8 *buffer, ++validate_ascii_string(efi_char16_t *var_name, int match, u8 *buffer, + unsigned long len) + { + int i; +@@ -165,67 +165,133 @@ validate_ascii_string(struct efi_variable *var, int match, u8 *buffer, + } + + struct variable_validate { ++ efi_guid_t vendor; + char *name; +- bool (*validate)(struct efi_variable *var, int match, u8 *data, ++ bool (*validate)(efi_char16_t *var_name, int match, u8 *data, + unsigned long len); + }; + ++/* ++ * This is the list of variables we need to validate, as well as the ++ * whitelist for what we think is safe not to default to immutable. ++ * ++ * If it has a validate() method that's not NULL, it'll go into the ++ * validation routine. If not, it is assumed valid, but still used for ++ * whitelisting. ++ * ++ * Note that it's sorted by {vendor,name}, but globbed names must come after ++ * any other name with the same prefix. ++ */ + static const struct variable_validate variable_validate[] = { +- { "BootNext", validate_uint16 }, +- { "BootOrder", validate_boot_order }, +- { "DriverOrder", validate_boot_order }, +- { "Boot*", validate_load_option }, +- { "Driver*", validate_load_option }, +- { "ConIn", validate_device_path }, +- { "ConInDev", validate_device_path }, +- { "ConOut", validate_device_path }, +- { "ConOutDev", validate_device_path }, +- { "ErrOut", validate_device_path }, +- { "ErrOutDev", validate_device_path }, +- { "Timeout", validate_uint16 }, +- { "Lang", validate_ascii_string }, +- { "PlatformLang", validate_ascii_string }, +- { "", NULL }, ++ { EFI_GLOBAL_VARIABLE_GUID, "BootNext", validate_uint16 }, ++ { EFI_GLOBAL_VARIABLE_GUID, "BootOrder", validate_boot_order }, ++ { EFI_GLOBAL_VARIABLE_GUID, "Boot*", validate_load_option }, ++ { EFI_GLOBAL_VARIABLE_GUID, "DriverOrder", validate_boot_order }, ++ { EFI_GLOBAL_VARIABLE_GUID, "Driver*", validate_load_option }, ++ { EFI_GLOBAL_VARIABLE_GUID, "ConIn", validate_device_path }, ++ { EFI_GLOBAL_VARIABLE_GUID, "ConInDev", validate_device_path }, ++ { EFI_GLOBAL_VARIABLE_GUID, "ConOut", validate_device_path }, ++ { EFI_GLOBAL_VARIABLE_GUID, "ConOutDev", validate_device_path }, ++ { EFI_GLOBAL_VARIABLE_GUID, "ErrOut", validate_device_path }, ++ { EFI_GLOBAL_VARIABLE_GUID, "ErrOutDev", validate_device_path }, ++ { EFI_GLOBAL_VARIABLE_GUID, "Lang", validate_ascii_string }, ++ { EFI_GLOBAL_VARIABLE_GUID, "OsIndications", NULL }, ++ { EFI_GLOBAL_VARIABLE_GUID, "PlatformLang", validate_ascii_string }, ++ { EFI_GLOBAL_VARIABLE_GUID, "Timeout", validate_uint16 }, ++ { LINUX_EFI_CRASH_GUID, "*", NULL }, ++ { NULL_GUID, "", NULL }, + }; + ++static bool ++variable_matches(const char *var_name, size_t len, const char *match_name, ++ int *match) ++{ ++ for (*match = 0; ; (*match)++) { ++ char c = match_name[*match]; ++ char u = var_name[*match]; ++ ++ /* Wildcard in the matching name means we've matched */ ++ if (c == '*') ++ return true; ++ ++ /* Case sensitive match */ ++ if (!c && *match == len) ++ return true; ++ ++ if (c != u) ++ return false; ++ ++ if (!c) ++ return true; ++ } ++ return true; ++} ++ + bool +-efivar_validate(struct efi_variable *var, u8 *data, unsigned long len) ++efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, ++ unsigned long data_size) + { + int i; +- u16 *unicode_name = var->VariableName; ++ unsigned long utf8_size; ++ u8 *utf8_name; + +- for (i = 0; variable_validate[i].validate != NULL; i++) { +- const char *name = variable_validate[i].name; +- int match; ++ utf8_size = ucs2_utf8size(var_name); ++ utf8_name = kmalloc(utf8_size + 1, GFP_KERNEL); ++ if (!utf8_name) ++ return false; + +- for (match = 0; ; match++) { +- char c = name[match]; +- u16 u = unicode_name[match]; ++ ucs2_as_utf8(utf8_name, var_name, utf8_size); ++ utf8_name[utf8_size] = '\0'; + +- /* All special variables are plain ascii */ +- if (u > 127) +- return true; ++ for (i = 0; variable_validate[i].name[0] != '\0'; i++) { ++ const char *name = variable_validate[i].name; ++ int match = 0; + +- /* Wildcard in the matching name means we've matched */ +- if (c == '*') +- return variable_validate[i].validate(var, +- match, data, len); ++ if (efi_guidcmp(vendor, variable_validate[i].vendor)) ++ continue; + +- /* Case sensitive match */ +- if (c != u) ++ if (variable_matches(utf8_name, utf8_size+1, name, &match)) { ++ if (variable_validate[i].validate == NULL) + break; +- +- /* Reached the end of the string while matching */ +- if (!c) +- return variable_validate[i].validate(var, +- match, data, len); ++ kfree(utf8_name); ++ return variable_validate[i].validate(var_name, match, ++ data, data_size); + } + } +- ++ kfree(utf8_name); + return true; + } + EXPORT_SYMBOL_GPL(efivar_validate); + ++bool ++efivar_variable_is_removable(efi_guid_t vendor, const char *var_name, ++ size_t len) ++{ ++ int i; ++ bool found = false; ++ int match = 0; ++ ++ /* ++ * Check if our variable is in the validated variables list ++ */ ++ for (i = 0; variable_validate[i].name[0] != '\0'; i++) { ++ if (efi_guidcmp(variable_validate[i].vendor, vendor)) ++ continue; ++ ++ if (variable_matches(var_name, len, ++ variable_validate[i].name, &match)) { ++ found = true; ++ break; ++ } ++ } ++ ++ /* ++ * If it's in our list, it is removable. ++ */ ++ return found; ++} ++EXPORT_SYMBOL_GPL(efivar_variable_is_removable); ++ + static efi_status_t + check_var_size(u32 attributes, unsigned long size) + { +@@ -797,7 +863,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, + + *set = false; + +- if (efivar_validate(&entry->var, data, *size) == false) ++ if (efivar_validate(*vendor, name, data, *size) == false) + return -EINVAL; + + /* +diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c +index 8dd524f32284..08f105a06fbf 100644 +--- a/fs/efivarfs/file.c ++++ b/fs/efivarfs/file.c +@@ -10,6 +10,7 @@ + #include <linux/efi.h> + #include <linux/fs.h> + #include <linux/slab.h> ++#include <linux/mount.h> + + #include "internal.h" + +@@ -108,9 +109,79 @@ out_free: + return size; + } + ++static int ++efivarfs_ioc_getxflags(struct file *file, void __user *arg) ++{ ++ struct inode *inode = file->f_mapping->host; ++ unsigned int i_flags; ++ unsigned int flags = 0; ++ ++ i_flags = inode->i_flags; ++ if (i_flags & S_IMMUTABLE) ++ flags |= FS_IMMUTABLE_FL; ++ ++ if (copy_to_user(arg, &flags, sizeof(flags))) ++ return -EFAULT; ++ return 0; ++} ++ ++static int ++efivarfs_ioc_setxflags(struct file *file, void __user *arg) ++{ ++ struct inode *inode = file->f_mapping->host; ++ unsigned int flags; ++ unsigned int i_flags = 0; ++ int error; ++ ++ if (!inode_owner_or_capable(inode)) ++ return -EACCES; ++ ++ if (copy_from_user(&flags, arg, sizeof(flags))) ++ return -EFAULT; ++ ++ if (flags & ~FS_IMMUTABLE_FL) ++ return -EOPNOTSUPP; ++ ++ if (!capable(CAP_LINUX_IMMUTABLE)) ++ return -EPERM; ++ ++ if (flags & FS_IMMUTABLE_FL) ++ i_flags |= S_IMMUTABLE; ++ ++ ++ error = mnt_want_write_file(file); ++ if (error) ++ return error; ++ ++ mutex_lock(&inode->i_mutex); ++ inode->i_flags &= ~S_IMMUTABLE; ++ inode->i_flags |= i_flags; ++ mutex_unlock(&inode->i_mutex); ++ ++ mnt_drop_write_file(file); ++ ++ return 0; ++} ++ ++long ++efivarfs_file_ioctl(struct file *file, unsigned int cmd, unsigned long p) ++{ ++ void __user *arg = (void __user *)p; ++ ++ switch (cmd) { ++ case FS_IOC_GETFLAGS: ++ return efivarfs_ioc_getxflags(file, arg); ++ case FS_IOC_SETFLAGS: ++ return efivarfs_ioc_setxflags(file, arg); ++ } ++ ++ return -ENOTTY; ++} ++ + const struct file_operations efivarfs_file_operations = { + .open = simple_open, + .read = efivarfs_file_read, + .write = efivarfs_file_write, + .llseek = no_llseek, ++ .unlocked_ioctl = efivarfs_file_ioctl, + }; +diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c +index 7e787fb90293..d0351bc7b533 100644 +--- a/fs/efivarfs/inode.c ++++ b/fs/efivarfs/inode.c +@@ -15,7 +15,8 @@ + #include "internal.h" + + struct inode *efivarfs_get_inode(struct super_block *sb, +- const struct inode *dir, int mode, dev_t dev) ++ const struct inode *dir, int mode, ++ dev_t dev, bool is_removable) + { + struct inode *inode = new_inode(sb); + +@@ -23,6 +24,7 @@ struct inode *efivarfs_get_inode(struct super_block *sb, + inode->i_ino = get_next_ino(); + inode->i_mode = mode; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; ++ inode->i_flags = is_removable ? 0 : S_IMMUTABLE; + switch (mode & S_IFMT) { + case S_IFREG: + inode->i_fop = &efivarfs_file_operations; +@@ -102,22 +104,17 @@ static void efivarfs_hex_to_guid(const char *str, efi_guid_t *guid) + static int efivarfs_create(struct inode *dir, struct dentry *dentry, + umode_t mode, bool excl) + { +- struct inode *inode; ++ struct inode *inode = NULL; + struct efivar_entry *var; + int namelen, i = 0, err = 0; ++ bool is_removable = false; + + if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len)) + return -EINVAL; + +- inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0); +- if (!inode) +- return -ENOMEM; +- + var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL); +- if (!var) { +- err = -ENOMEM; +- goto out; +- } ++ if (!var) ++ return -ENOMEM; + + /* length of the variable name itself: remove GUID and separator */ + namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1; +@@ -125,6 +122,16 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry, + efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1, + &var->var.VendorGuid); + ++ if (efivar_variable_is_removable(var->var.VendorGuid, ++ dentry->d_name.name, namelen)) ++ is_removable = true; ++ ++ inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0, is_removable); ++ if (!inode) { ++ err = -ENOMEM; ++ goto out; ++ } ++ + for (i = 0; i < namelen; i++) + var->var.VariableName[i] = dentry->d_name.name[i]; + +@@ -138,7 +145,8 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry, + out: + if (err) { + kfree(var); +- iput(inode); ++ if (inode) ++ iput(inode); + } + return err; + } +diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h +index b5ff16addb7c..b4505188e799 100644 +--- a/fs/efivarfs/internal.h ++++ b/fs/efivarfs/internal.h +@@ -15,7 +15,8 @@ extern const struct file_operations efivarfs_file_operations; + extern const struct inode_operations efivarfs_dir_inode_operations; + extern bool efivarfs_valid_name(const char *str, int len); + extern struct inode *efivarfs_get_inode(struct super_block *sb, +- const struct inode *dir, int mode, dev_t dev); ++ const struct inode *dir, int mode, dev_t dev, ++ bool is_removable); + + extern struct list_head efivarfs_list; + +diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c +index 141aee31884f..5a3655f690d9 100644 +--- a/fs/efivarfs/super.c ++++ b/fs/efivarfs/super.c +@@ -128,8 +128,9 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, + struct dentry *dentry, *root = sb->s_root; + unsigned long size = 0; + char *name; +- int len, i; ++ int len; + int err = -ENOMEM; ++ bool is_removable = false; + + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) +@@ -138,15 +139,17 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, + memcpy(entry->var.VariableName, name16, name_size); + memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); + +- len = ucs2_strlen(entry->var.VariableName); ++ len = ucs2_utf8size(entry->var.VariableName); + + /* name, plus '-', plus GUID, plus NUL*/ + name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL); + if (!name) + goto fail; + +- for (i = 0; i < len; i++) +- name[i] = entry->var.VariableName[i] & 0xFF; ++ ucs2_as_utf8(name, entry->var.VariableName, len); ++ ++ if (efivar_variable_is_removable(entry->var.VendorGuid, name, len)) ++ is_removable = true; + + name[len] = '-'; + +@@ -154,7 +157,8 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, + + name[len + EFI_VARIABLE_GUID_LEN+1] = '\0'; + +- inode = efivarfs_get_inode(sb, root->d_inode, S_IFREG | 0644, 0); ++ inode = efivarfs_get_inode(sb, root->d_inode, S_IFREG | 0644, 0, ++ is_removable); + if (!inode) + goto fail_name; + +@@ -210,7 +214,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) + sb->s_d_op = &efivarfs_d_ops; + sb->s_time_gran = 1; + +- inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0); ++ inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0, true); + if (!inode) + return -ENOMEM; + inode->i_op = &efivarfs_dir_inode_operations; +diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h +index 2f38daaab3d7..d61c11170213 100644 +--- a/include/crypto/if_alg.h ++++ b/include/crypto/if_alg.h +@@ -30,8 +30,6 @@ struct alg_sock { + + struct sock *parent; + +- unsigned int refcnt; +- + const struct af_alg_type *type; + void *private; + }; +@@ -66,7 +64,6 @@ int af_alg_register_type(const struct af_alg_type *type); + int af_alg_unregister_type(const struct af_alg_type *type); + + int af_alg_release(struct socket *sock); +-void af_alg_release_parent(struct sock *sk); + int af_alg_accept(struct sock *sk, struct socket *newsock); + + int af_alg_make_sg(struct af_alg_sgl *sgl, void __user *addr, int len, +@@ -83,6 +80,11 @@ static inline struct alg_sock *alg_sk(struct sock *sk) + return (struct alg_sock *)sk; + } + ++static inline void af_alg_release_parent(struct sock *sk) ++{ ++ sock_put(alg_sk(sk)->parent); ++} ++ + static inline void af_alg_init_completion(struct af_alg_completion *completion) + { + init_completion(&completion->completion); +diff --git a/include/linux/efi.h b/include/linux/efi.h +index 2bc0ad78d058..63fa51c864ec 100644 +--- a/include/linux/efi.h ++++ b/include/linux/efi.h +@@ -769,8 +769,10 @@ struct efivars { + * and we use a page for reading/writing. + */ + ++#define EFI_VAR_NAME_LEN 1024 ++ + struct efi_variable { +- efi_char16_t VariableName[1024/sizeof(efi_char16_t)]; ++ efi_char16_t VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)]; + efi_guid_t VendorGuid; + unsigned long DataSize; + __u8 Data[1024]; +@@ -832,7 +834,10 @@ int efivar_entry_iter(int (*func)(struct efivar_entry *, void *), + struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, + struct list_head *head, bool remove); + +-bool efivar_validate(struct efi_variable *var, u8 *data, unsigned long len); ++bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, ++ unsigned long data_size); ++bool efivar_variable_is_removable(efi_guid_t vendor, const char *name, ++ size_t len); + + extern struct work_struct efivar_work; + void efivar_run_worker(void); +diff --git a/include/linux/module.h b/include/linux/module.h +index 46f1ea01e6f6..761dc2848ffa 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -220,6 +220,12 @@ struct module_ref { + unsigned long decs; + } __attribute((aligned(2 * sizeof(unsigned long)))); + ++struct mod_kallsyms { ++ Elf_Sym *symtab; ++ unsigned int num_symtab; ++ char *strtab; ++}; ++ + struct module + { + enum module_state state; +@@ -308,14 +314,9 @@ struct module + #endif + + #ifdef CONFIG_KALLSYMS +- /* +- * We keep the symbol and string tables for kallsyms. +- * The core_* fields below are temporary, loader-only (they +- * could really be discarded after module init). +- */ +- Elf_Sym *symtab, *core_symtab; +- unsigned int num_symtab, core_num_syms; +- char *strtab, *core_strtab; ++ /* Protected by RCU and/or module_mutex: use rcu_dereference() */ ++ struct mod_kallsyms *kallsyms; ++ struct mod_kallsyms core_kallsyms; + + /* Section attributes */ + struct module_sect_attrs *sect_attrs; +diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h +index 0b2d0cbe0bab..36e5e9998865 100644 +--- a/include/linux/tracepoint.h ++++ b/include/linux/tracepoint.h +@@ -129,9 +129,6 @@ static inline void tracepoint_synchronize_unregister(void) + void *it_func; \ + void *__data; \ + \ +- if (!cpu_online(raw_smp_processor_id())) \ +- return; \ +- \ + if (!(cond)) \ + return; \ + prercu; \ +@@ -265,15 +262,19 @@ static inline void tracepoint_synchronize_unregister(void) + * "void *__data, proto" as the callback prototype. + */ + #define DECLARE_TRACE_NOARGS(name) \ +- __DECLARE_TRACE(name, void, , 1, void *__data, __data) ++ __DECLARE_TRACE(name, void, , \ ++ cpu_online(raw_smp_processor_id()), \ ++ void *__data, __data) + + #define DECLARE_TRACE(name, proto, args) \ +- __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), 1, \ +- PARAMS(void *__data, proto), \ +- PARAMS(__data, args)) ++ __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \ ++ cpu_online(raw_smp_processor_id()), \ ++ PARAMS(void *__data, proto), \ ++ PARAMS(__data, args)) + + #define DECLARE_TRACE_CONDITION(name, proto, args, cond) \ +- __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), PARAMS(cond), \ ++ __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \ ++ cpu_online(raw_smp_processor_id()) && (PARAMS(cond)), \ + PARAMS(void *__data, proto), \ + PARAMS(__data, args)) + +diff --git a/include/linux/ucs2_string.h b/include/linux/ucs2_string.h +index cbb20afdbc01..bb679b48f408 100644 +--- a/include/linux/ucs2_string.h ++++ b/include/linux/ucs2_string.h +@@ -11,4 +11,8 @@ unsigned long ucs2_strlen(const ucs2_char_t *s); + unsigned long ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength); + int ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len); + ++unsigned long ucs2_utf8size(const ucs2_char_t *src); ++unsigned long ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, ++ unsigned long maxlength); ++ + #endif /* _LINUX_UCS2_STRING_H_ */ +diff --git a/kernel/module.c b/kernel/module.c +index 70a4754c001f..f8a4f48b48a9 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -179,6 +179,9 @@ struct load_info { + struct _ddebug *debug; + unsigned int num_debug; + bool sig_ok; ++#ifdef CONFIG_KALLSYMS ++ unsigned long mod_kallsyms_init_off; ++#endif + struct { + unsigned int sym, str, mod, vers, info, pcpu; + } index; +@@ -2346,8 +2349,20 @@ static void layout_symtab(struct module *mod, struct load_info *info) + strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect, + info->index.str) | INIT_OFFSET_MASK; + pr_debug("\t%s\n", info->secstrings + strsect->sh_name); ++ ++ /* We'll tack temporary mod_kallsyms on the end. */ ++ mod->init_size = ALIGN(mod->init_size, ++ __alignof__(struct mod_kallsyms)); ++ info->mod_kallsyms_init_off = mod->init_size; ++ mod->init_size += sizeof(struct mod_kallsyms); ++ mod->init_size = debug_align(mod->init_size); + } + ++/* ++ * We use the full symtab and strtab which layout_symtab arranged to ++ * be appended to the init section. Later we switch to the cut-down ++ * core-only ones. ++ */ + static void add_kallsyms(struct module *mod, const struct load_info *info) + { + unsigned int i, ndst; +@@ -2356,28 +2371,33 @@ static void add_kallsyms(struct module *mod, const struct load_info *info) + char *s; + Elf_Shdr *symsec = &info->sechdrs[info->index.sym]; + +- mod->symtab = (void *)symsec->sh_addr; +- mod->num_symtab = symsec->sh_size / sizeof(Elf_Sym); ++ /* Set up to point into init section. */ ++ mod->kallsyms = mod->module_init + info->mod_kallsyms_init_off; ++ ++ mod->kallsyms->symtab = (void *)symsec->sh_addr; ++ mod->kallsyms->num_symtab = symsec->sh_size / sizeof(Elf_Sym); + /* Make sure we get permanent strtab: don't use info->strtab. */ +- mod->strtab = (void *)info->sechdrs[info->index.str].sh_addr; ++ mod->kallsyms->strtab = (void *)info->sechdrs[info->index.str].sh_addr; + + /* Set types up while we still have access to sections. */ +- for (i = 0; i < mod->num_symtab; i++) +- mod->symtab[i].st_info = elf_type(&mod->symtab[i], info); +- +- mod->core_symtab = dst = mod->module_core + info->symoffs; +- mod->core_strtab = s = mod->module_core + info->stroffs; +- src = mod->symtab; +- for (ndst = i = 0; i < mod->num_symtab; i++) { ++ for (i = 0; i < mod->kallsyms->num_symtab; i++) ++ mod->kallsyms->symtab[i].st_info ++ = elf_type(&mod->kallsyms->symtab[i], info); ++ ++ /* Now populate the cut down core kallsyms for after init. */ ++ mod->core_kallsyms.symtab = dst = mod->module_core + info->symoffs; ++ mod->core_kallsyms.strtab = s = mod->module_core + info->stroffs; ++ src = mod->kallsyms->symtab; ++ for (ndst = i = 0; i < mod->kallsyms->num_symtab; i++) { + if (i == 0 || + is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) { + dst[ndst] = src[i]; +- dst[ndst++].st_name = s - mod->core_strtab; +- s += strlcpy(s, &mod->strtab[src[i].st_name], ++ dst[ndst++].st_name = s - mod->core_kallsyms.strtab; ++ s += strlcpy(s, &mod->kallsyms->strtab[src[i].st_name], + KSYM_NAME_LEN) + 1; + } + } +- mod->core_num_syms = ndst; ++ mod->core_kallsyms.num_symtab = ndst; + } + #else + static inline void layout_symtab(struct module *mod, struct load_info *info) +@@ -3117,9 +3137,8 @@ static int do_init_module(struct module *mod) + module_put(mod); + trim_init_extable(mod); + #ifdef CONFIG_KALLSYMS +- mod->num_symtab = mod->core_num_syms; +- mod->symtab = mod->core_symtab; +- mod->strtab = mod->core_strtab; ++ /* Switch to core kallsyms now init is done: kallsyms may be walking! */ ++ rcu_assign_pointer(mod->kallsyms, &mod->core_kallsyms); + #endif + unset_module_init_ro_nx(mod); + module_free(mod, mod->module_init); +@@ -3398,9 +3417,9 @@ static inline int is_arm_mapping_symbol(const char *str) + && (str[2] == '\0' || str[2] == '.'); + } + +-static const char *symname(struct module *mod, unsigned int symnum) ++static const char *symname(struct mod_kallsyms *kallsyms, unsigned int symnum) + { +- return mod->strtab + mod->symtab[symnum].st_name; ++ return kallsyms->strtab + kallsyms->symtab[symnum].st_name; + } + + static const char *get_ksymbol(struct module *mod, +@@ -3410,6 +3429,7 @@ static const char *get_ksymbol(struct module *mod, + { + unsigned int i, best = 0; + unsigned long nextval; ++ struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms); + + /* At worse, next value is at end of module */ + if (within_module_init(addr, mod)) +@@ -3419,32 +3439,32 @@ static const char *get_ksymbol(struct module *mod, + + /* Scan for closest preceding symbol, and next symbol. (ELF + starts real symbols at 1). */ +- for (i = 1; i < mod->num_symtab; i++) { +- if (mod->symtab[i].st_shndx == SHN_UNDEF) ++ for (i = 1; i < kallsyms->num_symtab; i++) { ++ if (kallsyms->symtab[i].st_shndx == SHN_UNDEF) + continue; + + /* We ignore unnamed symbols: they're uninformative + * and inserted at a whim. */ +- if (*symname(mod, i) == '\0' +- || is_arm_mapping_symbol(symname(mod, i))) ++ if (*symname(kallsyms, i) == '\0' ++ || is_arm_mapping_symbol(symname(kallsyms, i))) + continue; + +- if (mod->symtab[i].st_value <= addr +- && mod->symtab[i].st_value > mod->symtab[best].st_value) ++ if (kallsyms->symtab[i].st_value <= addr ++ && kallsyms->symtab[i].st_value > kallsyms->symtab[best].st_value) + best = i; +- if (mod->symtab[i].st_value > addr +- && mod->symtab[i].st_value < nextval) +- nextval = mod->symtab[i].st_value; ++ if (kallsyms->symtab[i].st_value > addr ++ && kallsyms->symtab[i].st_value < nextval) ++ nextval = kallsyms->symtab[i].st_value; + } + + if (!best) + return NULL; + + if (size) +- *size = nextval - mod->symtab[best].st_value; ++ *size = nextval - kallsyms->symtab[best].st_value; + if (offset) +- *offset = addr - mod->symtab[best].st_value; +- return symname(mod, best); ++ *offset = addr - kallsyms->symtab[best].st_value; ++ return symname(kallsyms, best); + } + + /* For kallsyms to ask for address resolution. NULL means not found. Careful +@@ -3540,18 +3560,21 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, + + preempt_disable(); + list_for_each_entry_rcu(mod, &modules, list) { ++ struct mod_kallsyms *kallsyms; ++ + if (mod->state == MODULE_STATE_UNFORMED) + continue; +- if (symnum < mod->num_symtab) { +- *value = mod->symtab[symnum].st_value; +- *type = mod->symtab[symnum].st_info; +- strlcpy(name, symname(mod, symnum), KSYM_NAME_LEN); ++ kallsyms = rcu_dereference_sched(mod->kallsyms); ++ if (symnum < kallsyms->num_symtab) { ++ *value = kallsyms->symtab[symnum].st_value; ++ *type = kallsyms->symtab[symnum].st_info; ++ strlcpy(name, symname(kallsyms, symnum), KSYM_NAME_LEN); + strlcpy(module_name, mod->name, MODULE_NAME_LEN); + *exported = is_exported(name, *value, mod); + preempt_enable(); + return 0; + } +- symnum -= mod->num_symtab; ++ symnum -= kallsyms->num_symtab; + } + preempt_enable(); + return -ERANGE; +@@ -3560,11 +3583,12 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, + static unsigned long mod_find_symname(struct module *mod, const char *name) + { + unsigned int i; ++ struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms); + +- for (i = 0; i < mod->num_symtab; i++) +- if (strcmp(name, symname(mod, i)) == 0 && +- mod->symtab[i].st_info != 'U') +- return mod->symtab[i].st_value; ++ for (i = 0; i < kallsyms->num_symtab; i++) ++ if (strcmp(name, symname(kallsyms, i)) == 0 && ++ kallsyms->symtab[i].st_info != 'U') ++ return kallsyms->symtab[i].st_value; + return 0; + } + +@@ -3603,11 +3627,14 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, + int ret; + + list_for_each_entry(mod, &modules, list) { ++ /* We hold module_mutex: no need for rcu_dereference_sched */ ++ struct mod_kallsyms *kallsyms = mod->kallsyms; ++ + if (mod->state == MODULE_STATE_UNFORMED) + continue; +- for (i = 0; i < mod->num_symtab; i++) { +- ret = fn(data, symname(mod, i), +- mod, mod->symtab[i].st_value); ++ for (i = 0; i < kallsyms->num_symtab; i++) { ++ ret = fn(data, symname(kallsyms, i), ++ mod, kallsyms->symtab[i].st_value); + if (ret != 0) + return ret; + } +diff --git a/lib/ucs2_string.c b/lib/ucs2_string.c +index 6f500ef2301d..f0b323abb4c6 100644 +--- a/lib/ucs2_string.c ++++ b/lib/ucs2_string.c +@@ -49,3 +49,65 @@ ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len) + } + } + EXPORT_SYMBOL(ucs2_strncmp); ++ ++unsigned long ++ucs2_utf8size(const ucs2_char_t *src) ++{ ++ unsigned long i; ++ unsigned long j = 0; ++ ++ for (i = 0; i < ucs2_strlen(src); i++) { ++ u16 c = src[i]; ++ ++ if (c >= 0x800) ++ j += 3; ++ else if (c >= 0x80) ++ j += 2; ++ else ++ j += 1; ++ } ++ ++ return j; ++} ++EXPORT_SYMBOL(ucs2_utf8size); ++ ++/* ++ * copy at most maxlength bytes of whole utf8 characters to dest from the ++ * ucs2 string src. ++ * ++ * The return value is the number of characters copied, not including the ++ * final NUL character. ++ */ ++unsigned long ++ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, unsigned long maxlength) ++{ ++ unsigned int i; ++ unsigned long j = 0; ++ unsigned long limit = ucs2_strnlen(src, maxlength); ++ ++ for (i = 0; maxlength && i < limit; i++) { ++ u16 c = src[i]; ++ ++ if (c >= 0x800) { ++ if (maxlength < 3) ++ break; ++ maxlength -= 3; ++ dest[j++] = 0xe0 | (c & 0xf000) >> 12; ++ dest[j++] = 0x80 | (c & 0x0fc0) >> 6; ++ dest[j++] = 0x80 | (c & 0x003f); ++ } else if (c >= 0x80) { ++ if (maxlength < 2) ++ break; ++ maxlength -= 2; ++ dest[j++] = 0xc0 | (c & 0x7c0) >> 6; ++ dest[j++] = 0x80 | (c & 0x03f); ++ } else { ++ maxlength -= 1; ++ dest[j++] = c & 0x7f; ++ } ++ } ++ if (maxlength) ++ dest[j] = '\0'; ++ return j; ++} ++EXPORT_SYMBOL(ucs2_as_utf8); +diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c +index 31bf2586fb84..864408026202 100644 +--- a/net/mac80211/agg-rx.c ++++ b/net/mac80211/agg-rx.c +@@ -290,7 +290,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, + } + + /* prepare A-MPDU MLME for Rx aggregation */ +- tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL); ++ tid_agg_rx = kzalloc(sizeof(*tid_agg_rx), GFP_KERNEL); + if (!tid_agg_rx) + goto end; + +diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c +index f3bbea1eb9e7..13f10aab9213 100644 +--- a/net/mac80211/rc80211_minstrel_ht.c ++++ b/net/mac80211/rc80211_minstrel_ht.c +@@ -454,7 +454,7 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb) + if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) + return; + +- ieee80211_start_tx_ba_session(pubsta, tid, 5000); ++ ieee80211_start_tx_ba_session(pubsta, tid, 0); + } + + static void +diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c +index c8717c1d082e..87dd619fb2e9 100644 +--- a/net/wireless/wext-core.c ++++ b/net/wireless/wext-core.c +@@ -342,6 +342,39 @@ static const int compat_event_type_size[] = { + + /* IW event code */ + ++static void wireless_nlevent_flush(void) ++{ ++ struct sk_buff *skb; ++ struct net *net; ++ ++ ASSERT_RTNL(); ++ ++ for_each_net(net) { ++ while ((skb = skb_dequeue(&net->wext_nlevents))) ++ rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, ++ GFP_KERNEL); ++ } ++} ++ ++static int wext_netdev_notifier_call(struct notifier_block *nb, ++ unsigned long state, void *ptr) ++{ ++ /* ++ * When a netdev changes state in any way, flush all pending messages ++ * to avoid them going out in a strange order, e.g. RTM_NEWLINK after ++ * RTM_DELLINK, or with IFF_UP after without IFF_UP during dev_close() ++ * or similar - all of which could otherwise happen due to delays from ++ * schedule_work(). ++ */ ++ wireless_nlevent_flush(); ++ ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block wext_netdev_notifier = { ++ .notifier_call = wext_netdev_notifier_call, ++}; ++ + static int __net_init wext_pernet_init(struct net *net) + { + skb_queue_head_init(&net->wext_nlevents); +@@ -360,7 +393,12 @@ static struct pernet_operations wext_pernet_ops = { + + static int __init wireless_nlevent_init(void) + { +- return register_pernet_subsys(&wext_pernet_ops); ++ int err = register_pernet_subsys(&wext_pernet_ops); ++ ++ if (err) ++ return err; ++ ++ return register_netdevice_notifier(&wext_netdev_notifier); + } + + subsys_initcall(wireless_nlevent_init); +@@ -368,17 +406,8 @@ subsys_initcall(wireless_nlevent_init); + /* Process events generated by the wireless layer or the driver. */ + static void wireless_nlevent_process(struct work_struct *work) + { +- struct sk_buff *skb; +- struct net *net; +- + rtnl_lock(); +- +- for_each_net(net) { +- while ((skb = skb_dequeue(&net->wext_nlevents))) +- rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, +- GFP_KERNEL); +- } +- ++ wireless_nlevent_flush(); + rtnl_unlock(); + } + +diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c +index 754f88e1fdab..4892966fc1b8 100644 +--- a/sound/soc/codecs/wm8958-dsp2.c ++++ b/sound/soc/codecs/wm8958-dsp2.c +@@ -459,7 +459,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994 *control = wm8994->wm8994; +- int value = ucontrol->value.integer.value[0]; ++ int value = ucontrol->value.enumerated.item[0]; + int reg; + + /* Don't allow on the fly reconfiguration */ +@@ -549,7 +549,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol, + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994 *control = wm8994->wm8994; +- int value = ucontrol->value.integer.value[0]; ++ int value = ucontrol->value.enumerated.item[0]; + int reg; + + /* Don't allow on the fly reconfiguration */ +@@ -582,7 +582,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol, + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994 *control = wm8994->wm8994; +- int value = ucontrol->value.integer.value[0]; ++ int value = ucontrol->value.enumerated.item[0]; + int reg; + + /* Don't allow on the fly reconfiguration */ +@@ -749,7 +749,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol, + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994 *control = wm8994->wm8994; +- int value = ucontrol->value.integer.value[0]; ++ int value = ucontrol->value.enumerated.item[0]; + int reg; + + /* Don't allow on the fly reconfiguration */ +diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c +index 6e746c7474bf..cda3cf23474b 100644 +--- a/sound/soc/codecs/wm8994.c ++++ b/sound/soc/codecs/wm8994.c +@@ -361,7 +361,7 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol, + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = &control->pdata; + int drc = wm8994_get_drc(kcontrol->id.name); +- int value = ucontrol->value.integer.value[0]; ++ int value = ucontrol->value.enumerated.item[0]; + + if (drc < 0) + return drc; +@@ -468,7 +468,7 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = &control->pdata; + int block = wm8994_get_retune_mobile_block(kcontrol->id.name); +- int value = ucontrol->value.integer.value[0]; ++ int value = ucontrol->value.enumerated.item[0]; + + if (block < 0) + return block; +diff --git a/tools/testing/selftests/efivarfs/efivarfs.sh b/tools/testing/selftests/efivarfs/efivarfs.sh +index 77edcdcc016b..057278448515 100644 +--- a/tools/testing/selftests/efivarfs/efivarfs.sh ++++ b/tools/testing/selftests/efivarfs/efivarfs.sh +@@ -88,7 +88,11 @@ test_delete() + exit 1 + fi + +- rm $file ++ rm $file 2>/dev/null ++ if [ $? -ne 0 ]; then ++ chattr -i $file ++ rm $file ++ fi + + if [ -e $file ]; then + echo "$file couldn't be deleted" >&2 +@@ -111,6 +115,7 @@ test_zero_size_delete() + exit 1 + fi + ++ chattr -i $file + printf "$attrs" > $file + + if [ -e $file ]; then +@@ -141,7 +146,11 @@ test_valid_filenames() + echo "$file could not be created" >&2 + ret=1 + else +- rm $file ++ rm $file 2>/dev/null ++ if [ $? -ne 0 ]; then ++ chattr -i $file ++ rm $file ++ fi + fi + done + +@@ -174,7 +183,11 @@ test_invalid_filenames() + + if [ -e $file ]; then + echo "Creating $file should have failed" >&2 +- rm $file ++ rm $file 2>/dev/null ++ if [ $? -ne 0 ]; then ++ chattr -i $file ++ rm $file ++ fi + ret=1 + fi + done +diff --git a/tools/testing/selftests/efivarfs/open-unlink.c b/tools/testing/selftests/efivarfs/open-unlink.c +index 8c0764407b3c..4af74f733036 100644 +--- a/tools/testing/selftests/efivarfs/open-unlink.c ++++ b/tools/testing/selftests/efivarfs/open-unlink.c +@@ -1,10 +1,68 @@ ++#include <errno.h> + #include <stdio.h> + #include <stdint.h> + #include <stdlib.h> + #include <unistd.h> ++#include <sys/ioctl.h> + #include <sys/types.h> + #include <sys/stat.h> + #include <fcntl.h> ++#include <linux/fs.h> ++ ++static int set_immutable(const char *path, int immutable) ++{ ++ unsigned int flags; ++ int fd; ++ int rc; ++ int error; ++ ++ fd = open(path, O_RDONLY); ++ if (fd < 0) ++ return fd; ++ ++ rc = ioctl(fd, FS_IOC_GETFLAGS, &flags); ++ if (rc < 0) { ++ error = errno; ++ close(fd); ++ errno = error; ++ return rc; ++ } ++ ++ if (immutable) ++ flags |= FS_IMMUTABLE_FL; ++ else ++ flags &= ~FS_IMMUTABLE_FL; ++ ++ rc = ioctl(fd, FS_IOC_SETFLAGS, &flags); ++ error = errno; ++ close(fd); ++ errno = error; ++ return rc; ++} ++ ++static int get_immutable(const char *path) ++{ ++ unsigned int flags; ++ int fd; ++ int rc; ++ int error; ++ ++ fd = open(path, O_RDONLY); ++ if (fd < 0) ++ return fd; ++ ++ rc = ioctl(fd, FS_IOC_GETFLAGS, &flags); ++ if (rc < 0) { ++ error = errno; ++ close(fd); ++ errno = error; ++ return rc; ++ } ++ close(fd); ++ if (flags & FS_IMMUTABLE_FL) ++ return 1; ++ return 0; ++} + + int main(int argc, char **argv) + { +@@ -27,7 +85,7 @@ int main(int argc, char **argv) + buf[4] = 0; + + /* create a test variable */ +- fd = open(path, O_WRONLY | O_CREAT); ++ fd = open(path, O_WRONLY | O_CREAT, 0600); + if (fd < 0) { + perror("open(O_WRONLY)"); + return EXIT_FAILURE; +@@ -41,6 +99,18 @@ int main(int argc, char **argv) + + close(fd); + ++ rc = get_immutable(path); ++ if (rc < 0) { ++ perror("ioctl(FS_IOC_GETFLAGS)"); ++ return EXIT_FAILURE; ++ } else if (rc) { ++ rc = set_immutable(path, 0); ++ if (rc < 0) { ++ perror("ioctl(FS_IOC_SETFLAGS)"); ++ return EXIT_FAILURE; ++ } ++ } ++ + fd = open(path, O_RDONLY); + if (fd < 0) { + perror("open"); |