diff options
author | Michael Holzheu <holzheu@linux.vnet.ibm.com> | 2013-06-06 03:50:21 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-06-26 15:10:12 -0400 |
commit | e9a8f32a98a6099b009ea7da4f299bb5427db126 (patch) | |
tree | 0fc44d45b835859404ace9043c11696f64fea67a /drivers/s390/cio/chsc_sch.c | |
parent | 7a9cc6e18b8fe751a41349b188dd468a8317192a (diff) |
s390/cio: Introduce on-close CHSC IOCTLs
Introduce two new ioctls CHSC_ON_CLOSE_SET and CHSC_ON_CLOSE_REMOVE
that allow to add and remove one CHSC that is unconditionally executed
when the CHSC device node is closed.
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/chsc_sch.c')
-rw-r--r-- | drivers/s390/cio/chsc_sch.c | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 5fe9f8c4b4fb..64cd60063ffc 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c | |||
@@ -29,6 +29,10 @@ | |||
29 | static debug_info_t *chsc_debug_msg_id; | 29 | static debug_info_t *chsc_debug_msg_id; |
30 | static debug_info_t *chsc_debug_log_id; | 30 | static debug_info_t *chsc_debug_log_id; |
31 | 31 | ||
32 | static struct chsc_request *on_close_request; | ||
33 | static struct chsc_async_area *on_close_chsc_area; | ||
34 | static DEFINE_MUTEX(on_close_mutex); | ||
35 | |||
32 | #define CHSC_MSG(imp, args...) do { \ | 36 | #define CHSC_MSG(imp, args...) do { \ |
33 | debug_sprintf_event(chsc_debug_msg_id, imp , ##args); \ | 37 | debug_sprintf_event(chsc_debug_msg_id, imp , ##args); \ |
34 | } while (0) | 38 | } while (0) |
@@ -362,6 +366,68 @@ out_free: | |||
362 | return ret; | 366 | return ret; |
363 | } | 367 | } |
364 | 368 | ||
369 | static int chsc_ioctl_on_close_set(void __user *user_area) | ||
370 | { | ||
371 | char dbf[13]; | ||
372 | int ret; | ||
373 | |||
374 | mutex_lock(&on_close_mutex); | ||
375 | if (on_close_chsc_area) { | ||
376 | ret = -EBUSY; | ||
377 | goto out_unlock; | ||
378 | } | ||
379 | on_close_request = kzalloc(sizeof(*on_close_request), GFP_KERNEL); | ||
380 | if (!on_close_request) { | ||
381 | ret = -ENOMEM; | ||
382 | goto out_unlock; | ||
383 | } | ||
384 | on_close_chsc_area = (void *)get_zeroed_page(GFP_DMA | GFP_KERNEL); | ||
385 | if (!on_close_chsc_area) { | ||
386 | ret = -ENOMEM; | ||
387 | goto out_free_request; | ||
388 | } | ||
389 | if (copy_from_user(on_close_chsc_area, user_area, PAGE_SIZE)) { | ||
390 | ret = -EFAULT; | ||
391 | goto out_free_chsc; | ||
392 | } | ||
393 | ret = 0; | ||
394 | goto out_unlock; | ||
395 | |||
396 | out_free_chsc: | ||
397 | free_page((unsigned long)on_close_chsc_area); | ||
398 | on_close_chsc_area = NULL; | ||
399 | out_free_request: | ||
400 | kfree(on_close_request); | ||
401 | on_close_request = NULL; | ||
402 | out_unlock: | ||
403 | mutex_unlock(&on_close_mutex); | ||
404 | sprintf(dbf, "ocsret:%d", ret); | ||
405 | CHSC_LOG(0, dbf); | ||
406 | return ret; | ||
407 | } | ||
408 | |||
409 | static int chsc_ioctl_on_close_remove(void) | ||
410 | { | ||
411 | char dbf[13]; | ||
412 | int ret; | ||
413 | |||
414 | mutex_lock(&on_close_mutex); | ||
415 | if (!on_close_chsc_area) { | ||
416 | ret = -ENOENT; | ||
417 | goto out_unlock; | ||
418 | } | ||
419 | free_page((unsigned long)on_close_chsc_area); | ||
420 | on_close_chsc_area = NULL; | ||
421 | kfree(on_close_request); | ||
422 | on_close_request = NULL; | ||
423 | ret = 0; | ||
424 | out_unlock: | ||
425 | mutex_unlock(&on_close_mutex); | ||
426 | sprintf(dbf, "ocrret:%d", ret); | ||
427 | CHSC_LOG(0, dbf); | ||
428 | return ret; | ||
429 | } | ||
430 | |||
365 | static int chsc_ioctl_start_sync(void __user *user_area) | 431 | static int chsc_ioctl_start_sync(void __user *user_area) |
366 | { | 432 | { |
367 | struct chsc_sync_area *chsc_area; | 433 | struct chsc_sync_area *chsc_area; |
@@ -842,6 +908,10 @@ static long chsc_ioctl(struct file *filp, unsigned int cmd, | |||
842 | return chsc_ioctl_chpd(argp); | 908 | return chsc_ioctl_chpd(argp); |
843 | case CHSC_INFO_DCAL: | 909 | case CHSC_INFO_DCAL: |
844 | return chsc_ioctl_dcal(argp); | 910 | return chsc_ioctl_dcal(argp); |
911 | case CHSC_ON_CLOSE_SET: | ||
912 | return chsc_ioctl_on_close_set(argp); | ||
913 | case CHSC_ON_CLOSE_REMOVE: | ||
914 | return chsc_ioctl_on_close_remove(); | ||
845 | default: /* unknown ioctl number */ | 915 | default: /* unknown ioctl number */ |
846 | return -ENOIOCTLCMD; | 916 | return -ENOIOCTLCMD; |
847 | } | 917 | } |
@@ -860,6 +930,30 @@ static int chsc_open(struct inode *inode, struct file *file) | |||
860 | 930 | ||
861 | static int chsc_release(struct inode *inode, struct file *filp) | 931 | static int chsc_release(struct inode *inode, struct file *filp) |
862 | { | 932 | { |
933 | char dbf[13]; | ||
934 | int ret; | ||
935 | |||
936 | mutex_lock(&on_close_mutex); | ||
937 | if (!on_close_chsc_area) | ||
938 | goto out_unlock; | ||
939 | init_completion(&on_close_request->completion); | ||
940 | CHSC_LOG(0, "on_close"); | ||
941 | chsc_log_command(on_close_chsc_area); | ||
942 | spin_lock_irq(&chsc_lock); | ||
943 | ret = chsc_async(on_close_chsc_area, on_close_request); | ||
944 | spin_unlock_irq(&chsc_lock); | ||
945 | if (ret == -EINPROGRESS) { | ||
946 | wait_for_completion(&on_close_request->completion); | ||
947 | ret = chsc_examine_irb(on_close_request); | ||
948 | } | ||
949 | sprintf(dbf, "relret:%d", ret); | ||
950 | CHSC_LOG(0, dbf); | ||
951 | free_page((unsigned long)on_close_chsc_area); | ||
952 | on_close_chsc_area = NULL; | ||
953 | kfree(on_close_request); | ||
954 | on_close_request = NULL; | ||
955 | out_unlock: | ||
956 | mutex_unlock(&on_close_mutex); | ||
863 | atomic_inc(&chsc_ready_for_use); | 957 | atomic_inc(&chsc_ready_for_use); |
864 | return 0; | 958 | return 0; |
865 | } | 959 | } |