This question was actually fun for learning more about mount - and about the kernel code involved. =:c)
Fred Crowson wrote on Mon, Oct 02, 2006 at 10:31:24AM +0200: > Karel Kulhavy wrote: >> I tried to mount a CD-ROM twice: >> [EMAIL PROTECTED]:~$ mount /dev/cd0c /mnt/cdrom >> mount_ffs: /dev/cd0c on /mnt/cdrom: \ >> specified device does not match mounted device >> [EMAIL PROTECTED]:~$ mount /dev/cd0c /mnt/cdrom If i understand correctly, the second mount command succeeded. >> In first time I got an error message which doesn't make sense - >> there was only specified device, no mounted device (when you >> invoke the mount with intention to mount a device, the device >> is not mounted yet). Yes, *hopefully*. On the other hand, *if* you invoke mount(8) on a device which is already mounted, specifying the -u (change status) flag, you *do* get the same errno(2) in case you give the wrong mount point: [EMAIL PROTECTED] # mount | grep ftp /dev/wd0l on /ftp type ffs (local, nodev, noexec) [EMAIL PROTECTED] # mount /dev/wd0l /mnt mount_ffs: /dev/wd0l on /mnt: Device busy [EMAIL PROTECTED] # mount -u /dev/wd0l /mnt mount_ffs: /dev/wd0l on /mnt: \ specified device does not match mounted device >> Man mount doesn't mention the error message. When citing man pages, please do not omit the section number. The error message is not explained in mount(8), but in mount(2): "[EINVAL] An argument given was invalid." OK, i admit this is not at all obvious. >> I suggest the error message to be added and explained in the >> mount manual page. Maybe the mount_ffs(8) man page could be improved; i will perhaps think about it... >> Could you please also tell me what the error >> message means and why I got it once and not second time? > The error message is explicit mount_ffs (mount a Berkeley Fast > File System) does not match the file format on the CD-ROM - > if you had used the -t switch to mount(8) or used mount_cd9660(8) > you would have not received that error message. In one respect, this is almost certainly correct - clearly, if mount_ffs(8) is invoked on a cd9660 file system, it will fail just like Karel reported. But the point is - why did mount(8) invoke mount_ffs(8) at all? Usually, mount(8) is able to autodetect cd9660 file systems. It uses readlabelfs(3) from /usr/src/lib/libutil/readlabel.c to accomplish that. Thus, why did readlabelfs(3) fail the first time, and why did it succeed the second time? To find out, i just tried the following: I opened my CD drive, put a CD into the tray, typed the command below, hit return and only *then* pressed the "close tray" button on the CD drive. The first time i tried, the message "specified device does not match mounted device" did NOT show up. So i unmounted and removed the CD and started over. Now look at the result i got from the second try: [EMAIL PROTECTED] # \ > ( while true; do > mount /dev/cd0c /mnt && echo DONE && break > done; > mount /dev/cd0c /mnt > ) > mount.out 2>&1; \ > tail -n 6 mount.out mount_ffs: /dev/cd0c on /mnt: Operation not supported by device mount_ffs: /dev/cd0c on /mnt: Operation not supported by device mount_ffs: /dev/cd0c on /mnt: Operation not supported by device mount_ffs: /dev/cd0c on /mnt: \ specified device does not match mounted device DONE mount_cd9660: /dev/cd0c on /mnt: Device busy I read this as follows: Before the CD is accessible, readlabelfs(3) will fail, so mount(8) will use its default which happens to be "-t ffs". As soon as the CD becomes accessible, readlabelfs(3) will of course return the correct value "cd9660". Before the CD is accessible, mount(2) called by mount_ffs(8) will fail with ENODEV, translated to "Operation not supported by device" by strerror(3). As soon as the CD becomes accessible, mount(2) will notice the file system type mismatch, returning EINVAL, translated to "specified device does not match mounted device" by mount_ffs(8). Apparently, there is a race condition. Consider the following timeline: 1. the user starts mount(8) 2. mount(8) calls readlabelfs(3) *** ASSUME THE CD IS STILL UNAVAILABLE AT THIS TIME *** 3. readlabelfs(3) returns NULL to mount(8) (note: if the CD would already be readable now, the return value would be "cd9660" and the mount would succeed) 4. mount(8) does fork(2) and exec(3) to start mount_ffs(8) 5. mount_ffs(8) calls mount(2) with option MOUNT_FFS 6. switch to kernel space, sys_mount from kern/vfs_syscalls.c 7. sys_mount uses copyinstr(9) to get fstypename from user space 8. sys_mount calls ffs_mount from ufs/ffs/ffs_vfsops.c 9. ffs_mount uses copyinstr(9) to get mount point and device name 10. ffs_mount calls ffs_mountfs from ufs/ffs/ffs_vfsops.c *** ASSUME THE CD HAS NOW BECOME AVAILABLE *** 11. ffs_mountfs successfully opens the cd(4) device for reading by calling VOP_OPEN from kern/vnode_if.c = cdopen from scsi/cd.c 12. ffs_mountfs searches for an ffs superblock on the CD - of course, there is none, so it returns EINVAL 13. EINVAL is handed up the chain ffs_mount -> sys_mount -> mount(2) -> mount_ffs(8); the latter fails saying "specified device does not match mounted device" You see, there is quite a bit of work to be done between the time when mount(8) checks the disklabel to autodetect the file system type and the time when mount(2) can actually start accessing the device. In case the CD becomes readable during that time interval, mount(8) was indeed out of luck. By the way, mount(2) uses the EINVAL errno(2) in a catch-all style, and the details may even differ for different mount_*(8) backends. EINVAL from mount(2) can mean a lot of different things. And concerning ENODEV, the situation is not much better. Yet, it does not appear to be an easy task to implement error messages to distinguish more precisely among various reasons for mount(8) to fail. The point is, mount(2) receives failure information from various different file system drivers and from various different device drivers, and they all adhere to their own standards for reporting errors. Thus, it is hard for mount(2) to make head or tail from that jungle of information in the first place. Still worse, even if mount(2) does indeed unstand the gory details about what went wrong, it has no way of telling mount(8) - the only way to pass error information from mount(2) to mount(8) is via errno(2)... :-( While i was about it, i wondered where that other error message, "Operation not supported by device", comes from. In case the CD is still not readable at step 11 above, this is what happens: 12. cdopen calls scsi_test_unit_ready from scsi/scsi_base.c 13. scsi_test_unit_ready calls scsi_scsi_cmd 14. scsi_scsi_cmd calls scsi_execute_xs 15. scsi_execute_xs actually asks the CD drive whether it is ready 16. scsi_execute_xs passes the answer to sc_err1 17. sc_err1 calls scsi_interpret_sense 18. scsi_interpret_sense finds the sense key SKEY_NOT_READY subcode 0x3a /* Medium not present */ and *explicitely* decides to translate this into ENODEV This is a typical example that the medium-level device driver code, in this case the the SCSI base system, can indeed tell *exactly* what went wrong. But it cannot tell mount(2), because mount(2) obviously cannot and should not handle SCSI error codes - and even if sys_mount could handle the information, it would have a hard time to pass it out of the kernel space such that mount(8) could print it... It would be nice if mount(8) could print "Medium not present" in place of "Operation not supported by device" and "No FFS superblock found" in place of "specified device does not match mounted device". The information is in there, deep inside the kernel, but it cannot get out. -- "Drums, drums in the deep. They are coming. We cannot get out!" -- From the Book of Mazarbul, found by Frodo in Moria 23rd hall