patch-2.1.87 linux/fs/umsdos/namei.c

Next file: linux/fs/umsdos/rdir.c
Previous file: linux/fs/umsdos/mangle.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/namei.c linux/fs/umsdos/namei.c
@@ -31,97 +31,97 @@
 */
 static int umsdos_waitcreate(struct inode *dir)
 {
-	int ret = 0;
-	if (dir->u.umsdos_i.u.dir_info.creating
-		&& dir->u.umsdos_i.u.dir_info.pid != current->pid){
-		sleep_on(&dir->u.umsdos_i.u.dir_info.p);
-		ret = 1;
-	}
-	return ret;
+  int ret = 0;
+  if (dir->u.umsdos_i.u.dir_info.creating
+      && dir->u.umsdos_i.u.dir_info.pid != current->pid){
+    sleep_on(&dir->u.umsdos_i.u.dir_info.p);
+    ret = 1;
+  }
+  return ret;
 }
 /*
 	Wait for any lookup process to finish
 */
 static void umsdos_waitlookup (struct inode *dir)
 {
-	while (dir->u.umsdos_i.u.dir_info.looking){
-		sleep_on(&dir->u.umsdos_i.u.dir_info.p);
-	}
+  while (dir->u.umsdos_i.u.dir_info.looking){
+    sleep_on(&dir->u.umsdos_i.u.dir_info.p);
+  }
 }
 /*
 	Lock all other process out of this directory.
 */
 void umsdos_lockcreate (struct inode *dir)
 {
-	/* #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.
-	*/
-	/*
-		Wait for any creation process to finish except
-		if we (the process) own the lock
-	*/
-	while (umsdos_waitcreate(dir)!=0);
-	dir->u.umsdos_i.u.dir_info.creating++;
-	dir->u.umsdos_i.u.dir_info.pid = current->pid;
-	umsdos_waitlookup (dir);
+  /* #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.
+  */
+  /*
+    Wait for any creation process to finish except
+    if we (the process) own the lock
+  */
+  while (umsdos_waitcreate(dir)!=0);
+  dir->u.umsdos_i.u.dir_info.creating++;
+  dir->u.umsdos_i.u.dir_info.pid = current->pid;
+  umsdos_waitlookup (dir);
 }
 /*
 	Lock all other process out of those two directories.
 */
 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
 {
-	/*
-		We must check that both directory are available before
-		locking anyone of them. This is to avoid some deadlock.
-		Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing
-		this to me.
-	*/
-	while (1){
-		if (umsdos_waitcreate(dir1)==0
-			&& umsdos_waitcreate(dir2)==0){
-			/* We own both now */
-			dir1->u.umsdos_i.u.dir_info.creating++;
-			dir1->u.umsdos_i.u.dir_info.pid = current->pid;
-			dir2->u.umsdos_i.u.dir_info.creating++;
-			dir2->u.umsdos_i.u.dir_info.pid = current->pid;
-			break;
-		}
-	}
-	umsdos_waitlookup(dir1);
-	umsdos_waitlookup(dir2);
+  /*
+    We must check that both directory are available before
+    locking anyone of them. This is to avoid some deadlock.
+    Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing
+    this to me.
+  */
+  while (1){
+    if (umsdos_waitcreate(dir1)==0
+	&& umsdos_waitcreate(dir2)==0){
+      /* We own both now */
+      dir1->u.umsdos_i.u.dir_info.creating++;
+      dir1->u.umsdos_i.u.dir_info.pid = current->pid;
+      dir2->u.umsdos_i.u.dir_info.creating++;
+      dir2->u.umsdos_i.u.dir_info.pid = current->pid;
+      break;
+    }
+  }
+  umsdos_waitlookup(dir1);
+  umsdos_waitlookup(dir2);
 }
 /*
 	Wait until creation is finish in this directory.
 */
 void umsdos_startlookup (struct inode *dir)
 {
-	while (umsdos_waitcreate (dir) != 0);
-	dir->u.umsdos_i.u.dir_info.looking++;
+  while (umsdos_waitcreate (dir) != 0);
+  dir->u.umsdos_i.u.dir_info.looking++;
 }
 
 /*
@@ -129,25 +129,27 @@
 */
 void umsdos_unlockcreate (struct inode *dir)
 {
-	dir->u.umsdos_i.u.dir_info.creating--;
-	if (dir->u.umsdos_i.u.dir_info.creating < 0){
-		printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.creating < 0: %d"
-			,dir->u.umsdos_i.u.dir_info.creating);
-	}
-	wake_up (&dir->u.umsdos_i.u.dir_info.p);
+  dir->u.umsdos_i.u.dir_info.creating--;
+  if (dir->u.umsdos_i.u.dir_info.creating < 0){
+    printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.creating < 0: %d"
+	    ,dir->u.umsdos_i.u.dir_info.creating);
+  }
+  wake_up (&dir->u.umsdos_i.u.dir_info.p);
 }
+
 /*
 	Tell directory lookup is over.
 */
 void umsdos_endlookup (struct inode *dir)
 {
-	dir->u.umsdos_i.u.dir_info.looking--;
-	if (dir->u.umsdos_i.u.dir_info.looking < 0){
-		printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.looking < 0: %d"
-			,dir->u.umsdos_i.u.dir_info.looking);
-	}
-	wake_up (&dir->u.umsdos_i.u.dir_info.p);
+  dir->u.umsdos_i.u.dir_info.looking--;
+  if (dir->u.umsdos_i.u.dir_info.looking < 0){
+    printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.looking < 0: %d"
+	    ,dir->u.umsdos_i.u.dir_info.looking);
+  }
+  wake_up (&dir->u.umsdos_i.u.dir_info.p);
 }
+
 #else
 static void umsdos_lockcreate (struct inode *dir){}
 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2){}
