On Mon, 15 Jan 2007, David Brownell wrote:

> On Friday 12 January 2007 2:12 pm, Alan Stern wrote:
> 
> > On the other hand, I did find (another) bug in the async I/O handling in 
> > inode.c.  If you aren't using the AIO code in usb.c then it shouldn't 
> > affect you, but you might want to give it a try anyway.
> 
> Alan, could you explain what the bug here is?  ISTR that the policy
> for those retry routines is to always put the request.  I know that
> you removed that some time ago, and that it re-appeared with a recent
> update to change the AIO interface ... but the original code had no
> leaks, and this change seems likely to create one.

On the contrary, this isn't a leak (i.e., permanent loss of memory caused
by failure to release a reference).  Just the opposite -- it is memory
corruption caused by decrementing a refcount inappropriately and thus
allowing a data structure to be freed while it is still in use.

I really have no idea what has changed and what hasn't.  Looking through
some old kernel trees, it's apparent that the ep_aio_read_retry() did
change between 2.6.18 and 2.6.19, reintroducing the aio_put_req() call and
thereby reverting the earlier bugfix.  That's a pity; I don't enjoy
finding & fixing refcount bugs, and I enjoy even less having to fix the
same bug twice.

>  (Unless the AIO
> core changed incompatibly ... but I'd have expected that the person
> who updated this code to reflect the "new" API would get that right.)

I also can't explain the AIO policy/interface/API -- because as far as I
can tell, it is completely undocumented!  There's nothing to go by except
the source code for the AIO core.  Here are the relevant extracts from
fs/aio.c:

static int __aio_run_iocbs(struct kioctx *ctx)
{
        ...
        while (!list_empty(&run_list)) {
                iocb = list_entry(run_list.next, struct kiocb,
                        ki_run_list);
                list_del(&iocb->ki_run_list);
                /*
                 * Hold an extra reference while retrying i/o.
                 */
                iocb->ki_users++;       /* grab extra reference */
                aio_run_iocb(iocb);
                if (__aio_put_req(ctx, iocb))  /* drop extra ref */
                        put_ioctx(ctx);
        }
        ...
}

So the core acquires and releases its own reference around the call of the 
ki_wait method.

static ssize_t aio_run_iocb(struct kiocb *iocb)
{
        ...
        if (!(retry = iocb->ki_retry)) {
                printk("aio_run_iocb: iocb->ki_retry = NULL\n");
                return 0;
        }

        ...

        BUG_ON(current->io_wait != NULL);
        current->io_wait = &iocb->ki_wait;
        ret = retry(iocb);
        current->io_wait = NULL;

        if (ret != -EIOCBRETRY && ret != -EIOCBQUEUED) {
                BUG_ON(!list_empty(&iocb->ki_wait.task_list));
                aio_complete(iocb, ret, 0);
        }
        ...
}

So the core does not expect the ki_retry method to change iocb's refcount.

Alan Stern


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to