patch-2.4.10 linux/fs/umsdos/inode.c

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

diff -u --recursive --new-file v2.4.9/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c
@@ -38,7 +38,7 @@
 		 ,atomic_read(&inode->i_count)));
 
 	if (inode == pseudo_root) {
-		printk (KERN_ERR "Umsdos: debug: releasing pseudo_root - ino=%lu count=%d\n", inode->i_ino, atomic_read(&inode->i_count));
+		Printk ((KERN_ERR "Umsdos: debug: releasing pseudo_root - ino=%lu count=%d\n", inode->i_ino, atomic_read(&inode->i_count)));
 	}
 
 	if (atomic_read(&inode->i_count) == 1)
@@ -49,7 +49,7 @@
 void UMSDOS_put_super (struct super_block *sb)
 {
 	Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n"));
-	if (saved_root) {
+	if (saved_root && pseudo_root && sb->s_dev == ROOT_DEV) {
 		shrink_dcache_parent(saved_root);
 		dput(saved_root);
 		saved_root = NULL;
@@ -153,16 +153,56 @@
 }
 
 
-int umsdos_notify_change_locked(struct dentry *, struct iattr *);
 /*
  * lock the parent dir before starting ...
+ * also handles hardlink converting
  */
 int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr)
 {
-	struct inode *dir = dentry->d_parent->d_inode;
-	struct inode *inode = dentry->d_inode;
+	struct inode *dir, *inode;
+	struct umsdos_info info;
+	struct dentry *temp, *old_dentry = NULL;
 	int ret;
 
+	ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len,
+				&info);
+	if (ret)
+		goto out;
+	ret = umsdos_findentry (dentry->d_parent, &info, 0);
+	if (ret) {
+printk("UMSDOS_notify_change: %s/%s not in EMD, ret=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, ret);
+		goto out;
+	}
+
+	if (info.entry.flags & UMSDOS_HLINK) {
+		/*
+		 * In order to get the correct (real) inode, we just drop
+		 * the original dentry.
+		 */ 
+		d_drop(dentry);
+Printk(("UMSDOS_notify_change: hard link %s/%s, fake=%s\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname));
+	
+		/* Do a real lookup to get the short name dentry */
+		temp = umsdos_covered(dentry->d_parent, info.fake.fname,
+						info.fake.len);
+		ret = PTR_ERR(temp);
+		if (IS_ERR(temp))
+			goto out;
+	
+		/* now resolve the link ... */
+		temp = umsdos_solve_hlink(temp);
+		ret = PTR_ERR(temp);
+		if (IS_ERR(temp))
+			goto out;
+		old_dentry = dentry;
+		dentry = temp;	/* so umsdos_notify_change_locked will operate on that */
+	}
+
+	dir = dentry->d_parent->d_inode;
+	inode = dentry->d_inode;
+
 	ret = inode_change_ok (inode, attr);
 	if (ret)
 		goto out;
@@ -171,11 +211,14 @@
 	ret = umsdos_notify_change_locked(dentry, attr);
 	up(&dir->i_sem);
 	if (ret == 0)
-		inode_setattr (inode, attr);
+		ret = inode_setattr (inode, attr);
 out:
+	if (old_dentry)
+		dput (dentry);	/* if we had to use fake dentry for hardlinks, dput() it now */
 	return ret;
 }
 
+
 /*
  * Must be called with the parent lock held.
  */
@@ -316,16 +359,16 @@
 	struct super_block *res;
 	struct dentry *new_root;
 
-	MSDOS_SB(sb)->options.isvfat = 0;
 	/*
 	 * Call msdos-fs to mount the disk.
 	 * Note: this returns res == sb or NULL
 	 */
 	res = msdos_read_super (sb, data, silent);
+
 	if (!res)
 		goto out_fail;
 
-	printk (KERN_INFO "UMSDOS 0.86i "
+	printk (KERN_INFO "UMSDOS 0.86k "
 		"(compatibility level %d.%d, fast msdos)\n", 
 		UMSDOS_VERSION, UMSDOS_RELEASE);
 
@@ -334,6 +377,7 @@
 
 	/* install our dentry operations ... */
 	sb->s_root->d_op = &umsdos_dentry_operations;
+
 	umsdos_patch_dentry_inode(sb->s_root, 0);
 
 	/* Check whether to change to the /linux root */
@@ -345,10 +389,9 @@
 			printk("umsdos_read_super: pseudo-root wrong ops!\n");
 
 		pseudo_root = new_root->d_inode;
-
 		saved_root = sb->s_root;
-		sb->s_root = new_root;
 		printk(KERN_INFO "UMSDOS: changed to alternate root\n");
+		dget (sb->s_root); sb->s_root = dget(new_root);
 	}
 	return sb;
 
@@ -381,10 +424,12 @@
 	root = lookup_one_len(UMSDOS_PSDROOT_NAME, sb->s_root,UMSDOS_PSDROOT_LEN); 
 	if (IS_ERR(root))
 		goto out_noroot;
+		
 	if (!root->d_inode || !S_ISDIR(root->d_inode->i_mode))
 		goto out_dput;
 
-	printk(KERN_INFO "check_pseudo_root: found %s/%s\n", root->d_parent->d_name.name, root->d_name.name);
+printk(KERN_INFO "check_pseudo_root: found %s/%s\n",
+root->d_parent->d_name.name, root->d_name.name);
 
 	/* look for /sbin/init */
 	sbin = lookup_one_len("sbin", root, 4);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)