patch for 2.1.79 smbfs

Bill Hawes (whawes@star.net)
Wed, 14 Jan 1998 11:29:15 -0500


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

The attached patch does some further cleanup for smbfs and implements an
alternate call for getattr that may work better for Win 95 systems.

The new getattr uses the directory FIND_FIRST message to get the
attributes for a single file. If this works for Win 95 it will provide
an better workaround for the slow QPATHINFO message. This call also
works under Win NT, at about the same speed as the current QPATHINFO. So
if this operates correctly with Win 95, I could use it for both servers
and eliminate the bug-fix flags.

The new call is enabled with a bug fix flag of value 4, so to use this
you would specify a filemode of -f 5555 instead of -f 3555. I'd
appreciate it if people using Win 95 could give this a test.

I've also updated the smbfs.txt file to refer to the utilities in the
new Samba 1.9.18 release.

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

--- linux-2.1.79/include/linux/smb_fs.h.old Tue Jan 13 10:58:10 1998
+++ linux-2.1.79/include/linux/smb_fs.h Tue Jan 13 23:15:25 1998
@@ -76,6 +76,7 @@
*/
#define SMB_FIX_WIN95 0x0001 /* Win 95 server */
#define SMB_FIX_OLDATTR 0x0002 /* Use core getattr (Win 95 speedup) */
+#define SMB_FIX_DIRATTR 0x0004 /* Use find_first for getattr */

/* linux/fs/smbfs/mmap.c */
int smb_mmap(struct file *, struct vm_area_struct *);
@@ -95,7 +96,6 @@
void smb_get_inode_attr(struct inode *, struct smb_fattr *);
void smb_invalidate_inodes(struct smb_sb_info *);
int smb_revalidate_inode(struct dentry *);
-int smb_refresh_inode(struct inode *);
int smb_notify_change(struct dentry *, struct iattr *);
unsigned long smb_invent_inos(unsigned long);
struct inode *smb_iget(struct super_block *, struct smb_fattr *);
@@ -112,8 +112,8 @@
void smb_close_dentry(struct dentry *);
int smb_close_fileid(struct dentry *, __u16);
int smb_open(struct dentry *, int);
-int smb_proc_read(struct inode *, off_t, int, char *);
-int smb_proc_write(struct inode *, off_t, int, const char *);
+int smb_proc_read(struct dentry *, off_t, int, char *);
+int smb_proc_write(struct dentry *, off_t, int, const char *);
int smb_proc_create(struct dentry *, __u16, time_t, __u16 *);
int smb_proc_mv(struct dentry *, struct dentry *);
int smb_proc_mkdir(struct dentry *);
--- linux-2.1.79/fs/smbfs/inode.c.old Tue Jan 6 11:39:08 1998
+++ linux-2.1.79/fs/smbfs/inode.c Tue Jan 13 23:10:34 1998
@@ -181,6 +181,59 @@
}

/*
+ * This is called to update the inode attributes after
+ * we've made changes to a file or directory.
+ */
+static int
+smb_refresh_inode(struct dentry *dentry)
+{
+ struct inode *inode = dentry->d_inode;
+ int error;
+ struct smb_fattr fattr;
+
+ error = smb_proc_getattr(dentry, &fattr);
+ if (!error)
+ {
+ smb_renew_times(dentry);
+ /*
+ * Check whether the type part of the mode changed,
+ * and don't update the attributes if it did.
+ */
+ if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT))
+ smb_set_inode_attr(inode, &fattr);
+ else
+ {
+ /*
+ * Big trouble! The inode has become a new object,
+ * so any operations attempted on it are invalid.
+ *
+ * To limit damage, mark the inode as bad so that
+ * subsequent lookup validations will fail.
+ */
+#ifdef SMBFS_PARANOIA
+printk("smb_refresh_inode: %s/%s changed mode, %07o to %07o\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+inode->i_mode, fattr.f_mode);
+#endif
+ fattr.f_mode = inode->i_mode; /* save mode */
+ make_bad_inode(inode);
+ inode->i_mode = fattr.f_mode; /* restore mode */
+ /*
+ * No need to worry about unhashing the dentry: the
+ * lookup validation will see that the inode is bad.
+ * But we do want to invalidate the caches ...
+ */
+ if (!S_ISDIR(inode->i_mode))
+ invalidate_inode_pages(inode);
+ else
+ smb_invalid_dir_cache(inode);
+ error = -EIO;
+ }
+ }
+ return error;
+}
+
+/*
* This is called when we want to check whether the inode
* has changed on the server. If it has changed, we must
* invalidate our local caches.
@@ -220,7 +273,7 @@
* (Note: a size change should have a different mtime.)
*/
last_time = inode->i_mtime;
- error = smb_refresh_inode(inode);
+ error = smb_refresh_inode(dentry);
if (error || inode->i_mtime != last_time)
{
#ifdef SMBFS_DEBUG_VERBOSE
@@ -238,69 +291,6 @@
}