@@ -156,152 +158,155 @@
 void umsdos_endlookup (struct inode *dir){}
 #endif
 static int umsdos_nevercreat(
-	struct inode *dir,
-	const char *name,		/* Name of the file to add */
-	int len,
-	int errcod)				/* Length of the name */
+			     struct inode *dir,
+			     struct dentry *dentry,
+			     int errcod)				/* Length of the name */
 {
-	int ret = 0;
-	if (umsdos_is_pseudodos(dir,name,len)){
-		/* #Specification: pseudo root / any file creation /DOS
-			The pseudo sub-directory /DOS can't be created!
-			EEXIST is returned.
-
-			The pseudo sub-directory /DOS can't be removed!
-			EPERM is returned.
-		*/
-		ret = -EPERM;
-		ret = errcod;
-	}else if (name[0] == '.'
-		&& (len == 1 || (len == 2 && name[1] == '.'))){
-		/* #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 ?
-		*/
-		ret = errcod;
-	}
-	return ret;
+  const char *name = dentry->d_name.name;
+  int len = dentry->d_name.len;
+  int ret = 0;
+  if (umsdos_is_pseudodos(dir,dentry)){
+    /* #Specification: pseudo root / any file creation /DOS
+       The pseudo sub-directory /DOS can't be created!
+       EEXIST is returned.
+       
+       The pseudo sub-directory /DOS can't be removed!
+       EPERM is returned.
+    */
+    ret = -EPERM;
+    ret = errcod;
+  }else if (name[0] == '.'
+	    && (len == 1 || (len == 2 && name[1] == '.'))){
+    /* #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 ?
+    */
+    ret = errcod;
+  }
+  return ret;
 }
 	
 /*
-	Add a new file (ordinary or special) into the alternate directory.
-	The file is added to the real MSDOS directory. If successful, it
-	is then added to the EDM file.
-
-	Return the status of the operation. 0 mean success.
+  Add a new file (ordinary or special) into the alternate directory.
+  The file is added to the real MSDOS directory. If successful, it
+  is then added to the EDM file.
+  
+  Return the status of the operation. 0 mean success.
 */
 static int umsdos_create_any (
-	struct inode *dir,
-	const char *name,		/* Name of the file to add */
-	int len,				/* Length of the name */
-	int mode,				/* Permission bit + file type ??? */
-	int rdev,				/* major, minor or 0 for ordinary file */
-							/* and symlinks */
-	char flags,
-	struct inode **result)	/* Will hold the inode of the newly created */
-							/* file */
+   struct inode *dir,
+   struct dentry *dentry,  /* name/length etc*/
+   int mode,		   /* Permission bit + file type ??? */
+   int rdev,		   /* major, minor or 0 for ordinary file */
+   /* and symlinks */
+   char flags
+   )	/* Will hold the inode of the newly created */
+     /* file */
 {
-	int ret = umsdos_nevercreat(dir,name,len,-EEXIST);
+    
+  int ret = umsdos_nevercreat(dir,dentry,-EEXIST);
+  if (ret == 0){
+    struct umsdos_info info;
+    ret = umsdos_parse(dentry->d_name.name,dentry->d_name.len,&info);
+  
+    if (ret == 0){
+      info.entry.mode = mode;
+      info.entry.rdev = rdev;
+      info.entry.flags = flags;
+      info.entry.uid = current->fsuid;
+      info.entry.gid = (dir->i_mode & S_ISGID)
+	? dir->i_gid : current->fsgid;
+      info.entry.ctime = info.entry.atime = info.entry.mtime
+	= CURRENT_TIME;
+      info.entry.nlink = 1;
+      umsdos_lockcreate(dir);
+      ret = umsdos_newentry (dir,&info);
+      if (ret == 0){
+	dir->i_count++;
+      /* FIXME
+	 ret = msdos_create (dir,info.fake.fname,info.fake.len
+	 ,S_IFREG|0777,result);
+      */
+	ret =msdos_create(dir,dentry,S_IFREG|0777);
 	if (ret == 0){
-		struct umsdos_info info;
-		ret = umsdos_parse (name,len,&info);
-		*result = NULL;
-		if (ret == 0){
-			info.entry.mode = mode;
-			info.entry.rdev = rdev;
-			info.entry.flags = flags;
-			info.entry.uid = current->fsuid;
-			info.entry.gid = (dir->i_mode & S_ISGID)
-				? dir->i_gid : current->fsgid;
-			info.entry.ctime = info.entry.atime = info.entry.mtime
-				= CURRENT_TIME;
-			info.entry.nlink = 1;
-			umsdos_lockcreate(dir);
-			ret = umsdos_newentry (dir,&info);
-			if (ret == 0){
-				atomic_inc(&dir->i_count);
-				ret = msdos_create (dir,info.fake.fname,info.fake.len
-					,S_IFREG|0777,result);
-				if (ret == 0){
-					struct inode *inode = *result;
-					umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
-					PRINTK (("inode %p[%d] ",inode,
-						 atomic_read(&inode->i_count)));
-					PRINTK (("Creation OK: [%d] %s %d pos %d\n",dir->i_ino
-						,info.fake.fname,current->pid,info.f_pos));
-				}else{
-					/* #Specification: create / file exist in DOS
-						Here is a situation. Trying to create a file with
-						UMSDOS. The file is unknown to UMSDOS but already
-						exist in the DOS directory.
-
-						Here is what we are NOT doing:
-
-						We could silently assume that everything is fine
-						and allows the creation to succeed.
-
-						It is possible not all files in the partition
-						are mean to be visible from linux. By trying to create
-						those file in some directory, one user may get access
-						to those file without proper permissions. Looks like
-						a security hole to me. Off course sharing a file system
-						with DOS is some kind of security hole :-)
-
-						So ?
-
-						We return EEXIST in this case.
-						The same is true for directory creation.
-					*/
-					if (ret == -EEXIST){
-						printk ("UMSDOS: out of sync, Creation error [%ld], "
-							"deleting %s %d %d pos %ld\n",dir->i_ino
-							,info.fake.fname,-ret,current->pid,info.f_pos);
-					}
-					umsdos_delentry (dir,&info,0);
-				}
-				PRINTK (("umsdos_create %s ret = %d pos %d\n"
-					,info.fake.fname,ret,info.f_pos));
-			}
-			umsdos_unlockcreate(dir);
-		}
+	  struct inode *inode = dentry->d_inode;
+	  umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
+	  Printk (("inode %p[%d] ",inode,inode->i_count));
+	  Printk (("Creation OK: [%d] %s %d pos %d\n",dir->i_ino
+		   ,info.fake.fname,current->pid,info.f_pos));
+	}else{
+	  /* #Specification: create / file exist in DOS
+	     Here is a situation. Trying to create a file with
+	     UMSDOS. The file is unknown to UMSDOS but already
+	     exist in the DOS directory.
+	     
+	     Here is what we are NOT doing:
+	     
+	     We could silently assume that everything is fine
+	     and allows the creation to succeed.
+	     
+	     It is possible not all files in the partition
+	     are mean to be visible from linux. By trying to create
+	     those file in some directory, one user may get access
+	     to those file without proper permissions. Looks like
+	     a security hole to me. Off course sharing a file system
+	     with DOS is some kind of security hole :-)
+	     
+	     So ?
+	     
+	     We return EEXIST in this case.
+	     The same is true for directory creation.
+	  */
+	  if (ret == -EEXIST){
+	    printk ("UMSDOS: out of sync, Creation error [%ld], "
+		    "deleting %s %d %d pos %ld\n",dir->i_ino
+		    ,info.fake.fname,-ret,current->pid,info.f_pos);
+	  }
+	  umsdos_delentry (dir,&info,0);
 	}
-	iput (dir);
-	return ret;
+	Printk (("umsdos_create %s ret = %d pos %d\n"
+		 ,info.fake.fname,ret,info.f_pos));
+      }
+      umsdos_unlockcreate(dir);
+    }
+  }
+  d_add(dentry,dir);
+  return ret;
 }
 /*
 	Initialise the new_entry from the old for a rename operation.
 	(Only useful for umsdos_rename_f() below).
 */
 static void umsdos_ren_init(
-	struct umsdos_info *new_info,
-	struct umsdos_info *old_info,
-	int flags)		/* 0 == copy flags from old_name */
-					/* != 0, this is the value of flags */
+      struct umsdos_info *new_info,
+      struct umsdos_info *old_info,
+      int flags)		/* 0 == copy flags from old_name */
+     /* != 0, this is the value of flags */
 {
-	new_info->entry.mode = old_info->entry.mode;
-	new_info->entry.rdev = old_info->entry.rdev;
-	new_info->entry.uid = old_info->entry.uid;
-	new_info->entry.gid = old_info->entry.gid;
-	new_info->entry.ctime = old_info->entry.ctime;
-	new_info->entry.atime = old_info->entry.atime;
-	new_info->entry.mtime = old_info->entry.mtime;
-	new_info->entry.flags = flags ? flags : old_info->entry.flags;
-	new_info->entry.nlink = old_info->entry.nlink;
+  new_info->entry.mode = old_info->entry.mode;
+  new_info->entry.rdev = old_info->entry.rdev;
+  new_info->entry.uid = old_info->entry.uid;
+  new_info->entry.gid = old_info->entry.gid;
+  new_info->entry.ctime = old_info->entry.ctime;
+  new_info->entry.atime = old_info->entry.atime;
+  new_info->entry.mtime = old_info->entry.mtime;
+  new_info->entry.flags = flags ? flags : old_info->entry.flags;
+  new_info->entry.nlink = old_info->entry.nlink;
 }
 
 #define chkstk() \
-	if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page){\
-		printk(KERN_ALERT "UMSDOS: %s magic %x != %lx ligne %d\n" \
-		, current->comm,STACK_MAGIC \
-		,*(unsigned long *)current->kernel_stack_page \
-		,__LINE__); \
-	}
+if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page){\
+    printk(KERN_ALERT "UMSDOS: %s magic %x != %lx ligne %d\n" \
+	   , current->comm,STACK_MAGIC \
+	   ,*(unsigned long *)current->kernel_stack_page \
+	   ,__LINE__); \
+}
 
 #undef chkstk
 #define chkstk() do { } while (0)
@@ -310,798 +315,802 @@
 	Rename a file (move) in the file system.
 */
 static int umsdos_rename_f(
-	struct inode * old_dir,
-	const char * old_name,
-	int old_len,
-	struct inode * new_dir,
-	const char * new_name,
-	int new_len,
-	int flags)		/* 0 == copy flags from old_name */
-					/* != 0, this is the value of flags */
+			   struct inode * old_dir,
+			   struct dentry *old_dentry,
+			   struct inode * new_dir,
+			   struct dentry *new_dentry,
+			   int flags)		/* 0 == copy flags from old_name */
+     /* != 0, this is the value of flags */
 {
-	int ret = -EPERM;
-	struct umsdos_info old_info;
-	int old_ret = umsdos_parse (old_name,old_len,&old_info);
-	struct umsdos_info new_info;
-	int new_ret = umsdos_parse (new_name,new_len,&new_info);
-chkstk();
-	PRINTK (("umsdos_rename %d %d ",old_ret,new_ret));
-	if (old_ret == 0 && new_ret == 0){
-		umsdos_lockcreate2(old_dir,new_dir);
-chkstk();
-		PRINTK (("old findentry "));
-		ret = umsdos_findentry(old_dir,&old_info,0);
-chkstk();
-		PRINTK (("ret %d ",ret));
-		if (ret == 0){
-			/* check sticky bit on old_dir */
-			if ( !(old_dir->i_mode & S_ISVTX) ||
-			    current->fsuid == old_info.entry.uid ||
-			    current->fsuid == old_dir->i_uid ||
-			    fsuser()) {
-				/* Does new_name already exist? */
-				PRINTK(("new findentry "));
-				ret = umsdos_findentry(new_dir,&new_info,0);
-				if (ret != 0 || /* if destination file exists, are we allowed to replace it ? */
-				    !(new_dir->i_mode & S_ISVTX) ||
-				    current->fsuid == new_info.entry.uid ||
-				    current->fsuid == new_dir->i_uid ||
-				    fsuser()) {
-					PRINTK (("new newentry "));
-					umsdos_ren_init(&new_info,&old_info,flags);
-					ret = umsdos_newentry (new_dir,&new_info);
-chkstk();
-					PRINTK (("ret %d %d ",ret,new_info.fake.len));
-					if (ret == 0){
-						PRINTK (("msdos_rename "));
-						atomic_inc(&old_dir->i_count);
-						atomic_inc(&new_dir->i_count);	/* Both inode are needed later */
-						ret = msdos_rename (old_dir
-								    ,old_info.fake.fname,old_info.fake.len
-								    ,new_dir
-								    ,new_info.fake.fname,new_info.fake.len);
-chkstk();
-						PRINTK (("after m_rename ret %d ",ret));
-						if (ret != 0){
-							umsdos_delentry (new_dir,&new_info
-									 ,S_ISDIR(new_info.entry.mode));
-chkstk();
-						}else{
-							ret = umsdos_delentry (old_dir,&old_info
-									       ,S_ISDIR(old_info.entry.mode));
-chkstk();
-							if (ret == 0){
-								/*
-								   This UMSDOS_lookup does not look very useful.
-								   It makes sure that the inode of the file will
-								   be correctly setup (umsdos_patch_inode()) in
-								   case it is already in use.
-								   
-								   Not very efficient ...
-								   */
-								struct inode *inode;
-								atomic_inc(&new_dir->i_count);
-								PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags));
-								ret = UMSDOS_lookup (new_dir,new_name,new_len
-										     ,&inode);
-chkstk();
-								if (ret != 0){
-									printk ("UMSDOS: partial rename for file %s\n"
-										,new_info.entry.name);
-								}else{
-									/*
-									   Update f_pos so notify_change will succeed
-									   if the file was already in use.
-									   */
-									umsdos_set_dirinfo (inode,new_dir,new_info.f_pos);
-chkstk();
-									iput (inode);
-								}
-							}
-						}
-					}
-				}else{
-					/* sticky bit set on new_dir */
-					PRINTK(("sticky set on new "));
-					ret = -EPERM;
-				}
-			}else{
-				/* sticky bit set on old_dir */
-				PRINTK(("sticky set on old "));
-				ret = -EPERM;
-			}
+  int ret = -EPERM;
+  struct umsdos_info old_info;
+  int old_ret = umsdos_parse (old_dentry->d_name.name,
+			      old_dentry->d_name.len,&old_info);
+  struct umsdos_info new_info;
+  int new_ret = umsdos_parse (new_dentry->d_name.name,
+			      new_dentry->d_name.len,&new_info);
+  chkstk();
+  Printk (("umsdos_rename %d %d ",old_ret,new_ret));
+  if (old_ret == 0 && new_ret == 0){
+    umsdos_lockcreate2(old_dir,new_dir);
+    chkstk();
+    Printk (("old findentry "));
+    ret = umsdos_findentry(old_dir,&old_info,0);
+    chkstk();
+    Printk (("ret %d ",ret));
+    if (ret == 0){
+      /* check sticky bit on old_dir */
+      if ( !(old_dir->i_mode & S_ISVTX) || fsuser() ||
+	   current->fsuid == old_info.entry.uid ||
+	   current->fsuid == old_dir->i_uid ) {
+	/* Does new_name already exist? */
+	PRINTK(("new findentry "));
+	ret = umsdos_findentry(new_dir,&new_info,0);
+	if (ret != 0 || /* if destination file exists, are we allowed to replace it ? */
+	    !(new_dir->i_mode & S_ISVTX) || fsuser() ||
+	    current->fsuid == new_info.entry.uid ||
+	    current->fsuid == new_dir->i_uid ) {
+	  PRINTK (("new newentry "));
+	  umsdos_ren_init(&new_info,&old_info,flags);
+	  ret = umsdos_newentry (new_dir,&new_info);
+	  chkstk();
+	  PRINTK (("ret %d %d ",ret,new_info.fake.len));
+	  if (ret == 0){
+	    struct dentry *old, *new;
+	    old = creat_dentry (old_info.fake.fname, old_info.fake.len, NULL);
+	    new = creat_dentry (new_info.fake.fname, new_info.fake.len, NULL);
+
+	    PRINTK (("msdos_rename "));
+	    old_dir->i_count++;
+	    new_dir->i_count++;	/* Both inode are needed later */
+	    ret = msdos_rename (old_dir,
+				old,
+				new_dir,
+				new);
+	    chkstk();
+	    PRINTK (("after m_rename ret %d ",ret));
+	    if (ret != 0){
+	      umsdos_delentry (new_dir,&new_info
+			       ,S_ISDIR(new_info.entry.mode));
+	      chkstk();
+	    }else{
+	      ret = umsdos_delentry (old_dir,&old_info
+				     ,S_ISDIR(old_info.entry.mode));
+	      chkstk();
+	      if (ret == 0){
+		/*
+		  This UMSDOS_lookup does not look very useful.
+		  It makes sure that the inode of the file will
+		  be correctly setup (umsdos_patch_inode()) in
+		  case it is already in use.
+		  
+		  Not very efficient ...
+		*/
+		struct inode *inode;
+		new_dir->i_count++;
+		PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags));
+		ret = UMSDOS_lookup (new_dir,new_dentry);
+		inode = new_dentry->d_inode;
+		chkstk();
+		if (ret != 0){
+		  printk ("UMSDOS: partial rename for file %s\n"
+			  ,new_info.entry.name);
+		}else{
+		  /*
+		    Update f_pos so notify_change will succeed
+		    if the file was already in use.
+		  */
+		  umsdos_set_dirinfo (inode,new_dir,new_info.f_pos);
+		  chkstk();
+		  /* iput (inode); FIXME */
 		}
-		umsdos_unlockcreate(old_dir);
-		umsdos_unlockcreate(new_dir);
+	      }
+	    }
+	  }
+	}else{
+	  /* sticky bit set on new_dir */
+	  Printk(("sticky set on new "));
+	  ret = -EPERM;
 	}
-	iput (old_dir);
-	iput (new_dir);
-	PRINTK (("\n"));
-	return ret;
+      }else{
+	/* sticky bit set on old_dir */
+	Printk(("sticky set on old "));
+	ret = -EPERM;
+      }
+    }
+    umsdos_unlockcreate(old_dir);
+    umsdos_unlockcreate(new_dir);
+  }
+  d_move(old_dentry,new_dentry);
+  Printk (("\n"));
+  return ret;
 }
 /*
 	Setup un Symbolic link or a (pseudo) hard link
 	Return a negative error code or 0 if ok.
 */
 static int umsdos_symlink_x(
-	struct inode * dir,
-	const char * name,
-	int len,
-	const char * symname,	/* name will point to this path */
-	int mode,
-	char flags)
+			    struct inode * dir,
+			    struct dentry *dentry,
+			    const char * symname,	/* name will point to this path */
+			    int mode,
+			    char flags)
 {
-	/* #Specification: symbolic links / strategy
-		A symbolic link is simply a file which hold a path. It is
-		implemented as a normal MSDOS file (not very space efficient :-()
-
-		I see 2 different way to do it. One is to place the link data
-		in unused entry of the EMD file. The other is to have a separate
-		file dedicated to hold all symbolic links data.
-
-		Let's go for simplicity...
-	*/
-	struct inode *inode;
-	int ret;
-	atomic_inc(&dir->i_count);/* We keep the inode in case we need it */
-						/* later */
-	ret = umsdos_create_any (dir,name,len,mode,0,flags,&inode);
-	PRINTK (("umsdos_symlink ret %d ",ret));
-	if (ret == 0){
-		int len = strlen(symname);
-		struct file filp;
-		filp.f_pos = 0;
-		/* Make the inode acceptable to MSDOS */
-		ret = umsdos_file_write_kmem (inode,&filp,symname,len);
-		iput (inode);
-		if (ret >= 0){
-			if (ret != len){
-				ret = -EIO;
-				printk ("UMSDOS: "
-					"Can't write symbolic link data\n");
-			}else{
-				ret = 0;
-			}
-		}
-		if (ret != 0){
-			UMSDOS_unlink (dir,name,len);
-			dir = NULL;
-		}
-	}
-	iput (dir);
-	PRINTK (("\n"));
-	return ret;
+  /* #Specification: symbolic links / strategy
+     A symbolic link is simply a file which hold a path. It is
+     implemented as a normal MSDOS file (not very space efficient :-()
+     
+     I see 2 different way to do it. One is to place the link data
+     in unused entry of the EMD file. The other is to have a separate
+     file dedicated to hold all symbolic links data.
+     
+     Let's go for simplicity...
+  */
+  
+  
+  int ret;
+  dir->i_count++;/* We keep the inode in case we need it */
+  /* later */
+  ret = umsdos_create_any (dir,dentry,mode,0,flags);
+  Printk (("umsdos_symlink ret %d ",ret));
+  if (ret == 0){
+    int len = strlen(symname);
+    struct file filp;
+    filp.f_pos = 0;
+    /* Make the inode acceptable to MSDOS FIXME */
+    Printk ((KERN_ERR "umsdos_symlink_x: FIXME /mn/ Here goes the crash.. known wrong code...\n"));
+    ret = umsdos_file_write_kmem (dentry->d_inode->i_ino, &filp,symname,ret,NULL);	/* FIXME /mn/: dentry->d_inode->i_ino is totaly wrong, just put in to compile the beast... */
+    /* dput(dentry); ?? where did this come from FIXME */
+    if (ret >= 0){
+      if (ret != len){
+	ret = -EIO;
+	printk ("UMSDOS: "
+		"Can't write symbolic link data\n");
+      }else{
+	ret = 0;
+      }
+    }
+    if (ret != 0){
+      UMSDOS_unlink (dir,dentry);
+      dir = NULL;
+    }
+  }
+  d_instantiate(dentry,dir);
+  Printk (("\n"));
+  return ret;
 }
 /*
-	Setup un Symbolic link.
-	Return a negative error code or 0 if ok.
+  Setup un Symbolic link.
+  Return a negative error code or 0 if ok.
 */
 int UMSDOS_symlink(
-	struct inode * dir,
-	const char * name,
-	int len,
-	const char * symname)	/* name will point to this path */
+   struct inode * dir,
+   struct dentry *dentry,
+   const char * symname
+   )
 {
-	return umsdos_symlink_x (dir,name,len,symname,S_IFLNK|0777,0);
+  return umsdos_symlink_x (dir,dentry,symname,S_IFLNK|0777,0);
 }
 /*
-	Add a link to an inode in a directory
+  Add a link to an inode in a directory
 */
 int UMSDOS_link (
-	struct inode * oldinode,
-	struct inode * dir,
-	const char * name,
-	int len)
+		 struct dentry * olddentry,
+		 struct inode * dir,
+		 struct dentry *dentry)
 {
-	/* #Specification: hard link / strategy
-		Well ... hard link are difficult to implement on top of an
-		MsDOS fat file system. Unlike UNIX file systems, there are no
-		inode. A directory entry hold the functionality of the inode
-		and the entry.
-
-		We will used the same strategy as a normal Unix file system
-		(with inode) except we will do it symbolically (using paths).
-
-		Because anything can happen during a DOS session (defragment,
-		directory sorting, etc...), we can't rely on MsDOS pseudo
-		inode number to record the link. For this reason, the link
-		will be done using hidden symbolic links. The following
-		scenario illustrate how it work.
-		
-		Given a file /foo/file
-
-		#
-			ln /foo/file /tmp/file2
-
-			become internally
-
-			mv /foo/file /foo/-LINK1
-			ln -s /foo/-LINK1 /foo/file
-			ln -s /foo/-LINK1 /tmp/file2
-		#
-
-		Using this strategy, we can operate on /foo/file or /foo/file2.
-		We can remove one and keep the other, like a normal Unix hard link.
-		We can rename /foo/file or /tmp/file2 independently.
-			
-		The entry -LINK1 will be hidden. It will hold a link count.
-		When all link are erased, the hidden file is erased too.
-	*/
-	/* #Specification: weakness / hard link
-		The strategy for hard link introduces a side effect that
-		may or may not be acceptable. Here is the sequence
-
-		#
-		mkdir subdir1
-		touch subdir1/file
-		mkdir subdir2
-		ln    subdir1/file subdir2/file
-		rm    subdir1/file
-		rmdir subdir1
-		rmdir: subdir1: Directory not empty
-		#
-
-		This happen because there is an invisible file (--link) in
-		subdir1 which is referenced by subdir2/file.
-
-		Any idea ?
-	*/
-	/* #Specification: weakness / hard link / rename directory
-		Another weakness of hard link come from the fact that
-		it is based on hidden symbolic links. Here is an example.
-
-		#
-		mkdir /subdir1
-		touch /subdir1/file
-		mkdir /subdir2
-		ln    /subdir1/file subdir2/file
-		mv    /subdir1 subdir3
-		ls -l /subdir2/file
-		#
-
-		Since /subdir2/file is a hidden symbolic link
-		to /subdir1/..hlinkNNN, accessing it will fail since
-		/subdir1 does not exist anymore (has been renamed).
-	*/
-	int ret = 0;
-	if (S_ISDIR(oldinode->i_mode)){
-		/* #Specification: hard link / directory
-			A hard link can't be made on a directory. EPERM is returned
-			in this case.
-		*/
-		ret = -EPERM;
-	}else if ((ret = umsdos_nevercreat(dir,name,len,-EPERM))==0){
-		struct inode *olddir;
-		ret = umsdos_get_dirowner(oldinode,&olddir);
-		PRINTK (("umsdos_link dir_owner = %d -> %p [%d] "
-			,oldinode->u.umsdos_i.i_dir_owner,olddir,
-			 atomic_read(&olddir->i_count)));
+    struct inode *oldinode = olddentry->d_inode;
+  /* #Specification: hard link / strategy
+     Well ... hard link are difficult to implement on top of an
+     MsDOS fat file system. Unlike UNIX file systems, there are no
+     inode. A directory entry hold the functionality of the inode
+     and the entry.
+     
+     We will used the same strategy as a normal Unix file system
+     (with inode) except we will do it symbolically (using paths).
+     
+     Because anything can happen during a DOS session (defragment,
+     directory sorting, etc...), we can't rely on MsDOS pseudo
+     inode number to record the link. For this reason, the link
+     will be done using hidden symbolic links. The following
+     scenario illustrate how it work.
+     
+     Given a file /foo/file
+     
+     #
+     ln /foo/file /tmp/file2
+     
+     become internally
+     
+     mv /foo/file /foo/-LINK1
+     ln -s /foo/-LINK1 /foo/file
+     ln -s /foo/-LINK1 /tmp/file2
+     #
+     
+     Using this strategy, we can operate on /foo/file or /foo/file2.
+     We can remove one and keep the other, like a normal Unix hard link.
+     We can rename /foo/file or /tmp/file2 independently.
+     
+     The entry -LINK1 will be hidden. It will hold a link count.
+     When all link are erased, the hidden file is erased too.
+  */
+  /* #Specification: weakness / hard link
+     The strategy for hard link introduces a side effect that
+     may or may not be acceptable. Here is the sequence
+     
+     #
+     mkdir subdir1
+     touch subdir1/file
+     mkdir subdir2
+     ln    subdir1/file subdir2/file
+     rm    subdir1/file
+     rmdir subdir1
+     rmdir: subdir1: Directory not empty
+     #
+     
+     This happen because there is an invisible file (--link) in
+     subdir1 which is referenced by subdir2/file.
+     
+     Any idea ?
+  */
+  /* #Specification: weakness / hard link / rename directory
+     Another weakness of hard link come from the fact that
+     it is based on hidden symbolic links. Here is an example.
+     
+     #
+     mkdir /subdir1
+     touch /subdir1/file
+     mkdir /subdir2
+     ln    /subdir1/file subdir2/file
+     mv    /subdir1 subdir3
+     ls -l /subdir2/file
+     #
+     
+     Since /subdir2/file is a hidden symbolic link
+     to /subdir1/..hlinkNNN, accessing it will fail since
+     /subdir1 does not exist anymore (has been renamed).
+  */
+  int ret = 0;
+  if (S_ISDIR(oldinode->i_mode)){
+    /* #Specification: hard link / directory
+       A hard link can't be made on a directory. EPERM is returned
+       in this case.
+    */
+    ret = -EPERM;
+  }else if ((ret = umsdos_nevercreat(dir,dentry,-EPERM))==0){
+    struct inode *olddir;
+    ret = umsdos_get_dirowner(oldinode,&olddir);
+    Printk (("umsdos_link dir_owner = %d -> %p [%d] "
+	     ,oldinode->u.umsdos_i.i_dir_owner,olddir,olddir->i_count));
+    if (ret == 0){
+      struct umsdos_dirent entry;
+      umsdos_lockcreate2(dir,olddir);
+      ret = umsdos_inode2entry (olddir,oldinode,&entry);
+      if (ret == 0){
+	Printk (("umsdos_link :%s: ino %d flags %d "
+		 ,entry.name
+		 ,oldinode->i_ino,entry.flags));
+	if (!(entry.flags & UMSDOS_HIDDEN)){
+	  /* #Specification: hard link / first hard link
+	     The first time a hard link is done on a file, this
+	     file must be renamed and hidden. Then an internal
+	     symbolic link must be done on the hidden file.
+	     
+	     The second link is done after on this hidden file.
+	     
+	     It is expected that the Linux MSDOS file system
+	     keeps the same pseudo inode when a rename operation
+	     is done on a file in the same directory.
+	  */
+	  struct umsdos_info info;
+	  ret = umsdos_newhidden (olddir,&info);
+	  if (ret == 0){
+	    Printk (("olddir[%d] ",olddir->i_count));
+	    ret = umsdos_rename_f( 
+				  olddentry->d_inode,
+				  olddentry,
+				  dir,
+				  dentry,
+				   UMSDOS_HIDDEN);
+	    if (ret == 0){
+	      char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
+	      if (path == NULL){
+		ret = -ENOMEM;
+	      }else{
+		struct dentry *temp;
+		temp = creat_dentry (entry.name, entry.name_len, NULL);
+		Printk (("olddir[%d] ",olddir->i_count));
+		ret = umsdos_locate_path (oldinode,path);
+		Printk (("olddir[%d] ",olddir->i_count));
 		if (ret == 0){
-			struct umsdos_dirent entry;
-			umsdos_lockcreate2(dir,olddir);
-			ret = umsdos_inode2entry (olddir,oldinode,&entry);
-			if (ret == 0){
-				PRINTK (("umsdos_link :%s: ino %d flags %d "
-					,entry.name
-					,oldinode->i_ino,entry.flags));
-				if (!(entry.flags & UMSDOS_HIDDEN)){
-					/* #Specification: hard link / first hard link
-						The first time a hard link is done on a file, this
-						file must be renamed and hidden. Then an internal
-						symbolic link must be done on the hidden file.
-
-						The second link is done after on this hidden file.
-
-						It is expected that the Linux MSDOS file system
-						keeps the same pseudo inode when a rename operation
-						is done on a file in the same directory.
-					*/
-					struct umsdos_info info;
-					ret = umsdos_newhidden (olddir,&info);
-					if (ret == 0){
-						atomic_add(2, &olddir->i_count);
-						PRINTK (("olddir[%d] ",
-							 atomic_read(&olddir->i_count)));
-						ret = umsdos_rename_f (olddir,entry.name
-							,entry.name_len
-							,olddir,info.entry.name,info.entry.name_len
-							,UMSDOS_HIDDEN);
-						if (ret == 0){
-							char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
-							if (path == NULL){
-								ret = -ENOMEM;
-							}else{
-								PRINTK (("olddir[%d] ",
-									 atomic_read(&olddir->i_count)));
-								ret = umsdos_locate_path (oldinode,path);
-								PRINTK (("olddir[%d] ",
-									 atomic_read(&olddir->i_count)));
-								if (ret == 0){
-									atomic_inc(&olddir->i_count);
-									ret = umsdos_symlink_x (olddir
-										,entry.name
-										,entry.name_len,path
-										,S_IFREG|0777,UMSDOS_HLINK);
-									if (ret == 0){
-										atomic_inc(&dir->i_count);
-										ret = umsdos_symlink_x (dir,name,len
-											,path
-											,S_IFREG|0777,UMSDOS_HLINK);
-									}
-								}
-								kfree (path);
-							}
-						}
-					}
-				}else{
-					char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
-					if (path == NULL){
-						ret = -ENOMEM;
-					}else{
-						ret = umsdos_locate_path (oldinode,path);
-						if (ret == 0){
-							atomic_inc(&dir->i_count);
-							ret = umsdos_symlink_x (dir,name,len,path
-											,S_IFREG|0777,UMSDOS_HLINK);
-						}
-						kfree (path);
-					}
-				}
-			}
-			umsdos_unlockcreate(olddir);
-			umsdos_unlockcreate(dir);
+		  olddir->i_count++;
+		  ret = umsdos_symlink_x (olddir
+					  ,temp
+					  ,path
+					  ,S_IFREG|0777,UMSDOS_HLINK);
+		  if (ret == 0){
+		    dir->i_count++;
+		    ret = umsdos_symlink_x (dir,dentry,
+					    path,
+					    S_IFREG|0777,UMSDOS_HLINK);
+		  }
 		}
-		iput (olddir);
+		kfree (path);
+	      }
+	    }
+	  }
+	}else{
+	  char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
+	  if (path == NULL){
+	    ret = -ENOMEM;
+	  }else{
+	    ret = umsdos_locate_path (oldinode,path);
+	    if (ret == 0){
+	      dir->i_count++;
+	      ret = umsdos_symlink_x (dir,dentry,path
+				      ,S_IFREG|0777,UMSDOS_HLINK);
+	    }
+	    kfree (path);
+	  }
 	}
-	if (ret == 0){
-		struct iattr newattrs;
-		oldinode->i_nlink++;
-		newattrs.ia_valid = 0;
-		ret = UMSDOS_notify_change(oldinode, &newattrs);
-	}
-	iput (oldinode);
-	iput (dir);
-	PRINTK (("umsdos_link %d\n",ret));
-	return ret;
+      }
+      umsdos_unlockcreate(olddir);
+      umsdos_unlockcreate(dir);
+    }
+    iput (olddir);
+  }
+  if (ret == 0){
+    struct iattr newattrs;
+    oldinode->i_nlink++;
+    newattrs.ia_valid = 0;
+    ret = UMSDOS_notify_change(olddentry, &newattrs);
+  }
+  dput (olddentry);
+  dput (dentry);
+  Printk (("umsdos_link %d\n",ret));
+  return ret;
 }
 /*
-	Add a new file into the alternate directory.
-	The file is added to the real MSDOS directory. If successful, it
-	is then added to the EDM file.
-
-	Return the status of the operation. 0 mean success.
+  Add a new file into the alternate directory.
+  The file is added to the real MSDOS directory. If successful, it
+  is then added to the EDM file.
+  
+  Return the status of the operation. 0 mean success.
 */
 int UMSDOS_create (
-	struct inode *dir,
-	const char *name,		/* Name of the file to add */
-	int len,				/* Length of the name */
-	int mode,				/* Permission bit + file type ??? */
-	struct inode **result)	/* Will hold the inode of the newly created */
+		   struct inode *dir,
+		   struct dentry *dentry, /* Length of the name */
+		   int mode		  /* Permission bit + file type ??? */
+		   )	/* Will hold the inode of the newly created */
 							/* file */
 {
-	return umsdos_create_any (dir,name,len,mode,0,0,result);
+  return umsdos_create_any (dir,dentry,mode,0,0);
 }
 /*
 	Add a sub-directory in a directory
 */
 int UMSDOS_mkdir(
-	struct inode * dir,
-	const char * name,
-	int len,
-	int mode)
+		 struct inode * dir,
+		 struct dentry *dentry,
+		 int mode)
 {
-	int ret = umsdos_nevercreat(dir,name,len,-EEXIST);
-	if (ret == 0){
-		struct umsdos_info info;
-		ret = umsdos_parse (name,len,&info);
-		PRINTK (("umsdos_mkdir %d\n",ret));
-		if (ret == 0){
-			info.entry.mode = mode | S_IFDIR;
-			info.entry.rdev = 0;
-			info.entry.uid = current->fsuid;
-			info.entry.gid = (dir->i_mode & S_ISGID)
-				? dir->i_gid : current->fsgid;
-			info.entry.ctime = info.entry.atime = info.entry.mtime
-				= CURRENT_TIME;
-			info.entry.flags = 0;
-			umsdos_lockcreate(dir);
-			info.entry.nlink = 1;
-			ret = umsdos_newentry (dir,&info);
-			PRINTK (("newentry %d ",ret));
-			if (ret == 0){
-				atomic_inc(&dir->i_count);
-				ret = msdos_mkdir (dir,info.fake.fname,info.fake.len,mode);
-				if (ret != 0){
-					umsdos_delentry (dir,&info,1);
-					/* #Specification: mkdir / Directory already exist in DOS
-						We do the same thing as for file creation.
-						For all user it is an error.
-					*/
-				}else{
-					/* #Specification: mkdir / umsdos directory / create EMD
-						When we created a new sub-directory in a UMSDOS
-						directory (one with full UMSDOS semantic), we
-						create immediately an EMD file in the new
-						sub-directory so it inherit UMSDOS semantic.
-					*/
-					struct inode *subdir;
-					ret = umsdos_real_lookup (dir,info.fake.fname
-						,info.fake.len,&subdir);
-					if (ret == 0){
-						struct inode *result;
-						ret = msdos_create (subdir,UMSDOS_EMD_FILE
-							,UMSDOS_EMD_NAMELEN,S_IFREG|0777,&result);
-						subdir = NULL;
-						iput (result);
-					}
-					if (ret < 0){
-						printk ("UMSDOS: Can't create empty --linux-.---\n");
-					}
-					iput (subdir);
-				}
-			}
-			umsdos_unlockcreate(dir);
-		}
+  int ret = umsdos_nevercreat(dir,dentry,-EEXIST);
+  if (ret == 0){
+    struct umsdos_info info;
+    ret = umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info);
+    Printk (("umsdos_mkdir %d\n",ret));
+    if (ret == 0){
+      info.entry.mode = mode | S_IFDIR;
+      info.entry.rdev = 0;
+      info.entry.uid = current->fsuid;
+      info.entry.gid = (dir->i_mode & S_ISGID)
+	? dir->i_gid : current->fsgid;
+      info.entry.ctime = info.entry.atime = info.entry.mtime
+	= CURRENT_TIME;
+      info.entry.flags = 0;
+      umsdos_lockcreate(dir);
+      info.entry.nlink = 1;
+      ret = umsdos_newentry (dir,&info);
+      Printk (("newentry %d ",ret));
+      if (ret == 0){
+	struct dentry *temp;
+	temp = creat_dentry (info.fake.fname, info.fake.len, NULL);
+	dir->i_count++;
+	ret = msdos_mkdir (dir, temp, mode);
+	if (ret != 0){
+	  umsdos_delentry (dir,&info,1);
+	  /* #Specification: mkdir / Directory already exist in DOS
+	     We do the same thing as for file creation.
+	     For all user it is an error.
+	  */
+	}else{
+	  /* #Specification: mkdir / umsdos directory / create EMD
+	     When we created a new sub-directory in a UMSDOS
+	     directory (one with full UMSDOS semantic), we
+	     create immediately an EMD file in the new
+	     sub-directory so it inherit UMSDOS semantic.
+	  */
+	  struct inode *subdir;
+	  ret = compat_umsdos_real_lookup (dir,info.fake.fname,
+					   info.fake.len,&subdir);
+	  if (ret == 0){
+	    struct inode *result;
+	    struct dentry *tdentry;
+	    tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL);
+
+	    ret = msdos_create (subdir, tdentry,S_IFREG|0777);
+	    subdir = NULL;
+	    /* iput (result); FIXME */
+	  }
+	  if (ret < 0){
+	    printk ("UMSDOS: Can't create empty --linux-.---\n");
+	  }
+	  /* iput (subdir); FIXME */
 	}
-	PRINTK (("umsdos_mkdir %d\n",ret));
-	iput (dir);
-	return ret;
+      }
+      umsdos_unlockcreate(dir);
+    }
+  }
+  Printk (("umsdos_mkdir %d\n",ret));
+  dput (dentry);
+  return ret;
 }
 /*
 	Add a new device special file into a directory.
 */
 int UMSDOS_mknod(
 	struct inode * dir,
-	const char * name,
-	int len,
+	struct dentry *dentry,         
 	int mode,
 	int rdev)
 {
-	/* #Specification: Special files / strategy
-		Device special file, pipes, etc ... are created like normal
-		file in the msdos file system. Of course they remain empty.
-
-		One strategy was to create those files only in the EMD file
-		since they were not important for MSDOS. The problem with
-		that, is that there were not getting inode number allocated.
-		The MSDOS filesystems is playing a nice game to fake inode
-		number, so why not use it.
-
-		The absence of inode number compatible with those allocated
-		for ordinary files was causing major trouble with hard link
-		in particular and other parts of the kernel I guess.
-	*/
-	struct inode *inode;
-	int ret = umsdos_create_any (dir,name,len,mode,rdev,0,&inode);
-	iput (inode);
-	return ret;
+  /* #Specification: Special files / strategy
+     Device special file, pipes, etc ... are created like normal
+     file in the msdos file system. Of course they remain empty.
+     
+     One strategy was to create those files only in the EMD file
+     since they were not important for MSDOS. The problem with
+     that, is that there were not getting inode number allocated.
+     The MSDOS filesystems is playing a nice game to fake inode
+     number, so why not use it.
+     
+     The absence of inode number compatible with those allocated
+     for ordinary files was causing major trouble with hard link
+     in particular and other parts of the kernel I guess.
+  */
+  int ret = umsdos_create_any (dir,dentry,mode,rdev,0);
+  dput(dentry);
+  return ret;
 }
 
 /*
-	Remove a sub-directory.
+  Remove a sub-directory.
 */
 int UMSDOS_rmdir(
 	struct inode * dir,
-	const char * name,
-	int len)
+	struct dentry *dentry)
 {
-	/* #Specification: style / iput strategy
-		In the UMSDOS project, I am trying to apply a single
-		programming style regarding inode management. Many
-		entry point are receiving an inode to act on, and must
-		do an iput() as soon as they are finished with
-		the inode.
-
-		For simple case, there is no problem. When you introduce
-		error checking, you end up with many iput placed around the
-		code.
-
-		The coding style I use all around is one where I am trying
-		to provide independent flow logic (I don't know how to
-		name this). With this style, code is easier to understand
-		but you rapidly get iput() all around. Here is an exemple
-		of what I am trying to avoid.
-
-		#
-		if (a){
-			...
-			if(b){
-				...
-			}
-			...
-			if (c){
-				// Complex state. Was b true ? 
-				...
-			}
-			...
-		}
-		// Weird state
-		if (d){
-			// ...
-		}
-		// Was iput finally done ?
-		return status;
-		#
-
-		Here is the style I am using. Still sometime I do the
-		first when things are very simple (or very complicated :-( )
-
-		#
-		if (a){
-			if (b){
-				...
-			}else if (c){
-				// A single state gets here
-			}
-		}else if (d){
-			...
-		}
-		return status;
-		#
-
-		Again, while this help clarifying the code, I often get a lot
-		of iput(), unlike the first style, where I can place few 
-		"strategic" iput(). "strategic" also mean, more difficult
-		to place.
-
-		So here is the style I will be using from now on in this project.
-		There is always an iput() at the end of a function (which has
-		to do an iput()). One iput by inode. There is also one iput()
-		at the places where a successful operation is achieved. This
-		iput() is often done by a sub-function (often from the msdos
-		file system). So I get one too many iput() ? At the place
-		where an iput() is done, the inode is simply nulled, disabling
-		the last one.
-
-		#
-		if (a){
-			if (b){
-				...
-			}else if (c){
-				msdos_rmdir(dir,...);
-				dir = NULL;
-			}
-		}else if (d){
-			...
-		}
-		iput (dir);
-		return status;
-		#
-
-		Note that the umsdos_lockcreate() and umsdos_unlockcreate() function
-		pair goes against this practice of "forgetting" the inode as soon
-		as possible.
-	*/		
-	int ret = umsdos_nevercreat(dir,name,len,-EPERM);
-	if (ret == 0){
-		struct inode *sdir;
-		atomic_inc(&dir->i_count);
-		ret = UMSDOS_lookup (dir,name,len,&sdir);
-		PRINTK (("rmdir lookup %d ",ret));
-		if (ret == 0){
-			int empty;
-			umsdos_lockcreate(dir);
-			if (atomic_read(&sdir->i_count) > 1){
-				ret = -EBUSY;
-			}else if ((empty = umsdos_isempty (sdir)) != 0){
-				PRINTK (("isempty %d i_count %d ",empty,
-					 atomic_read(&sdir->i_count)));
+  /* #Specification: style / iput strategy
+     In the UMSDOS project, I am trying to apply a single
+     programming style regarding inode management. Many
+     entry point are receiving an inode to act on, and must
+     do an iput() as soon as they are finished with
+     the inode.
+     
+     For simple case, there is no problem. When you introduce
+     error checking, you end up with many iput placed around the
+     code.
+     
+     The coding style I use all around is one where I am trying
+     to provide independent flow logic (I don't know how to
+     name this). With this style, code is easier to understand
+     but you rapidly get iput() all around. Here is an exemple
+     of what I am trying to avoid.
+     
+     #
+     if (a){
+     ...
+     if(b){
+     ...
+     }
+     ...
+     if (c){
+     // Complex state. Was b true ? 
+     ...
+     }
+     ...
+     }
+     // Weird state
+     if (d){
+     // ...
+     }
+     // Was iput finally done ?
+     return status;
+     #
+     
+     Here is the style I am using. Still sometime I do the
+     first when things are very simple (or very complicated :-( )
+     
+     #
+     if (a){
+     if (b){
+     ...
+     }else if (c){
+     // A single state gets here
+     }
+     }else if (d){
+     ...
+     }
+     return status;
+     #
+     
+     Again, while this help clarifying the code, I often get a lot
+     of iput(), unlike the first style, where I can place few 
+     "strategic" iput(). "strategic" also mean, more difficult
+     to place.
+     
+     So here is the style I will be using from now on in this project.
+     There is always an iput() at the end of a function (which has
+     to do an iput()). One iput by inode. There is also one iput()
+     at the places where a successful operation is achieved. This
+     iput() is often done by a sub-function (often from the msdos
+     file system). So I get one too many iput() ? At the place
+     where an iput() is done, the inode is simply nulled, disabling
+     the last one.
+     
+     #
+     if (a){
+     if (b){
+     ...
+     }else if (c){
+     msdos_rmdir(dir,...);
+     dir = NULL;
+     }
+     }else if (d){
+     ...
+     }
+     iput (dir);
+     return status;
+     #
+     
+     Note that the umsdos_lockcreate() and umsdos_unlockcreate() function
+     pair goes against this practice of "forgetting" the inode as soon
+     as possible.
+  */		
+
+  int ret = umsdos_nevercreat(dir,dentry,-EPERM);
+  if (ret == 0){
+    volatile struct inode *sdir;
+    dir->i_count++;
+    ret = UMSDOS_lookup (dir, dentry);
+    sdir = dentry->d_inode;
+    Printk (("rmdir lookup %d ",ret));
+    if (ret == 0){
+      int empty;
+      umsdos_lockcreate(dir);
+      if (sdir->i_count > 1){
+	ret = -EBUSY;
+      }else if ((empty = umsdos_isempty (sdir)) != 0){
+	struct dentry *tdentry;
+	tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_FILE, NULL);
+	Printk (("isempty %d i_count %d ",empty,sdir->i_count));
 				/* check sticky bit */
-				if ( !(dir->i_mode & S_ISVTX) ||
-				    current->fsuid == sdir->i_uid ||
-				    current->fsuid == dir->i_uid ||
-				    fsuser()) {
-					if (empty == 1){
-						/* We have to removed the EMD file */
-						ret = msdos_unlink(sdir,UMSDOS_EMD_FILE
-								   ,UMSDOS_EMD_NAMELEN);
-						sdir = NULL;
-					}
-					/* sdir must be free before msdos_rmdir() */
-					iput (sdir);
-					sdir = NULL;
-					PRINTK (("isempty ret %d nlink %d ",ret,dir->i_nlink));
-					if (ret == 0){
-						struct umsdos_info info;
-						atomic_inc(&dir->i_count);
-						umsdos_parse (name,len,&info);
-						/* The findentry is there only to complete */
-						/* the mangling */
-						umsdos_findentry (dir,&info,2);
-						ret = msdos_rmdir (dir,info.fake.fname
-								   ,info.fake.len);
-						if (ret == 0){
-							ret = umsdos_delentry (dir,&info,1);
-						}
-					}
-				}else{
-					/* sticky bit set and we don't have permission */
-					PRINTK(("sticky set "));
-					ret = -EPERM;
-				}
-			}else{	
-				/*
-					The subdirectory is not empty, so leave it there
-				*/
-				ret = -ENOTEMPTY;
-			}
-			iput(sdir);
-			umsdos_unlockcreate(dir);
-		}	
+	if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
+	     current->fsuid == sdir->i_uid ||
+	     current->fsuid == dir->i_uid ) {
+	  if (empty == 1){
+	    /* We have to removed the EMD file */
+	    ret = msdos_unlink (sdir, tdentry);
+	    sdir = NULL;
+	  }
+	  /* sdir must be free before msdos_rmdir() */
+	  /* iput (sdir); FIXME */
+	  sdir = NULL;
+	  Printk (("isempty ret %d nlink %d ",ret,dir->i_nlink));
+	  if (ret == 0){
+	    struct umsdos_info info;
+	    struct dentry *temp;
+	    dir->i_count++;
+	    umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info);
+	    /* The findentry is there only to complete */
+	    /* the mangling */
+	    umsdos_findentry (dir,&info,2);
+	    temp = creat_dentry (info.fake.fname, info.fake.len, NULL);
+	    
+	    ret = msdos_rmdir (dir, temp);
+	    if (ret == 0){
+	      ret = umsdos_delentry (dir,&info,1);
+	    }
+	  }
+	}else{
+	  /* sticky bit set and we don't have permission */
+	  Printk(("sticky set "));
+	  ret = -EPERM;
 	}
-	iput (dir);
-	PRINTK (("umsdos_rmdir %d\n",ret));
-	return ret;
+      }else{	
+	/*
+	  The subdirectory is not empty, so leave it there
+	*/
+	ret = -ENOTEMPTY;
+      }
+      /* iput(sdir); FIXME */
+      umsdos_unlockcreate(dir);
+    }	
+  }
+  dput(dentry);
+  Printk (("umsdos_rmdir %d\n",ret));
+  return ret;
 }
+
+
+
 /*
-	Remove a file from the directory.
+  Remove a file from the directory.
 */
 int UMSDOS_unlink (
 	struct inode * dir,
-	const char * name,
-	int len)
+	struct dentry *dentry)
 {
-	int ret = umsdos_nevercreat(dir,name,len,-EPERM);
-	if (ret == 0){
-		struct umsdos_info info;
-		ret = umsdos_parse (name,len,&info);
-		if (ret == 0){
-			umsdos_lockcreate(dir);
-			ret = umsdos_findentry(dir,&info,1);
-			if (ret == 0){
-				PRINTK (("UMSDOS_unlink %s ",info.fake.fname));
+  int ret = umsdos_nevercreat(dir,dentry,-EPERM);
+  if (ret == 0){
+    struct umsdos_info info;
+    ret = umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info);
+    if (ret == 0){
+      umsdos_lockcreate(dir);
+      ret = umsdos_findentry(dir,&info,1);
+      if (ret == 0){
+	Printk (("UMSDOS_unlink %s ",info.fake.fname));
 				/* check sticky bit */
-				if ( !(dir->i_mode & S_ISVTX) ||
-				    current->fsuid == info.entry.uid ||
-				    current->fsuid == dir->i_uid ||
-				    fsuser()) {
-					if (info.entry.flags & UMSDOS_HLINK){
-						/* #Specification: hard link / deleting a link
-						   When we deletes a file, and this file is a link
-						   we must subtract 1 to the nlink field of the
-						   hidden link.
-						   
-						   If the count goes to 0, we delete this hidden
-						   link too.
-						   */
-						/*
-						   First, get the inode of the hidden link
-						   using the standard lookup function.
-						   */
-						struct inode *inode;
-						atomic_inc(&dir->i_count);
-						ret = UMSDOS_lookup (dir,name,len,&inode);
-						if (ret == 0){
-							PRINTK (("unlink nlink = %d ",inode->i_nlink));
-							inode->i_nlink--;
-							if (inode->i_nlink == 0){
-								struct inode *hdir = iget(inode->i_sb
-											  ,inode->u.umsdos_i.i_dir_owner);
-								struct umsdos_dirent entry;
-								ret = umsdos_inode2entry (hdir,inode,&entry);
-								if (ret == 0){
-									ret = UMSDOS_unlink (hdir,entry.name
-											     ,entry.name_len);
-								}else{
-									iput (hdir);
-								}
-							}else{
-								struct iattr newattrs;
-								newattrs.ia_valid = 0;
-								ret = UMSDOS_notify_change (inode, &newattrs);
-							}
-							iput (inode);
-						}
-					}
-					if (ret == 0){
-						ret = umsdos_delentry (dir,&info,0);
-						if (ret == 0){
-							PRINTK (("Avant msdos_unlink %s ",info.fake.fname));
-							atomic_inc(&dir->i_count);
-							ret = msdos_unlink_umsdos (dir,info.fake.fname
-										   ,info.fake.len);
-							PRINTK (("msdos_unlink %s %o ret %d ",info.fake.fname
-								 ,info.entry.mode,ret));
-						}
-					}
-				}else{
-					/* sticky bit set and we've not got permission */
-					PRINTK(("sticky set "));
-					ret = -EPERM;
-				}
-			}
-			umsdos_unlockcreate(dir);
+	if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
+	     current->fsuid == info.entry.uid ||
+	     current->fsuid == dir->i_uid ) {
+	  if (info.entry.flags & UMSDOS_HLINK){
+	    /* #Specification: hard link / deleting a link
+	       When we deletes a file, and this file is a link
+	       we must subtract 1 to the nlink field of the
+	       hidden link.
+	       
+	       If the count goes to 0, we delete this hidden
+	       link too.
+	    */
+	    /*
+	      First, get the inode of the hidden link
+	      using the standard lookup function.
+	    */
+	    struct inode *inode;
+	    dir->i_count++;
+	    ret = UMSDOS_lookup (dir,dentry);
+	    inode = dentry->d_inode;
+	    if (ret == 0){
+	      Printk (("unlink nlink = %d ",inode->i_nlink));
+	      inode->i_nlink--;
+	      if (inode->i_nlink == 0){
+		struct inode *hdir = iget(inode->i_sb
+					  ,inode->u.umsdos_i.i_dir_owner);
+		struct umsdos_dirent entry;
+		ret = umsdos_inode2entry (hdir,inode,&entry);
+		if (ret == 0){
+		  ret = UMSDOS_unlink (hdir,dentry);
+		}else{
+		    /* iput (hdir); FIXME */
 		}
-	}	
-	iput (dir);
-	PRINTK (("umsdos_unlink %d\n",ret));
-	return ret;
+	      }else{
+		struct iattr newattrs;
+		newattrs.ia_valid = 0;
+		ret = UMSDOS_notify_change (dentry, &newattrs);
+	      }
+	      /* iput (inode); FIXME */
+	    }
+	  }
+	  if (ret == 0){
+	    ret = umsdos_delentry (dir,&info,0);
+	    if (ret == 0){
+	      struct dentry *temp;
+	      Printk (("Avant msdos_unlink %s ",info.fake.fname));
+	      dir->i_count++;
+	      temp = creat_dentry (info.fake.fname, info.fake.len, NULL);
+	      ret = msdos_unlink_umsdos (dir, temp);
+	      Printk (("msdos_unlink %s %o ret %d ",info.fake.fname
+		       ,info.entry.mode,ret));
+	    }
+	  }
+	}else{
+	  /* sticky bit set and we've not got permission */
+	  Printk(("sticky set "));
+	  ret = -EPERM;
+	}
+      }
+      umsdos_unlockcreate(dir);
+    }
+  }	
+  dput(dentry);
+  Printk (("umsdos_unlink %d\n",ret));
+  return ret;
 }
 
