]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/cifs/inode.c
Merge branch 'master' into csb1725
[mv-sheeva.git] / fs / cifs / inode.c
index 53cce8cc2224f4abe4754d2cc320a05a6f36d215..589f3e3f6e0023b1f8b09f1e030119896117c94f 100644 (file)
@@ -52,7 +52,7 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
 
 
                /* check if server can support readpages */
-               if (cifs_sb->tcon->ses->server->maxBuf <
+               if (cifs_sb_master_tcon(cifs_sb)->ses->server->maxBuf <
                                PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
                        inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
                else
@@ -288,8 +288,8 @@ int cifs_get_file_info_unix(struct file *filp)
        struct cifs_fattr fattr;
        struct inode *inode = filp->f_path.dentry->d_inode;
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-       struct cifsTconInfo *tcon = cifs_sb->tcon;
        struct cifsFileInfo *cfile = filp->private_data;
+       struct cifsTconInfo *tcon = tlink_tcon(cfile->tlink);
 
        xid = GetXid();
        rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
@@ -313,15 +313,21 @@ int cifs_get_inode_info_unix(struct inode **pinode,
        FILE_UNIX_BASIC_INFO find_data;
        struct cifs_fattr fattr;
        struct cifsTconInfo *tcon;
+       struct tcon_link *tlink;
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 
-       tcon = cifs_sb->tcon;
        cFYI(1, "Getting info on %s", full_path);
 
+       tlink = cifs_sb_tlink(cifs_sb);
+       if (IS_ERR(tlink))
+               return PTR_ERR(tlink);
+       tcon = tlink_tcon(tlink);
+
        /* could have done a find first instead but this returns more info */
        rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data,
                                  cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
+       cifs_put_tlink(tlink);
 
        if (!rc) {
                cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
@@ -332,6 +338,13 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                return rc;
        }
 
+       /* check for Minshall+French symlinks */
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
+               int tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid);
+               if (tmprc)
+                       cFYI(1, "CIFSCheckMFSymlink: %d", tmprc);
+       }
+
        if (*pinode == NULL) {
                /* get new inode */
                cifs_fill_uniqueid(sb, &fattr);
@@ -353,7 +366,8 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
        int rc;
        int oplock = 0;
        __u16 netfid;
-       struct cifsTconInfo *pTcon = cifs_sb->tcon;
+       struct tcon_link *tlink;
+       struct cifsTconInfo *tcon;
        char buf[24];
        unsigned int bytes_read;
        char *pbuf;
@@ -372,7 +386,12 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
                return -EINVAL;  /* EOPNOTSUPP? */
        }
 
-       rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
+       tlink = cifs_sb_tlink(cifs_sb);
+       if (IS_ERR(tlink))
+               return PTR_ERR(tlink);
+       tcon = tlink_tcon(tlink);
+
+       rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, GENERIC_READ,
                         CREATE_NOT_DIR, &netfid, &oplock, NULL,
                         cifs_sb->local_nls,
                         cifs_sb->mnt_cifs_flags &
@@ -380,7 +399,7 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
        if (rc == 0) {
                int buf_type = CIFS_NO_BUFFER;
                        /* Read header */
-               rc = CIFSSMBRead(xid, pTcon, netfid,
+               rc = CIFSSMBRead(xid, tcon, netfid,
                                 24 /* length */, 0 /* offset */,
                                 &bytes_read, &pbuf, &buf_type);
                if ((rc == 0) && (bytes_read >= 8)) {
@@ -422,8 +441,9 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
                        fattr->cf_dtype = DT_REG;
                        rc = -EOPNOTSUPP; /* or some unknown SFU type */
                }
-               CIFSSMBClose(xid, pTcon, netfid);
+               CIFSSMBClose(xid, tcon, netfid);
        }
+       cifs_put_tlink(tlink);
        return rc;
 }
 
@@ -441,11 +461,19 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
        ssize_t rc;
        char ea_value[4];
        __u32 mode;
+       struct tcon_link *tlink;
+       struct cifsTconInfo *tcon;
 
-       rc = CIFSSMBQAllEAs(xid, cifs_sb->tcon, path, "SETFILEBITS",
+       tlink = cifs_sb_tlink(cifs_sb);
+       if (IS_ERR(tlink))
+               return PTR_ERR(tlink);
+       tcon = tlink_tcon(tlink);
+
+       rc = CIFSSMBQAllEAs(xid, tcon, path, "SETFILEBITS",
                            ea_value, 4 /* size of buf */, cifs_sb->local_nls,
                            cifs_sb->mnt_cifs_flags &
                                CIFS_MOUNT_MAP_SPECIAL_CHR);
+       cifs_put_tlink(tlink);
        if (rc < 0)
                return (int)rc;
        else if (rc > 3) {
@@ -468,6 +496,8 @@ static void
 cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
                       struct cifs_sb_info *cifs_sb, bool adjust_tz)
 {
+       struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
+
        memset(fattr, 0, sizeof(*fattr));
        fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
        if (info->DeletePending)
@@ -482,8 +512,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
        fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
 
        if (adjust_tz) {
-               fattr->cf_ctime.tv_sec += cifs_sb->tcon->ses->server->timeAdj;
-               fattr->cf_mtime.tv_sec += cifs_sb->tcon->ses->server->timeAdj;
+               fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj;
+               fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj;
        }
 
        fattr->cf_eof = le64_to_cpu(info->EndOfFile);
@@ -515,8 +545,8 @@ int cifs_get_file_info(struct file *filp)
        struct cifs_fattr fattr;
        struct inode *inode = filp->f_path.dentry->d_inode;
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-       struct cifsTconInfo *tcon = cifs_sb->tcon;
        struct cifsFileInfo *cfile = filp->private_data;
+       struct cifsTconInfo *tcon = tlink_tcon(cfile->tlink);
 
        xid = GetXid();
        rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
@@ -554,26 +584,33 @@ int cifs_get_inode_info(struct inode **pinode,
 {
        int rc = 0, tmprc;
        struct cifsTconInfo *pTcon;
+       struct tcon_link *tlink;
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
        char *buf = NULL;
        bool adjustTZ = false;
        struct cifs_fattr fattr;
 
-       pTcon = cifs_sb->tcon;
+       tlink = cifs_sb_tlink(cifs_sb);
+       if (IS_ERR(tlink))
+               return PTR_ERR(tlink);
+       pTcon = tlink_tcon(tlink);
+
        cFYI(1, "Getting info on %s", full_path);
 
        if ((pfindData == NULL) && (*pinode != NULL)) {
                if (CIFS_I(*pinode)->clientCanCacheRead) {
                        cFYI(1, "No need to revalidate cached inode sizes");
-                       return rc;
+                       goto cgii_exit;
                }
        }
 
        /* if file info not passed in then get it from server */
        if (pfindData == NULL) {
                buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
-               if (buf == NULL)
-                       return -ENOMEM;
+               if (buf == NULL) {
+                       rc = -ENOMEM;
+                       goto cgii_exit;
+               }
                pfindData = (FILE_ALL_INFO *)buf;
 
                /* could do find first instead but this returns more info */
@@ -649,18 +686,30 @@ int cifs_get_inode_info(struct inode **pinode,
                        cFYI(1, "cifs_sfu_type failed: %d", tmprc);
        }
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL
+#ifdef CONFIG_CIFS_ACL
        /* fill in 0777 bits from ACL */
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
-               cFYI(1, "Getting mode bits from ACL");
-               cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, pfid);
+               rc = cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path,
+                                               pfid);
+               if (rc) {
+                       cFYI(1, "%s: Getting ACL failed with error: %d",
+                               __func__, rc);
+                       goto cgii_exit;
+               }
        }
-#endif
+#endif /* CONFIG_CIFS_ACL */
 
        /* fill in remaining high mode bits e.g. SUID, VTX */
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
                cifs_sfu_mode(&fattr, full_path, cifs_sb, xid);
 
+       /* check for Minshall+French symlinks */
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
+               tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid);
+               if (tmprc)
+                       cFYI(1, "CIFSCheckMFSymlink: %d", tmprc);
+       }
+
        if (!*pinode) {
                *pinode = cifs_iget(sb, &fattr);
                if (!*pinode)
@@ -671,6 +720,7 @@ int cifs_get_inode_info(struct inode **pinode,
 
 cgii_exit:
        kfree(buf);
+       cifs_put_tlink(tlink);
        return rc;
 }
 
@@ -678,7 +728,8 @@ static const struct inode_operations cifs_ipc_inode_ops = {
        .lookup = cifs_lookup,
 };
 
-char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
+char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb,
+                               struct cifsTconInfo *tcon)
 {
        int pplen = cifs_sb->prepathlen;
        int dfsplen;
@@ -692,8 +743,8 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
                return full_path;
        }
 
-       if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
-               dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
+       if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
+               dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
        else
                dfsplen = 0;
 
@@ -702,7 +753,7 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
                return full_path;
 
        if (dfsplen) {
-               strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
+               strncpy(full_path, tcon->treeName, dfsplen);
                /* switch slash direction in prepath depending on whether
                 * windows or posix style path names
                 */
@@ -818,32 +869,34 @@ retry_iget5_locked:
 struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
 {
        int xid;
-       struct cifs_sb_info *cifs_sb;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
        struct inode *inode = NULL;
        long rc;
        char *full_path;
+       struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
 
-       cifs_sb = CIFS_SB(sb);
-       full_path = cifs_build_path_to_root(cifs_sb);
+       full_path = cifs_build_path_to_root(cifs_sb, tcon);
        if (full_path == NULL)
                return ERR_PTR(-ENOMEM);
 
        xid = GetXid();
-       if (cifs_sb->tcon->unix_ext)
+       if (tcon->unix_ext)
                rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
        else
                rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
                                                xid, NULL);
 
-       if (!inode)
-               return ERR_PTR(rc);
+       if (!inode) {
+               inode = ERR_PTR(rc);
+               goto out;
+       }
 
 #ifdef CONFIG_CIFS_FSCACHE
        /* populate tcon->resource_id */
-       cifs_sb->tcon->resource_id = CIFS_I(inode)->uniqueid;
+       tcon->resource_id = CIFS_I(inode)->uniqueid;
 #endif
 
-       if (rc && cifs_sb->tcon->ipc) {
+       if (rc && tcon->ipc) {
                cFYI(1, "ipc connection - fake read inode");
                inode->i_mode |= S_IFDIR;
                inode->i_nlink = 2;
@@ -852,13 +905,11 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
                inode->i_uid = cifs_sb->mnt_uid;
                inode->i_gid = cifs_sb->mnt_gid;
        } else if (rc) {
-               kfree(full_path);
-               _FreeXid(xid);
                iget_failed(inode);
-               return ERR_PTR(rc);
+               inode = ERR_PTR(rc);
        }
 
-
+out:
        kfree(full_path);
        /* can not call macro FreeXid here since in a void func
         * TODO: This is no longer true
@@ -879,7 +930,8 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
        struct cifsFileInfo *open_file;
        struct cifsInodeInfo *cifsInode = CIFS_I(inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-       struct cifsTconInfo *pTcon = cifs_sb->tcon;
+       struct tcon_link *tlink = NULL;
+       struct cifsTconInfo *pTcon;
        FILE_BASIC_INFO info_buf;
 
        if (attrs == NULL)
@@ -918,13 +970,22 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
        /*
         * If the file is already open for write, just use that fileid
         */
-       open_file = find_writable_file(cifsInode);
+       open_file = find_writable_file(cifsInode, true);
        if (open_file) {
                netfid = open_file->netfid;
                netpid = open_file->pid;
+               pTcon = tlink_tcon(open_file->tlink);
                goto set_via_filehandle;
        }
 
+       tlink = cifs_sb_tlink(cifs_sb);
+       if (IS_ERR(tlink)) {
+               rc = PTR_ERR(tlink);
+               tlink = NULL;
+               goto out;
+       }
+       pTcon = tlink_tcon(tlink);
+
        /*
         * NT4 apparently returns success on this call, but it doesn't
         * really work.
@@ -968,6 +1029,8 @@ set_via_filehandle:
        else
                cifsFileInfo_put(open_file);
 out:
+       if (tlink != NULL)
+               cifs_put_tlink(tlink);
        return rc;
 }
 
@@ -985,10 +1048,16 @@ cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid)
        struct inode *inode = dentry->d_inode;
        struct cifsInodeInfo *cifsInode = CIFS_I(inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-       struct cifsTconInfo *tcon = cifs_sb->tcon;
+       struct tcon_link *tlink;
+       struct cifsTconInfo *tcon;
        __u32 dosattr, origattr;
        FILE_BASIC_INFO *info_buf = NULL;
 
+       tlink = cifs_sb_tlink(cifs_sb);
+       if (IS_ERR(tlink))
+               return PTR_ERR(tlink);
+       tcon = tlink_tcon(tlink);
+
        rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
                         DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
                         &netfid, &oplock, NULL, cifs_sb->local_nls,
@@ -1057,6 +1126,7 @@ out_close:
        CIFSSMBClose(xid, tcon, netfid);
 out:
        kfree(info_buf);
+       cifs_put_tlink(tlink);
        return rc;
 
        /*
@@ -1096,12 +1166,18 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
        struct cifsInodeInfo *cifs_inode;
        struct super_block *sb = dir->i_sb;
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-       struct cifsTconInfo *tcon = cifs_sb->tcon;
+       struct tcon_link *tlink;
+       struct cifsTconInfo *tcon;
        struct iattr *attrs = NULL;
        __u32 dosattr = 0, origattr = 0;
 
        cFYI(1, "cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry);
 
+       tlink = cifs_sb_tlink(cifs_sb);
+       if (IS_ERR(tlink))
+               return PTR_ERR(tlink);
+       tcon = tlink_tcon(tlink);
+
        xid = GetXid();
 
        /* Unlink can be called from rename so we can not take the
@@ -1109,8 +1185,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
        full_path = build_path_from_dentry(dentry);
        if (full_path == NULL) {
                rc = -ENOMEM;
-               FreeXid(xid);
-               return rc;
+               goto unlink_out;
        }
 
        if ((tcon->ses->capabilities & CAP_UNIX) &&
@@ -1176,10 +1251,11 @@ out_reval:
        dir->i_ctime = dir->i_mtime = current_fs_time(sb);
        cifs_inode = CIFS_I(dir);
        CIFS_I(dir)->time = 0;  /* force revalidate of dir as well */
-
+unlink_out:
        kfree(full_path);
        kfree(attrs);
        FreeXid(xid);
+       cifs_put_tlink(tlink);
        return rc;
 }
 
@@ -1188,6 +1264,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
        int rc = 0, tmprc;
        int xid;
        struct cifs_sb_info *cifs_sb;
+       struct tcon_link *tlink;
        struct cifsTconInfo *pTcon;
        char *full_path = NULL;
        struct inode *newinode = NULL;
@@ -1195,16 +1272,18 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
 
        cFYI(1, "In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode);
 
-       xid = GetXid();
-
        cifs_sb = CIFS_SB(inode->i_sb);
-       pTcon = cifs_sb->tcon;
+       tlink = cifs_sb_tlink(cifs_sb);
+       if (IS_ERR(tlink))
+               return PTR_ERR(tlink);
+       pTcon = tlink_tcon(tlink);
+
+       xid = GetXid();
 
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
                rc = -ENOMEM;
-               FreeXid(xid);
-               return rc;
+               goto mkdir_out;
        }
 
        if ((pTcon->ses->capabilities & CAP_UNIX) &&
@@ -1362,6 +1441,7 @@ mkdir_get_info:
 mkdir_out:
        kfree(full_path);
        FreeXid(xid);
+       cifs_put_tlink(tlink);
        return rc;
 }
 
@@ -1370,6 +1450,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
        int rc = 0;
        int xid;
        struct cifs_sb_info *cifs_sb;
+       struct tcon_link *tlink;
        struct cifsTconInfo *pTcon;
        char *full_path = NULL;
        struct cifsInodeInfo *cifsInode;
@@ -1378,18 +1459,23 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
 
        xid = GetXid();
 
-       cifs_sb = CIFS_SB(inode->i_sb);
-       pTcon = cifs_sb->tcon;
-
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
                rc = -ENOMEM;
-               FreeXid(xid);
-               return rc;
+               goto rmdir_exit;
+       }
+
+       cifs_sb = CIFS_SB(inode->i_sb);
+       tlink = cifs_sb_tlink(cifs_sb);
+       if (IS_ERR(tlink)) {
+               rc = PTR_ERR(tlink);
+               goto rmdir_exit;
        }
+       pTcon = tlink_tcon(tlink);
 
        rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
                          cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       cifs_put_tlink(tlink);
 
        if (!rc) {
                drop_nlink(inode);
@@ -1410,6 +1496,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
        direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
                current_fs_time(inode->i_sb);
 
+rmdir_exit:
        kfree(full_path);
        FreeXid(xid);
        return rc;
@@ -1420,10 +1507,16 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
                struct dentry *to_dentry, const char *toPath)
 {
        struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
-       struct cifsTconInfo *pTcon = cifs_sb->tcon;
+       struct tcon_link *tlink;
+       struct cifsTconInfo *pTcon;
        __u16 srcfid;
        int oplock, rc;
 
+       tlink = cifs_sb_tlink(cifs_sb);
+       if (IS_ERR(tlink))
+               return PTR_ERR(tlink);
+       pTcon = tlink_tcon(tlink);
+
        /* try path-based rename first */
        rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls,
                           cifs_sb->mnt_cifs_flags &
@@ -1435,11 +1528,11 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
         * rename by filehandle to various Windows servers.
         */
        if (rc == 0 || rc != -ETXTBSY)
-               return rc;
+               goto do_rename_exit;
 
        /* open-file renames don't work across directories */
        if (to_dentry->d_parent != from_dentry->d_parent)
-               return rc;
+               goto do_rename_exit;
 
        /* open the file to be renamed -- we need DELETE perms */
        rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE,
@@ -1455,7 +1548,8 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
 
                CIFSSMBClose(xid, pTcon, srcfid);
        }
-
+do_rename_exit:
+       cifs_put_tlink(tlink);
        return rc;
 }
 
