5

I am working on a safe and race-condition-free alternative to umount -l with removable devices:

I'm planning on:

  1. umount --move under a 000 permissions directory so no more files can be opened by absolute path
  2. Interactively kill (or gracefully shutdown) processes with files open for writing
  3. Atomically remount read-only only if step (2) is complete
  4. Interactively kill / close read-only processes that may cause cause issues
  5. Finally have umount succeed

There is a race condition in step (3) where a file with relative path could be opened rw after the last interactive kill and before the mount -o remount,ro.

Is mount -o remount,ro guaranteed to fail if there is any file on the filesystem opened for writing?

The manual page is silent on this, and I'm a bit paranoid after finding out that devices are writable even after blockdev --setro.

Tom Hale
  • 30,455
  • I have to ask "why?". Why is a plain old umount not good enough for this job? umount is written to be deliberately cautious in order to prevent data loss through premature umounting, and you're throwing those safeguards away - is your reason for doing so good enough to justify that? or is this just satisfying some minor aesthetic itch? – cas Aug 14 '17 at 06:15
  • 1
    Plain umount will only succeed if all open files are closed. I'm generally ok in killing all ro processes, but I first want to investigate and gracefully close any rw processes so as to avoid in-file corruption. I want to avoid new rw processes being created while all that is going on. As it turns out, umount -f won't work on a non-NFS filesystem, so fuser -kM seems to be required for remaining ro processes. – Tom Hale Aug 14 '17 at 07:40
  • I agree with cas, this seems like a lot of effort for something you can do with umount. That does leave the race with new processes, but it’s not as if there’s a gremlin constantly starting processes writing to your removable drive, or at least there shouldn’t be... – Stephen Kitt Aug 14 '17 at 08:08
  • Perhaps I don't understand what you both intend by just using plain umount... Do you mean a fuser -kiM /mountpoint && umount /mountpoint? I am trying to get the advantages of umount --lazy without the non-determinism. – Tom Hale Aug 14 '17 at 08:21
  • @TomHale investigating and gracefully closing programs with open files (whether RO or RW) on a mounted fs you want to unmount IS the right way to do this. – cas Aug 14 '17 at 08:58
  • I think you're making the mistake of thinking that --lazy is a safe option that you can use for some imagined convenience, when it's really an option that you shouldn't use except as a last resort (when nothing else works and you really have to get that fs unmounted NOW before anything new writes to it), because it is inherently dangerous to the data and/or metadata on the fs. You can not use it routinely and expect not to have race-conditions and potential fs corruption to deal with. – cas Aug 14 '17 at 08:59
  • 1
    “Using plain umount” in my mind just means “run umount, if it succeeds, good, if it doesn’t, figure out why and try again”. Your putative approach still involves the figuring out part, so I don’t see much point in making it any more complex. – Stephen Kitt Aug 14 '17 at 09:50
  • You mount the partition read-only, but not the disk. So one process (in root) could create a device to access and change the data on the disk. (this just because you are paranoid). – Giacomo Catenazzi Aug 14 '17 at 14:30
  • @cas I've come to agree with you on the dangers of umount -l. My proposed approach in the question is precisely because I don't want to use it but still want to prevent writes based on absolute filenames by moving the namespace. – Tom Hale Aug 17 '17 at 07:22
  • when i've had to do things like that (e.g. cron backup jobs to external or network mount-points), I've dealt with that by just making the script check if the fs is mounted, try to mount it if not, and bail out (with an alert email) if there's any problem. In fact, i do something like that with most rsync etc scripts - if the target doesn't look like what I expect it to be (partition, network fs, zfs dataset or zvol, whatever) then bail. if my expectations change, i change the script. I've filled up the wrong fs too many times just assuming that a fs will be mounted, so now i check first. – cas Aug 17 '17 at 07:55

1 Answers1

5

Yes. The relevant code is in sb_prepare_remount_readonly (as of Linux 4.0, the code may be organized differently on other versions). The logic is:

  • For each instance of the mount:
    • If that instance is not read-only:
      • Prevent any new writer from registering (MNT_WRITE_HOLD).
      • If there are registered writers, set the error flag (return EBUSY).
  • If there are any files that are removed (inode count = 0) but not yet deleted (still present because the file is open), set the error flag.
  • If the error flag is not set, mark the partition as read-only.
  • For each instance of the mount:
    • Stop preventing writers from registering.

Registered writers are files open for writing as well as ongoing operations that write metadata (mkdir, chmod, etc.). Check out calls to mnt_want_write which is where the count of registered writers is incremented.

The design of the system ensures that a read-only remount is a write registration barrier: if it succeeds then there is no registered writer, in particular there can't be any file open for writing at the time of the remount operation. After the remount, no file can be opened for writing, so there is still no file that's open for writing.

Tom Hale
  • 30,455