Merge remote-tracking branch 'c6x/for-linux-next' into uapi-prep
[cascardo/linux.git] / fs / cifs / inode.c
index cb79c7e..afdff79 100644 (file)
@@ -282,7 +282,8 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
        fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
 }
 
-int cifs_get_file_info_unix(struct file *filp)
+static int
+cifs_get_file_info_unix(struct file *filp)
 {
        int rc;
        unsigned int xid;
@@ -294,7 +295,7 @@ int cifs_get_file_info_unix(struct file *filp)
        struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 
        xid = get_xid();
-       rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
+       rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->fid.netfid, &find_data);
        if (!rc) {
                cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
        } else if (rc == -EREMOTE) {
@@ -550,7 +551,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
        fattr->cf_gid = cifs_sb->mnt_gid;
 }
 
-int cifs_get_file_info(struct file *filp)
+static int
+cifs_get_file_info(struct file *filp)
 {
        int rc;
        unsigned int xid;
@@ -560,9 +562,13 @@ int cifs_get_file_info(struct file *filp)
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct cifsFileInfo *cfile = filp->private_data;
        struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+       struct TCP_Server_Info *server = tcon->ses->server;
+
+       if (!server->ops->query_file_info)
+               return -ENOSYS;
 
        xid = get_xid();
-       rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
+       rc = server->ops->query_file_info(xid, tcon, &cfile->fid, &find_data);
        switch (rc) {
        case 0:
                cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
@@ -601,7 +607,9 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
                    FILE_ALL_INFO *data, struct super_block *sb, int xid,
                    const __u16 *fid)
 {
-       int rc = 0, tmprc;
+       bool validinum = false;
+       __u16 srchflgs;
+       int rc = 0, tmprc = ENOSYS;
        struct cifs_tcon *tcon;
        struct TCP_Server_Info *server;
        struct tcon_link *tlink;
@@ -609,6 +617,7 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
        char *buf = NULL;
        bool adjust_tz = false;
        struct cifs_fattr fattr;
+       struct cifs_search_info *srchinf = NULL;
 
        tlink = cifs_sb_tlink(cifs_sb);
        if (IS_ERR(tlink))
@@ -647,9 +656,38 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
        } else if (rc == -EREMOTE) {
                cifs_create_dfs_fattr(&fattr, sb);
                rc = 0;
-       } else {
+       } else if (rc == -EACCES && backup_cred(cifs_sb)) {
+                       srchinf = kzalloc(sizeof(struct cifs_search_info),
+                                               GFP_KERNEL);
+                       if (srchinf == NULL) {
+                               rc = -ENOMEM;
+                               goto cgii_exit;
+                       }
+
+                       srchinf->endOfSearch = false;
+                       srchinf->info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
+
+                       srchflgs = CIFS_SEARCH_CLOSE_ALWAYS |
+                                       CIFS_SEARCH_CLOSE_AT_END |
+                                       CIFS_SEARCH_BACKUP_SEARCH;
+
+                       rc = CIFSFindFirst(xid, tcon, full_path,
+                               cifs_sb, NULL, srchflgs, srchinf, false);
+                       if (!rc) {
+                               data =
+                               (FILE_ALL_INFO *)srchinf->srch_entries_start;
+
+                               cifs_dir_info_to_fattr(&fattr,
+                               (FILE_DIRECTORY_INFO *)data, cifs_sb);
+                               fattr.cf_uniqueid = le64_to_cpu(
+                               ((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId);
+                               validinum = true;
+
+                               cifs_buf_release(srchinf->ntwrk_buf_start);
+                       }
+                       kfree(srchinf);
+       } else
                goto cgii_exit;
-       }
 
        /*
         * If an inode wasn't passed in, then get the inode number
@@ -660,23 +698,21 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
         */
        if (*inode == NULL) {
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
-                       if (server->ops->get_srv_inum)
-                               tmprc = server->ops->get_srv_inum(xid, tcon,
-                                       cifs_sb, full_path, &fattr.cf_uniqueid,
-                                       data);
-                       else
-                               tmprc = -ENOSYS;
-                       if (tmprc || !fattr.cf_uniqueid) {
-                               cFYI(1, "GetSrvInodeNum rc %d", tmprc);
-                               fattr.cf_uniqueid = iunique(sb, ROOT_I);
-                               cifs_autodisable_serverino(cifs_sb);
+                       if (validinum == false) {
+                               if (server->ops->get_srv_inum)
+                                       tmprc = server->ops->get_srv_inum(xid,
+                                               tcon, cifs_sb, full_path,
+                                               &fattr.cf_uniqueid, data);
+                               if (tmprc) {
+                                       cFYI(1, "GetSrvInodeNum rc %d", tmprc);
+                                       fattr.cf_uniqueid = iunique(sb, ROOT_I);
+                                       cifs_autodisable_serverino(cifs_sb);
+                               }
                        }
-               } else {
+               } else
                        fattr.cf_uniqueid = iunique(sb, ROOT_I);
-               }
-       } else {
+       } else
                fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
-       }
 
        /* query for SFU type info if supported and needed */
        if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
