[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH] xen/grant-table: Simplify the update to the per-vCPU maptrack freelist
On 26.05.2021 17:21, Julien Grall wrote: > From: Julien Grall <jgrall@xxxxxxxxxx> > > Since XSA-288 (commit 02cbeeb62075 "gnttab: split maptrack lock to make XSA-228 I suppose? > it fulfill its purpose again"), v->maptrack_head and v->maptrack_tail > are with the lock v->maptrack_freelist_lock held. Nit: missing "accessed" or alike? > Therefore it is not necessary to update the fields using cmpxchg() > and also read them atomically. Ah yes, very good observation. Should have noticed this back at the time, for an immediate follow-up change. > Note that there are two cases where v->maptrack_tail is accessed without > the lock. They both happen _get_maptrack_handle() when the current vCPU > list is empty. Therefore there is no possible race. I think you mean the other function here, without a leading underscore in its name. And if you want to explain the absence of a race, wouldn't you then better also mention that the list can get initially filled only on the local vCPU? > I am not sure whether we should try to protect the remaining unprotected > access with the lock or maybe add a comment? As per above I don't view adding locking as sensible. If you feel like adding a helpful comment, perhaps. I will admit that it took me more than just a moment to recall that "local vCPU only" argument. > --- a/xen/common/grant_table.c > +++ b/xen/common/grant_table.c > @@ -543,34 +543,26 @@ double_gt_unlock(struct grant_table *lgt, struct > grant_table *rgt) > static inline grant_handle_t > _get_maptrack_handle(struct grant_table *t, struct vcpu *v) > { > - unsigned int head, next, prev_head; > + unsigned int head, next; > > spin_lock(&v->maptrack_freelist_lock); > > - do { > - /* No maptrack pages allocated for this VCPU yet? */ > - head = read_atomic(&v->maptrack_head); > - if ( unlikely(head == MAPTRACK_TAIL) ) > - { > - spin_unlock(&v->maptrack_freelist_lock); > - return INVALID_MAPTRACK_HANDLE; Where did this and ... > - } > - > - /* > - * Always keep one entry in the free list to make it easier to > - * add free entries to the tail. > - */ > - next = read_atomic(&maptrack_entry(t, head).ref); > - if ( unlikely(next == MAPTRACK_TAIL) ) > - { > - spin_unlock(&v->maptrack_freelist_lock); > - return INVALID_MAPTRACK_HANDLE; ... this use of INVALID_MAPTRACK_HANDLE go? It is at present merely coincidence that INVALID_MAPTRACK_HANDLE == MAPTRACK_TAIL. If you want to fold them, you will need to do so properly (by eliminating one of the two constants). But I think they're separate on purpose. > - } > + /* No maptrack pages allocated for this VCPU yet? */ > + head = v->maptrack_head; > + if ( unlikely(head == MAPTRACK_TAIL) ) > + goto out; > > - prev_head = head; > - head = cmpxchg(&v->maptrack_head, prev_head, next); > - } while ( head != prev_head ); > + /* > + * Always keep one entry in the free list to make it easier to > + * add free entries to the tail. > + */ > + next = read_atomic(&maptrack_entry(t, head).ref); Since the lock protects the entire free list, why do you need to keep read_atomic() here? > + if ( unlikely(next == MAPTRACK_TAIL) ) > + head = MAPTRACK_TAIL; > + else > + v->maptrack_head = next; > > +out: Please indent labels by at least one blank, to avoid issues with diff's -p option. In fact if you didn't introduce a goto here in the first place, there'd be less code churn overall, as you'd need to alter the indentation of fewer lines. > @@ -623,7 +615,7 @@ put_maptrack_handle( > { > struct domain *currd = current->domain; > struct vcpu *v; > - unsigned int prev_tail, cur_tail; > + unsigned int prev_tail; > > /* 1. Set entry to be a tail. */ > maptrack_entry(t, handle).ref = MAPTRACK_TAIL; > @@ -633,11 +625,8 @@ put_maptrack_handle( > > spin_lock(&v->maptrack_freelist_lock); > > - cur_tail = read_atomic(&v->maptrack_tail); > - do { > - prev_tail = cur_tail; > - cur_tail = cmpxchg(&v->maptrack_tail, prev_tail, handle); > - } while ( cur_tail != prev_tail ); > + prev_tail = v->maptrack_tail; > + v->maptrack_tail = handle; > > /* 3. Update the old tail entry to point to the new entry. */ > write_atomic(&maptrack_entry(t, prev_tail).ref, handle); Since the write_atomic() here can then also be converted, may I ask that you then rename the local variable to just "tail" as well? > --- a/xen/include/xen/sched.h > +++ b/xen/include/xen/sched.h > @@ -255,7 +255,10 @@ struct vcpu > /* VCPU paused by system controller. */ > int controller_pause_count; > > - /* Grant table map tracking. */ > + /* > + * Grant table map tracking. The lock maptrack_freelist_lock protect Nit: protects > + * the access to maptrack_head and maptrack_tail. > + */ I'm inclined to suggest this doesn't need spelling out, considering ... > spinlock_t maptrack_freelist_lock; > unsigned int maptrack_head; > unsigned int maptrack_tail; ... both the name of the lock and its placement next to the two fields it protects. Also as per the docs change of the XSA-228 change, the lock protects more than just these two fields, so the comment may be misleading the way you have it now. Jan
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |