/** * efivar_create_sysfs_entry - create a new entry in sysfs * @new_var: efivar entry to create * * Returns 0 on success, negative error code on failure */ static int 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; int ret; variable_name = new_var->var.VariableName; variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t); /* * Length of the variable bytes in ASCII, 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); if (!short_name) return -ENOMEM; /* 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; } /* This is ugly, but necessary to separate one vendor's private variables from another's. */ *(short_name + strlen(short_name)) = '-'; efi_guid_to_str(&new_var->var.VendorGuid, short_name + strlen(short_name)); new_var->kobj.kset = efivars_kset; ret = kobject_init_and_add(&new_var->kobj, &efivar_ktype, NULL, "%s", short_name); kfree(short_name); if (ret) return ret; kobject_uevent(&new_var->kobj, KOBJ_ADD); efivar_entry_add(new_var, &efivar_sysfs_list); return 0; }
static int efivarfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { struct inode *inode; struct efivar_entry *var; int namelen, i = 0, err = 0; 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; } /* length of the variable name itself: remove GUID and separator */ namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1; efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1, &var->var.VendorGuid); for (i = 0; i < namelen; i++) var->var.VariableName[i] = dentry->d_name.name[i]; var->var.VariableName[i] = '\0'; inode->i_private = var; efivar_entry_add(var, &efivarfs_list); d_instantiate(dentry, inode); dget(dentry); out: if (err) { kfree(var); iput(inode); } return err; }
/** * efivar_create_sysfs_entry - create a new entry in sysfs * @new_var: efivar entry to create * * Returns 0 on success, negative error code on failure */ static int efivar_create_sysfs_entry(struct efivar_entry *new_var) { int short_name_size; char *short_name; unsigned long utf8_name_size; efi_char16_t *variable_name = new_var->var.VariableName; int ret; /* * Length of the variable bytes in UTF8, plus the '-' separator, * plus the GUID, plus trailing NUL */ 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 -ENOMEM; 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[utf8_name_size] = '-'; efi_guid_to_str(&new_var->var.VendorGuid, short_name + utf8_name_size + 1); new_var->kobj.kset = efivars_kset; ret = kobject_init_and_add(&new_var->kobj, &efivar_ktype, NULL, "%s", short_name); kfree(short_name); if (ret) return ret; kobject_uevent(&new_var->kobj, KOBJ_ADD); efivar_entry_add(new_var, &efivar_sysfs_list); return 0; }
static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, unsigned long name_size, void *data) { struct super_block *sb = (struct super_block *)data; struct efivar_entry *entry; struct inode *inode = NULL; struct dentry *dentry, *root = sb->s_root; unsigned long size = 0; char *name; int len; int err = -ENOMEM; bool is_removable = false; entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return err; memcpy(entry->var.VariableName, name16, name_size); memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); 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; ucs2_as_utf8(name, entry->var.VariableName, len); if (efivar_variable_is_removable(entry->var.VendorGuid, name, len)) is_removable = true; name[len] = '-'; efi_guid_unparse(&entry->var.VendorGuid, name + len + 1); name[len + EFI_VARIABLE_GUID_LEN+1] = '\0'; inode = efivarfs_get_inode(sb, root->d_inode, S_IFREG | 0644, 0, is_removable); if (!inode) goto fail_name; dentry = efivarfs_alloc_dentry(root, name); if (IS_ERR(dentry)) { err = PTR_ERR(dentry); goto fail_inode; } /* copied by the above to local storage in the dentry. */ kfree(name); efivar_entry_size(entry, &size); efivar_entry_add(entry, &efivarfs_list); mutex_lock(&inode->i_mutex); inode->i_private = entry; i_size_write(inode, size + sizeof(entry->var.Attributes)); mutex_unlock(&inode->i_mutex); d_add(dentry, inode); return 0; fail_inode: iput(inode); fail_name: kfree(name); fail: kfree(entry); return err; }