[linux/fs/umsdos/namei.c,55]
#Specification: file creation / not atomic
File creation is a two step process. First we create (allocate) an entry in the EMD file and then (using the entry offset) we build a unique name for MSDOS. We create this name in the msdos space.
We have to use semaphore (sleep_on/wake_up) to prevent lookup into a directory when we create a file or directory and to prevent creation while a lookup is going on. Since many lookup may happen at the same time, the semaphore is a counter.
Only one creation is allowed at the same time. This protection may not be necessary. The problem arise mainly when a lookup or a readdir is done while a file is partially created. The lookup process see that as a "normal" problem and silently erase the file from the EMD file. Normal because a file may be erased during a MSDOS session, but not removed from the EMD file.
The locking is done on a directory per directory basis. Each directory inode has its wait_queue.
For some operation like hard link, things even get worse. Many creation must occur at once (atomic). To simplify the design a process is allowed to recursively lock the directory for creation. The pid of the locking process is kept along with a counter so a second level of locking is granted or not.
[linux/fs/umsdos/namei.c,177]
#Specification: create / . and ..
If one try to creates . or .., it always fail and return EEXIST.
If one try to delete . or .., it always fail and return EPERM.
This should be test at the VFS layer level to avoid duplicating this in all file systems. Any comments ?
[linux/fs/umsdos/ioctl.c,29]
#Specification: ioctl / acces
Only root (effective id) is allowed to do IOCTL on directory in UMSDOS. EPERM is returned for other user.
[linux/fs/umsdos/ioctl.c,37]
#Specification: ioctl / prototypes
The official prototype for the umsdos ioctl on directory is:
int ioctl ( int fd, // File handle of the directory int cmd, // command struct umsdos_ioctl *data)
The struct and the commands are defined in linux/umsdos_fs.h.
umsdos_progs/umsdosio.c provide an interface in C++ to all these ioctl. umsdos_progs/udosctl is a small utility showing all this.
These ioctl generally allow one to work on the EMD or the DOS directory independently. These are essential to implement the synchronise.
[linux/fs/umsdos/ioctl.c,58]
#Specification: ioctl / UMSDOS_GETVERSION
The field version and release of the structure umsdos_ioctl are filled with the version and release number of the fs code in the kernel. This will allow some form of checking. Users won't be able to run incompatible utility such as the synchroniser (umssync). umsdos_progs/umsdosio.c enforce this checking.
Return always 0.
[linux/fs/umsdos/ioctl.c,72]
#Specification: ioctl / UMSDOS_READDIR_DOS
One entry is read from the DOS directory at the current file position. The entry is put as is in the dos_dirent field of struct umsdos_ioctl.
Return > 0 if success.
[linux/fs/umsdos/ioctl.c,193]
#Specification: ioctl / UMSDOS_RMDIR_DOS
The dos_dirent field of the struct umsdos_ioctl is used to execute a msdos_unlink operation. The d_name and d_reclen fields are used.
Return 0 if success.
[linux/fs/umsdos/ioctl.c,204]
#Specification: ioctl / UMSDOS_STAT_DOS
The dos_dirent field of the struct umsdos_ioctl is used to execute a stat operation in the DOS directory. The d_name and d_reclen fields are used.
The following field of umsdos_ioctl.stat are filled.
st_ino,st_mode,st_size,st_atime,st_mtime,st_ctime, Return 0 if success.
[linux/fs/umsdos/ioctl.c,182]
#Specification: ioctl / UMSDOS_UNLINK_DOS
The dos_dirent field of the struct umsdos_ioctl is used to execute a msdos_unlink operation. The d_name and d_reclen fields are used.
Return 0 if success.
[linux/fs/umsdos/ioctl.c,147]
#Specification: ioctl / UMSDOS_CREAT_EMD
The umsdos_dirent field of the struct umsdos_ioctl is used as is to create a new entry in the EMD of the directory. The DOS directory is not modified. No validation is done (yet).
Return 0 if success.
[linux/fs/umsdos/ioctl.c,81]
#Specification: ioctl / UMSDOS_READDIR_EMD
One entry is read from the EMD at the current file position. The entry is put as is in the umsdos_dirent field of struct umsdos_ioctl. The corresponding mangled DOS entry name is put in the dos_dirent field.
All entries are read including hidden links. Blank entries are skipped.
Return > 0 if success.
[linux/fs/umsdos/ioctl.c,164]
#Specification: ioctl / UMSDOS_UNLINK_EMD
The umsdos_dirent field of the struct umsdos_ioctl is used as is to remove an entry from the EMD of the directory. No validation is done (yet). The mode field is used to validate S_ISDIR or S_ISREG.
Return 0 if success.
[linux/fs/umsdos/ioctl.c,228]
#Specification: ioctl / UMSDOS_DOS_SETUP
The UMSDOS_DOS_SETUP ioctl allow changing the default permission of the MsDOS file system driver on the fly. The MsDOS driver apply global permission to every file and directory. Normally these permissions are controlled by a mount option. This is not available for root partition, so a special utility (umssetup) is provided to do this, normally in /etc/rc.local.
Be aware that this apply ONLY to MsDOS directory (those without EMD --linux-.---). Umsdos directory have independent (standard) permission for each and every file.
The field umsdos_dirent provide the information needed. umsdos_dirent.uid and gid sets the owner and group. umsdos_dirent.mode set the permissions flags.
[linux/fs/umsdos/ioctl.c,124]
#Specification: ioctl / UMSDOS_INIT_EMD
The UMSDOS_INIT_EMD command make sure the EMD exist for a directory. If it does not, it is created. Also, it makes sure the directory functions table (struct inode_operations) is set to the UMSDOS semantic. This mean that umssync may be applied to an "opened" msdos directory, and it will change behavior on the fly.
Return 0 if success.
[linux/fs/umsdos/dir.c,526]
#Specification: locating .. / strategy
We use the msdos filesystem to locate the parent directory. But it is more complicated than that.
We have to step back even further to get the parent of the parent, so we can get the EMD of the parent of the parent. Using the EMD file, we can locate all the info on the parent, such a permissions and owner.
[linux/fs/umsdos/dir.c,562]
#Specification: umsdos / lookup
A lookup for a file is done in two step. First, we locate the file in the EMD file. If not present, we return an error code (-ENOENT). If it is there, we repeat the operation on the msdos file system. If this fails, it means that the file system is not in sync with the emd file. We silently remove this entry from the emd file, and return ENOENT.
[linux/fs/umsdos/dir.c,284]
#Specification: umsdos / lookup / inode info
After successfully reading an inode from the MSDOS filesystem, we use the EMD file to complete it. We update the following field.
uid, gid, atime, ctime, mtime, mode.
We rely on MSDOS for mtime. If the file was modified during an MSDOS session, at least mtime will be meaningful. We do this only for regular file.
We don't rely on MSDOS for mtime for directory because the MSDOS directory date is creation time (strange MSDOS behavior) which fit nowhere in the three UNIX time stamp.
[linux/fs/umsdos/dir.c,309]
#Specification: umsdos / i_nlink
The nlink field of an inode is maintain by the MSDOS file system for directory and by UMSDOS for other file. The logic is that MSDOS is already figuring out what to do for directories and does nothing for other files. For MSDOS, there are no hard link so all file carry nlink==1. UMSDOS use some info in the EMD file to plug the correct value.
[linux/fs/umsdos/inode.c,351]
#Specification: notify_change / msdos fs
notify_change operation are done only on the EMD file. The msdos fs is not even called.
[linux/fs/umsdos/inode.c,295]
#Specification: root inode / attributes
I don't know yet how this should work. Normally the attributes (permissions bits, owner, times) of a directory are stored in the EMD file of its parent.
One thing we could do is store the attributes of the root inode in its own EMD file. A simple entry named "." could be used for this special case. It would be read once when the file system is mounted and update in UMSDOS_notify_change() (right here).
I am not sure of the behavior of the root inode for a real UNIX file system. For now, this is a nop.
[linux/fs/umsdos/inode.c,288]
#Specification: notify_change / i_nlink > 0
notify change is only done for inode with nlink > 0. An inode with nlink == 0 is no longer associated with any entry in the EMD file, so there is nothing to update.
[linux/fs/umsdos/dir.c,132]
#Specification: umsdos / readdir
umsdos_readdir() should fill a struct dirent with an inode number. The cheap way to get it is to do a lookup in the MSDOS directory for each entry processed by the readdir() function. This is not very efficient, but very simple. The other way around is to maintain a copy of the inode number in the EMD file. This is a problem because this has to be maintained in sync using tricks. Remember that MSDOS (the OS) does not update the modification time (mtime) of a directory. There is no easy way to tell that a directory was modified during a DOS session and synchronise the EMD file.
Suggestion welcome.
So the easy way is used!
[linux/fs/umsdos/dir.c,83]
#Specification: readdir / . and ..
The msdos filesystem manage the . and .. entry properly so the EMD file won't hold any info about it.
In readdir, we assume that for the root directory the read position will be 0 for ".", 1 for "..". For a non root directory, the read position will be 0 for "." and 32 for "..".
[linux/fs/umsdos/dir.c,204]
#Specification: umsdos / readdir / not in MSDOS
During a readdir operation, if the file is not in the MSDOS directory anymore, the entry is removed from the EMD file silently.
[linux/fs/umsdos/inode.c,394]
#Specification: mount / options
Umsdos run on top of msdos. Currently, it supports no mount option, but happily pass all option received to the msdos driver. I am not sure if all msdos mount option make sense with Umsdos. Here are at least those who are useful. uid= gid=
These options affect the operation of umsdos in directories which do not have an EMD file. They behave like normal msdos directory, with all limitation of msdos.
[linux/fs/umsdos/namei.c,1000]
#Specification: rename / new name exist
If the destination name already exist, it will silently be removed. EXT2 does it this way and this is the spec of SUNOS. So does UMSDOS.
If the destination is an empty directory it will also be removed.
[linux/fs/umsdos/namei.c,1008]
#Specification: rename / new name exist / possible flaw
The code to handle the deletion of the target (file and directory) use to be in umsdos_rename_f, surrounded by proper directory locking. This was insuring that only one process could achieve a rename (modification) operation in the source and destination directory. This was also insuring the operation was "atomic".
This has been changed because this was creating a kernel stack overflow (stack is only 4k in the kernel). To avoid the code doing the deletion of the target (if exist) has been moved to a upper layer. umsdos_rename_f is tried once and if it fails with EEXIST, the target is removed and umsdos_rename_f is done again.
This makes the code cleaner and (not sure) solve a deadlock problem one tester was experiencing.
The point is to mention that possibly, the semantic of "rename" may be wrong. Anyone dare to check that :-) Be aware that IF it is wrong, to produce the problem you will need two process trying to rename a file to the same target at the same time. Again, I am not sure it is a problem at all.
[linux/fs/umsdos/inode.c,177]
#Specification: inode / umsdos info
The first time an inode is seen (inode->i_count == 1), the inode number of the EMD file which control this inode is tagged to this inode. It allows operation such as notify_change to be handled.
[linux/fs/umsdos/inode.c,242]
#Specification: Inode / post initialisation
To completely initialise an inode, we need access to the owner directory, so we can locate more info in the EMD file. This is not available the first time the inode is access, we use a value in the inode to tell if it has been finally initialised.
At first, we have tried testing i_count but it was causing problem. It is possible that two or more process use the newly accessed inode. While the first one block during the initialisation (probably while reading the EMD file), the others believe all is well because i_count > 1. They go banana with a broken inode. See umsdos_lookup_patch and umsdos_patch_inode.