patch-2.1.56 linux/fs/smbfs/inode.c

Next file: linux/fs/smbfs/proc.c
Previous file: linux/fs/smbfs/file.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.55/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
@@ -26,6 +26,9 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
+#define SB_of(server) ((struct super_block *) ((char *)(server) - \
+	(unsigned long)(&((struct super_block *)0)->u.smbfs_sb)))
+
 extern int close_fp(struct file *filp);
 
 static void smb_put_inode(struct inode *);
@@ -82,6 +85,23 @@
 }
 
 static void
+smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
+{
+	inode->i_dev	= inode->i_sb->s_dev;
+	inode->i_mode	= fattr->f_mode;
+	inode->i_nlink	= fattr->f_nlink;
+	inode->i_uid	= fattr->f_uid;
+	inode->i_gid	= fattr->f_gid;
+	inode->i_rdev	= fattr->f_rdev;
+	inode->i_size	= fattr->f_size;
+	inode->i_mtime	= fattr->f_mtime;
+	inode->i_ctime	= fattr->f_ctime;
+	inode->i_atime	= fattr->f_atime;
+	inode->i_blksize= fattr->f_blksize;
+	inode->i_blocks = fattr->f_blocks;
+}
+
+static void
 smb_read_inode(struct inode *inode)
 {
 	pr_debug("smb_iget: %p\n", read_fattr);
@@ -92,18 +112,8 @@
 		printk("smb_read_inode called from invalid point\n");
 		return;
 	}
-	inode->i_mode = read_fattr->f_mode;
-	inode->i_nlink = read_fattr->f_nlink;
-	inode->i_uid = read_fattr->f_uid;
-	inode->i_gid = read_fattr->f_gid;
-	inode->i_rdev = read_fattr->f_rdev;
-	inode->i_size = read_fattr->f_size;
-	inode->i_mtime = read_fattr->f_mtime;
-	inode->i_ctime = read_fattr->f_ctime;
-	inode->i_atime = read_fattr->f_atime;
-	inode->i_blksize = read_fattr->f_blksize;
-	inode->i_blocks = read_fattr->f_blocks;
 
+	smb_set_inode_attr(inode, read_fattr);
 	memset(&(inode->u.smbfs_i), 0, sizeof(inode->u.smbfs_i));
 
 	if (S_ISREG(inode->i_mode))
@@ -114,39 +124,112 @@
 		inode->i_op = NULL;
 }
 
+/*
+ * This is called if the connection has gone bad ...
+ * try to kill off all the current inodes.
+ */
 void
 smb_invalidate_inodes(struct smb_sb_info *server)
 {
 	printk("smb_invalidate_inodes\n");
+	shrink_dcache(); /* should shrink only this sb */
+	invalidate_inodes(SB_of(server));
 }
 
 int
-smb_revalidate_inode(struct inode *i)
+smb_revalidate_inode(struct inode *ino)
 {
+	struct dentry * dentry = ino->u.smbfs_i.dentry;
+	int error = 0;
+
 	pr_debug("smb_revalidate_inode\n");
-	return 0;
+	if (!ino)
+		goto bad_no_inode;
+	dentry = ino->u.smbfs_i.dentry;
+#if 0
+	if (dentry)
+	{
+		printk("smb_revalidate: checking %s/%s\n",
+			dentry->d_parent->d_name.name, dentry->d_name.name);
+	}
+#endif
+out:
+	return error;
+
+bad_no_inode:
+	printk("smb_revalidate: no inode!\n");
+	error = -EINVAL;
+	goto out;
 }
 
 int
-smb_refresh_inode(struct inode *i)
+smb_refresh_inode(struct inode *ino)
 {
+	struct dentry * dentry = ino->u.smbfs_i.dentry;
+	struct smb_fattr fattr;
+	int error;
+
 	pr_debug("smb_refresh_inode\n");
-	return 0;
+	error = -EIO;
+	if (!dentry) {
+		printk("smb_refresh_inode: no dentry, can't refresh\n");
+		goto out;
+	}
+
+	/* N.B. Should check for changes of important fields! cf. NFS */
+	error = smb_proc_getattr(dentry->d_parent, &(dentry->d_name), &fattr);
+	if (!error)
+	{
+		smb_set_inode_attr(ino, &fattr);
+	}
+out:
+	return error;
 }
 
