Re: SMBFS & 2.1.62 (patch attached)

Bill Hawes (whawes@star.net)
Thu, 06 Nov 1997 12:02:11 -0500


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

Steve Clark wrote:
> If I copy a text file from my linux system to either of the above
> platforms and the target filename does not already exist, the file is
> copied but I receive and EIO error from the cp command. If I immediately
> try to do the same thing again I get the EIO error but now the length of
> the destination file is ZERO.

OK, I have a theory on what might be going wrong. Newer SMB servers
(e.g. Win NT) apparently create files already open and return a
filehandle. The current smbfs isn't ready to work with this, so it
closes the file immediately.

But if an older server -- Win 95 or 3.11? -- doesn't open the file, then
the attempted close might be generating the spurious error code. (The
fileid is probably bogus.)

To test this out, I've added code to print out the fileid after a
create, and to close it only if the protocol level is NT1 _and_ the
fileid is non-zero. (Win 95 unfortunately identifies itself as level
NT1, so just the protocol test isn't enough.)

Please give the attached patch a try. I'd like to track down the source
of the problem rather than just squashing a return error code.

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

--- linux-2.1.62/fs/smbfs/dir.c.old Tue Nov 4 16:07:02 1997
+++ linux-2.1.62/fs/smbfs/dir.c Wed Nov 5 14:28:36 1997
@@ -17,6 +17,10 @@
/* #define pr_debug printk */
#define SMBFS_MAX_AGE 5*HZ

+#ifndef shrink_dcache_parent
+#define shrink_dcache_parent(dentry) shrink_dcache_sb((dentry)->d_sb)
+#endif
+
static ssize_t smb_dir_read(struct file *, char *, size_t, loff_t *);
static int smb_readdir(struct file *, void *, filldir_t);
static int smb_dir_open(struct inode *, struct file *);
@@ -72,19 +76,6 @@
}

/*
- * Compute the hash for a qstr.
- * N.B. Move to include/linux/dcache.h?
- */
-static unsigned int
-hash_it(const char * name, unsigned int len)
-{
- unsigned long hash = init_name_hash();
- while (len--)
- hash = partial_name_hash(*name++, hash);
- return end_name_hash(hash);
-}
-
-/*
* If a dentry already exists, we have to give the cache entry
* the correct inode number. This is needed for getcwd().
*/
@@ -97,7 +88,7 @@
/* N.B. Make cache_dirent name a qstr! */
qname.name = entry->name;
qname.len = entry->len;
- qname.hash = hash_it(qname.name, qname.len);
+ qname.hash = full_name_hash(qname.name, qname.len);
new_dentry = d_lookup(dentry, &qname);
if (new_dentry)
{
@@ -436,8 +427,17 @@
* Since the dentry is holding an inode, the file
* is in use, so we have to close it first.
*/
- if (dentry->d_inode)
- smb_close(dentry->d_inode);
+ smb_close(dentry->d_inode);
+
+ /*
+ * Prune any child dentries so this dentry can become negative.
+ */
+ if (dentry->d_count > 1) {
+ shrink_dcache_parent(dentry);
+ error = -EBUSY;
+ if (dentry->d_count > 1)
+ goto out;
+ }

smb_invalid_dir_cache(dir);
error = smb_proc_rmdir(dentry->d_parent, &(dentry->d_name));
@@ -463,8 +463,7 @@
* Since the dentry is holding an inode, the file
* is in use, so we have to close it first.
*/
- if (dentry->d_inode)
- smb_close(dentry->d_inode);
+ smb_close(dentry->d_inode);

smb_invalid_dir_cache(dir);
error = smb_proc_unlink(dentry->d_parent, &(dentry->d_name));
--- linux-2.1.62/fs/smbfs/proc.c.old Tue Nov 4 16:07:02 1997
+++ linux-2.1.62/fs/smbfs/proc.c Thu Nov 6 12:42:10 1997
@@ -335,7 +335,6 @@
case ERRbadfunc:
return EINVAL;
case ERRbadfile:
- return ENOENT;
case ERRbadpath:
return ENOENT;
case ERRnofids:
@@ -351,7 +350,6 @@
case ERRbadmem:
return EFAULT;
case ERRbadenv:
- return EREMOTEIO;
case ERRbadformat:
return EREMOTEIO;
case ERRbadaccess:
@@ -376,6 +374,8 @@
return 0; /* Unknown error!! */
case 123: /* Invalid name?? e.g. .tmp* */
return ENOENT;
+ case 145: /* Win NT 4.0: non-empty directory? */
+ return EBUSY;
/* This next error seems to occur on an mv when
* the destination exists */
case 183:
@@ -409,7 +409,6 @@
case ERRnotready:
return EUCLEAN;
case ERRbadcmd:
- return EIO;
case ERRdata:
return EIO;
case ERRbadreq:
@@ -526,31 +525,41 @@
static int
smb_request_ok(struct smb_sb_info *s, int command, int wct, int bcc)
{
- int result = 0;
+ int result = -EIO;

s->rcls = 0;
s->err = 0;

/* Make sure we have a connection */
- if (s->state != CONN_VALID && !smb_retry(s))
+ if (s->state != CONN_VALID)
{
- result = -EIO;
- } else if (smb_request(s) < 0)
+ if (!smb_retry(s))
+ goto out;
+ }
+
+ if (smb_request(s) < 0)
{
pr_debug("smb_request failed\n");
- result = -EIO;
- } else if (smb_valid_packet(s->packet) != 0)
+ goto out;
+ }
+ if (smb_valid_packet(s->packet) != 0)
{
pr_debug("not a valid packet!\n");
- result = -EIO;
- } else if (s->rcls != 0)
+ goto out;
+ }
+ if (s->rcls != 0)
{
result = -smb_errno(s->rcls, s->err);
- } else if (smb_verify(s->packet, command, wct, bcc) != 0)
- {
- pr_debug("smb_verify failed\n");
- result = -EIO;
+ if (result)
+ goto out;
}
+ result = smb_verify(s->packet, command, wct, bcc);
+#ifdef SMBFS_PARANOIA
+ if (result)
+ printk("smb_request_ok: verify failed, result=%d\n", result);
+#endif
+
+out:
return result;
}

