s390/zcore: Add hsa file
Michael Holzheu [Mon, 21 Jan 2013 17:37:41 +0000 (18:37 +0100)]
Under LPAR the zfcpdump HSA is a shared resource. Up to now the HSA memory
is released when the zcore file is closed. Dump programs that know that
they do not need the HSA memory any more (e.g. because they already dumped it)
could release it earlier. This would allow other LPARs to use it again.

To achieve this a new debugfs file "hsa" is added that can be used to read
the HSA size and to release the HSA by writing "0" into the file.

Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

drivers/s390/char/zcore.c

index e3b9308..681749e 100644 (file)
@@ -62,6 +62,7 @@ static struct dentry *zcore_dir;
 static struct dentry *zcore_file;
 static struct dentry *zcore_memmap_file;
 static struct dentry *zcore_reipl_file;
+static struct dentry *zcore_hsa_file;
 static struct ipl_parameter_block *ipl_block;
 
 /*
@@ -77,6 +78,8 @@ static int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode)
        int offs, blk_num;
        static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
 
+       if (!hsa_available)
+               return -ENODATA;
        if (count == 0)
                return 0;
 
@@ -278,6 +281,15 @@ next:
 }
 
 /*
+ * Release the HSA
+ */
+static void release_hsa(void)
+{
+       diag308(DIAG308_REL_HSA, NULL);
+       hsa_available = 0;
+}
+
+/*
  * Read routine for zcore character device
  * First 4K are dump header
  * Next 32MB are HSA Memory
@@ -363,8 +375,8 @@ static int zcore_open(struct inode *inode, struct file *filp)
 
 static int zcore_release(struct inode *inode, struct file *filep)
 {
-       diag308(DIAG308_REL_HSA, NULL);
-       hsa_available = 0;
+       if (hsa_available)
+               release_hsa();
        return 0;
 }
 
@@ -474,6 +486,41 @@ static const struct file_operations zcore_reipl_fops = {
        .llseek         = no_llseek,
 };
 
+static ssize_t zcore_hsa_read(struct file *filp, char __user *buf,
+                             size_t count, loff_t *ppos)
+{
+       static char str[18];
+
+       if (hsa_available)
+               snprintf(str, sizeof(str), "%lx\n", ZFCPDUMP_HSA_SIZE);
+       else
+               snprintf(str, sizeof(str), "0\n");
+       return simple_read_from_buffer(buf, count, ppos, str, strlen(str));
+}
+
+static ssize_t zcore_hsa_write(struct file *filp, const char __user *buf,
+                              size_t count, loff_t *ppos)
+{
+       char value;
+
+       if (*ppos != 0)
+               return -EPIPE;
+       if (copy_from_user(&value, buf, 1))
+               return -EFAULT;
+       if (value != '0')
+               return -EINVAL;
+       release_hsa();
+       return count;
+}
+
+static const struct file_operations zcore_hsa_fops = {
+       .owner          = THIS_MODULE,
+       .write          = zcore_hsa_write,
+       .read           = zcore_hsa_read,
+       .open           = nonseekable_open,
+       .llseek         = no_llseek,
+};
+
 #ifdef CONFIG_32BIT
 
 static void __init set_lc_mask(struct save_area *map)
@@ -658,6 +705,7 @@ static int __init zcore_init(void)
        rc = check_sdias();
        if (rc)
                goto fail;
+       hsa_available = 1;
 
        rc = memcpy_hsa_kernel(&arch, __LC_AR_MODE_ID, 1);
        if (rc)
@@ -714,9 +762,16 @@ static int __init zcore_init(void)
                rc = -ENOMEM;
                goto fail_memmap_file;
        }
-       hsa_available = 1;
+       zcore_hsa_file = debugfs_create_file("hsa", S_IRUSR|S_IWUSR, zcore_dir,
+                                            NULL, &zcore_hsa_fops);
+       if (!zcore_hsa_file) {
+               rc = -ENOMEM;
+               goto fail_reipl_file;
+       }
        return 0;
 
+fail_reipl_file:
+       debugfs_remove(zcore_reipl_file);
 fail_memmap_file:
        debugfs_remove(zcore_memmap_file);
 fail_file:
@@ -733,6 +788,7 @@ static void __exit zcore_exit(void)
        debug_unregister(zcore_dbf);
        sclp_sdias_exit();
        free_page((unsigned long) ipl_block);
+       debugfs_remove(zcore_hsa_file);
        debugfs_remove(zcore_reipl_file);
        debugfs_remove(zcore_memmap_file);
        debugfs_remove(zcore_file);