@@ -1465,13 +1559,17 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
        char *fromName = NULL;
        char *toName = NULL;
        struct cifs_sb_info *cifs_sb;
+       struct tcon_link *tlink;
        struct cifsTconInfo *tcon;
        FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
        FILE_UNIX_BASIC_INFO *info_buf_target;
        int xid, rc, tmprc;
 
        cifs_sb = CIFS_SB(source_dir->i_sb);
-       tcon = cifs_sb->tcon;
+       tlink = cifs_sb_tlink(cifs_sb);
+       if (IS_ERR(tlink))
+               return PTR_ERR(tlink);
+       tcon = tlink_tcon(tlink);
 
        xid = GetXid();
 
@@ -1547,6 +1645,7 @@ cifs_rename_exit:
        kfree(fromName);
        kfree(toName);
        FreeXid(xid);
+       cifs_put_tlink(tlink);
        return rc;
 }
 
@@ -1554,6 +1653,7 @@ static bool
 cifs_inode_needs_reval(struct inode *inode)
 {
        struct cifsInodeInfo *cifs_i = CIFS_I(inode);
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 
        if (cifs_i->clientCanCacheRead)
                return false;
@@ -1564,19 +1664,21 @@ cifs_inode_needs_reval(struct inode *inode)
        if (cifs_i->time == 0)
                return true;
 
-       /* FIXME: the actimeo should be tunable */
-       if (time_after_eq(jiffies, cifs_i->time + HZ))
+       if (!time_in_range(jiffies, cifs_i->time,
+                               cifs_i->time + cifs_sb->actimeo))
                return true;
 
        /* hardlinked files w/ noserverino get "special" treatment */
-       if (!(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
+       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
            S_ISREG(inode->i_mode) && inode->i_nlink != 1)
                return true;
 
        return false;
 }
 
-/* check invalid_mapping flag and zap the cache if it's set */
+/*
+ * Zap the cache. Called when invalid_mapping flag is set.
+ */
 static void
 cifs_invalidate_mapping(struct inode *inode)
 {
@@ -1588,8 +1690,7 @@ cifs_invalidate_mapping(struct inode *inode)
        /* write back any cached data */
        if (inode->i_mapping && inode->i_mapping->nrpages != 0) {
                rc = filemap_write_and_wait(inode->i_mapping);
-               if (rc)
-                       cifs_i->write_behind_rc = rc;
+               mapping_set_error(inode->i_mapping, rc);
        }
        invalidate_remote_inode(inode);
        cifs_fscache_reset_inode_cookie(inode);
@@ -1599,11 +1700,12 @@ int cifs_revalidate_file(struct file *filp)
 {
        int rc = 0;
        struct inode *inode = filp->f_path.dentry->d_inode;
+       struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
 
        if (!cifs_inode_needs_reval(inode))
                goto check_inval;
 
-       if (CIFS_SB(inode->i_sb)->tcon->unix_ext)
+       if (tlink_tcon(cfile->tlink)->unix_ext)
                rc = cifs_get_file_info_unix(filp);
        else
                rc = cifs_get_file_info(filp);
@@ -1644,7 +1746,7 @@ int cifs_revalidate_dentry(struct dentry *dentry)
                 "jiffies %ld", full_path, inode, inode->i_count.counter,
                 dentry, dentry->d_time, jiffies);
 
-       if (CIFS_SB(sb)->tcon->unix_ext)
+       if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
                rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
        else
                rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
@@ -1660,13 +1762,29 @@ check_inval:
 }
 
 int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
-       struct kstat *stat)
+                struct kstat *stat)
 {
+       struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
+       struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
        int err = cifs_revalidate_dentry(dentry);
+
        if (!err) {
                generic_fillattr(dentry->d_inode, stat);
                stat->blksize = CIFS_MAX_MSGSIZE;
                stat->ino = CIFS_I(dentry->d_inode)->uniqueid;
+
+               /*
+                * If on a multiuser mount without unix extensions, and the
+                * admin hasn't overridden them, set the ownership to the
+                * fsuid/fsgid of the current process.
+                */
+               if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) &&
+                   !tcon->unix_ext) {
+                       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID))
+                               stat->uid = current_fsuid();
+                       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID))
+                               stat->gid = current_fsgid();
+               }
        }
        return err;
 }