/*
- * This is called to update the inode attributes after
- * we've made changes to a file or directory.
- */
-int
-smb_refresh_inode(struct inode *inode)
-{
- struct dentry * dentry = inode->u.smbfs_i.dentry;
- struct smb_fattr fattr;
- int error;
-
- pr_debug("smb_refresh_inode\n");
- if (!dentry)
- {
- printk("smb_refresh_inode: no dentry, can't refresh\n");
- error = -EIO;
- goto out;
- }
-
- error = smb_proc_getattr(dentry, &fattr);
- if (!error)
- {
- smb_renew_times(dentry);
- /*
- * Check whether the type part of the mode changed,
- * and don't update the attributes if it did.
- */
- if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT))
- smb_set_inode_attr(inode, &fattr);
- else
- {
- /*
- * Big trouble! The inode has become a new object,
- * so any operations attempted on it are invalid.
- *
- * To limit damage, mark the inode as bad so that
- * subsequent lookup validations will fail.
- */
-#ifdef SMBFS_PARANOIA
-printk("smb_refresh_inode: %s/%s changed mode, %07o to %07o\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
-inode->i_mode, fattr.f_mode);
-#endif
- fattr.f_mode = inode->i_mode; /* save mode */
- make_bad_inode(inode);
- inode->i_mode = fattr.f_mode; /* restore mode */
- /*
- * No need to worry about unhashing the dentry: the
- * lookup validation will see that the inode is bad.
- * But we do want to invalidate the caches ...
- */
- if (!S_ISDIR(inode->i_mode))
- invalidate_inode_pages(inode);
- else
- smb_invalid_dir_cache(inode);
- error = -EIO;
- }
- }
-out:
- return error;
-
-}
-
-/*
* This routine is called for every iput().
*/
static void
@@ -609,7 +599,7 @@

out:
if (refresh)
- smb_refresh_inode(inode);
+ smb_refresh_inode(dentry);
return error;
}

--- linux-2.1.79/fs/smbfs/file.c.old Tue Jan 6 11:39:08 1998
+++ linux-2.1.79/fs/smbfs/file.c Tue Jan 13 23:10:34 1998
@@ -54,10 +54,9 @@
static int
smb_readpage_sync(struct dentry *dentry, struct page *page)
{
- struct inode *inode = dentry->d_inode;
char *buffer = (char *) page_address(page);
unsigned long offset = page->offset;
- int rsize = smb_get_rsize(SMB_SERVER(inode));
+ int rsize = smb_get_rsize(server_from_dentry(dentry));
int count = PAGE_SIZE;
int result;

@@ -81,14 +80,14 @@
if (count < rsize)
rsize = count;

- result = smb_proc_read(inode, offset, rsize, buffer);
+ result = smb_proc_read(dentry, offset, rsize, buffer);
if (result < 0)
goto io_error;

count -= result;
offset += result;
buffer += result;
- inode->i_atime = CURRENT_TIME;
+ dentry->d_inode->i_atime = CURRENT_TIME;
if (result < rsize)
break;
} while (count);
@@ -129,7 +128,7 @@
{
struct inode *inode = dentry->d_inode;
u8 *buffer = (u8 *) page_address(page) + offset;
- int wsize = smb_get_wsize(SMB_SERVER(inode));
+ int wsize = smb_get_wsize(server_from_dentry(dentry));
int result, written = 0;

offset += page->offset;
@@ -142,7 +141,7 @@
if (count < wsize)
wsize = count;

- result = smb_proc_write(inode, offset, wsize, buffer);
+ result = smb_proc_write(dentry, offset, wsize, buffer);
if (result < 0)
goto io_error;
/* N.B. what if result < wsize?? */
--- linux-2.1.79/fs/smbfs/proc.c.old Sat Dec 20 16:58:31 1997
+++ linux-2.1.79/fs/smbfs/proc.c Wed Jan 14 00:10:13 1998
@@ -987,9 +987,9 @@
file-id would not be valid after a reconnection. */

int
-smb_proc_read(struct inode *ino, off_t offset, int count, char *data)
+smb_proc_read(struct dentry *dentry, off_t offset, int count, char *data)
{
- struct smb_sb_info *server = SMB_SERVER(ino);
+ struct smb_sb_info *server = server_from_dentry(dentry);
__u16 returned_count, data_len;
char *buf;
int result;
@@ -997,7 +997,7 @@
smb_lock_server(server);
smb_setup_header(server, SMBread, 5, 0);
buf = server->packet;
- WSET(buf, smb_vwv0, ino->u.smbfs_i.fileid);
+ WSET(buf, smb_vwv0, dentry->d_inode->u.smbfs_i.fileid);
WSET(buf, smb_vwv1, count);
DSET(buf, smb_vwv2, offset);
WSET(buf, smb_vwv4, 0);
@@ -1022,29 +1022,27 @@
out:
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_proc_read: file %s/%s, count=%d, result=%d\n",
-((struct dentry *) ino->u.smbfs_i.dentry)->d_parent->d_name.name,
-((struct dentry *) ino->u.smbfs_i.dentry)->d_name.name, count, result);
+dentry->d_parent->d_name.name, dentry->d_name.name, count, result);
#endif
smb_unlock_server(server);
return result;
}

