File and Record Locking

You don't need to use traditional file I/O to do locking of file elements.
The lighter weight synchronization mechanisms described in Multithreaded Programming Guide
can be used effectively with mapped files and are much more efficient than
the old style file locking described in this section.

You lock files, or portions of files, to prevent the errors that can
occur when two or more users of a file try to update information at the same
time.

File locking and record locking are really the same thing, except that
file locking blocks access to the whole file, while record locking blocks
access to only a specified segment of the file. (In the SunOS 5.0 through 5.8 system, all
files are a sequence of bytes of data: a record is a concept of the programs
that use the file.)

Supported File Systems

Both advisory and mandatory locking are supported on the following types
of file systems:

ufs--the default disk-based file system

fifofs--a pseudo file system of named
pipe files that give processes common access to data

namefs--a pseudo file system used
mostly by STREAMS for dynamic mounts of file descriptors on top of file

specfs--a pseudo file system that
provides access to special character and block devices

Only advisory file locking is supported on NFS.

File locking is not supported for the proc and fd file systems.

Choosing a Lock Type

Mandatory locking suspends a process until the requested file segments
are free. Advisory locking returns a result indicating whether the lock was
obtained or not: processes can ignore the result and do the I/O anyway. You
cannot use both mandatory and advisory file locking on the same file at the
same time. The mode of a file at the time it is opened determines whether
locks on a file are treated as mandatory or advisory.

Of the two basic locking calls, fcntl(2) is more portable, more powerful, and
less easy to use than lockf(3C).fcntl(2) is specified in Posix 1003.1 standard. lockf(3C)
is provided to be compatible with older applications.

Terminology

Some useful definitions for reading the rest of this section are shown
below:

record

An arbitrary sequence of bytes in a file. The UNIX operating
system supports no record structure. Programs that use the files can impose
any arbitrary record structure.

cooperating processes

Two or more processes using some mechanism
to regulate access to a shared resource.

read lock

Lets other processes also apply a read lock
and/or perform reads, and blocks other processes from writing or applying
a write lock.

write lock

Blocks all other process from reading, writing,
or applying any lock.

advisory lock

Returns an error without blocking to
a process that does not hold the lock. Advisory locking is not enforced on creat(2), open(2), read(2), or write(2) operations.

Opening a File for Locking

A lock can only be requested on a file with a valid open descriptor.
For read locks, the file must be opened with at least read access. For write
locks, the file must also be opened with write access. In this example, a
file is opened for both read and write access.

Setting a File Lock

To lock an entire file, set the offset to zero and set the size to zero.

There are several ways to set a lock on a file. Choice of method depends
on how the lock interacts with the rest of the program, performance, and portability.
This example uses the POSIX standard-compatible fcntl(2) function. It tries to lock
a file until one of the following happens:

Locks are removed the same way they are set--only the lock type
is different (F_ULOCK). An unlock cannot be blocked by
another process and affects only locks placed by the calling process. The
unlock affects only the segment of the file specified in the preceding locking
call.

Getting Lock Information

You can determine which process, if any, is holding a lock. Use this
as a simple test or to find locks on a file. A lock is set, as in the previous
examples, and F_GETLK is used in fcntl(2). The next example finds and
prints indentifying data on all the locked segments of a file.

Forking and Locks

When a process forks, the child receives a copy of the file descriptors
that the parent opened. Locks are not inherited by the child because they
are owned by a specific process. The parent and child share a common file
pointer for each file. Both processes can try to set locks on the same location
in the same file. This problem happens with both lockf(3C) and fcntl(2). If a program holding a record
lock forks, the child process should close the file and reopen it to set a
new, separate file pointer.

Deadlock Handling

The UNIX locking facilities provide deadlock detection/avoidance. Deadlocks
can happen only when the system is about to put a record locking function
to sleep. A search is made to determine whether process A will wait for a
lock that B holds while B is waiting for a lock that A holds. If a potential
deadlock is detected, the locking function fails and sets errno
to indicate deadlock. Processes setting locks using F_SETLK
do not cause a deadlock because they do not wait when the lock cannot be granted
immediately.

Selecting Advisory or Mandatory Locking

For mandatory locks, the file must be a regular file with the set-group-ID
bit on and the group execute permission off. If either condition fails, all
record locks are advisory. Set a mandatory lock as follows.

Files to be record locked should never have any execute permission set.
This is because the operating system ignores record locks when executing a
file.

The chmod(1)
command can also be used to set a file to permit mandatory locking. For example:

$ chmod +lfile

This command sets the O20n0 permission bit in the
file mode, which indicates mandatory locking on the file. If n
is even, the bit is interpreted as enabling mandatory locking. If n is odd,
the bit is interpreted as "set group ID on execution."

The ls(1)
command shows this setting when you ask for the long listing format with the -l
option:

$ ls -lfile

displays following information:

-rw---l--- 1 user group size mod_time file

The letter "l" in the permissions indicates that the set-group-ID bit
is on, so mandatory locking is enabled, along with the normal semantics of
set group ID.

Cautions About Mandatory Locking

Mandatory locking works only for local files. It is not supported
when accessing files through NFS.

Mandatory locking protects only the segments of a file that
are locked. The remainder of the file can be accessed according to normal
file permissions.

If multiple reads or writes are needed for an atomic transaction,
the process should explicitly lock all such segments before any I/O begins.
Advisory locks are sufficient for all programs that perform in this way.

Arbitrary programs should not have unrestricted access permission
to files on which record locks are used.

Advisory locking is more efficient because a record lock check
does not have to be performed for every I/O request.