lkml.org 
[lkml]   [2006]   [Nov]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    SubjectRe: [PATCH -mm 3/3][AIO] - AIO completion signal notification
    From
    Date
    On Thu, 2006-11-09 at 19:08 +0000, Christoph Hellwig wrote:
    > > +static long aio_setup_sigevent(struct kiocb *iocb,
    > > + struct sigevent __user *user_event)
    > > +{
    > > + int error = 0;
    > > + sigevent_t event;
    > > + struct task_struct *target;
    > > + unsigned long flags;
    > > +
    > > + if (!access_ok(VERIFY_READ, user_event, sizeof(struct sigevent)))
    > > + return -EFAULT;
    > > +
    > > + if (copy_from_user(&event, user_event, sizeof (event)))
    > > + return -EFAULT;
    >
    > > +
    >
    > > +
    > > + /* Check for the SIGEV_NONE case */
    > > + if (event.sigev_notify == SIGEV_NONE)
    > > + return 0;
    > > +
    > > + /* Setup the request completion notification parameters */
    > > + iocb->ki_notify.notify = event.sigev_notify;
    > > + iocb->ki_notify.signo = event.sigev_signo;
    > > + iocb->ki_notify.value = event.sigev_value;
    > > +
    > > + /* Now get the notification target */
    > > + read_lock(&tasklist_lock);
    > > +
    > > + if ((target = good_sigevent(&event))) {
    > > +
    > > + spin_lock_irqsave(&target->sighand->siglock, flags);
    > > +
    > > + if (!(target->flags & PF_EXITING)) {
    > > + iocb->ki_notify.target = target;
    > > +
    > > + spin_unlock_irqrestore(&target->sighand->siglock, flags);
    > > +
    >
    > I don't think there's a need to have the siglock for checking PF_EXITING,
    > and I also don't see why you need it for the assignment to
    > iocb->ki_notify.target. What is it intended to protect?

    Right, some remnant that managed to sneak through, will fix.

    >
    > > + /*
    > > + * Get a ref on the task. It is dropped in really_put_req()
    > > + * when we're done with the iocb, be it from the normal
    > > + * completion path, the cancellation path or an error path.
    > > + */
    > > + if (iocb->ki_notify.notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID))
    > > + get_task_struct(target);
    > > + } else {
    > > + spin_unlock_irqrestore(&target->sighand->siglock, flags);
    > > + error = -EINVAL;
    > > + }
    > > + } else
    > > + error = -EINVAL;
    > > +
    > > + read_unlock(&tasklist_lock);
    > > +
    > > + if (!error) {
    > > + /*
    > > + * Alloc a sigqueue for this request
    > > + *
    > > + * NOTE: we cannot free the sigqueue in the completion path as
    > > + * the signal may not have been delivered to the target task.
    > > + * Therefore it has to be freed in __sigqueue_free() when the
    > > + * signal is collected if si_code is SI_ASYNCIO.
    > > + */
    > > + if (unlikely(!(iocb->ki_sigq = sigqueue_alloc())))
    > > + error = -EAGAIN;
    >
    > We leak the task reference here.

    I don't think so, the reference is dropped in really_pu_req() when
    the iocb is freed, unless I missed something.

    >
    > All in all aio_setup_sigevent is a big mess and the style is very odd.
    > It's also overcommented on what's beeing done instead of why.
    > I've attached an draft on how it should look like below.
    >
    > > + /* handle setting up the sigevent for POSIX AIO signals */
    > > + req->ki_notify.notify = SIGEV_NONE;
    > > +
    > > + if (iocb->aio_sigeventp) {
    > > + ret = aio_setup_sigevent(req,
    > > + (struct sigevent __user *)(unsigned long)
    > > + iocb->aio_sigeventp);
    > > + if (ret)
    > > + goto out_put_req;
    > > + }
    > > +
    > > ret = aio_setup_iocb(req);
    > >
    > > if (ret)
    > > @@ -1610,6 +1729,10 @@ int fastcall io_submit_one(struct kioctx
    > > return 0;
    > >
    > > out_put_req:
    > > + /* Undo the sigqueue alloc if someting went bad */
    > > + if (req->ki_sigq)
    > > + sigqueue_free(req->ki_sigq);
    > > +
    >
    > Please put this after a separate label, so only callers after
    > aio_setup_sigevent try to check ki_sigq.


    Okay, cleaner that way.
    >
    >
    >
    > static long aio_setup_sigevent(struct kiocb *iocb,
    > struct sigevent __user *user_event)
    > {
    > sigevent_t event;
    > struct task_struct *target;
    > unsigned long flags;
    >
    > if (copy_from_user(&event, user_event, sizeof (event)))
    > return -EFAULT;
    >
    > if (event.sigev_notify == SIGEV_NONE)
    > return 0;
    >
    > iocb->ki_notify.notify = event.sigev_notify;
    > iocb->ki_notify.signo = event.sigev_signo;
    > iocb->ki_notify.value = event.sigev_value;
    >
    > read_lock(&tasklist_lock);
    > target = good_sigevent(&event);
    > if (unlikely(!target || (target->flags & PF_EXITING)))
    > goto out_unlock;
    > iocb->ki_notify.target = target;
    >
    > if (iocb->ki_notify.notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID)) {
    > /*
    > * This reference will be dropped when we're done with
    > * the request.
    > */
    > get_task_struct(target);
    > }
    > read_unlock(&tasklist_lock);
    >
    > /*
    > * NOTE: we cannot free the sigqueue in the completion path as
    > * the signal may not have been delivered to the target task.
    > * Therefore it has to be freed in __sigqueue_free() when the
    > * signal is collected if si_code is SI_ASYNCIO.
    > */
    > iocb->ki_sigq = sigqueue_alloc();
    > if (unlikely(!iocb->ki_sigq)) {
    > put_task_struct(target);
    > return -EAGAIN;
    > }
    >
    > return 0;
    > out_unlock:
    > read_unlock(&tasklist_lock);
    > return -EINVAL;
    > }
    >

    Cool, clearly better without taking the siglock, but again I don't
    think the put_task_struct() is needed here.

    Thanks,
    Sébastien.


    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2006-11-10 10:17    [W:0.032 / U:68.632 seconds]
    ©2003-2017 Jasper Spaans. hosted at Digital OceanAdvertise on this site