+/*
+ * This routine is called for every iput().
+ */
 static void
 smb_put_inode(struct inode *ino)
 {
+	struct dentry * dentry;
 	pr_debug("smb_put_inode: count = %d\n", ino->i_count);
 
-	if (smb_close(ino))
-		printk("smbfs: could not close inode\n");
+	if (ino->i_count > 1) {
+		/*
+		 * Check whether the dentry still holds this inode. 
+		 * This looks scary, but should work ... d_inode is 
+		 * cleared before iput() in the dcache. 
+		 */
+		dentry = (struct dentry *) ino->u.smbfs_i.dentry;
+		if (dentry && dentry->d_inode != ino) {
+			ino->u.smbfs_i.dentry = NULL;
+#if 1
+printk("smb_put_inode: cleared dentry for %s/%s (%ld), count=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, ino->i_ino, ino->i_count);
+#endif
+		}
+	} else {
+		/*
+		 * Last use ... clear i_nlink to force
+		 * smb_delete_inode to be called.
+	 	*/
+		ino->i_nlink = 0;
+	}
 }
 
+/*
+ * This routine is called when i_nlink == 0 and i_count goes to 0.
+ * All blocking cleanup operations need to go here to avoid races.
+ */
 static void
-smb_delete_inode(struct inode *i)
+smb_delete_inode(struct inode *ino)
 {
 	pr_debug("smb_delete_inode\n");
+	if (smb_close(ino))
+		printk("smb_delete_inode: could not close inode %ld\n",
+			ino->i_ino);
+	clear_inode(ino);
 }
 
 static void
@@ -181,33 +264,20 @@
 	struct smb_fattr root;
 	kdev_t dev = sb->s_dev;
 	unsigned char *packet;
+	struct inode *root_inode;
+	struct dentry *dentry;
 
 	MOD_INC_USE_COUNT;
 
-	if (!data) {
-		printk("smb_read_super: missing data argument\n");
-		sb->s_dev = 0;
-		MOD_DEC_USE_COUNT;
-		return NULL;
-	}
+	if (!data)
+		goto out_no_data;
 		
 	if (data->version != SMB_MOUNT_VERSION)
-	{
-		printk(KERN_ERR "smb_read_super: wrong data argument."
-		       " Recompile smbmount.\n");
-		sb->s_dev = 0;
-		MOD_DEC_USE_COUNT;
-		return NULL;
-	}
+		goto out_wrong_data;
 
 	packet = smb_vmalloc(SMB_INITIAL_PACKET_SIZE);	
 	if (!packet)
-	{
-		pr_debug("smb_read_super: could not alloc packet\n");
-		sb->s_dev = 0;
-		MOD_DEC_USE_COUNT;
-  		return NULL;
-  	}
+		goto out_no_mem;
 
 	lock_super(sb);
 
@@ -222,7 +292,7 @@
 	sb->u.smbfs_sb.conn_pid = 0;
 	sb->u.smbfs_sb.packet = packet;
 	sb->u.smbfs_sb.packet_size = SMB_INITIAL_PACKET_SIZE;
-	sb->u.smbfs_sb.generation = 1;
+	sb->u.smbfs_sb.generation = 0;
 
 	sb->u.smbfs_sb.m = *data;
 	sb->u.smbfs_sb.m.file_mode = (sb->u.smbfs_sb.m.file_mode &
@@ -232,18 +302,38 @@
 
 	smb_init_root_dirent(&(sb->u.smbfs_sb), &root);
 
+	sb->s_root = NULL;
 	unlock_super(sb);
 
-	sb->s_root = d_alloc_root(smb_iget(sb, &root), NULL);
-	if (!sb->s_root)
-	{
-		sb->s_dev = 0;
-		printk(KERN_ERR "smb_read_super: get root inode failed\n");
-		smb_vfree(sb->u.smbfs_sb.packet);
-		MOD_DEC_USE_COUNT;
-		return NULL;
-	}
+	root_inode = smb_iget(sb, &root);
+	if (!root_inode)
+		goto out_no_root;
+	dentry = d_alloc_root(root_inode, NULL);
+	if (!dentry)
+		goto out_no_root;
+	root_inode->u.smbfs_i.dentry = dentry;
+	sb->s_root = dentry;
 	return sb;
+
+out_no_data:
+	printk("smb_read_super: missing data argument\n");
+	goto out;
+out_wrong_data:
+	printk(KERN_ERR "smb_read_super: wrong data argument."
+	       " Recompile smbmount.\n");
+	goto out;
+out_no_mem:
+	pr_debug("smb_read_super: could not alloc packet\n");
+	goto out;
+out_no_root:
+	sb->s_dev = 0; /* iput() might block */
+	printk(KERN_ERR "smb_read_super: get root inode failed\n");
+	iput(root_inode);
+	smb_vfree(packet);
+out:
+	sb->s_dev = 0;
+	MOD_DEC_USE_COUNT;
+	return NULL;
 }
 
 static int
@@ -265,32 +355,46 @@
 int
 smb_notify_change(struct inode *inode, struct iattr *attr)
 {
-	int error = 0;
+	struct dentry *dentry = inode->u.smbfs_i.dentry;
+	int error;
+
+	error = -EIO;
+	if (!dentry)
+	{
+		printk("smb_notify_change: no dentry for inode!\n");
+		goto out;
+	}
 
 	if ((error = inode_change_ok(inode, attr)) < 0)
-		return error;
+		goto out;
 
+	error = -EPERM;
 	if (((attr->ia_valid & ATTR_UID) &&
 	     (attr->ia_uid != SMB_SERVER(inode)->m.uid)))
-		return -EPERM;
+		goto out;
 
 	if (((attr->ia_valid & ATTR_GID) &&
 	     (attr->ia_uid != SMB_SERVER(inode)->m.gid)))
-		return -EPERM;
+		goto out;
 
 	if (((attr->ia_valid & ATTR_MODE) &&
 	(attr->ia_mode & ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
-		return -EPERM;
+		goto out;
+
+	/*
+	 * Assume success and invalidate the parent's dir cache
+	 */ 
+	smb_invalid_dir_cache(dentry->d_parent->d_inode);
 
 	if ((attr->ia_valid & ATTR_SIZE) != 0)
 	{
-		if ((error = smb_open(inode, O_WRONLY)) < 0)
-			goto fail;
+		if ((error = smb_open(dentry, O_WRONLY)) < 0)
+			goto out;
 
 		if ((error = smb_proc_trunc(SMB_SERVER(inode),
 					    inode->u.smbfs_i.fileid,
 					    attr->ia_size)) < 0)
-			goto fail;
+			goto out;
 	}
 	if ((attr->ia_valid & (ATTR_CTIME | ATTR_MTIME | ATTR_ATIME)) != 0)
 	{
@@ -300,36 +404,30 @@
 		fattr.attr = 0;
 		fattr.f_size = inode->i_size;
 		fattr.f_blksize = inode->i_blksize;
+		fattr.f_ctime = inode->i_ctime;
+		fattr.f_mtime = inode->i_mtime;
+		fattr.f_atime = inode->i_atime;
 
 		if ((attr->ia_valid & ATTR_CTIME) != 0)
 			fattr.f_ctime = attr->ia_ctime;
-		else
-			fattr.f_ctime = inode->i_ctime;
 
 		if ((attr->ia_valid & ATTR_MTIME) != 0)
 			fattr.f_mtime = attr->ia_mtime;
-		else
-			fattr.f_mtime = inode->i_mtime;
 
 		if ((attr->ia_valid & ATTR_ATIME) != 0)
 			fattr.f_atime = attr->ia_atime;
-		else
-			fattr.f_atime = inode->i_atime;
 
-		if ((error = smb_proc_setattr(SMB_SERVER(inode),
-					      inode, &fattr)) >= 0)
+		error = smb_proc_setattr(SMB_SERVER(inode), dentry, &fattr);
+		if (error >= 0)
 		{
 			inode->i_ctime = fattr.f_ctime;
 			inode->i_mtime = fattr.f_mtime;
 			inode->i_atime = fattr.f_atime;
 		}
 	}
-      fail:
-/*	smb_invalid_dir_cache(smb_info_ino(SMB_INOP(inode)->dir));*/
-
+out:
 	return error;
 }
-
 
 #ifdef DEBUG_SMB_MALLOC
 int smb_malloced;

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