@@ -1708,7 +1826,8 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
        struct cifsFileInfo *open_file;
        struct cifsInodeInfo *cifsInode = CIFS_I(inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-       struct cifsTconInfo *pTcon = cifs_sb->tcon;
+       struct tcon_link *tlink = NULL;
+       struct cifsTconInfo *pTcon = NULL;
 
        /*
         * To avoid spurious oplock breaks from server, in the case of
@@ -1719,10 +1838,11 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
         * writebehind data than the SMB timeout for the SetPathInfo
         * request would allow
         */
-       open_file = find_writable_file(cifsInode);
+       open_file = find_writable_file(cifsInode, true);
        if (open_file) {
                __u16 nfid = open_file->netfid;
                __u32 npid = open_file->pid;
+               pTcon = tlink_tcon(open_file->tlink);
                rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid,
                                        npid, false);
                cifsFileInfo_put(open_file);
@@ -1737,6 +1857,13 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
                rc = -EINVAL;
 
        if (rc != 0) {
+               if (pTcon == NULL) {
+                       tlink = cifs_sb_tlink(cifs_sb);
+                       if (IS_ERR(tlink))
+                               return PTR_ERR(tlink);
+                       pTcon = tlink_tcon(tlink);
+               }
+
                /* Set file size by pathname rather than by handle
                   either because no valid, writeable file handle for
                   it was found or because there was an error setting
@@ -1766,6 +1893,8 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
                                CIFSSMBClose(xid, pTcon, netfid);
                        }
                }
+               if (tlink)
+                       cifs_put_tlink(tlink);
        }
 
        if (rc == 0) {
@@ -1786,7 +1915,8 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
        struct inode *inode = direntry->d_inode;
        struct cifsInodeInfo *cifsInode = CIFS_I(inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-       struct cifsTconInfo *pTcon = cifs_sb->tcon;
+       struct tcon_link *tlink;
+       struct cifsTconInfo *pTcon;
        struct cifs_unix_set_info_args *args = NULL;
        struct cifsFileInfo *open_file;
 
@@ -1820,10 +1950,8 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
         * the flush returns error?
         */
        rc = filemap_write_and_wait(inode->i_mapping);
-       if (rc != 0) {
-               cifsInode->write_behind_rc = rc;
-               rc = 0;
-       }
+       mapping_set_error(inode->i_mapping, rc);
+       rc = 0;
 
        if (attrs->ia_valid & ATTR_SIZE) {
                rc = cifs_set_file_size(inode, attrs, xid, full_path);
@@ -1873,17 +2001,25 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
                args->ctime = NO_CHANGE_64;
 
        args->device = 0;
-       open_file = find_writable_file(cifsInode);
+       open_file = find_writable_file(cifsInode, true);
        if (open_file) {
                u16 nfid = open_file->netfid;
                u32 npid = open_file->pid;
+               pTcon = tlink_tcon(open_file->tlink);
                rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
                cifsFileInfo_put(open_file);
        } else {
+               tlink = cifs_sb_tlink(cifs_sb);
+               if (IS_ERR(tlink)) {
+                       rc = PTR_ERR(tlink);
+                       goto out;
+               }
+               pTcon = tlink_tcon(tlink);
                rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args,
                                    cifs_sb->local_nls,
                                    cifs_sb->mnt_cifs_flags &
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
+               cifs_put_tlink(tlink);
        }
 
        if (rc)
@@ -1956,10 +2092,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
         * the flush returns error?
         */
        rc = filemap_write_and_wait(inode->i_mapping);
-       if (rc != 0) {
-               cifsInode->write_behind_rc = rc;
-               rc = 0;
-       }
+       mapping_set_error(inode->i_mapping, rc);
+       rc = 0;
 
        if (attrs->ia_valid & ATTR_SIZE) {
                rc = cifs_set_file_size(inode, attrs, xid, full_path);
@@ -1988,11 +2122,16 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
 
        if (attrs->ia_valid & ATTR_MODE) {
                rc = 0;
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
-                       rc = mode_to_acl(inode, full_path, mode);
-               else
-#endif
+#ifdef CONFIG_CIFS_ACL
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
+                       rc = mode_to_cifs_acl(inode, full_path, mode);
+                       if (rc) {
+                               cFYI(1, "%s: Setting ACL failed with error: %d",
+                                       __func__, rc);
+                               goto cifs_setattr_exit;
+                       }
+               } else
+#endif /* CONFIG_CIFS_ACL */
                if (((mode & S_IWUGO) == 0) &&
                    (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
 
@@ -2051,7 +2190,6 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
 
        setattr_copy(inode, attrs);
        mark_inode_dirty(inode);
-       return 0;
 
 cifs_setattr_exit:
        kfree(full_path);
@@ -2064,7 +2202,7 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 {
        struct inode *inode = direntry->d_inode;
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-       struct cifsTconInfo *pTcon = cifs_sb->tcon;
+       struct cifsTconInfo *pTcon = cifs_sb_master_tcon(cifs_sb);
 
        if (pTcon->unix_ext)
                return cifs_setattr_unix(direntry, attrs);