@@ -876,25 +912,22 @@ out:
        return inode;
 }
 
-static int
+int
 cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
-                   char *full_path, __u32 dosattr)
+                  char *full_path, __u32 dosattr)
 {
-       int rc;
-       int oplock = 0;
-       __u16 netfid;
-       __u32 netpid;
        bool set_time = false;
-       struct cifsFileInfo *open_file;
-       struct cifsInodeInfo *cifsInode = CIFS_I(inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-       struct tcon_link *tlink = NULL;
-       struct cifs_tcon *pTcon;
+       struct TCP_Server_Info *server;
        FILE_BASIC_INFO info_buf;
 
        if (attrs == NULL)
                return -EINVAL;
 
+       server = cifs_sb_master_tcon(cifs_sb)->ses->server;
+       if (!server->ops->set_file_info)
+               return -ENOSYS;
+
        if (attrs->ia_valid & ATTR_ATIME) {
                set_time = true;
                info_buf.LastAccessTime =
@@ -925,81 +958,17 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
        info_buf.CreationTime = 0;      /* don't change */
        info_buf.Attributes = cpu_to_le32(dosattr);
 
-       /*
-        * If the file is already open for write, just use that fileid
-        */
-       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.
-        */
-       if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
-               rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
-                                    &info_buf, cifs_sb->local_nls,
-                                    cifs_sb->mnt_cifs_flags &
-                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
-               if (rc == 0) {
-                       cifsInode->cifsAttrs = dosattr;
-                       goto out;
-               } else if (rc != -EOPNOTSUPP && rc != -EINVAL)
-                       goto out;
-       }
-
-       cFYI(1, "calling SetFileInfo since SetPathInfo for "
-                "times not supported by this server");
-       rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
-                        SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
-                        CREATE_NOT_DIR, &netfid, &oplock,
-                        NULL, cifs_sb->local_nls,
-                        cifs_sb->mnt_cifs_flags &
-                               CIFS_MOUNT_MAP_SPECIAL_CHR);
-
-       if (rc != 0) {
-               if (rc == -EIO)
-                       rc = -EINVAL;
-               goto out;
-       }
-
-       netpid = current->tgid;
-
-set_via_filehandle:
-       rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
-       if (!rc)
-               cifsInode->cifsAttrs = dosattr;
-
-       if (open_file == NULL)
-               CIFSSMBClose(xid, pTcon, netfid);
-       else
-               cifsFileInfo_put(open_file);
-out:
-       if (tlink != NULL)
-               cifs_put_tlink(tlink);
-       return rc;
+       return server->ops->set_file_info(inode, full_path, &info_buf, xid);
 }
 
 /*
- * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
+ * Open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
  * and rename it to a random name that hopefully won't conflict with
  * anything else.
  */
