Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 18 Nov 2009 10:44:08 -0500
From:      John Baldwin <jhb@freebsd.org>
To:        "Robert N. M. Watson" <rwatson@freebsd.org>
Cc:        FreeBSD Net <freebsd-net@freebsd.org>, Brooks Davis <brooks@freebsd.org>, "M. Warner Losh" <imp@bsdimp.com>, Antoine Brodin <antoine.brodin@laposte.net>
Subject:   Re: [PATCH FOR REVIEW] interface description (revised)
Message-ID:  <200911181044.08772.jhb@freebsd.org>
In-Reply-To: <70A1A5B3-1F19-4AC1-8975-F7E950785BBF@freebsd.org>
References:  <a78074950911171839u3e3fb4f1oae4aa3fc79f1b152@mail.gmail.com> <200911181012.07167.jhb@freebsd.org> <70A1A5B3-1F19-4AC1-8975-F7E950785BBF@freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Wednesday 18 November 2009 10:35:36 am Robert N. M. Watson wrote:
> 
> On 18 Nov 2009, at 15:12, John Baldwin wrote:
> 
> > However, this is a bit complicated, and to be honest, I don't think interface
> > descriptions are a critical path.  Robert has already said before that
> > IF_AFDATA_RLOCK() isn't really the "correct" lock but is being abused for 
> > this.  Given that, I would probably just add a single global sx lock.  This
> > has the added advantage that you can just use copyin/copyout directly and
> > skip all the extra complication.  I don't think we need the extra concurrency
> > for interface descriptions to make this so complicated.  If you used a global
> > sx lock with a simple string for descriptions, the code would end up looking
> > like this:
> > 
> > static struct sx ifdescr_lock;
> > SX_SYSINIT(&ifdescr_lock, "ifnet descr");
> 
> This strikes me as a good idea -- there won't be much real-world contention on
> the lock, I'd think, and this greatly simplifies the code. We might think about
> whether there's other, currently under-synchronized, ifnet meta-data that could
> be protected usefully with the same lock.   
> 
> > 	case SIOCSIFDESCR:
> > 		error = priv_check();
> > 		if (error)
> > 			break;
> > 
> > 		if (ifr->ifr_buffer.length > ifdescr_maxlen)
> > 			return (ENAMETOOLONG);
> > 
> > 		buf = malloc(ifr->ifr_buffer.length, M_IFDESCR, M_WAITOK |
> > 		    M_ZERO);
> > 		error = copyin(ifr->ifr_buffer.buffer, buf,
> > 		    ifr->ifr_buffer.length - 1);
> > 		if (error) {
> > 			free(buf, M_IFDESCR);
> > 			break;
> > 		}
> > 		sx_xlock(&ifdescr_lock);
> > 		ifp->if_description = buf;
> > 		sx_xunlock(&ifdescr_lock);
> > 		break;
> > 
> > Note that this takes approach 1) from above, but it is also a moot point now 
> > since the 'get' ioctl doesn't allocate memory anymore.
> 
> This code seems pretty reasonable to me, but there's a race here if two threads
> try to use the set ioctl on the same interface at once. We should test whether
> ifp->if_description is already set after the sx_xlock() above, and swap pointers,
> freeing the old one after xunlock(), if so.

Actually, it's just a straight up bug.  The race with two threads doing a set is
a userland race, but what I missed was freeing the old buffer if it existed.  One
would just modify the end of SIFDESCR case as follows:

	char *old;

		sx_xlock(&ifdescr_lock);
		old = ifp->if_description;
		ifp->if_description = buf;
		sx_xunlock(&ifdescr_lock);
		free(old, M_IFDESCR);
		break;

-- 
John Baldwin



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200911181044.08772.jhb>