lkml.org 
[lkml]   [1998]   [Jan]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subjectupdated patch for 2.1.79 smbfs
I've made some changes to try to resolve the problems reported with Win
95 OSR2 directory scans. The new patch makes Win 95 use info level 1 in
the directory scans instead of level 259 (used by NT.) Info level 1 is
what's currently used in smbclient.

To use the patch with Win 95, please try it first with filemode -f 3xxx
and if successful test again with mode -f 5xxx. If the latter mode works
correctly it would be preferred, as this returns all three timestamps on
a getattr call.

Please report back any test results, especially for those using Win 95
OSR2.

Regards,
Bill--- 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 Thu Jan 15 12:07:44 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);
@@ -1544,9 +1542,10 @@
* Check whether to change the info level. There appears to be
* a bug in Win NT 4.0's handling of info level 1, whereby it
* truncates the directory scan for certain patterns of files.
- * Hence we use level 259 for NT. (And Win 95 as well ...)
+ * Hence we use level 259 for NT.
*/
- if (server->opt.protocol >= SMB_PROTOCOL_NT1)
+ if (server->opt.protocol >= SMB_PROTOCOL_NT1 &&
+ !(server->mnt->version & SMB_FIX_WIN95))
info_level = 259;

smb_lock_server(server);
@@ -1639,8 +1638,8 @@
if (server->rcls != 0)
{
#ifdef SMBFS_PARANOIA
-printk("smb_proc_readdir_long: rcls=%d, err=%d, breaking\n",
-server->rcls, server->err);
+printk("smb_proc_readdir_long: name=%s, entries=%d, rcls=%d, err=%d\n",
+mask, entries, server->rcls, server->err);
#endif
entries = -smb_errno(server);
break;
@@ -1750,6 +1749,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 +1974,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
\
 
 \ /
  Last update: 2005-03-22 13:41    [from the cache]
©2003-2011 Jasper Spaans