summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pagano <mpagano@gentoo.org>2016-03-16 15:40:25 -0400
committerMike Pagano <mpagano@gentoo.org>2016-03-16 15:40:25 -0400
commitdeeb81d32b2d6b7408271c5d0483307f20262d08 (patch)
tree78cb64355456f6613b413ed5fcede3e54c4b8a09
parentLinux patch 3.10.100 (diff)
downloadlinux-patches-deeb81d32b2d6b7408271c5d0483307f20262d08.tar.gz
linux-patches-deeb81d32b2d6b7408271c5d0483307f20262d08.tar.bz2
linux-patches-deeb81d32b2d6b7408271c5d0483307f20262d08.zip
Linux patch 3.10.1013.10-106
-rw-r--r--0000_README4
-rw-r--r--1100_linux-3.10.101.patch1493
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");