patch for 2.0.33 smbfs inode probs

Bill Hawes (whawes@star.net)
Fri, 23 Jan 1998 15:30:26 -0500


This is a multi-part message in MIME format.
--------------066E518D5776076E9650505B
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

I've seen several reports of problems with 2.0.33 smbfs following a
"could not close" message, and have attached a patch that may help solve
the problem. What I think is happening is that an inode info structure
is being referenced again while the file is being closed in preparation
for deleting the structure. As the info structures for ordinary files
aren't use-counted, there's nothing to prevent the deletion after a
reference is added.

The patch simply clears the file length field before clearing the inode
and closing the file, so a search for the file name won't find the old
info structure. It also has a warning message so we can see if this is
really occurring.

I've also fixed a number of possible stale references to the
server->packet buffer, as the packet is sometimes changed while
receiving a message.

The patch is untested except for compilation, but if you've had smbfs
problems as described above, please give it a try and report any
messages logged.

Regards,
Bill
--------------066E518D5776076E9650505B
Content-Type: text/plain; charset=us-ascii; name="smbfs_inode33-patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="smbfs_inode33-patch"

--- ./fs/smbfs/inode.c.old Mon Sep 15 13:02:41 1997
+++ ./fs/smbfs/inode.c Fri Jan 23 15:47:11 1998
@@ -95,7 +95,6 @@
{
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) {
@@ -107,6 +106,12 @@
if (S_ISDIR(inode->i_mode))
{
smb_invalid_dir_cache(inode->i_ino);
+ } else
+ {
+ /*
+ * Clear the length so the info structure can't be found.
+ */
+ info->finfo.len = 0;
}
clear_inode(inode);

@@ -116,13 +121,13 @@
*/
inode->i_count++;
if (info) {
- finfo = &info->finfo;
- if (finfo->opened != 0)
+ if (info->finfo.opened != 0)
{
- if (smb_proc_close(server, finfo->fileid, mtime))
+ if (smb_proc_close(server, info->finfo.fileid, mtime))
{
/* We can't do anything but complain. */
- printk("smb_put_inode: could not close\n");
+ printk("smb_put_inode: could not close %s\n",
+ info->finfo.name);
}
}
smb_free_inode_info(info);
--- ./fs/smbfs/dir.c.old Wed Aug 13 12:57:46 1997
+++ ./fs/smbfs/dir.c Fri Jan 23 15:52:46 1998
@@ -107,21 +107,6 @@
return result;
}

-static int
-compare_filename(const struct smb_server *server,
- const char *s1, int len, struct smb_dirent *entry)
-{
- if (len != entry->len)
- {
- return 1;
- }
- if (server->case_handling == CASE_DEFAULT)
- {
- return strncasecmp(s1, entry->name, len);
- }
- return strncmp(s1, entry->name, len);
-}
-
struct smb_inode_info *
smb_find_inode(struct smb_server *server, ino_t ino)
{
@@ -507,9 +492,35 @@
return;
}

-/* We will search the inode that belongs to this name, currently by a
- complete linear search through the inodes belonging to this
- filesystem. This has to be fixed. */
+static int
+compare_filename(const struct smb_server *server,
+ const char *s1, int len, struct smb_dirent *entry)
+{
+ /* Check whether the entry is about to be removed */
+ if (!entry->len)
+ {
+ printk("SMBFS: dead entry %s\n", entry->name);
+ return 1;
+ }
+
+ if (len != entry->len)
+ {
+ return 1;
+ }
+ if (server->case_handling == CASE_DEFAULT)
+ {
+ return strncasecmp(s1, entry->name, len);
+ }
+ return strncmp(s1, entry->name, len);
+}
+
+/*
+ * Search for the smb_inode_info that belongs to this name,
+ * currently by a complete linear search through the inodes
+ * belonging to this filesystem.
+ *
+ * Note that this returns files as well as directories.
+ */
static struct smb_inode_info *
smb_find_dir_inode(struct inode *parent, const char *name, int len)
{
--- ./fs/smbfs/proc.c.old Mon Sep 15 13:02:41 1997
+++ ./fs/smbfs/proc.c Fri Jan 23 15:40:39 1998
@@ -570,6 +570,8 @@
smb_unlock_server(server);
return error;
}
+ /* N.B. Packet may change after request */
+ buf = server->packet;
p = smb_setup_header(server, SMBopen, 2, 0);
WSET(buf, smb_vwv0, 0x40); /* read only */
WSET(buf, smb_vwv1, o_attr);
@@ -589,6 +591,8 @@
}
/* We should now have data in vwv[0..6]. */

+ /* N.B. Packet may change after request */
+ buf = server->packet;
entry->fileid = WVAL(buf, smb_vwv0);
entry->attr = WVAL(buf, smb_vwv1);
entry->f_ctime = entry->f_atime =
@@ -646,7 +650,7 @@
smb_unlock_server(server);
return error;
}
- returned_count = WVAL(buf, smb_vwv0);
+ returned_count = WVAL(server->packet, smb_vwv0);

smb_decode_data(SMB_BUF(server->packet), data, &data_len, fs);

@@ -682,7 +686,7 @@

if ((res = smb_request_ok(server, SMBwrite, 1, 0)) >= 0)
{
- res = WVAL(buf, smb_vwv0);
+ res = WVAL(server->packet, smb_vwv0);
}
smb_unlock_server(server);

@@ -718,7 +722,7 @@
smb_unlock_server(server);
return error;
}
- fileid = WVAL(buf, smb_vwv0);
+ fileid = WVAL(server->packet, smb_vwv0);
smb_unlock_server(server);

smb_proc_close(server, fileid, CURRENT_TIME);
@@ -1374,6 +1378,8 @@
smb_unlock_server(server);
return result;
}
+ /* N.B. Packet may change after request */
+ buf = server->packet;
entry->attr = WVAL(buf, smb_vwv0);
entry->f_ctime = entry->f_atime =
entry->f_mtime = local2utc(DVAL(buf, smb_vwv1));

--------------066E518D5776076E9650505B--