-static int
-cifs_rename_pending_delete(char *full_path, struct dentry *dentry,
-                          unsigned int xid)
+int
+cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
+                          const unsigned int xid)
 {
        int oplock = 0;
        int rc;
@@ -1136,6 +1105,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
        struct tcon_link *tlink;
        struct cifs_tcon *tcon;
+       struct TCP_Server_Info *server;
        struct iattr *attrs = NULL;
        __u32 dosattr = 0, origattr = 0;
 
@@ -1145,6 +1115,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
        if (IS_ERR(tlink))
                return PTR_ERR(tlink);
        tcon = tlink_tcon(tlink);
+       server = tcon->ses->server;
 
        xid = get_xid();
 
@@ -1167,8 +1138,12 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
        }
 
 retry_std_delete:
-       rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
-                       cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       if (!server->ops->unlink) {
+               rc = -ENOSYS;
+               goto psx_del_no_retry;
+       }
+
+       rc = server->ops->unlink(xid, tcon, full_path, cifs_sb);
 
 psx_del_no_retry:
        if (!rc) {
@@ -1177,9 +1152,14 @@ psx_del_no_retry:
        } else if (rc == -ENOENT) {
                d_drop(dentry);
        } else if (rc == -ETXTBSY) {
-               rc = cifs_rename_pending_delete(full_path, dentry, xid);
-               if (rc == 0)
-                       cifs_drop_nlink(inode);
+               if (server->ops->rename_pending_delete) {
+                       rc = server->ops->rename_pending_delete(full_path,
+                                                               dentry, xid);
+                       if (rc == 0)
+                               cifs_drop_nlink(inode);
+               }
+               if (rc == -ETXTBSY)
+                       rc = -EBUSY;
        } else if ((rc == -EACCES) && (dosattr == 0) && inode) {
                attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
                if (attrs == NULL) {
@@ -1227,34 +1207,33 @@ unlink_out:
 }
 
 static int
-cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode,
+cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
                 const char *full_path, struct cifs_sb_info *cifs_sb,
                 struct cifs_tcon *tcon, const unsigned int xid)
 {
        int rc = 0;
-       struct inode *newinode = NULL;
+       struct inode *inode = NULL;
 
        if (tcon->unix_ext)
-               rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,
+               rc = cifs_get_inode_info_unix(&inode, full_path, parent->i_sb,
                                              xid);
        else
-               rc = cifs_get_inode_info(&newinode, full_path, NULL,
-                                        inode->i_sb, xid, NULL);
+               rc = cifs_get_inode_info(&inode, full_path, NULL, parent->i_sb,
+                                        xid, NULL);
+
        if (rc)
                return rc;
 
-       d_instantiate(dentry, newinode);
        /*
         * setting nlink not necessary except in cases where we failed to get it
-        * from the server or was set bogus
+        * from the server or was set bogus. Also, since this is a brand new
+        * inode, no need to grab the i_lock before setting the i_nlink.
         */
-       spin_lock(&dentry->d_inode->i_lock);
-       if ((dentry->d_inode) && (dentry->d_inode->i_nlink < 2))
-               set_nlink(dentry->d_inode, 2);
-       spin_unlock(&dentry->d_inode->i_lock);
+       if (inode->i_nlink < 2)
+               set_nlink(inode, 2);
        mode &= ~current_umask();
        /* must turn on setgid bit if parent dir has it */
-       if (inode->i_mode & S_ISGID)
+       if (parent->i_mode & S_ISGID)
                mode |= S_ISGID;
 
        if (tcon->unix_ext) {
@@ -1267,8 +1246,8 @@ cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode,
                };
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
                        args.uid = (__u64)current_fsuid();
-                       if (inode->i_mode & S_ISGID)
-                               args.gid = (__u64)inode->i_gid;
+                       if (parent->i_mode & S_ISGID)
+                               args.gid = (__u64)parent->i_gid;
                        else
                                args.gid = (__u64)current_fsgid();
                } else {
@@ -1283,22 +1262,20 @@ cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode,
                struct TCP_Server_Info *server = tcon->ses->server;
                if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
                    (mode & S_IWUGO) == 0 && server->ops->mkdir_setinfo)
