s390 patches for 2.6.23-rc3
Subsystems (5)
cover s390 patches for 2.6.23-rc3
10 patches for s390. The new vmur driver still has some rough edges but we are getting there. Patch #10 is our solution to the atomic_t vs. volatile problem. As prediced by Linus adding a barrier to atomic_read/atomic_set has close to zero impact to the generated code and adding the barrier to atomic_read/atomic_set forces the compiler to read/write the value to/from memory. This seems to be the most convenient way to solve this problem.
--
blue skies,
Martin.
"Reality continues to ruin my life." - Calvin.
PATCH 1/10 cio: dont forget to set last slot to NULL in ccw_uevent().
From: Cornelia Huck <[email protected]>
---
drivers/s390/cio/device.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/s390/cio/device.c +4 -1
@@ -117,7 +117,10 @@ static int ccw_uevent(struct device *devsnprint_alias (modalias_buf,sizeof (modalias_buf), id,"" ); ret =add_uevent_var (envp, num_envp, &i, buffer, buffer_size, &len,"MODALIAS=%s" , modalias_buf); -return ret; +if (ret) +return ret; + envp[i] =NULL ; +return 0 ; }struct bus_type ccw_bus_type;
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 2/10 cio: change confusing message in cmf.
In reply to Martin SchwidefskyFrom: Cornelia Huck <[email protected]>
cmf currently prints a message that more than 4096 channels are not allowed in basic mode - however, this can only be enforced if cmf was a module (which is no longer possible). It makes much more sense to not check the specified number of channels and just print a message if the block for basic mode could not be allocated (which may happen for any number of specified channels).
---
drivers/s390/cio/cmf.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-)
drivers/s390/cio/cmf.c +3 -7
@@ -594,6 +594,9 @@ alloc_cmb (struct ccw_device *cdev)free_pages ((unsigned long )mem,get_order (size)); }else if (!mem) {/* no luck */ +printk (KERN_WARNING "cio: failed to allocate area " +"for measuring %d subchannels\n" , + cmb_area.num_channels); ret = -ENOMEM ; goto out; }else {
@@ -1279,13 +1282,6 @@ init_cmf(void)case CMF_BASIC : format_string ="basic" ; cmbops = &cmbops_basic; -if (cmb_area.num_channels >4096 || cmb_area.num_channels <1 ) { -printk (KERN_ERR "cio: Basic channel measurement " -"facility can only use 1 to 4096 devices\n" -KERN_ERR "when the cmf driver is built" -" as a loadable module\n" ); -return 1 ; - }break ;case CMF_EXTENDED : format_string ="extended" ;
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 3/10 qdio: fix EQBS handling on CCQ96
In reply to Martin SchwidefskyFrom: Klaus D. Wacker <[email protected]>
QDIO returned from EQBS instruction in any case after return code CCQ=96 was issued regardless whether buffer states for at least one buffer were extracted or not.
This caused FCP devices to hang when running under z/VM and having QIOASSASIST=ON and having high I/O rates.
In order to fix this qdio return code processing of EQBS instruction after CCQ=96 is changed that buffers are returned and if no buffers where extracted the instruction is repeated at once.
---
drivers/s390/cio/qdio.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/s390/cio/qdio.c +2 -0
@@ -195,6 +195,8 @@ qdio_do_eqbs(struct qdio_q *q, unsigned again: ccq =do_eqbs (irq->sch_token, state, q_no, start, cnt); rc =qdio_check_ccq (q, ccq); +if ((ccq ==96 ) && (tmp_cnt != *cnt)) + rc =0 ;if (rc ==1 ) {QDIO_DBF_TEXT5 (1 ,trace,"eqAGAIN" ); goto again;
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 4/10 qdio: Refresh buffer states for IQDIO Asynchronous output queue
In reply to Martin SchwidefskyFrom: Klaus D. Wacker <[email protected]>
Hipersocket Multicast queue works asynchronously. When sending buffers, the buffer state change may happen delayed. The tasklet for checking changes in the outbound queue excluded IQDIO async queues from this process. This created either a hang situation when the queue ran full, or presented a hang situation a interface close time.
The tasklet processing is changed to include IQDIO async queues when requesting buffer state refresh.
---
drivers/s390/cio/qdio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/s390/cio/qdio.c +2 -1
@@ -742,7 +742,8 @@ qdio_get_outbound_buffer_frontier(struct first_not_to_check=f+qdio_min (atomic_read (&q->number_of_buffers_used), (QDIO_MAX_BUFFERS_PER_Q -1 )); -if ((!q->is_iqdio_q)&&(!q->hydra_gives_outbound_pcis)) +if (((!q->is_iqdio_q) && (!q->hydra_gives_outbound_pcis)) || + (q->queue_type ==QDIO_IQDIO_QFMT_ASYNCH ))SYNC_MEMORY ; check_next:
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 5/10 vmur: fix diag14 exceptions with addresses > 2GB.
In reply to Martin SchwidefskyFrom: Michael Holzheu <[email protected]>
There are several s390 diagnose calls, which must be executed below the 2GB memory boundary. In order to enforce this, those diagnoses must be compiled into the kernel. Currently diag 14 can be called within the vmur kernel module from addresses above 2GB. This leads to specification exceptions. This patch moves diag10, diag14 and diag210 into the new diag.c file.
---
arch/s390/kernel/Makefile | 2 arch/s390/kernel/diag.c | 102 +++++++++++++++++++++++++++++++++++++++++ arch/s390/kernel/s390_ksyms.c | 1 arch/s390/mm/cmm.c | 1 arch/s390/mm/init.c | 17 ------ drivers/s390/block/dasd_diag.c | 1 drivers/s390/char/raw3270.c | 1 drivers/s390/char/vmur.c | 32 +----------- drivers/s390/cio/device_id.c | 48 ------------------- include/asm-s390/cio.h | 15 ------ include/asm-s390/diag.h | 39 +++++++++++++++ include/asm-s390/pgalloc.h | 2 12 files changed, 150 insertions(+), 111 deletions(-)
arch/s390/kernel/diag.c new file +102 -0
@@ -0,0 +1,102 @@ +/* +* Implementation of s390 diagnose codes +* +* Copyright IBM Corp. 2007 +* Author(s): Michael Holzheu <[email protected]> +*/ + +#include <linux/module.h> +#include <asm/diag.h> + +/* +* Diagnose 10: Release pages +*/ +void diag10 (unsigned long addr) +{ +if (addr >=0x7ff00000 ) +return ; + asmvolatile ( +#ifdef CONFIG_64BIT + " sam31\n" + " diag %0,%0,0x10\n" + "0: sam64\n" +#else + " diag %0,%0,0x10\n" + "0:\n" +#endif + EX_TABLE(0b, 0b) + : : "a" (addr)); +} +EXPORT_SYMBOL (diag10); + +/* +* Diagnose 14: Input spool file manipulation +*/ +int diag14 (unsigned long rx,unsigned long ry1,unsigned long subcode) +{ + register unsigned long _ry1 asm("2") = ry1; + register unsigned long _ry2 asm("3") = subcode; +int rc =0 ; + + asmvolatile ( +#ifdef CONFIG_64BIT + " sam31\n" + " diag %2,2,0x14\n" + " sam64\n" +#else +" diag %2,2,0x14\n" +#endif +" ipm %0\n" +" srl %0,28\n" + :"=d" (rc),"+d" (_ry2) + :"d" (rx),"d" (_ry1) + :"cc" ); + +return rc; +} +EXPORT_SYMBOL (diag14); + +/* +* Diagnose 210: Get information about a virtual device +*/ +int diag210 (struct diag210 *addr) +{ +/* +* diag 210 needs its data below the 2GB border, so we +* use a static data area to be sure +*/ +static struct diag210 diag210_tmp; +static DEFINE_SPINLOCK (diag210_lock); +unsigned long flags; +int ccode; + +spin_lock_irqsave (&diag210_lock, flags); + diag210_tmp = *addr; + +#ifdef CONFIG_64BIT + asm volatile( + " lhi %0,-1\n" + " sam31\n" + " diag %1,0,0x210\n" + "0: ipm %0\n" + " srl %0,28\n" + "1: sam64\n" + EX_TABLE(0b, 1b) + : "=&d" (ccode) : "a" (&diag210_tmp) : "cc", "memory"); +#else + asm volatile( + " lhi %0,-1\n" + " diag %1,0,0x210\n" + "0: ipm %0\n" + " srl %0,28\n" + "1:\n" + EX_TABLE(0b, 1b) + : "=&d" (ccode) : "a" (&diag210_tmp) : "cc", "memory"); +#endif + + *addr = diag210_tmp; +spin_unlock_irqrestore (&diag210_lock, flags); + + return ccode; +} +EXPORT_SYMBOL (diag210);
arch/s390/kernel/Makefile +1 -1
@@ -6,7 +6,7 @@ EXTRA_AFLAGS := -traditional obj-y := bitmap.o traps.o time.o process.o base.o early.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ - semaphore.o s390_ext.o debug.o irq.o ipl.o dis.o + semaphore.o s390_ext.o debug.o irq.o ipl.o dis.o diag.o obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
arch/s390/kernel/s390_ksyms.c +0 -1
@@ -25,7 +25,6 @@ EXPORT_SYMBOL(_oi_bitmap);EXPORT_SYMBOL (_ni_bitmap);EXPORT_SYMBOL (_zb_findmap);EXPORT_SYMBOL (_sb_findmap); -EXPORT_SYMBOL (diag10);/* * semaphore ops
arch/s390/mm/cmm.c +1 -0
@@ -20,6 +20,7 @@#include <asm/pgalloc.h> #include <asm/uaccess.h> +#include <asm/diag.h> static char *sender ="VMRMSVM" ;module_param (sender, charp,0400 );
arch/s390/mm/init.c +0 -17
@@ -42,23 +42,6 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_ga pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE))); char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); -void diag10 (unsigned long addr) -{ -if (addr >=0x7ff00000 ) -return ; - asmvolatile ( -#ifdef CONFIG_64BIT - " sam31\n" - " diag %0,%0,0x10\n" - "0: sam64\n" -#else - " diag %0,%0,0x10\n" - "0:\n" -#endif - EX_TABLE(0b,0b) - : : "a" (addr)); -} -void show_mem (void ) {int i, total =0 , reserved =0 ;
drivers/s390/block/dasd_diag.c +1 -0
@@ -24,6 +24,7 @@#include <asm/s390_ext.h> #include <asm/todclk.h> #include <asm/vtoc.h> +#include <asm/diag.h> #include "dasd_int.h" #include "dasd_diag.h"
drivers/s390/char/raw3270.c +1 -0
@@ -21,6 +21,7 @@#include <asm/ccwdev.h> #include <asm/cio.h> #include <asm/ebcdic.h> +#include <asm/diag.h> #include "raw3270.h"
drivers/s390/char/vmur.c +4 -28
@@ -14,6 +14,7 @@#include <asm/cio.h> #include <asm/ccwdev.h> #include <asm/debug.h> +#include <asm/diag.h> #include "vmur.h"
@@ -379,31 +380,6 @@ static ssize_t ur_write(struct file *filreturn do_write (urf->urd, udata, count, urf->dev_reclen, ppos); } -static int do_diag_14 (unsigned long rx,unsigned long ry1, -unsigned long subcode) -{ - register unsigned long _ry1 asm("2") = ry1; - register unsigned long _ry2 asm("3") = subcode; -int rc =0 ; - - asmvolatile ( -#ifdef CONFIG_64BIT - " sam31\n" - " diag %2,2,0x14\n" - " sam64\n" -#else -" diag %2,2,0x14\n" -#endif -" ipm %0\n" -" srl %0,28\n" - :"=d" (rc),"+d" (_ry2) - :"d" (rx),"d" (_ry1) - :"cc" ); - -TRACE ("diag 14: subcode=0x%lx, cc=%i\n" , subcode, rc); -return rc; -} -/* * diagnose code 0x14 subcode 0x0028 - position spool file to designated * record
@@ -415,7 +391,7 @@ static int diag_position_to_record(int d {int cc; - cc =do_diag_14 (record, devno,0x28 ); + cc =diag14 (record, devno,0x28 );switch (cc) {case 0 :return 0 ;
@@ -440,7 +416,7 @@ static int diag_read_file(int devno, cha {int cc; - cc =do_diag_14 ((unsigned long ) buf, devno,0x00 ); + cc =diag14 ((unsigned long ) buf, devno,0x00 );switch (cc) {case 0 :return 0 ;
@@ -533,7 +509,7 @@ static int diag_read_next_file_info(stru {int cc; - cc =do_diag_14 ((unsigned long ) buf, spid,0xfff ); + cc =diag14 ((unsigned long ) buf, spid,0xfff );switch (cc) {case 0 :return 0 ;
drivers/s390/cio/device_id.c +1 -47
63 lines not on this page · raw message
include/asm-s390/cio.h +0 -15
@@ -258,19 +258,6 @@ struct ciw {/* Sick revalidation of device. */ #define CIO_REVALIDATE 0x0008 -struct diag210 { -__u16 vrdcdvno :16 ;/* device number (input) */ -__u16 vrdclen :16 ;/* data block length (input) */ -__u32 vrdcvcla :8 ;/* virtual device class (output) */ -__u32 vrdcvtyp :8 ;/* virtual device type (output) */ -__u32 vrdcvsta :8 ;/* virtual device status (output) */ -__u32 vrdcvfla :8 ;/* virtual device flags (output) */ -__u32 vrdcrccl :8 ;/* real device class (output) */ -__u32 vrdccrty :8 ;/* real device type (output) */ -__u32 vrdccrmd :8 ;/* real device model (output) */ -__u32 vrdccrft :8 ;/* real device feature (output) */ -} __attribute__ ((packed,aligned (4 ))); -struct ccw_dev_id {u8 ssid;u16 devno;
@@ -285,8 +272,6 @@ static inline int ccw_dev_id_is_equal(streturn 0 ; } -extern int diag210 (struct diag210 *addr); -extern void wait_cons_dev (void );extern void css_schedule_reprobe (void );
include/asm-s390/diag.h new file +39 -0
@@ -0,0 +1,39 @@ +/* +* s390 diagnose functions +* +* Copyright IBM Corp. 2007 +* Author(s): Michael Holzheu <[email protected]> +*/ + +#ifndef _ASM_S390_DIAG_H +#define _ASM_S390_DIAG_H + +/* +* Diagnose 10: Release pages +*/ +extern void diag10 (unsigned long addr); + +/* +* Diagnose 14: Input spool file manipulation +*/ +extern int diag14 (unsigned long rx,unsigned long ry1,unsigned long subcode); + +/* +* Diagnose 210: Get information about a virtual device +*/ +struct diag210 { +u16 vrdcdvno;/* device number (input) */ +u16 vrdclen;/* data block length (input) */ +u8 vrdcvcla;/* virtual device class (output) */ +u8 vrdcvtyp;/* virtual device type (output) */ +u8 vrdcvsta;/* virtual device status (output) */ +u8 vrdcvfla;/* virtual device flags (output) */ +u8 vrdcrccl;/* real device class (output) */ +u8 vrdccrty;/* real device type (output) */ +u8 vrdccrmd;/* real device model (output) */ +u8 vrdccrft;/* real device feature (output) */ +} __attribute__((packed,aligned (4 ))); + +extern int diag210 (struct diag210 *addr); + +#endif /* _ASM_S390_DIAG_H */
include/asm-s390/pgalloc.h +0 -2
@@ -19,8 +19,6 @@#define check_pgt_cache () do {} while (0) -extern void diag10 (unsigned long addr); -/* * Page allocation orders. */
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 6/10 vmur: fix reference counting for vmur device structure
In reply to Martin SchwidefskyFrom: Michael Holzheu <[email protected]>
When a vmur device is removed due to a detach of the device, currently the ur device structure is freed. Unfortunately it can happen, that there is still a user of the device structure, when the character device is open during the detach process. To fix this, reference counting for the vmur structure is introduced.
In addition to that, the online, offline, probe and remove functions are serialized now using a global mutex.
---
drivers/s390/char/vmur.c | 218 ++++++++++++++++++++++++++++++++++------------- drivers/s390/char/vmur.h | 1 2 files changed, 161 insertions(+), 58 deletions(-)
drivers/s390/char/vmur.c +160 -58
@@ -69,8 +69,26 @@ static struct ccw_driver ur_driver = { .set_offline = ur_set_offline, }; +static DEFINE_MUTEX (vmur_mutex); +/* * Allocation, freeing, getting and putting of urdev structures +* +* Each ur device (urd) contains a reference to its corresponding ccw device +* (cdev) using the urd->cdev pointer. Each ccw device has a reference to the +* ur device using the cdev->dev.driver_data pointer. +* +* urd references: +* - ur_probe gets a urd reference, ur_remove drops the reference +* (cdev->dev.driver_data) +* - ur_open gets a urd reference, ur_relase drops the reference +* (urf->urd) +* +* cdev references: +* - urdev_alloc get a cdev reference (urd->cdev) +* - urdev_free drops the cdev reference (urd->cdev) +* +* Setting and clearing of cdev->dev.driver_data is protected by the ccwdev lock */ static struct urdev *urdev_alloc (struct ccw_device *cdev) {
@@ -79,42 +97,61 @@ static struct urdev *urdev_alloc(struct urd =kzalloc (sizeof (struct urdev ),GFP_KERNEL );if (!urd)return NULL ; - urd->cdev = cdev; urd->reclen = cdev->id.driver_info;ccw_device_get_id (cdev, &urd->dev_id);mutex_init (&urd->io_mutex);mutex_init (&urd->open_mutex); +atomic_set (&urd->ref_count,1 ); + urd->cdev = cdev; +get_device (&cdev->dev);return urd; }static void urdev_free (struct urdev *urd) { +TRACE ("urdev_free: %p\n" , urd); +if (urd->cdev) +put_device (&urd->cdev->dev);kfree (urd); } -/* -* This is how the character device driver gets a reference to a -* ur device. When this call returns successfully, a reference has -* been taken (by get_device) on the underlying kobject. The recipient -* of this urdev pointer must eventually drop it with urdev_put(urd) -* which does the corresponding put_device(). -*/ +static void urdev_get (struct urdev *urd) +{ +atomic_inc (&urd->ref_count); +} + +static struct urdev *urdev_get_from_cdev (struct ccw_device *cdev) +{ +struct urdev *urd; +unsigned long flags; + +spin_lock_irqsave (get_ccwdev_lock (cdev), flags); + urd = cdev->dev.driver_data; +if (urd) +urdev_get (urd); +spin_unlock_irqrestore (get_ccwdev_lock (cdev), flags); +return urd; +} +static struct urdev *urdev_get_from_devno (u16 devno) {char bus_id[16 ];struct ccw_device *cdev; +struct urdev *urd;sprintf (bus_id,"0.0.%04x" , devno); cdev =get_ccwdev_by_busid (&ur_driver, bus_id);if (!cdev)return NULL ; - -return cdev->dev.driver_data; + urd =urdev_get_from_cdev (cdev); +put_device (&cdev->dev); +return urd; }static void urdev_put (struct urdev *urd) { -put_device (&urd->cdev->dev); +if (atomic_dec_and_test (&urd->ref_count)) +urdev_free (urd); }/*
@@ -246,6 +283,7 @@ static void ur_int_handler(struct ccw_dereturn ; } urd = cdev->dev.driver_data; +BUG_ON (!urd);/* On special conditions irb is an error pointer */ if (IS_ERR (irb)) urd->io_request_rc =PTR_ERR (irb);
@@ -263,9 +301,15 @@ static void ur_int_handler(struct ccw_destatic ssize_t ur_attr_reclen_show (struct device *dev,struct device_attribute *attr,char *buf) { -struct urdev *urd = dev->driver_data; +struct urdev *urd; +int rc; -return sprintf (buf,"%zu\n" , urd->reclen); + urd =urdev_get_from_cdev (to_ccwdev (dev)); +if (!urd) +return -ENODEV ; + rc =sprintf (buf,"%zu\n" , urd->reclen); +urdev_put (urd); +return rc; } static DEVICE_ATTR(reclen, 0444, ur_attr_reclen_show, NULL);
@@ -726,64 +770,63 @@ static struct file_operations ur_fops =/* * ccw_device infrastructure: -* ur_probe gets its own ref to the device (i.e. get_device), -* creates the struct urdev, the device attributes, sets up -* the interrupt handler and validates the virtual unit record device. -* ur_remove removes the device attributes, frees the struct urdev -* and drops (put_device) the ref to the device we got in ur_probe. +* ur_probe creates the struct urdev (with refcount = 1), the device +* attributes, sets up the interrupt handler and validates the virtual +* unit record device. +* ur_remove removes the device attributes and drops the reference to +* struct urdev. +* +* ur_probe, ur_remove, ur_set_online and ur_set_offline are serialized +* by the vmur_mutex lock. +* +* urd->char_device is used as indication that the online function has +* been completed successfully. */ static int ur_probe (struct ccw_device *cdev) {struct urdev *urd;int rc; -TRACE ("ur_probe: cdev=%p state=%d\n" , cdev, *(int *) cdev->private); - -if (!get_device (&cdev->dev)) -return -ENODEV ; +TRACE ("ur_probe: cdev=%p\n" , cdev); +mutex_lock (&vmur_mutex); urd =urdev_alloc (cdev);if (!urd) { rc = -ENOMEM ; - goto fail; + goto fail_unlock; } + rc =ur_create_attributes (&cdev->dev);if (rc) { rc = -ENOMEM ; - goto fail; + goto fail_urdev_put; } - cdev->dev.driver_data = urd; cdev->handler = ur_int_handler;/* validate virtual unit record device */ urd->class =get_urd_class (urd);if (urd->class <0 ) { rc = urd->class; - goto fail; + goto fail_remove_attr; }if ((urd->class !=DEV_CLASS_UR_I ) && (urd->class !=DEV_CLASS_UR_O )) { rc = -ENOTSUPP ; - goto fail; + goto fail_remove_attr; } +spin_lock_irq (get_ccwdev_lock (cdev)); + cdev->dev.driver_data = urd; +spin_unlock_irq (get_ccwdev_lock (cdev)); +mutex_unlock (&vmur_mutex);return 0 ; -fail: -urdev_free (urd); -put_device (&cdev->dev); -return rc; -} - -static void ur_remove (struct ccw_device *cdev) -{ -struct urdev *urd = cdev->dev.driver_data; - -TRACE ("ur_remove\n" ); -if (cdev->online) -ur_set_offline (cdev); +fail_remove_attr:ur_remove_attributes (&cdev->dev); -urdev_free (urd); -put_device (&cdev->dev); +fail_urdev_put: +urdev_put (urd); +fail_unlock: +mutex_unlock (&vmur_mutex); +return rc; }static int ur_set_online (struct ccw_device *cdev)
@@ -792,20 +835,29 @@ static int ur_set_online(struct ccw_deviint minor, major, rc;char node_id[16 ]; -TRACE ("ur_set_online: cdev=%p state=%d\n" , cdev, - *(int *) cdev->private); +TRACE ("ur_set_online: cdev=%p\n" , cdev); -if (!try_module_get (ur_driver.owner)) -return -EINVAL ; +mutex_lock (&vmur_mutex); + urd =urdev_get_from_cdev (cdev); +if (!urd) { +/* ur_remove already deleted our urd */ + rc = -ENODEV ; + goto fail_unlock; + } + +if (urd->char_device) { +/* Another ur_set_online was faster */ + rc = -EBUSY ; + goto fail_urdev_put; + } - urd = (struct urdev *) cdev->dev.driver_data; minor = urd->dev_id.devno; major =MAJOR (ur_first_dev_maj_min); urd->char_device =cdev_alloc ();if (!urd->char_device) { rc = -ENOMEM ; - goto fail_module_put; + goto fail_urdev_put; }cdev_init (urd->char_device, &ur_fops);
@@ -834,29 +886,79 @@ static int ur_set_online(struct ccw_deviTRACE ("ur_set_online: device_create rc=%d\n" , rc); goto fail_free_cdev; } - +urdev_put (urd); +mutex_unlock (&vmur_mutex);return 0 ; fail_free_cdev:cdev_del (urd->char_device); -fail_module_put: -module_put (ur_driver.owner); - + urd->char_device =NULL ; +fail_urdev_put: +urdev_put (urd); +fail_unlock: +mutex_unlock (&vmur_mutex);return rc; } -static int ur_set_offline (struct ccw_device *cdev) +static int ur_set_offline_force (struct ccw_device *cdev,int force) {struct urdev *urd; +int rc; -TRACE ("ur_set_offline: cdev=%p cdev->private=%p state=%d\n" , - cdev, cdev->private, *(int *) cdev->private); - urd = (struct urdev *) cdev->dev.driver_data; +TRACE ("ur_set_offline: cdev=%p\n" , cdev); + urd =urdev_get_from_cdev (cdev); +if (!urd) +/* ur_remove already deleted our urd */ +return -ENODEV ; +if (!urd->char_device) { +/* Another ur_set_offline was faster */ + rc = -EBUSY ; + goto fail_urdev_put; + } +if (!force && (atomic_read (&urd->ref_count) >2 )) { +/* There is still a user of urd (e.g. ur_open) */ +TRACE ("ur_set_offline: BUSY\n" ); + rc = -EBUSY ; + goto fail_urdev_put; + }device_destroy (vmur_class, urd->char_device->dev);cdev_del (urd->char_device); -module_put (ur_driver.owner); + urd->char_device =NULL ; + rc =0 ; -return 0 ; +fail_urdev_put: +urdev_put (urd); +return rc; +} + +static int ur_set_offline (struct ccw_device *cdev) +{ +int rc; + +mutex_lock (&vmur_mutex); + rc =ur_set_offline_force (cdev,0 ); +mutex_unlock (&vmur_mutex); +return rc; +} + +static void ur_remove (struct ccw_device *cdev) +{ +unsigned long flags; + +TRACE ("ur_remove\n" ); + +mutex_lock (&vmur_mutex); + +if (cdev->online) +ur_set_offline_force (cdev,1 ); +ur_remove_attributes (&cdev->dev); + +spin_lock_irqsave (get_ccwdev_lock (cdev), flags); +urdev_put (cdev->dev.driver_data); + cdev->dev.driver_data =NULL ; +spin_unlock_irqrestore (get_ccwdev_lock (cdev), flags); + +mutex_unlock (&vmur_mutex); }/*
drivers/s390/char/vmur.h +1 -0
@@ -70,6 +70,7 @@ struct urdev {size_t reclen;/* Record length for *write* CCWs */ int class;/* VM device class */ int io_request_rc;/* return code from I/O request */ +atomic_t ref_count;/* reference counter */ };/*
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 7/10 disassembler: fix b2 opcodes like srst, bsg, and others
In reply to Martin SchwidefskyFrom: Christian Borntraeger <[email protected]>
The instruction table for b2 opcodes was missing an opfrag value for the cpya instruction. All instructions specified after cpya were not considered by the disassembler. The fix is simple and obvious - add the opfrag field to the cpya instruction.
---
arch/s390/kernel/dis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/kernel/dis.c +1 -1
@@ -577,7 +577,7 @@ static struct insn opcode_b2[] = { { "esta", 0x4a, INSTR_RRE_RR }, { "lura", 0x4b, INSTR_RRE_RR }, { "tar", 0x4c, INSTR_RRE_AR }, - { "cpya", INSTR_RRE_AA }, + { "cpya", 0x4d, INSTR_RRE_AA }, { "sar", 0x4e, INSTR_RRE_AR }, { "ear", 0x4f, INSTR_RRE_RA }, { "csp", 0x50, INSTR_RRE_RR },
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 8/10 hypfs: inode corruption due to missing locking
In reply to Martin SchwidefskyFrom: Michael Holzheu <[email protected]>
hypfs removes the whole hypfs directory tree and creates a new one, when a process triggers an update by writing to the "update" attribute. When removing and creating files, it is necessary to lock the inode of the parent directory where the files live. Currently hypfs does not lock the parent inode, which can lead to inode corruption. This patch:
* Introduces correct locking
* Fixes i_nlink reference counting for inodes, when creating directories
* Adds info printk, when hypfs filesystem has been mounted
---
arch/s390/hypfs/inode.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-)
arch/s390/hypfs/inode.c +25 -8
@@ -60,17 +60,28 @@ static void hypfs_add_dentry(struct dent hypfs_last_dentry = dentry; } +static inline int hypfs_positive (struct dentry *dentry) +{ +return dentry->d_inode && !d_unhashed (dentry); +} +static void hypfs_remove (struct dentry *dentry) {struct dentry *parent; parent = dentry->d_parent; -if (S_ISDIR (dentry->d_inode->i_mode)) -simple_rmdir (parent->d_inode, dentry); -else -simple_unlink (parent->d_inode, dentry); +if (!parent || !parent->d_inode) +return ; +mutex_lock (&parent->d_inode->i_mutex); +if (hypfs_positive (dentry)) { +if (S_ISDIR (dentry->d_inode->i_mode)) +simple_rmdir (parent->d_inode, dentry); +else +simple_unlink (parent->d_inode, dentry); + }d_delete (dentry);dput (dentry); +mutex_unlock (&parent->d_inode->i_mutex); }static void hypfs_delete_tree (struct dentry *root)
@@ -315,6 +326,7 @@ static int hypfs_fill_super(struct super }hypfs_update_update (sb); sb->s_root = root_dentry; +printk (KERN_INFO "hypfs: Hypervisor filesystem mounted\n" );return 0 ; err_tree:
@@ -356,13 +368,17 @@ static struct dentry *hypfs_create_file( qname.name = name; qname.len =strlen (name); qname.hash =full_name_hash (name, qname.len); +mutex_lock (&parent->d_inode->i_mutex); dentry =lookup_one_len (name, parent,strlen (name)); -if (IS_ERR (dentry)) -return ERR_PTR (-ENOMEM ); +if (IS_ERR (dentry)) { + dentry =ERR_PTR (-ENOMEM ); + goto fail; + } inode =hypfs_make_inode (sb, mode);if (!inode) {dput (dentry); -return ERR_PTR (-ENOMEM ); + dentry =ERR_PTR (-ENOMEM ); + goto fail; }if (mode &S_IFREG ) { inode->i_fop = &hypfs_file_ops;
@@ -379,6 +395,8 @@ static struct dentry *hypfs_create_file( inode->i_private = data;d_instantiate (dentry, inode);dget (dentry); +fail: +mutex_unlock (&parent->d_inode->i_mutex);return dentry; }
@@ -391,7 +409,6 @@ struct dentry *hypfs_mkdir(struct super_if (IS_ERR (dentry))return dentry;hypfs_add_dentry (dentry); - parent->d_inode->i_nlink++;return dentry; }
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 9/10 kprobes: fix instruction length calculation
In reply to Martin SchwidefskyFrom: David Wilder <[email protected]>
Placing a kprobe on "bc" instruction (s390/s390x) can cause an oops. The instruction length is encoded into the first two bits of the s390 instruction. Kprobe is incorrectly computing the instruction length. The instruction length is used for determining what type of "fix-up" is needed for conditional branch instruction. The problem can bee seen by placing a kprobe on a "bc" instruction that will not branch. The results is that Kprobe incorrectly computes the new instruction pointer (psw.addr) after single stepping the instruction. The problem is corrected with this patch.
---
arch/s390/kernel/kprobes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/kernel/kprobes.c +1 -1
@@ -85,7 +85,7 @@ void __kprobes get_instruction_type(stru ainsn->reg = (*ainsn->insn &0xf0 ) >>4 ;/* save the instruction length (pop 5-5) in bytes */ -switch (*(__u8 *) (ainsn->insn) >>4 ) { +switch (*(__u8 *) (ainsn->insn) >>6 ) {case 0 : ainsn->ilen =2 ;break ;
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 10/10 Change atomic_read/set to inline functions with barrier semantics.
In reply to Martin SchwidefskyFrom: Heiko Carstens <[email protected]>
After doing some tests this seems to be the best variant for s390 and should be correct as well. With gcc 4.2.1 we get the following kernel image sizes using the default configuration:
atomic_t type volatile, atomic_read/set defines 5311824 bytes atomic_t type int, atomic_read/set defines 5270864 bytes atomic_t type int, atomic_read/set inline asm 5279056 bytes
atomic_t type int, atomic_read/set inline barrier 5270864 bytes
---
include/asm-s390/atomic.h | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-)
include/asm-s390/atomic.h +22 -4
@@ -67,8 +67,17 @@ typedef struct {#endif /* __GNUC__ */ -#define atomic_read (v) ((v)->counter) -#define atomic_set (v,i) (((v)->counter) = (i)) +static inline int atomic_read (const atomic_t *v) +{ +barrier (); +return v->counter; +} + +static inline void atomic_set (atomic_t *v,int i) +{ + v->counter = i; +barrier (); +}static __inline__int atomic_add_return (int i,atomic_t * v) {
@@ -182,8 +191,17 @@ typedef struct {#endif /* __GNUC__ */ -#define atomic64_read (v) ((v)->counter) -#define atomic64_set (v,i) (((v)->counter) = (i)) +static inline long long atomic64_read (const atomic64_t *v) +{ +barrier (); +return v->counter; +} + +static inline void atomic64_set (atomic64_t *v,long long i) +{ + v->counter = i; +barrier (); +}static __inline__long long atomic64_add_return (long long i,atomic64_t * v) {
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.