patch for 2.1.78 smbfs

Bill Hawes (whawes@star.net)
Tue, 06 Jan 1998 12:07:39 -0500


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

Hi Gordon,

I've attached an experimental patch to try to fix the getattr slowness
on your system. It uses a different SMB message to get file attributes
-- basically it's like a directory scan but for just a single file.

The new code is controlled by the mount-time flag with the value 2,
which previously was used to select the core getattr for Win 95 systems.
(Hopefully this patch will provide better speed for Win 95 attributes as
well.) So to use the new routine, prepend a 2 to the file attributes on
the mount command (e.g. -f 2755).

If you could run some directory scans on both NT and Win 95 comparing
the new routine to the old, we can then decide whether it's a suitable
fix.

I've CC'ed this to the kernel list in case anyone else wants to test as
well.

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

--- linux-2.1.78/include/linux/smb_fs.h.old Tue Jan 6 11:39:10 1998
+++ linux-2.1.78/include/linux/smb_fs.h Tue Jan 6 12:07:05 1998
@@ -95,7 +95,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 +111,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.78/fs/smbfs/inode.c.old Tue Jan 6 11:39:08 1998
+++ linux-2.1.78/fs/smbfs/inode.c Tue Jan 6 11:53:37 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.78/fs/smbfs/file.c.old Tue Jan 6 11:39:08 1998
+++ linux-2.1.78/fs/smbfs/file.c Tue Jan 6 11:53:37 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.78/fs/smbfs/proc.c.old Sat Dec 20 16:58:31 1997
+++ linux-2.1.78/fs/smbfs/proc.c Tue Jan 6 11:53:37 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,93 @@
}

/*
+ * 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 ff_searchcount = 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)
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_proc_getattr_ff: rcls=%d, err=%d\n", server->rcls, server->err);
+#endif
+ result = -smb_errno(server);
+ goto out;
+ }
+
+ /* parse out some important return info */
+ ff_searchcount = WVAL(resp_param, 2);
+ if (ff_searchcount != 1)
+ printk("smb_proc_getattr_ff: bad result %d\n", ff_searchcount);
+
+ /*
+ * 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,10 +1968,12 @@
* 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)
+ result = smb_proc_getattr_ff(server, dir, fattr);
+ else
+ result = smb_proc_getattr_trans2(server, dir, fattr);
+ } else
result = smb_proc_getattr_core(server, dir, fattr);

smb_finish_dirent(server, fattr);

--------------526B073CE7442674159EA5FA--