@@ -975,8 +984,9 @@
__u16 attr, time_t ctime)
{
struct smb_sb_info *server;
- int error;
char *p;
+ __u16 fileid;
+ int error;

server = server_from_dentry(dir);
smb_lock_server(server);
@@ -989,13 +999,25 @@
p = smb_encode_path(server, p, dir, name);
smb_setup_bcc(server, p);

- if ((error = smb_request_ok(server, SMBcreate, 1, 0)) < 0)
+ error = smb_request_ok(server, SMBcreate, 1, 0);
+ if (error < 0)
{
if (smb_retry(server))
goto retry;
goto out;
}
- smb_proc_close(server, WVAL(server->packet, smb_vwv0), CURRENT_TIME);
+ /*
+ * N.B. We should return the filehandle instead of closing ...
+ */
+ fileid = WVAL(server->packet, smb_vwv0);
+#ifdef SMBFS_PARANOIA
+printk("smb_proc_create: %s/%s created, fileid=%u\n",
+dir->d_name.name, name->name, fileid);
+#endif
+ if (server->opt.protocol >= SMB_PROTOCOL_NT1) {
+ if (fileid) /* Win 95 doesn't open files? */
+ smb_proc_close(server, fileid, CURRENT_TIME);
+ }
error = 0;

out:
--- linux-2.1.62/fs/smbfs/sock.c.old Tue Nov 4 16:07:02 1997
+++ linux-2.1.62/fs/smbfs/sock.c Thu Nov 6 11:07:36 1997
@@ -420,8 +420,8 @@
#endif
goto out;
}
- server->rcls = *(packet+9);
- server->err = WVAL(packet, 11);
+ server->rcls = *(packet + smb_rcls);
+ server->err = WVAL(packet, smb_err);

#ifdef SMBFS_DEBUG_VERBOSE
if (server->rcls != 0)

--------------370689927635B73B076E61CC--