patch for smbfs filesize 0

Bill Hawes (whawes@star.net)
Sat, 15 Nov 1997 09:47:01 -0500


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

Hi Steve,

I've attached a patch to check whether the iozone reading problem is
caused by an incorrect file size of 0. The fix is simply to force the
inode revalidation to check with the server following a close. Assuming
the server has updated the size to the correct value, this will allow
the read to proceed.

The patch also adds a diagnostic message giving the inode i_size and
number of pages when reading. After iozone switches from writing to
reading, the first read should show the correct size and a number of
pages cached.

Hopefully this will fix the problem, but if the size is still remains 0
when starting the read, it may be necessary to add a delay to the
revalidation.

Regards,
Bill
--------------53EB8B9A0D7E1CC18AAA5A6D
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 Sat Nov 15 10:24:01 1997
@@ -72,42 +72,25 @@
}

/*
- * Compute the hash for a qstr.
- * N.B. Move to include/linux/dcache.h?
+ * 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 unsigned int
-hash_it(const char * name, unsigned int len)
+static ino_t
+find_inode_number(struct dentry *dir, struct qstr *name)
{
- unsigned long hash = init_name_hash();
- while (len--)
- hash = partial_name_hash(*name++, hash);
- return end_name_hash(hash);
-}
+ struct dentry * dentry;
+ ino_t ino = 0;

-/*
- * If a dentry already exists, we have to give the cache entry
- * the correct inode number. This is needed for getcwd().
- */
-static void
-smb_find_ino(struct dentry *dentry, struct cache_dirent *entry)
-{
- struct dentry * new_dentry;
- struct qstr qname;
-
- /* 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 +151,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 +336,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 +404,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 +427,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 +446,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 +482,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 Sat Nov 15 10:18:02 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,31 @@
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;
}
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_file_read: inode size=%ld, pages=%ld\n",
+inode->i_size, inode->i_nrpages);
+#endif
+ status = generic_file_read(file, buf, count, ppos);
+out:
return status;
}

@@ -255,14 +271,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 +294,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 +333,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 +343,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 +356,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 +367,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 +424,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 Sat Nov 15 10:22:46 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,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 +706,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 +731,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 +745,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 +758,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 +794,12 @@
* 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);
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 +816,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 +861,13 @@
ino->u.smbfs_i.open = 0;
result = smb_proc_close(server, ino->u.smbfs_i.fileid,
ino->i_mtime);
+ /*
+ * Force a revalidation after closing ... some servers
+ * don't post the size until the file has been closed.
+ */
+ if (server->opt.protocol < SMB_PROTOCOL_NT1)
+ ino->u.smbfs_i.oldmtime = 0;
+ ino->u.smbfs_i.closed = jiffies;
}
return result;
}
@@ -892,6 +927,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 +1023,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 +1040,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 +1216,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)

--------------53EB8B9A0D7E1CC18AAA5A6D--