-                       server->ops->mkdir_setinfo(newinode, full_path, cifs_sb,
+                       server->ops->mkdir_setinfo(inode, full_path, cifs_sb,
                                                   tcon, xid);
-               if (dentry->d_inode) {
-                       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
-                               dentry->d_inode->i_mode = (mode | S_IFDIR);
-
-                       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
-                               dentry->d_inode->i_uid = current_fsuid();
-                               if (inode->i_mode & S_ISGID)
-                                       dentry->d_inode->i_gid = inode->i_gid;
-                               else
-                                       dentry->d_inode->i_gid =
-                                                               current_fsgid();
-                       }
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
+                       inode->i_mode = (mode | S_IFDIR);
+
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+                       inode->i_uid = current_fsuid();
+                       if (inode->i_mode & S_ISGID)
+                               inode->i_gid = parent->i_gid;
+                       else
+                               inode->i_gid = current_fsgid();
                }
        }
+       d_instantiate(dentry, inode);
        return rc;
 }
 
@@ -1495,29 +1472,32 @@ rmdir_exit:
 }
 
 static int
-cifs_do_rename(unsigned int xid, struct dentry *from_dentry,
-              const char *fromPath, struct dentry *to_dentry,
-              const char *toPath)
+cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
+              const char *from_path, struct dentry *to_dentry,
+              const char *to_path)
 {
        struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
        struct tcon_link *tlink;
-       struct cifs_tcon *pTcon;
+       struct cifs_tcon *tcon;
+       struct TCP_Server_Info *server;
        __u16 srcfid;
        int oplock, rc;
 
        tlink = cifs_sb_tlink(cifs_sb);
        if (IS_ERR(tlink))
                return PTR_ERR(tlink);
-       pTcon = tlink_tcon(tlink);
+       tcon = tlink_tcon(tlink);
+       server = tcon->ses->server;
+
+       if (!server->ops->rename)
+               return -ENOSYS;
 
        /* try path-based rename first */
-       rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls,
-                          cifs_sb->mnt_cifs_flags &
-                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+       rc = server->ops->rename(xid, tcon, from_path, to_path, cifs_sb);
 
        /*
-        * don't bother with rename by filehandle unless file is busy and
-        * source Note that cross directory moves do not work with
+        * Don't bother with rename by filehandle unless file is busy and
+        * source. Note that cross directory moves do not work with
         * rename by filehandle to various Windows servers.
         */
        if (rc == 0 || rc != -ETXTBSY)
@@ -1528,29 +1508,28 @@ cifs_do_rename(unsigned int xid, struct dentry *from_dentry,
                goto do_rename_exit;
 
        /* open the file to be renamed -- we need DELETE perms */
-       rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE,
+       rc = CIFSSMBOpen(xid, tcon, from_path, FILE_OPEN, DELETE,
                         CREATE_NOT_DIR, &srcfid, &oplock, NULL,
                         cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
                                CIFS_MOUNT_MAP_SPECIAL_CHR);
-
        if (rc == 0) {
-               rc = CIFSSMBRenameOpenFile(xid, pTcon, srcfid,
+               rc = CIFSSMBRenameOpenFile(xid, tcon, srcfid,
                                (const char *) to_dentry->d_name.name,
                                cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
-
-               CIFSSMBClose(xid, pTcon, srcfid);
+               CIFSSMBClose(xid, tcon, srcfid);
        }
 do_rename_exit:
        cifs_put_tlink(tlink);
        return rc;
 }
 
-int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
-       struct inode *target_dir, struct dentry *target_dentry)
+int
+cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
+           struct inode *target_dir, struct dentry *target_dentry)
 {
-       char *fromName = NULL;
-       char *toName = NULL;
+       char *from_name = NULL;
+       char *to_name = NULL;
        struct cifs_sb_info *cifs_sb;
        struct tcon_link *tlink;
        struct cifs_tcon *tcon;
@@ -1571,25 +1550,25 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
         * we already have the rename sem so we do not need to
         * grab it again here to protect the path integrity
         */
-       fromName = build_path_from_dentry(source_dentry);
-       if (fromName == NULL) {
+       from_name = build_path_from_dentry(source_dentry);
+       if (from_name == NULL) {
                rc = -ENOMEM;
                goto cifs_rename_exit;
        }
 
-       toName = build_path_from_dentry(target_dentry);
-       if (toName == NULL) {
+       to_name = build_path_from_dentry(target_dentry);
+       if (to_name == NULL) {
                rc = -ENOMEM;
                goto cifs_rename_exit;
        }
 
-       rc = cifs_do_rename(xid, source_dentry, fromName,
-                           target_dentry, toName);
+       rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
+                           to_name);
 
        if (rc == -EEXIST && tcon->unix_ext) {
                /*
-                * Are src and dst hardlinks of same inode? We can
-                * only tell with unix extensions enabled
+                * Are src and dst hardlinks of same inode? We can only tell
+                * with unix extensions enabled.
                 */
                info_buf_source =
                        kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
@@ -1600,19 +1579,19 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
                }
 
                info_buf_target = info_buf_source + 1;
-               tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName,
-                                       info_buf_source,
-                                       cifs_sb->local_nls,
-                                       cifs_sb->mnt_cifs_flags &
-                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
+               tmprc = CIFSSMBUnixQPathInfo(xid, tcon, from_name,
+                                            info_buf_source,
+                                            cifs_sb->local_nls,
+                                            cifs_sb->mnt_cifs_flags &
+                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
                if (tmprc != 0)
                        goto unlink_target;
 
-               tmprc = CIFSSMBUnixQPathInfo(xid, tcon, toName,
-                                       info_buf_target,
-                                       cifs_sb->local_nls,
-                                       cifs_sb->mnt_cifs_flags &
-                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
+               tmprc = CIFSSMBUnixQPathInfo(xid, tcon, to_name,
+                                            info_buf_target,
+                                            cifs_sb->local_nls,
+                                            cifs_sb->mnt_cifs_flags &
+                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
 
                if (tmprc == 0 && (info_buf_source->UniqueId ==
                                   info_buf_target->UniqueId)) {
@@ -1620,8 +1599,11 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
                        rc = 0;
                        goto cifs_rename_exit;
                }
-       } /* else ... BB we could add the same check for Windows by
-                    checking the UniqueId via FILE_INTERNAL_INFO */
+       }
+       /*
+        * else ... BB we could add the same check for Windows by
+        * checking the UniqueId via FILE_INTERNAL_INFO
+        */
 
 unlink_target:
        /* Try unlinking the target dentry if it's not negative */
@@ -1629,15 +1611,14 @@ unlink_target:
                tmprc = cifs_unlink(target_dir, target_dentry);
                if (tmprc)
                        goto cifs_rename_exit;
-
-               rc = cifs_do_rename(xid, source_dentry, fromName,
-                                   target_dentry, toName);
+               rc = cifs_do_rename(xid, source_dentry, from_name,
+                                   target_dentry, to_name);
        }
 
 cifs_rename_exit:
        kfree(info_buf_source);
-       kfree(fromName);
-       kfree(toName);
+       kfree(from_name);
+       kfree(to_name);
        free_xid(xid);
        cifs_put_tlink(tlink);
        return rc;
@@ -1862,7 +1843,8 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
        struct cifsInodeInfo *cifsInode = CIFS_I(inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct tcon_link *tlink = NULL;
-       struct cifs_tcon *pTcon = NULL;
+       struct cifs_tcon *tcon = NULL;
+       struct TCP_Server_Info *server;
        struct cifs_io_parms io_parms;
 
        /*
@@ -1876,19 +1858,21 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
         */
        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);
+               tcon = tlink_tcon(open_file->tlink);
+               server = tcon->ses->server;
+               if (server->ops->set_file_size)
+                       rc = server->ops->set_file_size(xid, tcon, open_file,
+                                                       attrs->ia_size, false);
+               else
+                       rc = -ENOSYS;
                cifsFileInfo_put(open_file);
                cFYI(1, "SetFSize for attrs rc = %d", rc);
                if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
                        unsigned int bytes_written;
 
-                       io_parms.netfid = nfid;
-                       io_parms.pid = npid;
-                       io_parms.tcon = pTcon;
+                       io_parms.netfid = open_file->fid.netfid;
+                       io_parms.pid = open_file->pid;
+                       io_parms.tcon = tcon;
                        io_parms.offset = 0;
                        io_parms.length = attrs->ia_size;
                        rc = CIFSSMBWrite(xid, &io_parms, &bytes_written,
@@ -1898,52 +1882,55 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
        } else
                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);
-               }
+       if (!rc)
+               goto set_size_out;
 
-               /* 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
-                  it by handle */
-               rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,
-                                  false, cifs_sb->local_nls,
+       if (tcon == NULL) {
+               tlink = cifs_sb_tlink(cifs_sb);
+               if (IS_ERR(tlink))
+                       return PTR_ERR(tlink);
+               tcon = tlink_tcon(tlink);
+               server = tcon->ses->server;
+       }
+
+       /*
+        * 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 it by handle.
+        */
+       if (server->ops->set_path_size)
+               rc = server->ops->set_path_size(xid, tcon, full_path,
+                                               attrs->ia_size, cifs_sb, false);
+       else
+               rc = -ENOSYS;
+       cFYI(1, "SetEOF by path (setattrs) rc = %d", rc);
+       if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
+               __u16 netfid;
+               int oplock = 0;
+
+               rc = SMBLegacyOpen(xid, tcon, full_path, FILE_OPEN,
+                                  GENERIC_WRITE, CREATE_NOT_DIR, &netfid,
+                                  &oplock, NULL, cifs_sb->local_nls,
                                   cifs_sb->mnt_cifs_flags &
-                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
-               cFYI(1, "SetEOF by path (setattrs) rc = %d", rc);
-               if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
-                       __u16 netfid;
-                       int oplock = 0;
-
-                       rc = SMBLegacyOpen(xid, pTcon, full_path,
-                               FILE_OPEN, GENERIC_WRITE,
-                               CREATE_NOT_DIR, &netfid, &oplock, NULL,
-                               cifs_sb->local_nls,
-                               cifs_sb->mnt_cifs_flags &
-                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
-                       if (rc == 0) {
-                               unsigned int bytes_written;
-
-                               io_parms.netfid = netfid;
-                               io_parms.pid = current->tgid;
-                               io_parms.tcon = pTcon;
-                               io_parms.offset = 0;
-                               io_parms.length = attrs->ia_size;
-                               rc = CIFSSMBWrite(xid, &io_parms,
-                                                 &bytes_written,
-                                                 NULL, NULL,  1);
-                               cFYI(1, "wrt seteof rc %d", rc);
-                               CIFSSMBClose(xid, pTcon, netfid);
-                       }
+                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+               if (rc == 0) {
+                       unsigned int bytes_written;
+
+                       io_parms.netfid = netfid;
+                       io_parms.pid = current->tgid;
+                       io_parms.tcon = tcon;
+                       io_parms.offset = 0;
+                       io_parms.length = attrs->ia_size;
+                       rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, NULL,
+                                         NULL,  1);
+                       cFYI(1, "wrt seteof rc %d", rc);
+                       CIFSSMBClose(xid, tcon, netfid);
                }
-               if (tlink)
-                       cifs_put_tlink(tlink);
        }
+       if (tlink)
+               cifs_put_tlink(tlink);
 
+set_size_out:
        if (rc == 0) {
                cifsInode->server_eof = attrs->ia_size;
                cifs_setsize(inode, attrs->ia_size);
@@ -2050,7 +2037,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
        args->device = 0;
        open_file = find_writable_file(cifsInode, true);
        if (open_file) {
-               u16 nfid = open_file->netfid;
+               u16 nfid = open_file->fid.netfid;
                u32 npid = open_file->pid;
                pTcon = tlink_tcon(open_file->tlink);
                rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);