On 04/10/2019 02:49, Richard Elling wrote:
> isn't this addressed by the compiler builtins for atomics?

'This' -- what specifically?
I do not think that plain reads of 64-bit objects on 32-bit platforms can be
addressed by anything until they cease being plain.

>> On Oct 3, 2019, at 10:38 AM, Matthew Ahrens <mahr...@delphix.com
>> <mailto:mahr...@delphix.com>> wrote:
>>
>> On Wed, Oct 2, 2019 at 7:51 AM Andriy Gapon <a...@freebsd.org
>> <mailto:a...@freebsd.org>> wrote:
>>
>>
>>     This is a work in progress report for my work on safer use of atomics in 
>> ZFS
>>     that was discussed in the August developer meeting.
>>
>>     I took the approach suggested at the meeting of creating a new type that 
>> is to
>>     be used for all objects that should be modified atomically.
>>     The type is trivial:
>>     typedef struct zatomic64 {
>>             volatile uint64_t val;
>>     } zatomic64_t;
>>
>>     I also made a decision upfront to use a wrapper type only for 64-bit
>>     objects as
>>     32-bit objects should be already safe on all supported platforms where a
>>     native
>>     integer size is either 32 or 64 bit.
>>
>>     Then, as suggested, I wrote trivial wrappers for all 64-bit atomic 
>> operations
>>     that are used in ZFS code.  For example:
>>       static inline void
>>       zatomic_add_64(zatomic64_t *a, uint64_t val)
>>       {
>>               atomic_add_64(&a->val, val);
>>       }
>>
>>     A side note on naming.  I simply prepended original function names with 
>> 'z'.
>>     Although names like zatomic64_add() could be prettier and more aligned
>>     with the
>>     type name.
>>
>>     After that I added three new functions:
>>     - zatomic_load_64 -- safe (with respect to torn values) read of a 64-bit
>>     atomic
>>     - zatomic_store_64 -- safe write of a 64-bit atomic
>>     - zatomic_init_64 -- unsafe write of a 64-bit atomic
>>
>>     The last function just sets zatomic64_t.val and it is supposed to be 
>> used when
>>     it is known that there are no concurrent accesses.  It's pretty 
>> redundant the
>>     field can be set directly or the whole object can be initialized with x =
>>     { 0 },
>>     but I decided to add it for symmetry.
>>
>>     The first two functions are implemented like this:
>>       static inline uint64_t
>>       zatomic_load_64(zatomic64_t *a)
>>       {
>>       #ifdef __LP64__
>>               return (a->val);
>>       #else
>>               return (zatomic_add_64_nv(a, 0));
>>       #endif
>>       }
>>
>>       static inline void
>>       zatomic_store_64(zatomic64_t *a, uint64_t val)
>>       {
>>       #ifdef __LP64__
>>               a->val = val;
>>       #else
>>               (void)zatomic_swap_64(a, 0);
>>       #endif
>>       }
>>
>>     I am not sure if this was a right way to do it.
>>     Maybe there should be a standard implementation only for 64-bit 
>> platforms and
>>     each 32-bit platform should do its own thing?
>>     For example, there is more than one way to get atomic 64-bit loads on 
>> x86,
>>     according to this:
>>     
>> https://stackoverflow.com/questions/48046591/how-do-i-atomically-move-a-64bit-value-in-x86-asm
>>
>>
>> What you did above seems fine to me.
>>  
>>
>>     Anyway, I started converting ZFS (/FreeBSD) code to use the new type.
>>     Immediately, I got some problems and some questions.
>>
>>     First, I am quite hesitant about what to do with kstat-s.
>>     I wanted to confine the change to ZFS, but kstat is an external thing (at
>>     least
>>     on illumos).  For now I decided to leave the kstat-s alone.  Especially 
>> as
>>     I was
>>     not going to change any code that reads the kstat-s.
>>     But this also means that some things like arc_c and arc_p, which are
>>     aliases to
>>     kstat value, remain potentially unsafe with respect to torn reads.
>>
>>
>> Yeah, we would have to convert these kstats to have callbacks that do the
>> atomic reads.
>>  
>>
>>
>>     I have not converted atomics in the aggsum code yet.
>>     I am actually a little bit confused about why as_lower_bound and
>>     as_upper_bound
>>     are manipulated with atomics.  All manipulations seems to be done under
>>     as_lock.
>>     Maybe I overlooked something...
>>
>>
>> The comment in aggsum_flush_bucket() has the (perhaps incorrect) 
>> justification:
>>
>> /*
>>  * We use atomic instructions for this because we read the upper and
>>  * lower bounds without the lock, so we need stores to be atomic.
>>  */
>> atomic_add_64((volatile uint64_t *)&as->as_lower_bound, asb->asc_delta);
>>
>> So the assumption is that as long as we do an atomic store, we can read with 
>> a
>> normal read.  The lock doesn't help because the readers don't hold the lock.
>>  
>>
>>
>>     I converted refcount.h.
>>     That had a bit of unexpected effect on rrwlock_t.
>>     zfs_refcount_t is used for rr_anon_rcount and rr_linked_rcount fields.
>>     The fields are always accessed rr_lock, so their atomicity is not 
>> actually
>>     required.  I guess that zfs_refcount_t is used for the support of 
>> references
>>     with ownership. 
>>
>>
>> That's right.
>>  
>>
>>     So, some bits of the rrwlock code access those fields through
>>     the refcount interface, but other (conditional) pieces directly access
>>     rc_count
>>     as a simple integer.
>>     So, there are a couple of options here.  The direct accesses can be 
>> replaced
>>     with refcount accesses, but then we get unnecessary atomic operations in 
>> the
>>     fast paths. 
>>
>>
>> That would be true only on 32-bit platforms, right?  I don't think a small
>> performance hit to 32-bit kernels is worth worrying about.
>>  
>>
>>     Or the code can keep directly accessing internals of both
>>     zfs_refcount_t and zatomic64_t.  Another option is to create a copy of
>>     zfs_refcount_t that relies on external synchronization (so that it does
>>     not use
>>     atomics or any internal locks).  But that would be a bit of code 
>> duplication.
>>
>>
>> I'd prefer to keep the code simple, consistent, and easy to see its
>> correctness, even if it costs some performance on 32-bit.
>>  
>>
>>
>>     Yet another hard case is znode's z_size.
>>     It's changed with atomic_cas_64() in a single place, in all other places 
>> it's
>>     used as a normal integer.  On the one hand, there can be a torn read
>>     because of
>>     that atomic operation.  On the other hand, it's quite messy to update 
>> all uses
>>     of z_size.
>>
>>     So, the work is progressing, but I feel like limiting the scope of the 
>> change.
>>     Originally I planned to convert everything to zatomic in one go.
>>     But now I feel that just a few things really need that.
>>     Probably os_obj_next_percpu.
>>     Likely zfs_refcount_t.
>>     Anything else?
>>     I am thinking that maybe a few things could be converted initially and 
>> the
>>     rest
>>     could be converted on as needed basis.
>>
>>     I don't like having a mix of regular atomics and zatomics, but alas.
>>
>>     Any suggestions, comments, observations, ideas, etc are very welcome!
>>
>>     P.S.
>>     Another thought is creeping in: maybe it's not worth bothering with ZFS 
>> on
>>     32-bit platforms.
>>
>>
>> Fine by me, although I think that opinions may vary on this one :-)
>>  Especially as long as some of the most popular operating systems to run
>> OpenZFS support 32-bit kernels (although it looks like FreeBSD and Ubuntu are
>> in the process of dropping support for i386?  But ZoL still supports much
>> older releases of Ubuntu and RHEL.).
>>
>> --matt
> 
> *openzfs <https://openzfs.topicbox.com/latest>* / openzfs-developer / see
> discussions <https://openzfs.topicbox.com/groups/developer> + participants
> <https://openzfs.topicbox.com/groups/developer/members> + delivery options
> <https://openzfs.topicbox.com/groups/developer/subscription> Permalink
> <https://openzfs.topicbox.com/groups/developer/T3ee8a81d5f09f2ec-M2869ca2fabcee5f4249ece1f>
> 


-- 
Andriy Gapon

------------------------------------------
openzfs: openzfs-developer
Permalink: 
https://openzfs.topicbox.com/groups/developer/T3ee8a81d5f09f2ec-Mbeda3898a9fc51e251f56538
Delivery options: https://openzfs.topicbox.com/groups/developer/subscription

Reply via email to