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

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

diff -u --recursive --new-file v2.0.30/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
@@ -59,7 +59,8 @@
 	{
 		/* Ok, now we're in trouble. The inode info is not
 		   there. What should we do now??? */
-		printk("smb_read_inode: inode info not found\n");
+		printk("smb_read_inode: inode %ld info not found\n",
+			inode->i_ino);
 		return;
 	}
 	inode_info->state = SMB_INODE_VALID;
@@ -92,24 +93,43 @@
 static void
 smb_put_inode(struct inode *inode)
 {
-	struct smb_dirent *finfo = SMB_FINFO(inode);
 	struct smb_server *server = SMB_SERVER(inode);
 	struct smb_inode_info *info = SMB_INOP(inode);
+	struct smb_dirent *finfo;
+	__u32 mtime = inode->i_mtime;
+
+	if (inode->i_count > 1) {
+		printk("smb_put_inode: in use device %s, inode %ld count=%d\n",
+			kdevname(inode->i_dev), inode->i_ino, inode->i_count);
+		return;
+	}
 
 	if (S_ISDIR(inode->i_mode))
 	{
 		smb_invalid_dir_cache(inode->i_ino);
 	}
-	if (finfo->opened != 0)
-	{
-		if (smb_proc_close(server, finfo->fileid, inode->i_mtime))
+	clear_inode(inode);
+
+	/*
+	 * We don't want the inode to be reused as free if we block here,
+	 * so temporarily increment i_count.
+	 */
+	inode->i_count++;
+	if (info) {
+		finfo = &info->finfo;
+		if (finfo->opened != 0)
 		{
-			/* We can't do anything but complain. */
-			DPRINTK("smb_put_inode: could not close\n");
+			if (smb_proc_close(server, finfo->fileid, mtime))
+			{
+				/* We can't do anything but complain. */
+				printk("smb_put_inode: could not close\n");
+			}
 		}
-	}
-	smb_free_inode_info(info);
-	clear_inode(inode);
+		smb_free_inode_info(info);
+	} else
+		printk("smb_put_inode: no inode info??\n");
+
+	inode->i_count--;
 }
 
 static void
@@ -212,10 +232,13 @@
 	kdev_t dev = sb->s_dev;
 	int error;
 
+	MOD_INC_USE_COUNT;
+
 	if (smb_get_mount_data(&data, raw_data) != 0)
 	{
 		printk("smb_read_super: wrong data argument\n");
 		sb->s_dev = 0;
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 	fd = data.fd;
@@ -223,12 +246,14 @@
 	{
 		printk("smb_read_super: invalid file descriptor\n");
 		sb->s_dev = 0;
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 	if (!S_ISSOCK(filp->f_inode->i_mode))
 	{
 		printk("smb_read_super: not a socket!\n");
 		sb->s_dev = 0;
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 	/* We must malloc our own super-block info */
@@ -238,6 +263,8 @@
 	if (smb_sb == NULL)
 	{
 		printk("smb_read_super: could not alloc smb_sb_info\n");
+		sb->s_dev = 0;
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 	filp->f_count += 1;
@@ -308,7 +335,6 @@
 		printk("smb_read_super: get root inode failed\n");
 		goto fail;
 	}
-	MOD_INC_USE_COUNT;
 	return sb;
 
       fail:
@@ -320,6 +346,7 @@
 	filp->f_count -= 1;
 	smb_dont_catch_keepalive(server);
 	smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info));
+	MOD_DEC_USE_COUNT;
 	return NULL;
 }
 
@@ -362,12 +389,35 @@
 		return -EPERM;
 
 	if (((attr->ia_valid & ATTR_GID) &&
-	     (attr->ia_uid != SMB_SERVER(inode)->m.gid)))
+	     (attr->ia_gid != SMB_SERVER(inode)->m.gid)))
 		return -EPERM;
 
-	if (((attr->ia_valid & ATTR_MODE) &&
-	(attr->ia_mode & ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
-		return -EPERM;
+	if (attr->ia_valid & ATTR_MODE) {
+		struct smb_dirent *fold = SMB_FINFO(inode);
+		struct smb_dirent finfo;
+
+		if (attr->ia_mode & ~(S_IFREG | S_IFDIR |
+				      S_IRWXU | S_IRWXG | S_IRWXO))
+			return -EPERM;
+
+		memset((char *)&finfo, 0, sizeof(finfo));
+		finfo.attr = fold->attr;
+
+		if((attr->ia_mode & 0200) == 0)
+		    finfo.attr |= aRONLY;
+		else
+		    finfo.attr &= ~aRONLY;
+
+		if ((error = smb_proc_setattr(SMB_SERVER(inode),
+					      inode, &finfo)) >= 0)
+		{
+			fold->attr = finfo.attr;
+			if ((attr->ia_mode & 0200) == 0)
+				inode->i_mode &= ~0222;
+			else
+				inode->i_mode |= 0222;
+		}
+	}
 
 	if ((attr->ia_valid & ATTR_SIZE) != 0)
 	{
@@ -381,41 +431,18 @@
 			goto fail;
 
 	}
-	if ((attr->ia_valid & (ATTR_CTIME | ATTR_MTIME | ATTR_ATIME)) != 0)
-	{
-
-		struct smb_dirent finfo;
-
-		finfo.attr = 0;
-		finfo.f_size = inode->i_size;
-		finfo.f_blksize = inode->i_blksize;
 
-		if ((attr->ia_valid & ATTR_CTIME) != 0)
-			finfo.f_ctime = attr->ia_ctime;
-		else
-			finfo.f_ctime = inode->i_ctime;
-
-		if ((attr->ia_valid & ATTR_MTIME) != 0)
-			finfo.f_mtime = attr->ia_mtime;
-		else
-			finfo.f_mtime = inode->i_mtime;
+	/* ATTR_CTIME and ATTR_ATIME can not be set via SMB, so ignore it. */
 
-		if ((attr->ia_valid & ATTR_ATIME) != 0)
-			finfo.f_atime = attr->ia_atime;
+	if (attr->ia_valid & ATTR_MTIME)
+	{
+		if (smb_make_open(inode, O_WRONLY) != 0)
+			error = -EACCES;
 		else
-			finfo.f_atime = inode->i_atime;
-
-		if ((error = smb_proc_setattr(SMB_SERVER(inode),
-					      inode, &finfo)) >= 0)
-		{
-			inode->i_ctime = finfo.f_ctime;
-			inode->i_mtime = finfo.f_mtime;
-			inode->i_atime = finfo.f_atime;
-		}
+			inode->i_mtime = attr->ia_mtime;
 	}
       fail:
 	smb_invalid_dir_cache(smb_info_ino(SMB_INOP(inode)->dir));
-
 	return error;
 }
 

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