diff options
Diffstat (limited to 'fs/cifs/inode.c')
| -rw-r--r-- | fs/cifs/inode.c | 444 | 
1 files changed, 216 insertions, 228 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index cb79c7edecb..ed6208ff85a 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -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_DYNPERM) +			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_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; @@ -1810,11 +1791,12 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,  	stat->ino = CIFS_I(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 on a multiuser mount without unix extensions or cifsacl being +	 * enabled, 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) && +	    !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&  	    !tcon->unix_ext) {  		if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID))  			stat->uid = current_fsuid(); @@ -1862,7 +1844,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 +1859,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 +1883,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, -				   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; +	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; +	} -			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; +	/* +	 * 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; -				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); -			} +		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); +		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 +2038,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);  |