Skip to content

Commit 3043a4b

Browse files
author
Fox Snowpatch
committed
1 parent 182544a commit 3043a4b

2 files changed

Lines changed: 97 additions & 85 deletions

File tree

arch/powerpc/platforms/pseries/papr-hvpipe.c

Lines changed: 97 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -190,33 +190,34 @@ static int hvpipe_rtas_recv_msg(char __user *buf, int size)
190190
return -ENOMEM;
191191
}
192192

193-
ret = rtas_ibm_receive_hvpipe_msg(work_area, &srcID,
194-
&bytes_written);
195-
if (!ret) {
196-
/*
197-
* Recv HVPIPE RTAS is successful.
198-
* When releasing FD or no one is waiting on the
199-
* specific source, issue recv HVPIPE RTAS call
200-
* so that pipe is not blocked - this func is called
201-
* with NULL buf.
202-
*/
203-
if (buf) {
204-
if (size < bytes_written) {
205-
pr_err("Received the payload size = %d, but the buffer size = %d\n",
206-
bytes_written, size);
207-
bytes_written = size;
208-
}
209-
ret = copy_to_user(buf,
210-
rtas_work_area_raw_buf(work_area),
211-
bytes_written);
212-
if (!ret)
213-
ret = bytes_written;
214-
}
215-
} else {
216-
pr_err("ibm,receive-hvpipe-msg failed with %d\n",
217-
ret);
193+
/*
194+
* Recv HVPIPE RTAS is successful.
195+
* When releasing FD or no one is waiting on the
196+
* specific source, issue recv HVPIPE RTAS call
197+
* so that pipe is not blocked - this func is called
198+
* with NULL buf.
199+
*/
200+
ret = rtas_ibm_receive_hvpipe_msg(work_area, &srcID, &bytes_written);
201+
if (ret) {
202+
pr_err("ibm,receive-hvpipe-msg failed with %d\n", ret);
203+
goto out;
218204
}
219205

206+
if (!buf)
207+
goto out;
208+
209+
if (size < bytes_written) {
210+
pr_err("Received the payload size = %d, but the buffer size = %d\n",
211+
bytes_written, size);
212+
bytes_written = size;
213+
}
214+
215+
if (copy_to_user(buf, rtas_work_area_raw_buf(work_area), bytes_written))
216+
ret = -EFAULT;
217+
else
218+
ret = bytes_written;
219+
220+
out:
220221
rtas_work_area_free(work_area);
221222
return ret;
222223
}
@@ -327,8 +328,8 @@ static ssize_t papr_hvpipe_handle_read(struct file *file,
327328
{
328329

329330
struct hvpipe_source_info *src_info = file->private_data;
330-
struct papr_hvpipe_hdr hdr;
331-
long ret;
331+
struct papr_hvpipe_hdr hdr = {};
332+
ssize_t ret = 0;
332333

333334
/*
334335
* Return -ENXIO during migration
@@ -376,7 +377,7 @@ static ssize_t papr_hvpipe_handle_read(struct file *file,
376377

377378
ret = copy_to_user(buf, &hdr, HVPIPE_HDR_LEN);
378379
if (ret)
379-
return ret;
380+
return -EFAULT;
380381

381382
/*
382383
* Message event has payload, so get the payload with
@@ -385,19 +386,23 @@ static ssize_t papr_hvpipe_handle_read(struct file *file,
385386
if (hdr.flags & HVPIPE_MSG_AVAILABLE) {
386387
ret = hvpipe_rtas_recv_msg(buf + HVPIPE_HDR_LEN,
387388
size - HVPIPE_HDR_LEN);
388-
if (ret > 0) {
389+
/*
390+
* Always clear MSG_AVAILABLE once the RTAS call has drained
391+
* the message, regardless of whether copy_to_user succeeded.
392+
*/
393+
if (ret >= 0 || ret == -EFAULT)
389394
src_info->hvpipe_status &= ~HVPIPE_MSG_AVAILABLE;
390-
ret += HVPIPE_HDR_LEN;
391-
}
392395
} else if (hdr.flags & HVPIPE_LOST_CONNECTION) {
393396
/*
394397
* Hypervisor is closing the pipe for the specific
395398
* source. So notify user space.
396399
*/
397400
src_info->hvpipe_status &= ~HVPIPE_LOST_CONNECTION;
398-
ret = HVPIPE_HDR_LEN;
399401
}
400402