int
-smb_proc_write(struct inode *ino, off_t offset, int count, const char *data)
+smb_proc_write(struct dentry *dentry, off_t offset, int count, const char *data)
{
- struct smb_sb_info *server = SMB_SERVER(ino);
+ struct smb_sb_info *server = server_from_dentry(dentry);
int result;
__u8 *p;

- smb_lock_server(server);
#if SMBFS_DEBUG_VERBOSE
printk("smb_proc_write: file %s/%s, count=%d@%ld, packet_size=%d\n",
-((struct dentry *)ino->u.smbfs_i.dentry)->d_parent->d_name.name,
-((struct dentry *)ino->u.smbfs_i.dentry)->d_name.name,
+dentry->d_parent->d_name.name, dentry->d_name.name,
count, offset, server->packet_size);
#endif
+ smb_lock_server(server);
p = smb_setup_header(server, SMBwrite, 5, count + 3);
- WSET(server->packet, smb_vwv0, ino->u.smbfs_i.fileid);
+ WSET(server->packet, smb_vwv0, dentry->d_inode->u.smbfs_i.fileid);
WSET(server->packet, smb_vwv1, count);
DSET(server->packet, smb_vwv2, offset);
WSET(server->packet, smb_vwv4, 0);
@@ -1750,6 +1748,98 @@
}

