lkml.org 
[lkml]   [1997]   [Nov]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subjectpatch 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)
    \
     
     \ /
      Last update: 2005-03-22 13:40    [W:0.064 / U:245.832 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site