+
+
 /*
 	Rename a file (move) in the file system.
 */
 int UMSDOS_rename(
-	struct inode * old_dir,
-	const char * old_name,
-	int old_len,
-	struct inode * new_dir,
-	const char * new_name,
-	int new_len)
+		  struct inode * old_dir,
+		  struct dentry * old_dentry,
+		  struct inode * new_dir,
+		  struct dentry * new_dentry)
 {
-	/* #Specification: weakness / rename
-		There is a case where UMSDOS rename has a different behavior
-		than normal UNIX file system. Renaming an open file across
-		directory boundary does not work. Renaming an open file within
-		a directory does work however.
-
-		The problem (not sure) is in the linux VFS msdos driver.
-		I believe this is not a bug but a design feature, because
-		an inode number represent some sort of directory address
-		in the MSDOS directory structure. So moving the file into
-		another directory does not preserve the inode number.
-	*/
-	int ret = umsdos_nevercreat(new_dir,new_name,new_len,-EEXIST);
-	if (ret == 0){
-		/* umsdos_rename_f eat the inode and we may need those later */
-		atomic_inc(&old_dir->i_count);
-		atomic_inc(&new_dir->i_count);
-		ret = umsdos_rename_f (old_dir,old_name,old_len,new_dir,new_name
-			,new_len,0);
-		if (ret == -EEXIST){
-			/* #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.
-			*/
-			/* #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.
-			*/
-			/* This is not super efficient but should work */
-			atomic_inc(&new_dir->i_count);
-			ret = UMSDOS_unlink (new_dir,new_name,new_len);
-chkstk();
-			PRINTK (("rename unlink ret %d %d -- ",ret,new_len));
-			if (ret == -EISDIR){
-				atomic_inc(&new_dir->i_count);
-				ret = UMSDOS_rmdir (new_dir,new_name,new_len);
-chkstk();
-				PRINTK (("rename rmdir ret %d -- ",ret));
-			}
-			if (ret == 0){
-				ret = umsdos_rename_f (old_dir,old_name,old_len
-					,new_dir,new_name,new_len,0);
-				new_dir = old_dir = NULL;
-			}
-		}
-	}
-	iput (new_dir);
-	iput (old_dir);
-	return ret;
+  /* #Specification: weakness / rename
+     There is a case where UMSDOS rename has a different behavior
+     than normal UNIX file system. Renaming an open file across
+     directory boundary does not work. Renaming an open file within
+     a directory does work however.
+     
+     The problem (not sure) is in the linux VFS msdos driver.
+     I believe this is not a bug but a design feature, because
+     an inode number represent some sort of directory address
+     in the MSDOS directory structure. So moving the file into
+     another directory does not preserve the inode number.
+  */
+  int ret = umsdos_nevercreat(new_dir,new_dentry,-EEXIST);
+  if (ret == 0){
+    /* umsdos_rename_f eat the inode and we may need those later */
+    old_dir->i_count++;
+    new_dir->i_count++;
+    ret = umsdos_rename_f (old_dir,old_dentry,new_dir,new_dentry,0);
+    if (ret == -EEXIST){
+      /* #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.
+      */
+      /* #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.
+      */
+      /* This is not super efficient but should work */
+      new_dir->i_count++;
+      ret = UMSDOS_unlink (new_dir,new_dentry);
+      chkstk();
+      Printk (("rename unlink ret %d -- ",ret));
+      if (ret == -EISDIR){
+	new_dir->i_count++;
+	ret = UMSDOS_rmdir (new_dir,new_dentry);
+	chkstk();
+	Printk (("rename rmdir ret %d -- ",ret));
+      }
+      if (ret == 0){
+	ret = umsdos_rename_f(old_dir,old_dentry,
+			      new_dir,new_dentry,0);
+	new_dir = old_dir = NULL;
+      }
+    }
+  }
+  dput (new_dentry);
+  dput (old_dentry);
+  return ret;
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov