cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hypfs_diag.c (16577B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *    Hypervisor filesystem for Linux on s390. Diag 204 and 224
      4 *    implementation.
      5 *
      6 *    Copyright IBM Corp. 2006, 2008
      7 *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
      8 */
      9
     10#define KMSG_COMPONENT "hypfs"
     11#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
     12
     13#include <linux/types.h>
     14#include <linux/errno.h>
     15#include <linux/slab.h>
     16#include <linux/string.h>
     17#include <linux/vmalloc.h>
     18#include <linux/mm.h>
     19#include <asm/diag.h>
     20#include <asm/ebcdic.h>
     21#include "hypfs.h"
     22
     23#define TMP_SIZE 64		/* size of temporary buffers */
     24
     25#define DBFS_D204_HDR_VERSION	0
     26
     27static char *diag224_cpu_names;			/* diag 224 name table */
     28static enum diag204_sc diag204_store_sc;	/* used subcode for store */
     29static enum diag204_format diag204_info_type;	/* used diag 204 data format */
     30
     31static void *diag204_buf;		/* 4K aligned buffer for diag204 data */
     32static void *diag204_buf_vmalloc;	/* vmalloc pointer for diag204 data */
     33static int diag204_buf_pages;		/* number of pages for diag204 data */
     34
     35static struct dentry *dbfs_d204_file;
     36
     37/*
     38 * DIAG 204 member access functions.
     39 *
     40 * Since we have two different diag 204 data formats for old and new s390
     41 * machines, we do not access the structs directly, but use getter functions for
     42 * each struct member instead. This should make the code more readable.
     43 */
     44
     45/* Time information block */
     46
     47static inline int info_blk_hdr__size(enum diag204_format type)
     48{
     49	if (type == DIAG204_INFO_SIMPLE)
     50		return sizeof(struct diag204_info_blk_hdr);
     51	else /* DIAG204_INFO_EXT */
     52		return sizeof(struct diag204_x_info_blk_hdr);
     53}
     54
     55static inline __u8 info_blk_hdr__npar(enum diag204_format type, void *hdr)
     56{
     57	if (type == DIAG204_INFO_SIMPLE)
     58		return ((struct diag204_info_blk_hdr *)hdr)->npar;
     59	else /* DIAG204_INFO_EXT */
     60		return ((struct diag204_x_info_blk_hdr *)hdr)->npar;
     61}
     62
     63static inline __u8 info_blk_hdr__flags(enum diag204_format type, void *hdr)
     64{
     65	if (type == DIAG204_INFO_SIMPLE)
     66		return ((struct diag204_info_blk_hdr *)hdr)->flags;
     67	else /* DIAG204_INFO_EXT */
     68		return ((struct diag204_x_info_blk_hdr *)hdr)->flags;
     69}
     70
     71static inline __u16 info_blk_hdr__pcpus(enum diag204_format type, void *hdr)
     72{
     73	if (type == DIAG204_INFO_SIMPLE)
     74		return ((struct diag204_info_blk_hdr *)hdr)->phys_cpus;
     75	else /* DIAG204_INFO_EXT */
     76		return ((struct diag204_x_info_blk_hdr *)hdr)->phys_cpus;
     77}
     78
     79/* Partition header */
     80
     81static inline int part_hdr__size(enum diag204_format type)
     82{
     83	if (type == DIAG204_INFO_SIMPLE)
     84		return sizeof(struct diag204_part_hdr);
     85	else /* DIAG204_INFO_EXT */
     86		return sizeof(struct diag204_x_part_hdr);
     87}
     88
     89static inline __u8 part_hdr__rcpus(enum diag204_format type, void *hdr)
     90{
     91	if (type == DIAG204_INFO_SIMPLE)
     92		return ((struct diag204_part_hdr *)hdr)->cpus;
     93	else /* DIAG204_INFO_EXT */
     94		return ((struct diag204_x_part_hdr *)hdr)->rcpus;
     95}
     96
     97static inline void part_hdr__part_name(enum diag204_format type, void *hdr,
     98				       char *name)
     99{
    100	if (type == DIAG204_INFO_SIMPLE)
    101		memcpy(name, ((struct diag204_part_hdr *)hdr)->part_name,
    102		       DIAG204_LPAR_NAME_LEN);
    103	else /* DIAG204_INFO_EXT */
    104		memcpy(name, ((struct diag204_x_part_hdr *)hdr)->part_name,
    105		       DIAG204_LPAR_NAME_LEN);
    106	EBCASC(name, DIAG204_LPAR_NAME_LEN);
    107	name[DIAG204_LPAR_NAME_LEN] = 0;
    108	strim(name);
    109}
    110
    111/* CPU info block */
    112
    113static inline int cpu_info__size(enum diag204_format type)
    114{
    115	if (type == DIAG204_INFO_SIMPLE)
    116		return sizeof(struct diag204_cpu_info);
    117	else /* DIAG204_INFO_EXT */
    118		return sizeof(struct diag204_x_cpu_info);
    119}
    120
    121static inline __u8 cpu_info__ctidx(enum diag204_format type, void *hdr)
    122{
    123	if (type == DIAG204_INFO_SIMPLE)
    124		return ((struct diag204_cpu_info *)hdr)->ctidx;
    125	else /* DIAG204_INFO_EXT */
    126		return ((struct diag204_x_cpu_info *)hdr)->ctidx;
    127}
    128
    129static inline __u16 cpu_info__cpu_addr(enum diag204_format type, void *hdr)
    130{
    131	if (type == DIAG204_INFO_SIMPLE)
    132		return ((struct diag204_cpu_info *)hdr)->cpu_addr;
    133	else /* DIAG204_INFO_EXT */
    134		return ((struct diag204_x_cpu_info *)hdr)->cpu_addr;
    135}
    136
    137static inline __u64 cpu_info__acc_time(enum diag204_format type, void *hdr)
    138{
    139	if (type == DIAG204_INFO_SIMPLE)
    140		return ((struct diag204_cpu_info *)hdr)->acc_time;
    141	else /* DIAG204_INFO_EXT */
    142		return ((struct diag204_x_cpu_info *)hdr)->acc_time;
    143}
    144
    145static inline __u64 cpu_info__lp_time(enum diag204_format type, void *hdr)
    146{
    147	if (type == DIAG204_INFO_SIMPLE)
    148		return ((struct diag204_cpu_info *)hdr)->lp_time;
    149	else /* DIAG204_INFO_EXT */
    150		return ((struct diag204_x_cpu_info *)hdr)->lp_time;
    151}
    152
    153static inline __u64 cpu_info__online_time(enum diag204_format type, void *hdr)
    154{
    155	if (type == DIAG204_INFO_SIMPLE)
    156		return 0;	/* online_time not available in simple info */
    157	else /* DIAG204_INFO_EXT */
    158		return ((struct diag204_x_cpu_info *)hdr)->online_time;
    159}
    160
    161/* Physical header */
    162
    163static inline int phys_hdr__size(enum diag204_format type)
    164{
    165	if (type == DIAG204_INFO_SIMPLE)
    166		return sizeof(struct diag204_phys_hdr);
    167	else /* DIAG204_INFO_EXT */
    168		return sizeof(struct diag204_x_phys_hdr);
    169}
    170
    171static inline __u8 phys_hdr__cpus(enum diag204_format type, void *hdr)
    172{
    173	if (type == DIAG204_INFO_SIMPLE)
    174		return ((struct diag204_phys_hdr *)hdr)->cpus;
    175	else /* DIAG204_INFO_EXT */
    176		return ((struct diag204_x_phys_hdr *)hdr)->cpus;
    177}
    178
    179/* Physical CPU info block */
    180
    181static inline int phys_cpu__size(enum diag204_format type)
    182{
    183	if (type == DIAG204_INFO_SIMPLE)
    184		return sizeof(struct diag204_phys_cpu);
    185	else /* DIAG204_INFO_EXT */
    186		return sizeof(struct diag204_x_phys_cpu);
    187}
    188
    189static inline __u16 phys_cpu__cpu_addr(enum diag204_format type, void *hdr)
    190{
    191	if (type == DIAG204_INFO_SIMPLE)
    192		return ((struct diag204_phys_cpu *)hdr)->cpu_addr;
    193	else /* DIAG204_INFO_EXT */
    194		return ((struct diag204_x_phys_cpu *)hdr)->cpu_addr;
    195}
    196
    197static inline __u64 phys_cpu__mgm_time(enum diag204_format type, void *hdr)
    198{
    199	if (type == DIAG204_INFO_SIMPLE)
    200		return ((struct diag204_phys_cpu *)hdr)->mgm_time;
    201	else /* DIAG204_INFO_EXT */
    202		return ((struct diag204_x_phys_cpu *)hdr)->mgm_time;
    203}
    204
    205static inline __u64 phys_cpu__ctidx(enum diag204_format type, void *hdr)
    206{
    207	if (type == DIAG204_INFO_SIMPLE)
    208		return ((struct diag204_phys_cpu *)hdr)->ctidx;
    209	else /* DIAG204_INFO_EXT */
    210		return ((struct diag204_x_phys_cpu *)hdr)->ctidx;
    211}
    212
    213/* Diagnose 204 functions */
    214/*
    215 * For the old diag subcode 4 with simple data format we have to use real
    216 * memory. If we use subcode 6 or 7 with extended data format, we can (and
    217 * should) use vmalloc, since we need a lot of memory in that case. Currently
    218 * up to 93 pages!
    219 */
    220
    221static void diag204_free_buffer(void)
    222{
    223	if (!diag204_buf)
    224		return;
    225	if (diag204_buf_vmalloc) {
    226		vfree(diag204_buf_vmalloc);
    227		diag204_buf_vmalloc = NULL;
    228	} else {
    229		free_pages((unsigned long) diag204_buf, 0);
    230	}
    231	diag204_buf = NULL;
    232}
    233
    234static void *page_align_ptr(void *ptr)
    235{
    236	return (void *) PAGE_ALIGN((unsigned long) ptr);
    237}
    238
    239static void *diag204_alloc_vbuf(int pages)
    240{
    241	/* The buffer has to be page aligned! */
    242	diag204_buf_vmalloc = vmalloc(array_size(PAGE_SIZE, (pages + 1)));
    243	if (!diag204_buf_vmalloc)
    244		return ERR_PTR(-ENOMEM);
    245	diag204_buf = page_align_ptr(diag204_buf_vmalloc);
    246	diag204_buf_pages = pages;
    247	return diag204_buf;
    248}
    249
    250static void *diag204_alloc_rbuf(void)
    251{
    252	diag204_buf = (void*)__get_free_pages(GFP_KERNEL,0);
    253	if (!diag204_buf)
    254		return ERR_PTR(-ENOMEM);
    255	diag204_buf_pages = 1;
    256	return diag204_buf;
    257}
    258
    259static void *diag204_get_buffer(enum diag204_format fmt, int *pages)
    260{
    261	if (diag204_buf) {
    262		*pages = diag204_buf_pages;
    263		return diag204_buf;
    264	}
    265	if (fmt == DIAG204_INFO_SIMPLE) {
    266		*pages = 1;
    267		return diag204_alloc_rbuf();
    268	} else {/* DIAG204_INFO_EXT */
    269		*pages = diag204((unsigned long)DIAG204_SUBC_RSI |
    270				 (unsigned long)DIAG204_INFO_EXT, 0, NULL);
    271		if (*pages <= 0)
    272			return ERR_PTR(-ENOSYS);
    273		else
    274			return diag204_alloc_vbuf(*pages);
    275	}
    276}
    277
    278/*
    279 * diag204_probe() has to find out, which type of diagnose 204 implementation
    280 * we have on our machine. Currently there are three possible scanarios:
    281 *   - subcode 4   + simple data format (only one page)
    282 *   - subcode 4-6 + extended data format
    283 *   - subcode 4-7 + extended data format
    284 *
    285 * Subcode 5 is used to retrieve the size of the data, provided by subcodes
    286 * 6 and 7. Subcode 7 basically has the same function as subcode 6. In addition
    287 * to subcode 6 it provides also information about secondary cpus.
    288 * In order to get as much information as possible, we first try
    289 * subcode 7, then 6 and if both fail, we use subcode 4.
    290 */
    291
    292static int diag204_probe(void)
    293{
    294	void *buf;
    295	int pages, rc;
    296
    297	buf = diag204_get_buffer(DIAG204_INFO_EXT, &pages);
    298	if (!IS_ERR(buf)) {
    299		if (diag204((unsigned long)DIAG204_SUBC_STIB7 |
    300			    (unsigned long)DIAG204_INFO_EXT, pages, buf) >= 0) {
    301			diag204_store_sc = DIAG204_SUBC_STIB7;
    302			diag204_info_type = DIAG204_INFO_EXT;
    303			goto out;
    304		}
    305		if (diag204((unsigned long)DIAG204_SUBC_STIB6 |
    306			    (unsigned long)DIAG204_INFO_EXT, pages, buf) >= 0) {
    307			diag204_store_sc = DIAG204_SUBC_STIB6;
    308			diag204_info_type = DIAG204_INFO_EXT;
    309			goto out;
    310		}
    311		diag204_free_buffer();
    312	}
    313
    314	/* subcodes 6 and 7 failed, now try subcode 4 */
    315
    316	buf = diag204_get_buffer(DIAG204_INFO_SIMPLE, &pages);
    317	if (IS_ERR(buf)) {
    318		rc = PTR_ERR(buf);
    319		goto fail_alloc;
    320	}
    321	if (diag204((unsigned long)DIAG204_SUBC_STIB4 |
    322		    (unsigned long)DIAG204_INFO_SIMPLE, pages, buf) >= 0) {
    323		diag204_store_sc = DIAG204_SUBC_STIB4;
    324		diag204_info_type = DIAG204_INFO_SIMPLE;
    325		goto out;
    326	} else {
    327		rc = -ENOSYS;
    328		goto fail_store;
    329	}
    330out:
    331	rc = 0;
    332fail_store:
    333	diag204_free_buffer();
    334fail_alloc:
    335	return rc;
    336}
    337
    338static int diag204_do_store(void *buf, int pages)
    339{
    340	int rc;
    341
    342	rc = diag204((unsigned long) diag204_store_sc |
    343		     (unsigned long) diag204_info_type, pages, buf);
    344	return rc < 0 ? -ENOSYS : 0;
    345}
    346
    347static void *diag204_store(void)
    348{
    349	void *buf;
    350	int pages, rc;
    351
    352	buf = diag204_get_buffer(diag204_info_type, &pages);
    353	if (IS_ERR(buf))
    354		goto out;
    355	rc = diag204_do_store(buf, pages);
    356	if (rc)
    357		return ERR_PTR(rc);
    358out:
    359	return buf;
    360}
    361
    362/* Diagnose 224 functions */
    363
    364static int diag224_get_name_table(void)
    365{
    366	/* memory must be below 2GB */
    367	diag224_cpu_names = (char *) __get_free_page(GFP_KERNEL | GFP_DMA);
    368	if (!diag224_cpu_names)
    369		return -ENOMEM;
    370	if (diag224(diag224_cpu_names)) {
    371		free_page((unsigned long) diag224_cpu_names);
    372		return -EOPNOTSUPP;
    373	}
    374	EBCASC(diag224_cpu_names + 16, (*diag224_cpu_names + 1) * 16);
    375	return 0;
    376}
    377
    378static void diag224_delete_name_table(void)
    379{
    380	free_page((unsigned long) diag224_cpu_names);
    381}
    382
    383static int diag224_idx2name(int index, char *name)
    384{
    385	memcpy(name, diag224_cpu_names + ((index + 1) * DIAG204_CPU_NAME_LEN),
    386	       DIAG204_CPU_NAME_LEN);
    387	name[DIAG204_CPU_NAME_LEN] = 0;
    388	strim(name);
    389	return 0;
    390}
    391
    392struct dbfs_d204_hdr {
    393	u64	len;		/* Length of d204 buffer without header */
    394	u16	version;	/* Version of header */
    395	u8	sc;		/* Used subcode */
    396	char	reserved[53];
    397} __attribute__ ((packed));
    398
    399struct dbfs_d204 {
    400	struct dbfs_d204_hdr	hdr;	/* 64 byte header */
    401	char			buf[];	/* d204 buffer */
    402} __attribute__ ((packed));
    403
    404static int dbfs_d204_create(void **data, void **data_free_ptr, size_t *size)
    405{
    406	struct dbfs_d204 *d204;
    407	int rc, buf_size;
    408	void *base;
    409
    410	buf_size = PAGE_SIZE * (diag204_buf_pages + 1) + sizeof(d204->hdr);
    411	base = vzalloc(buf_size);
    412	if (!base)
    413		return -ENOMEM;
    414	d204 = page_align_ptr(base + sizeof(d204->hdr)) - sizeof(d204->hdr);
    415	rc = diag204_do_store(d204->buf, diag204_buf_pages);
    416	if (rc) {
    417		vfree(base);
    418		return rc;
    419	}
    420	d204->hdr.version = DBFS_D204_HDR_VERSION;
    421	d204->hdr.len = PAGE_SIZE * diag204_buf_pages;
    422	d204->hdr.sc = diag204_store_sc;
    423	*data = d204;
    424	*data_free_ptr = base;
    425	*size = d204->hdr.len + sizeof(struct dbfs_d204_hdr);
    426	return 0;
    427}
    428
    429static struct hypfs_dbfs_file dbfs_file_d204 = {
    430	.name		= "diag_204",
    431	.data_create	= dbfs_d204_create,
    432	.data_free	= vfree,
    433};
    434
    435__init int hypfs_diag_init(void)
    436{
    437	int rc;
    438
    439	if (diag204_probe()) {
    440		pr_err("The hardware system does not support hypfs\n");
    441		return -ENODATA;
    442	}
    443
    444	if (diag204_info_type == DIAG204_INFO_EXT)
    445		hypfs_dbfs_create_file(&dbfs_file_d204);
    446
    447	if (MACHINE_IS_LPAR) {
    448		rc = diag224_get_name_table();
    449		if (rc) {
    450			pr_err("The hardware system does not provide all "
    451			       "functions required by hypfs\n");
    452			debugfs_remove(dbfs_d204_file);
    453			return rc;
    454		}
    455	}
    456	return 0;
    457}
    458
    459void hypfs_diag_exit(void)
    460{
    461	debugfs_remove(dbfs_d204_file);
    462	diag224_delete_name_table();
    463	diag204_free_buffer();
    464	hypfs_dbfs_remove_file(&dbfs_file_d204);
    465}
    466
    467/*
    468 * Functions to create the directory structure
    469 * *******************************************
    470 */
    471
    472static int hypfs_create_cpu_files(struct dentry *cpus_dir, void *cpu_info)
    473{
    474	struct dentry *cpu_dir;
    475	char buffer[TMP_SIZE];
    476	void *rc;
    477
    478	snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_info_type,
    479							    cpu_info));
    480	cpu_dir = hypfs_mkdir(cpus_dir, buffer);
    481	rc = hypfs_create_u64(cpu_dir, "mgmtime",
    482			      cpu_info__acc_time(diag204_info_type, cpu_info) -
    483			      cpu_info__lp_time(diag204_info_type, cpu_info));
    484	if (IS_ERR(rc))
    485		return PTR_ERR(rc);
    486	rc = hypfs_create_u64(cpu_dir, "cputime",
    487			      cpu_info__lp_time(diag204_info_type, cpu_info));
    488	if (IS_ERR(rc))
    489		return PTR_ERR(rc);
    490	if (diag204_info_type == DIAG204_INFO_EXT) {
    491		rc = hypfs_create_u64(cpu_dir, "onlinetime",
    492				      cpu_info__online_time(diag204_info_type,
    493							    cpu_info));
    494		if (IS_ERR(rc))
    495			return PTR_ERR(rc);
    496	}
    497	diag224_idx2name(cpu_info__ctidx(diag204_info_type, cpu_info), buffer);
    498	rc = hypfs_create_str(cpu_dir, "type", buffer);
    499	return PTR_ERR_OR_ZERO(rc);
    500}
    501
    502static void *hypfs_create_lpar_files(struct dentry *systems_dir, void *part_hdr)
    503{
    504	struct dentry *cpus_dir;
    505	struct dentry *lpar_dir;
    506	char lpar_name[DIAG204_LPAR_NAME_LEN + 1];
    507	void *cpu_info;
    508	int i;
    509
    510	part_hdr__part_name(diag204_info_type, part_hdr, lpar_name);
    511	lpar_name[DIAG204_LPAR_NAME_LEN] = 0;
    512	lpar_dir = hypfs_mkdir(systems_dir, lpar_name);
    513	if (IS_ERR(lpar_dir))
    514		return lpar_dir;
    515	cpus_dir = hypfs_mkdir(lpar_dir, "cpus");
    516	if (IS_ERR(cpus_dir))
    517		return cpus_dir;
    518	cpu_info = part_hdr + part_hdr__size(diag204_info_type);
    519	for (i = 0; i < part_hdr__rcpus(diag204_info_type, part_hdr); i++) {
    520		int rc;
    521		rc = hypfs_create_cpu_files(cpus_dir, cpu_info);
    522		if (rc)
    523			return ERR_PTR(rc);
    524		cpu_info += cpu_info__size(diag204_info_type);
    525	}
    526	return cpu_info;
    527}
    528
    529static int hypfs_create_phys_cpu_files(struct dentry *cpus_dir, void *cpu_info)
    530{
    531	struct dentry *cpu_dir;
    532	char buffer[TMP_SIZE];
    533	void *rc;
    534
    535	snprintf(buffer, TMP_SIZE, "%i", phys_cpu__cpu_addr(diag204_info_type,
    536							    cpu_info));
    537	cpu_dir = hypfs_mkdir(cpus_dir, buffer);
    538	if (IS_ERR(cpu_dir))
    539		return PTR_ERR(cpu_dir);
    540	rc = hypfs_create_u64(cpu_dir, "mgmtime",
    541			      phys_cpu__mgm_time(diag204_info_type, cpu_info));
    542	if (IS_ERR(rc))
    543		return PTR_ERR(rc);
    544	diag224_idx2name(phys_cpu__ctidx(diag204_info_type, cpu_info), buffer);
    545	rc = hypfs_create_str(cpu_dir, "type", buffer);
    546	return PTR_ERR_OR_ZERO(rc);
    547}
    548
    549static void *hypfs_create_phys_files(struct dentry *parent_dir, void *phys_hdr)
    550{
    551	int i;
    552	void *cpu_info;
    553	struct dentry *cpus_dir;
    554
    555	cpus_dir = hypfs_mkdir(parent_dir, "cpus");
    556	if (IS_ERR(cpus_dir))
    557		return cpus_dir;
    558	cpu_info = phys_hdr + phys_hdr__size(diag204_info_type);
    559	for (i = 0; i < phys_hdr__cpus(diag204_info_type, phys_hdr); i++) {
    560		int rc;
    561		rc = hypfs_create_phys_cpu_files(cpus_dir, cpu_info);
    562		if (rc)
    563			return ERR_PTR(rc);
    564		cpu_info += phys_cpu__size(diag204_info_type);
    565	}
    566	return cpu_info;
    567}
    568
    569int hypfs_diag_create_files(struct dentry *root)
    570{
    571	struct dentry *systems_dir, *hyp_dir;
    572	void *time_hdr, *part_hdr;
    573	int i, rc;
    574	void *buffer, *ptr;
    575
    576	buffer = diag204_store();
    577	if (IS_ERR(buffer))
    578		return PTR_ERR(buffer);
    579
    580	systems_dir = hypfs_mkdir(root, "systems");
    581	if (IS_ERR(systems_dir)) {
    582		rc = PTR_ERR(systems_dir);
    583		goto err_out;
    584	}
    585	time_hdr = (struct x_info_blk_hdr *)buffer;
    586	part_hdr = time_hdr + info_blk_hdr__size(diag204_info_type);
    587	for (i = 0; i < info_blk_hdr__npar(diag204_info_type, time_hdr); i++) {
    588		part_hdr = hypfs_create_lpar_files(systems_dir, part_hdr);
    589		if (IS_ERR(part_hdr)) {
    590			rc = PTR_ERR(part_hdr);
    591			goto err_out;
    592		}
    593	}
    594	if (info_blk_hdr__flags(diag204_info_type, time_hdr) &
    595	    DIAG204_LPAR_PHYS_FLG) {
    596		ptr = hypfs_create_phys_files(root, part_hdr);
    597		if (IS_ERR(ptr)) {
    598			rc = PTR_ERR(ptr);
    599			goto err_out;
    600		}
    601	}
    602	hyp_dir = hypfs_mkdir(root, "hyp");
    603	if (IS_ERR(hyp_dir)) {
    604		rc = PTR_ERR(hyp_dir);
    605		goto err_out;
    606	}
    607	ptr = hypfs_create_str(hyp_dir, "type", "LPAR Hypervisor");
    608	if (IS_ERR(ptr)) {
    609		rc = PTR_ERR(ptr);
    610		goto err_out;
    611	}
    612	rc = 0;
    613
    614err_out:
    615	return rc;
    616}