403+
if (ret >= 0)
404+
ret += HVPIPE_HDR_LEN;
405+
401406
return ret;
402407
}
403408

@@ -444,27 +449,27 @@ static int papr_hvpipe_handle_release(struct inode *inode,
444449
struct file *file)
445450
{
446451
struct hvpipe_source_info *src_info;
452+
unsigned long flags;
447453

448454
/*
449455
* Hold the lock, remove source from src_list, reset the
450456
* hvpipe status and release the lock to prevent any race
451457
* with message event IRQ.
452458
*/
453-
spin_lock(&hvpipe_src_list_lock);
459+
spin_lock_irqsave(&hvpipe_src_list_lock, flags);
454460
src_info = file->private_data;
455461
list_del(&src_info->list);
456462
file->private_data = NULL;
463+
spin_unlock_irqrestore(&hvpipe_src_list_lock, flags);
457464
/*
458465
* If the pipe for this specific source has any pending
459466
* payload, issue recv HVPIPE RTAS so that pipe will not
460467
* be blocked.
461468
*/
462469
if (src_info->hvpipe_status & HVPIPE_MSG_AVAILABLE) {
463470
src_info->hvpipe_status = 0;
464-
spin_unlock(&hvpipe_src_list_lock);
465471
hvpipe_rtas_recv_msg(NULL, 0);
466-
} else
467-
spin_unlock(&hvpipe_src_list_lock);
472+
}
468473

469474
kfree(src_info);
470475
return 0;
@@ -479,50 +484,53 @@ static const struct file_operations papr_hvpipe_handle_ops = {
479484

480485
static int papr_hvpipe_dev_create_handle(u32 srcID)
481486
{
482-
struct hvpipe_source_info *src_info __free(kfree) = NULL;
483-
484-
spin_lock(&hvpipe_src_list_lock);
485-
/*
486-
* Do not allow more than one process communicates with
487-
* each source.
488-
*/
489-
src_info = hvpipe_find_source(srcID);
490-
if (src_info) {
491-
spin_unlock(&hvpipe_src_list_lock);
492-
pr_err("pid(%d) is already using the source(%d)\n",
493-
src_info->tsk->pid, srcID);
494-
return -EALREADY;
495-
}
496-
spin_unlock(&hvpipe_src_list_lock);
487+
struct hvpipe_source_info *src_info;
488+
int fd;
489+
unsigned long flags;
497490

498491
src_info = kzalloc_obj(*src_info, GFP_KERNEL_ACCOUNT);
499492
if (!src_info)
500493
return -ENOMEM;
501494

502495
src_info->srcID = srcID;
503-
src_info->tsk = current;
504496
init_waitqueue_head(&src_info->recv_wqh);
505497

506-
FD_PREPARE(fdf, O_RDONLY | O_CLOEXEC,
507-
anon_inode_getfile("[papr-hvpipe]", &papr_hvpipe_handle_ops,
508-
(void *)src_info, O_RDWR));
509-
if (fdf.err)
510-
return fdf.err;
511-
512-
retain_and_null_ptr(src_info);
513-
spin_lock(&hvpipe_src_list_lock);
514498
/*
515-
* If two processes are executing ioctl() for the same
516-
* source ID concurrently, prevent the second process to
517-
* acquire FD.
499+
* Do not allow more than one process communicates with
500+
* each source.
518501
*/
502+
spin_lock_irqsave(&hvpipe_src_list_lock, flags);
519503
if (hvpipe_find_source(srcID)) {
520-
spin_unlock(&hvpipe_src_list_lock);
504+
spin_unlock_irqrestore(&hvpipe_src_list_lock, flags);
505+
pr_err("pid(%s:%d) could not get the source(%d)\n",
506+
current->comm, task_pid_nr(current), srcID);
507+
kfree(src_info);
521508
return -EALREADY;
522509
}
523510
list_add(&src_info->list, &hvpipe_src_list);
524-
spin_unlock(&hvpipe_src_list_lock);
525-
return fd_publish(fdf);
511+
spin_unlock_irqrestore(&hvpipe_src_list_lock, flags);
512+
513+
fd = FD_ADD(O_RDONLY | O_CLOEXEC,
514+
anon_inode_getfile("[papr-hvpipe]", &papr_hvpipe_handle_ops,
515+
(void *)src_info, O_RDWR));
516+
if (fd < 0) {
517+
spin_lock_irqsave(&hvpipe_src_list_lock, flags);
518+
list_del(&src_info->list);
519+
spin_unlock_irqrestore(&hvpipe_src_list_lock, flags);
520+
/*
521+
* if we fail to add FD, that means no userspace program is
522+
* polling. In that case if there is a msg pending because the
523+
* interrupt was fired after the src_info was added to the
524+
* global list, then let's consume it here, to unblock the
525+
* hvpipe
526+
*/
527+
if (src_info->hvpipe_status & HVPIPE_MSG_AVAILABLE)
528+
hvpipe_rtas_recv_msg(NULL, 0);
529+
kfree(src_info);
530+
return fd;
531+
}
532+
533+
return fd;
526534
}
527535

528536
/*
@@ -685,20 +693,19 @@ static int __init enable_hvpipe_IRQ(void)
685693
struct device_node *np;
686694

687695
hvpipe_check_exception_token = rtas_function_token(RTAS_FN_CHECK_EXCEPTION);
688-
if (hvpipe_check_exception_token == RTAS_UNKNOWN_SERVICE)
696+
if (hvpipe_check_exception_token == RTAS_UNKNOWN_SERVICE)
689697
return -ENODEV;
690698

691699
/* hvpipe events */
692700
np = of_find_node_by_path("/event-sources/ibm,hvpipe-msg-events");
693-
if (np != NULL) {
694-
request_event_sources_irqs(np, hvpipe_event_interrupt,
695-
"HPIPE_EVENT");
696-
of_node_put(np);
697-
} else {
698-
pr_err("Can not enable hvpipe event IRQ\n");
701+
if (!np) {
702+
pr_err("No device node found, could not enable hvpipe event IRQ\n");
699703
return -ENODEV;
700704
}
701705

706+
request_event_sources_irqs(np, hvpipe_event_interrupt, "HPIPE_EVENT");
707+
of_node_put(np);
708+
702709
return 0;
703710
}
704711

@@ -775,23 +782,29 @@ static int __init papr_hvpipe_init(void)
775782
}
776783

