Date: Sat, 12 Apr 2008 13:51:15 -1000 (HST) From: Jeff Roberson <jroberson@jroberson.net> To: arch@freebsd.org Subject: f_offset Message-ID: <20080412132457.W43186@desktop>
next in thread | raw e-mail | index | archive | help
So I'm in the midst of working on other filesystem concurrency issues and that has brought me back around to f_offset again. I'm working on a method to allow non-overlapping writes and reads to proceed concurrently to the same file. This means the exclusive vnode lock can not be used to protect f_offset even in the write case. To maintain the existing semantics I'm simply going to add an exclusive sx_xlock() around access to f_offset. This is done inconsistently today which is fine from the perspective of the updates in most cases being user-space races. However, f_offset is 64bit and can not be written atomically on 32bit systems and so requires some extra synchronization there. The sx lock will nearly double the size of struct file. Although it's lost some weight in 8.0 that is quite unfortunate. However, the method of using LOCKED & WAITING flags, msleep and a mutex has ruined performance in too many cases to continue using it. It's worth discussing what posix actually guarantees for f_offset as well as what other operating systems do. POSIX actually does not guarantee any behavior with simultaneous access. Multiple readers may read the same position in the file concurrently and update the position to different offsets. Multiple writers may write to the same file location, although the io should be serialized by some other means. Posix allows for and Solaris, Linux, and historic implementations of f_offset work in the following way: off = fp->f_offset; lock(vnode); vn_rdwr() unlock(vnode) fp->f_offset = uio->uio_offset; What we implement is much stricter. It is essentially this: lock(offset); off = fp->f_offset; lock(vnode); vn_rdwr() unlock(vnode); fp->f_offset = uio->uio_offset; unlock(offset); We provide the following extra guarantees: 1) Multiple readers will never see overlapping segments of the file 2) Multiple writers will never write to overlapping segments of the file McKusick changed the behavior in 1986, I would guess for an rforked process. There is some test code in this fairly interesting lkml thread where they discuss the problem in linux: http://lkml.org/lkml/2006/4/12/227 Simply having multiple threads write to stdout in a file on linux is enough to lose or corrupt output. I believe it is worth retaining the write guarantee. However, I believe the read guarantees are simply a side-effect of the original implementation of the write fix. I will probably commit a patch to add the sx with exclusive behavior to start. We need to at least protect 64bit access on 32bit machines in lseek() which we don't today. Beyond that I think we can relax the read restriction and allow f_offset readers to operate locklessly and only serialize writers. For this to work it would be nice if we had a MD way to write 64bits atomically that simply acquired a lock on 32bit platforms without something like cmpxchg8b. Or on UP just did the write with interrupts disabled. Comments? Thanks, Jeff
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20080412132457.W43186>