Harry
Harry

Reputation: 3927

How do file-systems implement sector-locking?

Though this is a general question, specific answers for any of the Windows- or Linux- or Mac- supported file-system(s) are welcome.

How does a file-system prevent 2 or more processes from concurrent read/write access to a sector of a local drive?

I understand that some type of sector-locking would obviously need to be employed, but...

  1. What would be the 'type' of this OS-wide sector lock:

    a) Named-mutex / named-semaphore / file-mapping ? (on Windows)

    b) Shared memory ? (on Linux)

  2. Where is this sector-lock kept: In memory? On disk? In either case, wherever this lock is stored, I understand that...

    a) the storage for locks has to be a logically-temporary storage, since the lock should not be left dangling permanently or indefinitely if its owner process were to crash. So, it helps if these locks exist in memory.

    b) the whereabouts of the lock have to be publicly discoverable by all processes via a name or ID which found a function of the sector number. So, if process A needs to lock sector S, A should know how to first get access to the lock L(S) for sector S, create L(S) if it does not already exist, try to lock L(S), and either return or block -- all atomically, since another process B could also be racing alongside A trying to carry out the same sequence of steps.

  3. For a large storage device, the number of sectors would be large too. So, a lock each for each sector cannot obviously be pre-allocated either in memory or on disk.

What I don't know or understand, however, is how this problem is already handled by ext* file-systems on Linux, FAT* and NTFS on Windows, and likewise for Mac.

The actual context of my questions: Ultimately, I have to apply the answers to the above for a Java-based, custom file-system that I'm writing using Java 7 NIO2 FileSystemProvider, where 2 or more independent Java processes could be accessing a bunch of sectors of the attached drive for reading/writing . In Java 7, the only non-JNI way that I know of to achieve shared memory between processes is via a MappedByteBuffer. But the problem is, this byte buffer would be 'raw' memory - whereas what I need is an OS-wide, mutex-type mechanism AND also probably a mutex each for each sector S. It seems, my changes to this MappedByteBuffer won't get carried out atomically OS-wide unless I also call MappedByteBuffer.force.

Would greatly appreciate all answers and comments.

Upvotes: 3

Views: 329

Answers (1)

Elliott Frisch
Elliott Frisch

Reputation: 201447

I think you're confused as to how a modern file-system is implemented, and older systems weren't usually multi-user; with that preface let's look at something called a journal. Now there are some alternatives - namely

  1. Soft updates
  2. Log-structured file system
  3. Copy-on-write

However, the most common is probably a Journaling file-system. Which writes into empty blocks and simply moves pointers on completion of the write (while atomically writing to a "journal"), this allows for "rapid" recovery in the event of a power failure (or other write interruption).

As for locking your "journal" at the system level, I would probably use a FileLock like so -

FileLock lock = null;
FileChannel channel = null;
try {
  // Get a file channel for the file
  File file = new File("journal");
  channel = new RandomAccessFile(file,
      "rw").getChannel();

  // Try acquiring the lock without blocking.
  try {
    lock = channel.tryLock();
    if (lock != null) {
      // GOT THE LOCK.... DO WORK...
      return true; // write success.
    }
  } catch (OverlappingFileLockException e) {
    // File is already locked in this thread or virtual
    // machine
  } finally {
    if (lock != null) {
      lock.release(); // Release the lock
    }
    if (channel != null) {
      channel.close(); // Close the file.
    }
  }
  return false; // Write must be retried?

Upvotes: 2

Related Questions