summaryrefslogtreecommitdiffstats
path: root/fs/cifs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r--fs/cifs/inode.c441
1 files changed, 214 insertions, 227 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index cb79c7edecb0..afdff79651f1 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_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);