Messages in this thread Patch in this message | | | Date | Thu, 13 Nov 1997 09:11:22 -0500 | From | Bill Hawes <> | Subject | patch for 2.1.63 smbfs |
| |
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--- 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) | |