This is essentially a matter of checking a whole bag of corner cases.
- A drive can appear in /proc/mounts
- A drive can be used as swap (use /proc/swaps)
- A drive can be part of an active LVM pv (use pvdisplay)
- A drive can be part of a dm-mapper RAID group (use /proc/mdstat)
- A drive can be directly accessed by an application (e.g. Oracle supports writing directly to a drive or partition instead of a filesystem) (use fuser)
- A drive can be directly accessed by a virtual machine (use fuser)
- A drive can be referenced by a loopback device (e.g:
mount /dev/sda -o offset=1M /foo) (use losetup -a)
These are just the examples I came up with given a minute and a half to think about it. I'm sure there's a dozen others.
This last example I think is the most interesting and few people know about it. It allows you to mount a filesystem without using partitions. Just specify the starting offset and Linux will transparently create a loopback device. The example above yields the following:
# cat /proc/mounts
/dev/loop0 /foo ext4 relatime,data=ordered 0 0
# losetup -a
/dev/loop0 :2048 (/dev/sda), offset 1048576
Why would you do that? Typically it involves situations where things have previously gone horribly wrong.
Also bear in mind that with the namespacing feature now in mainline (see unshare), different processes can have different views about what's mounted and what isn't. Here things start to get a little bit red-pill.