777784
ret = enable_hvpipe_IRQ();
778-
if (!ret) {
779-
ret = set_hvpipe_sys_param(1);
780-
if (!ret)
781-
ret = misc_register(&papr_hvpipe_dev);
782-
}
785+
if (ret)
786+
goto out_wq;
783787

784-
if (!ret) {
785-
pr_info("hvpipe feature is enabled\n");
786-
hvpipe_feature = true;
787-
return 0;
788-
}
788+
ret = misc_register(&papr_hvpipe_dev);
789+
if (ret)
790+
goto out_wq;
789791

790-
pr_err("hvpipe feature is not enabled %d\n", ret);
792+
ret = set_hvpipe_sys_param(1);
793+
if (ret)
794+
goto out_misc;
795+
796+
pr_info("hvpipe feature is enabled\n");
797+
hvpipe_feature = true;
798+
return 0;
799+
800+
out_misc:
801+
misc_deregister(&papr_hvpipe_dev);
802+
out_wq:
791803
destroy_workqueue(papr_hvpipe_wq);
792804
out:
793805
kfree(papr_hvpipe_work);
794806
papr_hvpipe_work = NULL;
807+
pr_err("hvpipe feature is not enabled %d\n", ret);
795808
return ret;
796809
}
797810
machine_device_initcall(pseries, papr_hvpipe_init);

arch/powerpc/platforms/pseries/papr-hvpipe.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ struct hvpipe_source_info {
2121
u32 srcID;
2222
u32 hvpipe_status;
2323
wait_queue_head_t recv_wqh; /* wake up poll() waitq */
24-
struct task_struct *tsk;
2524
};
2625

2726
/*

0 commit comments

Comments
 (0)