The attached patch for 2.1.63 smbfs should fix the problem with
reopening files too quickly on Win 3.1 servers. I've added a
conditional delay when reopening a file, enabled by the CONFIG_SMB_WIN95
option. The delay is currently set at HZ/4, but please experiment with
this value so we can set it as small as possible. If the delay is
triggered, you'll see a little message. Thanks to Steve Hirsch for
helping track this down.
The patch also fixes the handling of files with the read-only attribute
set. These will now show up on the Linux side with no write
permissions, and an attempt to write to the file will fail with a
permissions error. (I'm using the user permission bits for the test.)
Please give this patch a test and let me know of remaining problems.
Note that the spurious errors on file creation under Win 3.1/95 as
reported by several people is probably _not_ fixed. It appears that not
everyone with Win 3.1/95 systems is affected, and so far no one has sent
me sufficient debugging output to track it down.
Regards,
Bill
--------------0ABD9BE53AE1945702434577
Content-Type: text/plain; charset=us-ascii; name="smbfs_63-patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="smbfs_63-patch"
--- linux-2.1.63/include/linux/smb_fs.h.old Wed Nov 12 17:44:17 1997
+++ linux-2.1.63/include/linux/smb_fs.h Thu Nov 13 09:32:40 1997
@@ -80,35 +80,28 @@
/* linux/fs/smbfs/inode.c */
struct super_block *smb_read_super(struct super_block *, void *, int);
-extern int init_smb_fs(void);
void smb_invalidate_inodes(struct smb_sb_info *);
int smb_revalidate_inode(struct inode *);
int smb_refresh_inode(struct inode *);
int smb_notify_change(struct inode *, struct iattr *);
-void smb_invalidate_connection(struct smb_sb_info *);
-int smb_conn_is_valid(struct smb_sb_info *);
unsigned long smb_invent_inos(unsigned long);
struct inode *smb_iget(struct super_block *, struct smb_fattr *);
/* linux/fs/smbfs/proc.c */
-__u32 smb_len(unsigned char *packet);
-__u8 *smb_encode_smb_length(__u8 *p, __u32 len);
-__u8 *smb_setup_header(struct smb_sb_info *server, __u8 command,
- __u16 wct, __u16 bcc);
-int smb_offerconn(struct smb_sb_info *server);
-int smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt);
+__u32 smb_len(unsigned char *);
+__u8 *smb_encode_smb_length(__u8 *, __u32);
+__u8 *smb_setup_header(struct smb_sb_info *, __u8, __u16, __u16);
+int smb_get_rsize(struct smb_sb_info *);
+int smb_get_wsize(struct smb_sb_info *);
+int smb_offerconn(struct smb_sb_info *);
+int smb_newconn(struct smb_sb_info *, struct smb_conn_opt *);
int smb_close(struct inode *);
void smb_close_dentry(struct dentry *);
+int smb_close_fileid(struct dentry *, __u16);
int smb_open(struct dentry *, int);
-static inline int
-smb_is_open(struct inode *i)
-{
- return (i->u.smbfs_i.open == SMB_SERVER(i)->generation);
-}
-
int smb_proc_read(struct inode *, off_t, int, char *);
int smb_proc_write(struct inode *, off_t, int, const char *);
-int smb_proc_create(struct dentry *, struct qstr *, __u16, time_t);
+int smb_proc_create(struct dentry *, struct qstr *, __u16, time_t, __u16 *);
int smb_proc_mv(struct dentry *, struct qstr *, struct dentry *, struct qstr *);
int smb_proc_mkdir(struct dentry *, struct qstr *);
int smb_proc_rmdir(struct dentry *, struct qstr *);
@@ -121,7 +114,13 @@
int smb_proc_connect(struct smb_sb_info *);
int smb_proc_disconnect(struct smb_sb_info *);
int smb_proc_trunc(struct smb_sb_info *, __u16, __u32);
-void smb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *);
+void smb_init_root_dirent(struct smb_sb_info *, struct smb_fattr *);
+
+static inline int
+smb_is_open(struct inode *i)
+{
+ return (i->u.smbfs_i.open == SMB_SERVER(i)->generation);
+}
/* linux/fs/smbfs/sock.c */
int smb_round_length(int);
--- linux-2.1.63/include/linux/smb_fs_i.h.old Wed Nov 12 17:38:55 1997
+++ linux-2.1.63/include/linux/smb_fs_i.h Wed Nov 12 22:53:11 1997
@@ -28,6 +28,7 @@
__u16 access; /* Access bits. */
__u16 cache_valid; /* dircache valid? */
unsigned long oldmtime; /* last time refreshed */
+ unsigned long closed; /* timestamp when closed */
void * dentry; /* The dentry we were opened with */
};
--- linux-2.1.63/fs/smbfs/dir.c.old Wed Nov 12 17:33:10 1997
+++ linux-2.1.63/fs/smbfs/dir.c Wed Nov 12 19:13:54 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,42 +76,25 @@
}
/*
- * 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().
+ * Check whether a dentry already exists for the given name,
+ * and return the inode number if it has an inode. This is
+ * needed to keep getcwd() working.
*/
-static void
-smb_find_ino(struct dentry *dentry, struct cache_dirent *entry)
+static ino_t
+find_inode_number(struct dentry *dir, struct qstr *name)
{
- struct dentry * new_dentry;
- struct qstr qname;
+ struct dentry * dentry;
+ ino_t ino = 0;
- /* N.B. Make cache_dirent name a qstr! */
- qname.name = entry->name;
- qname.len = entry->len;
- qname.hash = hash_it(qname.name, qname.len);
- new_dentry = d_lookup(dentry, &qname);
- if (new_dentry)
+ name->hash = full_name_hash(name->name, name->len);
+ dentry = d_lookup(dir, name);
+ if (dentry)
{
- struct inode * inode = new_dentry->d_inode;
- if (inode)
- entry->ino = inode->i_ino;
- dput(new_dentry);
+ if (dentry->d_inode)
+ ino = dentry->d_inode->i_ino;
+ dput(dentry);
}
- if (!entry->ino)
- entry->ino = smb_invent_inos(1);
+ return ino;
}
static int
@@ -168,8 +155,15 @@
/*
* Check whether to look up the inode number.
*/
- if (!entry->ino)
- smb_find_ino(dentry, entry);
+ if (!entry->ino) {
+ struct qstr qname;
+ /* N.B. Make cache_dirent name a qstr! */
+ qname.name = entry->name;
+ qname.len = entry->len;
+ entry->ino = find_inode_number(dentry, &qname);
+ if (!entry->ino)
+ entry->ino = smb_invent_inos(1);
+ }
if (filldir(dirent, entry->name, entry->len,
filp->f_pos, entry->ino) < 0)
@@ -346,38 +340,58 @@
* This code is common to all routines creating a new inode.
*/
static int
-smb_instantiate(struct dentry *dentry)
+smb_instantiate(struct dentry *dentry, __u16 fileid)
{
+ struct smb_sb_info *server = server_from_dentry(dentry);
+ struct inode *inode;
struct smb_fattr fattr;
int error;
- error = smb_proc_getattr(dentry->d_parent, &(dentry->d_name), &fattr);
- if (!error)
- {
- struct inode *inode;
- error = -EACCES;
- fattr.f_ino = smb_invent_inos(1);
- inode = smb_iget(dentry->d_sb, &fattr);
- if (inode)
- {
- /* cache the dentry pointer */
- inode->u.smbfs_i.dentry = dentry;
- d_instantiate(dentry, inode);
- smb_renew_times(dentry);
- error = 0;
- }
- }
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_instantiate: file %s/%s, error=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, error);
+printk("smb_instantiate: file %s/%s, fileid=%u\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, fileid);
#endif
+ error = smb_proc_getattr(dentry->d_parent, &(dentry->d_name), &fattr);
+ if (error)
+ goto out_close;
+
+ fattr.f_ino = smb_invent_inos(1);
+ inode = smb_iget(dentry->d_sb, &fattr);
+ if (!inode)
+ goto out_no_inode;
+
+ if (fileid)
+ {
+ inode->u.smbfs_i.fileid = fileid;
+ inode->u.smbfs_i.access = O_RDWR;
+ inode->u.smbfs_i.open = server->generation;
+ }
+ /* cache the dentry pointer */
+ inode->u.smbfs_i.dentry = dentry;
+ d_instantiate(dentry, inode);
+ smb_renew_times(dentry);
+out:
return error;
+
+out_no_inode:
+ error = -EACCES;
+out_close:
+ if (fileid)
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_instantiate: %s/%s error=%d, closing %u\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, error, fileid);
+#endif
+ smb_close_fileid(dentry, fileid);
+ }
+ goto out;
}
/* N.B. Should the mode argument be put into the fattr? */
static int
smb_create(struct inode *dir, struct dentry *dentry, int mode)
{
+ __u16 fileid;
int error;
#ifdef SMBFS_DEBUG_VERBOSE
@@ -394,10 +408,10 @@
smb_invalid_dir_cache(dir);
error = smb_proc_create(dentry->d_parent, &(dentry->d_name),
- 0, CURRENT_TIME);
+ 0, CURRENT_TIME, &fileid);
if (!error)
{
- error = smb_instantiate(dentry);
+ error = smb_instantiate(dentry, fileid);
}
out:
return error;
@@ -417,7 +431,7 @@
error = smb_proc_mkdir(dentry->d_parent, &(dentry->d_name));
if (!error)
{
- error = smb_instantiate(dentry);
+ error = smb_instantiate(dentry, 0);
}
out:
return error;
@@ -436,8 +450,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 +486,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.63/fs/smbfs/file.c.old Wed Nov 12 17:32:16 1997
+++ linux-2.1.63/fs/smbfs/file.c Thu Nov 13 09:27:56 1997
@@ -12,20 +12,18 @@
#include <linux/fcntl.h>
#include <linux/stat.h>
#include <linux/mm.h>
-#include <linux/smb_fs.h>
#include <linux/malloc.h>
#include <linux/pagemap.h>
#include <asm/uaccess.h>
#include <asm/system.h>
+#include <linux/smb_fs.h>
+
#define SMBFS_PARANOIA 1
/* #define SMBFS_DEBUG_VERBOSE 1 */
/* #define pr_debug printk */
-extern int smb_get_rsize(struct smb_sb_info *);
-extern int smb_get_wsize(struct smb_sb_info *);
-
static inline int
min(int a, int b)
{
@@ -77,7 +75,13 @@
#endif
result = smb_open(dentry, O_RDONLY);
if (result < 0)
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_readpage_sync: %s/%s open failed, error=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, result);
+#endif
goto io_error;
+ }
do {
if (count < rsize)
@@ -230,19 +234,27 @@
static ssize_t
smb_file_read(struct file * file, char * buf, size_t count, loff_t *ppos)
{
+ struct dentry * dentry = file->f_dentry;
+ struct inode * inode = dentry->d_inode;
ssize_t status;
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_file_read: file %s/%s, count=%lu@%lu\n",
-file->f_dentry->d_parent->d_name.name, file->f_dentry->d_name.name,
-count, (unsigned long) *ppos);
+dentry->d_parent->d_name.name, dentry->d_name.name,
+(unsigned long) count, (unsigned long) *ppos);
#endif
- status = smb_revalidate_inode(file->f_dentry->d_inode);
- if (status >= 0)
+ status = smb_revalidate_inode(inode);
+ if (status)
{
- status = generic_file_read(file, buf, count, ppos);
+#ifdef SMBFS_PARANOIA
+printk("smb_file_read: %s/%s validation failed, error=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, status);
+#endif
+ goto out;
}
+ status = generic_file_read(file, buf, count, ppos);
+out:
return status;
}
@@ -255,14 +267,20 @@
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_file_mmap: file %s/%s, address %lu - %lu\n",
-file->f_dentry->d_parent->d_name.name, file->f_dentry->d_name.name,
+dentry->d_parent->d_name.name, dentry->d_name.name,
vma->vm_start, vma->vm_end);
#endif
status = smb_revalidate_inode(inode);
- if (status >= 0)
+ if (status)
{
- status = generic_file_mmap(file, vma);
+#ifdef SMBFS_PARANOIA
+printk("smb_file_mmap: %s/%s validation failed, error=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, status);
+#endif
+ goto out;
}
+ status = generic_file_mmap(file, vma);
+out:
return status;
}
@@ -272,30 +290,38 @@
static ssize_t
smb_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
+ struct dentry * dentry = file->f_dentry;
+ struct inode * inode = dentry->d_inode;
ssize_t result;
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_file_write: file %s/%s, count=%lu@%lu\n",
-file->f_dentry->d_parent->d_name.name, file->f_dentry->d_name.name,
-count, (unsigned long) *ppos);
+dentry->d_parent->d_name.name, dentry->d_name.name,
+(unsigned long) count, (unsigned long) *ppos);
#endif
#ifdef SMBFS_PARANOIA
/* Should be impossible now that inodes can't change mode */
result = -EINVAL;
- if (!S_ISREG(file->f_dentry->d_inode->i_mode))
+ if (!S_ISREG(inode->i_mode))
{
printk("smb_file_write: write to non-file, mode %07o\n",
- file->f_dentry->d_inode->i_mode);
+ inode->i_mode);
goto out;
}
#endif
- result = smb_revalidate_inode(file->f_dentry->d_inode);
+ result = smb_revalidate_inode(inode);
if (result)
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_file_write: %s/%s validation failed, error=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, result);
+#endif
goto out;
+ }
- result = smb_open(file->f_dentry, O_WRONLY);
+ result = smb_open(dentry, O_WRONLY);
if (result)
goto out;
@@ -303,7 +329,7 @@
{
result = generic_file_write(file, buf, count, ppos);
if (result > 0)
- smb_refresh_inode(file->f_dentry->d_inode);
+ smb_refresh_inode(inode);
}
out:
return result;
@@ -313,7 +339,9 @@
smb_file_open(struct inode *inode, struct file * file)
{
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_file_open: inode=%p, file=%p\n", inode, file);
+printk("smb_file_open: opening %s/%s, d_count=%d\n",
+file->f_dentry->d_parent->d_name.name, file->f_dentry->d_name.name,
+file->f_dentry->d_count);
#endif
return 0;
}
@@ -324,7 +352,7 @@
struct dentry * dentry = file->f_dentry;
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_file_release: closing file %s/%s, d_count=%d\n",
+printk("smb_file_release: closing %s/%s, d_count=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
#endif
@@ -335,6 +363,27 @@
return 0;
}
+/*
+ * Check whether the required access is compatible with
+ * an inode's permission. SMB doesn't recognize superuser
+ * privileges, so we need our own check for this.
+ */
+static int
+smb_file_permission(struct inode *inode, int mask)
+{
+ int mode = inode->i_mode;
+ int error = 0;
+
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_file_permission: mode=%x, mask=%x\n", mode, mask);
+#endif
+ /* Look at user permissions */
+ mode >>= 6;
+ if ((mode & 7 & mask) != mask)
+ error = -EACCES;
+ return error;
+}
+
static struct file_operations smb_file_operations =
{
NULL, /* lseek - default */
@@ -371,7 +420,7 @@
smb_writepage, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
- NULL, /* permission */
+ smb_file_permission, /* permission */
NULL, /* smap */
smb_updatepage, /* updatepage */
smb_revalidate_inode, /* revalidate */
--- linux-2.1.63/fs/smbfs/proc.c.old Wed Nov 12 17:33:10 1997
+++ linux-2.1.63/fs/smbfs/proc.c Thu Nov 13 09:12:17 1997
@@ -36,6 +36,8 @@
#define SMB_DIRINFO_SIZE 43
#define SMB_STATUS_SIZE 21
+#define SMB_OPENPAUSE HZ/4
+
static inline int
min(int a, int b)
{
@@ -335,7 +337,6 @@
case ERRbadfunc:
return EINVAL;
case ERRbadfile:
- return ENOENT;
case ERRbadpath:
return ENOENT;
case ERRnofids:
@@ -351,7 +352,6 @@
case ERRbadmem:
return EFAULT;
case ERRbadenv:
- return EREMOTEIO;
case ERRbadformat:
return EREMOTEIO;
case ERRbadaccess:
@@ -376,6 +376,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 +411,6 @@
case ERRnotready:
return EUCLEAN;
case ERRbadcmd:
- return EIO;
case ERRdata:
return EIO;
case ERRbadreq:
@@ -526,31 +527,45 @@
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;
+#ifdef SMBFS_PARANOIA
+printk("smb_request_ok: rcls=%d, err=%d mapped to 0\n", s->rcls, s->err);
+#endif
}
+
+ 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;
}
@@ -693,18 +708,21 @@
/*
* We're called with the server locked, and we leave it that way.
- * Set the permissions to be consistent with the desired access.
*/
-
static int
-smb_proc_open(struct smb_sb_info *server, struct dentry *dir, int wish)
+smb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish)
{
- struct inode *ino = dir->d_inode;
+ struct inode *ino = dentry->d_inode;
int mode, read_write = 0x42, read_only = 0x40;
int error;
char *p;
+ /*
+ * Attempt to open r/w, unless there are no write privileges.
+ */
mode = read_write;
+ if (!(ino->i_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
+ mode = read_only;
#if 0
if (!(wish & (O_WRONLY | O_RDWR)))
mode = read_only;
@@ -715,7 +733,7 @@
WSET(server->packet, smb_vwv0, mode);
WSET(server->packet, smb_vwv1, aSYSTEM | aHIDDEN | aDIR);
*p++ = 4;
- p = smb_encode_path(server, p, dir, NULL);
+ p = smb_encode_path(server, p, dentry, NULL);
smb_setup_bcc(server, p);
error = smb_request_ok(server, SMBopen, 7, 0);
@@ -729,7 +747,7 @@
{
#ifdef SMBFS_PARANOIA
printk("smb_proc_open: %s/%s open failed, error=%d, retrying R/O\n",
-dir->d_parent->d_name.name, dir->d_name.name, error);
+dentry->d_parent->d_name.name, dentry->d_name.name, error);
#endif
mode = read_only;
goto retry;
@@ -742,25 +760,31 @@
/* smb_vwv2 has mtime */
/* smb_vwv4 has size */
ino->u.smbfs_i.access = WVAL(server->packet, smb_vwv6);
- ino->u.smbfs_i.access &= 3;
+ ino->u.smbfs_i.access &= (O_RDWR | O_WRONLY | O_RDONLY);
/* N.B. Suppose the open failed?? */
ino->u.smbfs_i.open = server->generation;
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_open: error=%d, access=%d\n", error, ino->u.smbfs_i.access);
+#ifdef SMBFS_PARANOIA
+if (error)
+printk("smb_proc_open: %s/%s failed, error=%d, access=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,error,ino->u.smbfs_i.access);
#endif
return error;
}
+/*
+ * Make sure the file is open, and check that the access
+ * is compatible with the desired access.
+ */
int
smb_open(struct dentry *dentry, int wish)
{
- struct inode *i = dentry->d_inode;
+ struct inode *inode = dentry->d_inode;
int result;
result = -ENOENT;
- if (!i)
+ if (!inode)
{
printk("smb_open: no inode for dentry %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
@@ -772,12 +796,32 @@
* currently open, we can be sure that the file isn't about
* to be closed. (See smb_close_dentry() below.)
*/
- if (!smb_is_open(i))
+ if (!smb_is_open(inode))
{
- struct smb_sb_info *server = SMB_SERVER(i);
+ struct smb_sb_info *server = SMB_SERVER(inode);
+ /*
+ * Kludge alert! Some Win 3.1 systems can't open a
+ * file too soon after closing it, so we pause for
+ * a bit.
+ */
+ if (server->mnt->version & 1)
+ {
+ unsigned long diff = jiffies - inode->u.smbfs_i.closed;
+ if (diff < SMB_OPENPAUSE)
+ {
+ unsigned long timeout = SMB_OPENPAUSE - diff;
+#ifdef SMBFS_PARANOIA
+printk("smb_open: pausing %lu\n", timeout);
+#endif
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + timeout;
+ schedule();
+ current->timeout = 0;
+ }
+ }
smb_lock_server(server);
result = 0;
- if (!smb_is_open(i))
+ if (!smb_is_open(inode))
result = smb_proc_open(server, dentry, wish);
smb_unlock_server(server);
if (result)
@@ -794,14 +838,20 @@
smb_renew_times(dentry);
}
- result = -EACCES;
- if (((wish == O_RDONLY) && ((i->u.smbfs_i.access == O_RDONLY)
- || (i->u.smbfs_i.access == O_RDWR)))
- || ((wish == O_WRONLY) && ((i->u.smbfs_i.access == O_WRONLY)
- || (i->u.smbfs_i.access == O_RDWR)))
- || ((wish == O_RDWR) && (i->u.smbfs_i.access == O_RDWR)))
- result = 0;
-
+ /*
+ * Check whether the access is compatible with the desired mode.
+ */
+ result = 0;
+ if (inode->u.smbfs_i.access != wish &&
+ inode->u.smbfs_i.access != O_RDWR)
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_open: %s/%s access denied, access=%x, wish=%x\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+inode->u.smbfs_i.access, wish);
+#endif
+ result = -EACCES;
+ }
out:
return result;
}
@@ -833,6 +883,7 @@
ino->u.smbfs_i.open = 0;
result = smb_proc_close(server, ino->u.smbfs_i.fileid,
ino->i_mtime);
+ ino->u.smbfs_i.closed = jiffies;
}
return result;
}
@@ -892,6 +943,22 @@
}
}
+/*
+ * This is used to close a file following a failed instantiate.
+ * Since we don't have an inode, we can't use any of the above.
+ */
+int
+smb_close_fileid(struct dentry *dentry, __u16 fileid)
+{
+ struct smb_sb_info *server = server_from_dentry(dentry);
+ int result = 0;
+
+ smb_lock_server(server);
+ result = smb_proc_close(server, fileid, CURRENT_TIME);
+ smb_unlock_server(server);
+ return result;
+}
+
/* In smb_proc_read and smb_proc_write we do not retry, because the
file-id would not be valid after a reconnection. */
@@ -972,11 +1039,11 @@
int
smb_proc_create(struct dentry *dir, struct qstr *name,
- __u16 attr, time_t ctime)
+ __u16 attr, time_t ctime, __u16 *fileid)
{
struct smb_sb_info *server;
- int error;
char *p;
+ int error;
server = server_from_dentry(dir);
smb_lock_server(server);
@@ -989,13 +1056,14 @@
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);
+ *fileid = WVAL(server->packet, smb_vwv0);
error = 0;
out:
@@ -1164,14 +1232,19 @@
static void
smb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
{
- fattr->f_mode = server->mnt->file_mode;
if (fattr->attr & aDIR)
{
+ /* N.B. check for read-only directories */
fattr->f_mode = server->mnt->dir_mode;
fattr->f_size = 512;
+ } else
+ {
+ fattr->f_mode = server->mnt->file_mode;
+ if (fattr->attr & aRONLY)
+ fattr->f_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
}
- fattr->f_blocks = 0; /* already set to zero? */
+ fattr->f_blocks = 0;
if ((fattr->f_blksize != 0) && (fattr->f_size != 0))
{
fattr->f_blocks =
--- linux-2.1.63/fs/smbfs/sock.c.old Wed Nov 12 17:33:10 1997
+++ linux-2.1.63/fs/smbfs/sock.c Wed Nov 12 19:13:54 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)
--------------0ABD9BE53AE1945702434577--