/*
+ * This version use the trans2 findfirst to get the attribute info.
+ *
+ * Bugs Noted:
+ */
+static int
+smb_proc_getattr_ff(struct smb_sb_info *server, struct dentry *dentry,
+ struct smb_fattr *fattr)
+{
+ char *mask, *param = server->temp_buf;
+ __u16 date, time;
+ unsigned char *resp_data = NULL;
+ unsigned char *resp_param = NULL;
+ int resp_data_len = 0;
+ int resp_param_len = 0;
+ int mask_len, result;
+
+retry:
+ mask = param + 12;
+ mask_len = smb_encode_path(server, mask, dentry, NULL) - mask;
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_proc_getattr_ff: name=%s\n", mask);
+#endif
+ WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
+ WSET(param, 2, 1); /* max count */
+ WSET(param, 4, 2 + 1); /* close on end + close after this call */
+ WSET(param, 6, 1); /* info_level */
+ DSET(param, 8, 0);
+
+ result = smb_trans2_request(server, TRANSACT2_FINDFIRST,
+ 0, NULL, 12 + mask_len + 1, param,
+ &resp_data_len, &resp_data,
+ &resp_param_len, &resp_param);
+
+ if (result < 0)
+ {
+ if (smb_retry(server))
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_proc_getattr_ff: error=%d, retrying\n", result);
+#endif
+ goto retry;
+ }
+ goto out;
+ }
+ if (server->rcls != 0)
+ {
+ result = -smb_errno(server);
+#ifdef SMBFS_PARANOIA
+if (result != -ENOENT)
+printk("smb_proc_getattr_ff: rcls=%d, err=%d\n", server->rcls, server->err);
+#endif
+ goto out;
+ }
+ /* Make sure we got enough data ... */
+ result = -EINVAL;
+ if (resp_data_len < 22 || WVAL(resp_param, 2) != 1)
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_proc_getattr_ff: bad result, len=%d, count=%d\n",
+ resp_data_len, WVAL(resp_param, 2));
+#endif
+ goto out;
+ }
+
+ /*
+ * Decode the response into the fattr ...
+ */
+ date = WVAL(resp_data, 0);
+ time = WVAL(resp_data, 2);
+ fattr->f_ctime = date_dos2unix(date, time);
+
+ date = WVAL(resp_data, 4);
+ time = WVAL(resp_data, 6);
+ fattr->f_atime = date_dos2unix(date, time);
+
+ date = WVAL(resp_data, 8);
+ time = WVAL(resp_data, 10);
+ fattr->f_mtime = date_dos2unix(date, time);
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_proc_getattr_ff: %s, date=%x, time=%x, mtime=%ld\n",
+mask, date, time, fattr->f_mtime);
+#endif
+ fattr->f_size = DVAL(resp_data, 12);
+ /* ULONG allocation size */
+ fattr->attr = WVAL(resp_data, 20);
+ result = 0;
+
+out:
+ return result;
+}
+
+/*
* Note: called with the server locked.
*/
static int
@@ -1883,11 +1973,17 @@
* Win 95 is painfully slow at returning trans2 getattr info,
* so we provide the SMB_FIX_OLDATTR option switch.
*/
- if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2 &&
- !(server->mnt->version & SMB_FIX_OLDATTR))
- result = smb_proc_getattr_trans2(server, dir, fattr);
- else
+ if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) {
+ if (server->mnt->version & SMB_FIX_OLDATTR)
+ goto core_attr;
+ if (server->mnt->version & SMB_FIX_DIRATTR)
+ result = smb_proc_getattr_ff(server, dir, fattr);
+ else
+ result = smb_proc_getattr_trans2(server, dir, fattr);
+ } else {
+ core_attr:
result = smb_proc_getattr_core(server, dir, fattr);
+ }

smb_finish_dirent(server, fattr);

--- linux-2.1.79/Documentation/filesystems/smbfs.txt.old Sun Nov 30 11:26:38 1997
+++ linux-2.1.79/Documentation/filesystems/smbfs.txt Wed Jan 14 11:59:40 1998
@@ -1,27 +1,15 @@
Smbfs is a filesystem that implements the SMB protocol, which is the
protocol used by Windows for Workgroups, Windows 95 and Windows NT.
-Smbfs was inspired by samba, the program written by Andrew Tridgell
+Smbfs was inspired by Samba, the program written by Andrew Tridgell
that turns any unix host into a file server for DOS or Windows clients.
See ftp://nimbus.anu.edu.au/pub/tridge/samba/ for this interesting
program suite and much more information on SMB, NetBIOS over TCP/IP,
and explanations for concepts like netbios name or share.

-To use smbfs, you need to install the Samba package (Samba-1.9.17p1 or
-later), and you need the special mount program from the smbfs package
-(smbfs-2.1.0 or later), found on
-
- ftp://ftp.gwdg.de/pub/linux/misc/smbfs/dontuse
-
-After downloading the smbfs package, apply the patch to the smbclient
-program and recompile. Smbfs can then be mounted from the smbclient
-command line, as for example:
-
- smb: \>mount /mnt/tmp -f 755
-
-For convenience, you may wish to package the command in a script like this:
-
-#!/bin/sh
-echo "mount /mnt/tmp -f 755" | smbclient //server/c$ -U administrator%
+To use smbfs, you need to install the Samba package (Samba-1.9.18p1 or
+later). This package includes the special smbmount program needed to mount
+smbfs volumes. Refer to the smbmount(8) and smbmnt(8) manpages for the
+details regarding smbfs mounts.

Mount-Time Options
Windows 95 has several bugs that affect SMB operations, and smbfs includes
@@ -37,11 +25,12 @@
Option Value Effect
Identify Win 95 Server 1 Enables bug fixes
Use Core Attributes 2 Speeds up directory scans, only mtime
+Use Dir Attributes 4 Alternate way to get file attributes

To apply the options, sum the values and prepend it to the file mode. For
example, to use both options with file mode 755, you would prepend 3 to 755:

- cnt>mount /mnt/tmp -f 3755
+ mount /mnt/tmp -f 3755

Smbfs will print a message at mount time confirming the selected options.
Note that _only_ Windows 95 servers require special treatment; using the

--------------0FAEA8BE9446E84A4D5D08E2--