# Buggy code
def _lock(self, op, timeout):
    """This takes a lock using POSIX locks (``fnctl.lockf``).

    The lock is implemented as a spin lock using a nonblocking
    call to lockf().

    On acquiring an exclusive lock, the lock writes this process's
    pid and host to the lock file, in case the holding process
    needs to be killed later.

    If the lock times out, it raises a ``LockError``.
    """
    start_time = time.time()
    while (time.time() - start_time) < timeout:
        try:
            if self._fd is None:
                mode = os.O_RDWR if op == fcntl.LOCK_EX else os.O_RDONLY
                self._fd = os.open(self._file_path, mode)

            fcntl.lockf(self._fd, op | fcntl.LOCK_NB)
            if op == fcntl.LOCK_EX:
                os.write(self._fd, "pid=%s,host=%s" % (os.getpid(), socket.getfqdn()))
            return

        except IOError as error:
            if error.errno == errno.EAGAIN or error.errno == errno.EACCES:
                pass
            else:
                raise
        time.sleep(_sleep_time)

    raise LockError("Timed out waiting for lock.")


# Traceback (IOError)
$ ./spack/bin/spack find
Traceback (most recent call last):
File "./spack/bin/spack", line 192, in <module>
main()
File "./spack/bin/spack", line 169, in main
return_val = command(parser, args)
File "/users/kumbhar/spack/lib/spack/spack/cmd/find.py", line 148, in find
specs = set(spack.installed_db.query(**q_args))
File "/users/kumbhar/spack/lib/spack/spack/database.py", line 630, in query
with self.read_transaction():
File "/users/kumbhar/spack/lib/spack/llnl/util/lock.py", line 211, in __enter__
self._as = self._acquire_fn()
self._file_path = file_path
File "/users/kumbhar/spack/lib/spack/spack/database.py", line 447, in _read
self.reindex(spack.install_layout)
File "/users/kumbhar/spack/lib/spack/spack/database.py", line 351, in reindex
with transaction:
File "/users/kumbhar/spack/lib/spack/llnl/util/lock.py", line 210, in __enter__
if self._enter() and self._acquire_fn:
File "/users/kumbhar/spack/lib/spack/llnl/util/lock.py", line 241, in _enter
return self._lock.acquire_write(self._timeout)
File "/users/kumbhar/spack/lib/spack/llnl/util/lock.py", line 134, in acquire_write
self._lock(fcntl.LOCK_EX, timeout)   # can raise LockError.
File "/users/kumbhar/spack/lib/spack/llnl/util/lock.py", line 76, in _lock
fcntl.lockf(self._fd, op | fcntl.LOCK_NB)
IOError: [Errno 9] Bad file descriptor

# Fixed code
def _lock(self, op, timeout):
    """This takes a lock using POSIX locks (``fnctl.lockf``).

    The lock is implemented as a spin lock using a nonblocking
    call to lockf().

    On acquiring an exclusive lock, the lock writes this process's
    pid and host to the lock file, in case the holding process
    needs to be killed later.

    If the lock times out, it raises a ``LockError``.
    """
    start_time = time.time()
    while (time.time() - start_time) < timeout:
        try:
            # If this is already open read-only and we want to
            # upgrade to an exclusive write lock, close first.
            if self._fd is not None:
                flags = fcntl.fcntl(self._fd, fcntl.F_GETFL)
                if op == fcntl.LOCK_EX and flags | os.O_RDONLY:
                    os.close(self._fd)
                    self._fd = None

            if self._fd is None:
                mode = os.O_RDWR if op == fcntl.LOCK_EX else os.O_RDONLY
                self._fd = os.open(self._file_path, mode)

            fcntl.lockf(self._fd, op | fcntl.LOCK_NB)
            if op == fcntl.LOCK_EX:
                os.write(self._fd, "pid=%s,host=%s" % (os.getpid(), socket.getfqdn()))
            return

        except IOError as error:
            if error.errno == errno.EAGAIN or error.errno == errno.EACCES:
                pass
            else:
                raise
        time.sleep(_sleep_time)

    raise LockError("Timed out waiting for lock.")