Merge tag 'v7.0-rc3-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client fixes from Steve French:
 - Fix reconnect when using non-default port
 - Fix default retransmission behavior
 - Fix open handle reuse in cifs_open
 - Fix export for smb2-mapperror-test
 - Fix potential corruption on write retry
 - Fix potentially uninitialized superblock flags
 - Fix missing O_DIRECT and O_SYNC flags on create

* tag 'v7.0-rc3-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: make default value of retrans as zero
  smb: client: fix open handle lookup in cifs_open()
  smb: client: fix iface port assignment in parse_server_interfaces
  smb/client: only export symbol for 'smb2maperror-test' module
  smb: client: fix in-place encryption corruption in SMB2_write()
  smb: client: fix sbflags initialization
  smb: client: fix atomic open with O_DIRECT & O_SYNC
This commit is contained in:
Linus Torvalds
2026-03-13 10:46:32 -07:00
13 changed files with 151 additions and 99 deletions

View File

@@ -1489,7 +1489,7 @@ struct smb_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
struct cifsFileInfo *open_file = NULL; struct cifsFileInfo *open_file = NULL;
if (inode) if (inode)
open_file = find_readable_file(CIFS_I(inode), true); open_file = find_readable_file(CIFS_I(inode), FIND_FSUID_ONLY);
if (!open_file) if (!open_file)
return get_cifs_acl_by_path(cifs_sb, path, pacllen, info); return get_cifs_acl_by_path(cifs_sb, path, pacllen, info);

View File

@@ -1269,7 +1269,7 @@ static int cifs_precopy_set_eof(struct inode *src_inode, struct cifsInodeInfo *s
struct cifsFileInfo *writeable_srcfile; struct cifsFileInfo *writeable_srcfile;
int rc = -EINVAL; int rc = -EINVAL;
writeable_srcfile = find_writable_file(src_cifsi, FIND_WR_FSUID_ONLY); writeable_srcfile = find_writable_file(src_cifsi, FIND_FSUID_ONLY);
if (writeable_srcfile) { if (writeable_srcfile) {
if (src_tcon->ses->server->ops->set_file_size) if (src_tcon->ses->server->ops->set_file_size)
rc = src_tcon->ses->server->ops->set_file_size( rc = src_tcon->ses->server->ops->set_file_size(

View File

@@ -20,6 +20,7 @@
#include <linux/utsname.h> #include <linux/utsname.h>
#include <linux/sched/mm.h> #include <linux/sched/mm.h>
#include <linux/netfs.h> #include <linux/netfs.h>
#include <linux/fcntl.h>
#include "cifs_fs_sb.h" #include "cifs_fs_sb.h"
#include "cifsacl.h" #include "cifsacl.h"
#include <crypto/internal/hash.h> #include <crypto/internal/hash.h>
@@ -1884,12 +1885,12 @@ static inline bool is_replayable_error(int error)
} }
/* cifs_get_writable_file() flags */ enum cifs_find_flags {
enum cifs_writable_file_flags { FIND_ANY = 0U,
FIND_WR_ANY = 0U, FIND_FSUID_ONLY = (1U << 0),
FIND_WR_FSUID_ONLY = (1U << 0), FIND_WITH_DELETE = (1U << 1),
FIND_WR_WITH_DELETE = (1U << 1), FIND_NO_PENDING_DELETE = (1U << 2),
FIND_WR_NO_PENDING_DELETE = (1U << 2), FIND_OPEN_FLAGS = (1U << 3),
}; };
#define MID_FREE 0 #define MID_FREE 0
@@ -2375,4 +2376,14 @@ static inline bool cifs_forced_shutdown(const struct cifs_sb_info *sbi)
return cifs_sb_flags(sbi) & CIFS_MOUNT_SHUTDOWN; return cifs_sb_flags(sbi) & CIFS_MOUNT_SHUTDOWN;
} }
static inline int cifs_open_create_options(unsigned int oflags, int opts)
{
/* O_SYNC also has bit for O_DSYNC so following check picks up either */
if (oflags & O_SYNC)
opts |= CREATE_WRITE_THROUGH;
if (oflags & O_DIRECT)
opts |= CREATE_NO_BUFFER;
return opts;
}
#endif /* _CIFS_GLOB_H */ #endif /* _CIFS_GLOB_H */

View File

@@ -138,12 +138,14 @@ void cifs_write_subrequest_terminated(struct cifs_io_subrequest *wdata,
ssize_t result); ssize_t result);
struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
int flags); int flags);
int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, int flags, int __cifs_get_writable_file(struct cifsInodeInfo *cifs_inode,
struct cifsFileInfo **ret_file); unsigned int find_flags, unsigned int open_flags,
struct cifsFileInfo **ret_file);
int cifs_get_writable_path(struct cifs_tcon *tcon, const char *name, int flags, int cifs_get_writable_path(struct cifs_tcon *tcon, const char *name, int flags,
struct cifsFileInfo **ret_file); struct cifsFileInfo **ret_file);
struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, struct cifsFileInfo *__find_readable_file(struct cifsInodeInfo *cifs_inode,
bool fsuid_only); unsigned int find_flags,
unsigned int open_flags);
int cifs_get_readable_path(struct cifs_tcon *tcon, const char *name, int cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
struct cifsFileInfo **ret_file); struct cifsFileInfo **ret_file);
int cifs_get_hardlink_path(struct cifs_tcon *tcon, struct inode *inode, int cifs_get_hardlink_path(struct cifs_tcon *tcon, struct inode *inode,
@@ -596,4 +598,20 @@ static inline void cifs_sg_set_buf(struct sg_table *sgtable,
} }
} }
static inline int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode,
unsigned int find_flags,
struct cifsFileInfo **ret_file)
{
find_flags &= ~FIND_OPEN_FLAGS;
return __cifs_get_writable_file(cifs_inode, find_flags, 0, ret_file);
}
static inline struct cifsFileInfo *
find_readable_file(struct cifsInodeInfo *cinode, unsigned int find_flags)
{
find_flags &= ~FIND_OPEN_FLAGS;
find_flags |= FIND_NO_PENDING_DELETE;
return __find_readable_file(cinode, find_flags, 0);
}
#endif /* _CIFSPROTO_H */ #endif /* _CIFSPROTO_H */

View File

@@ -187,7 +187,7 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned
const char *full_path; const char *full_path;
void *page = alloc_dentry_path(); void *page = alloc_dentry_path();
struct inode *newinode = NULL; struct inode *newinode = NULL;
unsigned int sbflags; unsigned int sbflags = cifs_sb_flags(cifs_sb);
int disposition; int disposition;
struct TCP_Server_Info *server = tcon->ses->server; struct TCP_Server_Info *server = tcon->ses->server;
struct cifs_open_parms oparms; struct cifs_open_parms oparms;
@@ -308,6 +308,7 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned
goto out; goto out;
} }
create_options |= cifs_open_create_options(oflags, create_options);
/* /*
* if we're not using unix extensions, see if we need to set * if we're not using unix extensions, see if we need to set
* ATTR_READONLY on the create call * ATTR_READONLY on the create call
@@ -367,7 +368,6 @@ retry_open:
* If Open reported that we actually created a file then we now have to * If Open reported that we actually created a file then we now have to
* set the mode if possible. * set the mode if possible.
*/ */
sbflags = cifs_sb_flags(cifs_sb);
if ((tcon->unix_ext) && (*oplock & CIFS_CREATE_ACTION)) { if ((tcon->unix_ext) && (*oplock & CIFS_CREATE_ACTION)) {
struct cifs_unix_set_info_args args = { struct cifs_unix_set_info_args args = {
.mode = mode, .mode = mode,

View File

@@ -255,7 +255,7 @@ static void cifs_begin_writeback(struct netfs_io_request *wreq)
struct cifs_io_request *req = container_of(wreq, struct cifs_io_request, rreq); struct cifs_io_request *req = container_of(wreq, struct cifs_io_request, rreq);
int ret; int ret;
ret = cifs_get_writable_file(CIFS_I(wreq->inode), FIND_WR_ANY, &req->cfile); ret = cifs_get_writable_file(CIFS_I(wreq->inode), FIND_ANY, &req->cfile);
if (ret) { if (ret) {
cifs_dbg(VFS, "No writable handle in writepages ret=%d\n", ret); cifs_dbg(VFS, "No writable handle in writepages ret=%d\n", ret);
return; return;
@@ -584,15 +584,8 @@ static int cifs_nt_open(const char *full_path, struct inode *inode, struct cifs_
*********************************************************************/ *********************************************************************/
disposition = cifs_get_disposition(f_flags); disposition = cifs_get_disposition(f_flags);
/* BB pass O_SYNC flag through on file attributes .. BB */ /* BB pass O_SYNC flag through on file attributes .. BB */
create_options |= cifs_open_create_options(f_flags, create_options);
/* O_SYNC also has bit for O_DSYNC so following check picks up either */
if (f_flags & O_SYNC)
create_options |= CREATE_WRITE_THROUGH;
if (f_flags & O_DIRECT)
create_options |= CREATE_NO_BUFFER;
retry_open: retry_open:
oparms = (struct cifs_open_parms) { oparms = (struct cifs_open_parms) {
@@ -963,7 +956,7 @@ int cifs_file_flush(const unsigned int xid, struct inode *inode,
return tcon->ses->server->ops->flush(xid, tcon, return tcon->ses->server->ops->flush(xid, tcon,
&cfile->fid); &cfile->fid);
} }
rc = cifs_get_writable_file(CIFS_I(inode), FIND_WR_ANY, &cfile); rc = cifs_get_writable_file(CIFS_I(inode), FIND_ANY, &cfile);
if (!rc) { if (!rc) {
tcon = tlink_tcon(cfile->tlink); tcon = tlink_tcon(cfile->tlink);
rc = tcon->ses->server->ops->flush(xid, tcon, &cfile->fid); rc = tcon->ses->server->ops->flush(xid, tcon, &cfile->fid);
@@ -988,7 +981,7 @@ static int cifs_do_truncate(const unsigned int xid, struct dentry *dentry)
return -ERESTARTSYS; return -ERESTARTSYS;
mapping_set_error(inode->i_mapping, rc); mapping_set_error(inode->i_mapping, rc);
cfile = find_writable_file(cinode, FIND_WR_FSUID_ONLY); cfile = find_writable_file(cinode, FIND_FSUID_ONLY);
rc = cifs_file_flush(xid, inode, cfile); rc = cifs_file_flush(xid, inode, cfile);
if (!rc) { if (!rc) {
if (cfile) { if (cfile) {
@@ -1068,32 +1061,29 @@ int cifs_open(struct inode *inode, struct file *file)
/* Get the cached handle as SMB2 close is deferred */ /* Get the cached handle as SMB2 close is deferred */
if (OPEN_FMODE(file->f_flags) & FMODE_WRITE) { if (OPEN_FMODE(file->f_flags) & FMODE_WRITE) {
rc = cifs_get_writable_path(tcon, full_path, rc = __cifs_get_writable_file(CIFS_I(inode),
FIND_WR_FSUID_ONLY | FIND_FSUID_ONLY |
FIND_WR_NO_PENDING_DELETE, FIND_NO_PENDING_DELETE |
&cfile); FIND_OPEN_FLAGS,
file->f_flags, &cfile);
} else { } else {
rc = cifs_get_readable_path(tcon, full_path, &cfile); cfile = __find_readable_file(CIFS_I(inode),
FIND_NO_PENDING_DELETE |
FIND_OPEN_FLAGS,
file->f_flags);
rc = cfile ? 0 : -ENOENT;
} }
if (rc == 0) { if (rc == 0) {
unsigned int oflags = file->f_flags & ~(O_CREAT|O_EXCL|O_TRUNC); file->private_data = cfile;
unsigned int cflags = cfile->f_flags & ~(O_CREAT|O_EXCL|O_TRUNC); spin_lock(&CIFS_I(inode)->deferred_lock);
cifs_del_deferred_close(cfile);
if (cifs_convert_flags(oflags, 0) == cifs_convert_flags(cflags, 0) && spin_unlock(&CIFS_I(inode)->deferred_lock);
(oflags & (O_SYNC|O_DIRECT)) == (cflags & (O_SYNC|O_DIRECT))) { goto use_cache;
file->private_data = cfile;
spin_lock(&CIFS_I(inode)->deferred_lock);
cifs_del_deferred_close(cfile);
spin_unlock(&CIFS_I(inode)->deferred_lock);
goto use_cache;
}
_cifsFileInfo_put(cfile, true, false);
} else {
/* hard link on the defeered close file */
rc = cifs_get_hardlink_path(tcon, inode, file);
if (rc)
cifs_close_deferred_file(CIFS_I(inode));
} }
/* hard link on the deferred close file */
rc = cifs_get_hardlink_path(tcon, inode, file);
if (rc)
cifs_close_deferred_file(CIFS_I(inode));
if (server->oplocks) if (server->oplocks)
oplock = REQ_OPLOCK; oplock = REQ_OPLOCK;
@@ -1314,13 +1304,8 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
rdwr_for_fscache = 1; rdwr_for_fscache = 1;
desired_access = cifs_convert_flags(cfile->f_flags, rdwr_for_fscache); desired_access = cifs_convert_flags(cfile->f_flags, rdwr_for_fscache);
create_options |= cifs_open_create_options(cfile->f_flags,
/* O_SYNC also has bit for O_DSYNC so following check picks up either */ create_options);
if (cfile->f_flags & O_SYNC)
create_options |= CREATE_WRITE_THROUGH;
if (cfile->f_flags & O_DIRECT)
create_options |= CREATE_NO_BUFFER;
if (server->ops->get_lease_key) if (server->ops->get_lease_key)
server->ops->get_lease_key(inode, &cfile->fid); server->ops->get_lease_key(inode, &cfile->fid);
@@ -2524,10 +2509,33 @@ void cifs_write_subrequest_terminated(struct cifs_io_subrequest *wdata, ssize_t
netfs_write_subrequest_terminated(&wdata->subreq, result); netfs_write_subrequest_terminated(&wdata->subreq, result);
} }
struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, static bool open_flags_match(struct cifsInodeInfo *cinode,
bool fsuid_only) unsigned int oflags, unsigned int cflags)
{
struct inode *inode = &cinode->netfs.inode;
int crw = 0, orw = 0;
oflags &= ~(O_CREAT | O_EXCL | O_TRUNC);
cflags &= ~(O_CREAT | O_EXCL | O_TRUNC);
if (cifs_fscache_enabled(inode)) {
if (OPEN_FMODE(cflags) & FMODE_WRITE)
crw = 1;
if (OPEN_FMODE(oflags) & FMODE_WRITE)
orw = 1;
}
if (cifs_convert_flags(oflags, orw) != cifs_convert_flags(cflags, crw))
return false;
return (oflags & (O_SYNC | O_DIRECT)) == (cflags & (O_SYNC | O_DIRECT));
}
struct cifsFileInfo *__find_readable_file(struct cifsInodeInfo *cifs_inode,
unsigned int find_flags,
unsigned int open_flags)
{ {
struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode); struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode);
bool fsuid_only = find_flags & FIND_FSUID_ONLY;
struct cifsFileInfo *open_file = NULL; struct cifsFileInfo *open_file = NULL;
/* only filter by fsuid on multiuser mounts */ /* only filter by fsuid on multiuser mounts */
@@ -2541,6 +2549,13 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
if (fsuid_only && !uid_eq(open_file->uid, current_fsuid())) if (fsuid_only && !uid_eq(open_file->uid, current_fsuid()))
continue; continue;
if ((find_flags & FIND_NO_PENDING_DELETE) &&
open_file->status_file_deleted)
continue;
if ((find_flags & FIND_OPEN_FLAGS) &&
!open_flags_match(cifs_inode, open_flags,
open_file->f_flags))
continue;
if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) { if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) {
if ((!open_file->invalidHandle)) { if ((!open_file->invalidHandle)) {
/* found a good file */ /* found a good file */
@@ -2559,17 +2574,17 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
} }
/* Return -EBADF if no handle is found and general rc otherwise */ /* Return -EBADF if no handle is found and general rc otherwise */
int int __cifs_get_writable_file(struct cifsInodeInfo *cifs_inode,
cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, int flags, unsigned int find_flags, unsigned int open_flags,
struct cifsFileInfo **ret_file) struct cifsFileInfo **ret_file)
{ {
struct cifsFileInfo *open_file, *inv_file = NULL; struct cifsFileInfo *open_file, *inv_file = NULL;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
bool any_available = false; bool any_available = false;
int rc = -EBADF; int rc = -EBADF;
unsigned int refind = 0; unsigned int refind = 0;
bool fsuid_only = flags & FIND_WR_FSUID_ONLY; bool fsuid_only = find_flags & FIND_FSUID_ONLY;
bool with_delete = flags & FIND_WR_WITH_DELETE; bool with_delete = find_flags & FIND_WITH_DELETE;
*ret_file = NULL; *ret_file = NULL;
/* /*
@@ -2603,9 +2618,13 @@ refind_writable:
continue; continue;
if (with_delete && !(open_file->fid.access & DELETE)) if (with_delete && !(open_file->fid.access & DELETE))
continue; continue;
if ((flags & FIND_WR_NO_PENDING_DELETE) && if ((find_flags & FIND_NO_PENDING_DELETE) &&
open_file->status_file_deleted) open_file->status_file_deleted)
continue; continue;
if ((find_flags & FIND_OPEN_FLAGS) &&
!open_flags_match(cifs_inode, open_flags,
open_file->f_flags))
continue;
if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
if (!open_file->invalidHandle) { if (!open_file->invalidHandle) {
/* found a good writable file */ /* found a good writable file */
@@ -2722,17 +2741,7 @@ cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
cinode = CIFS_I(d_inode(cfile->dentry)); cinode = CIFS_I(d_inode(cfile->dentry));
spin_unlock(&tcon->open_file_lock); spin_unlock(&tcon->open_file_lock);
free_dentry_path(page); free_dentry_path(page);
*ret_file = find_readable_file(cinode, 0); *ret_file = find_readable_file(cinode, FIND_ANY);
if (*ret_file) {
spin_lock(&cinode->open_file_lock);
if ((*ret_file)->status_file_deleted) {
spin_unlock(&cinode->open_file_lock);
cifsFileInfo_put(*ret_file);
*ret_file = NULL;
} else {
spin_unlock(&cinode->open_file_lock);
}
}
return *ret_file ? 0 : -ENOENT; return *ret_file ? 0 : -ENOENT;
} }
@@ -2804,7 +2813,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
} }
if ((OPEN_FMODE(smbfile->f_flags) & FMODE_WRITE) == 0) { if ((OPEN_FMODE(smbfile->f_flags) & FMODE_WRITE) == 0) {
smbfile = find_writable_file(CIFS_I(inode), FIND_WR_ANY); smbfile = find_writable_file(CIFS_I(inode), FIND_ANY);
if (smbfile) { if (smbfile) {
rc = server->ops->flush(xid, tcon, &smbfile->fid); rc = server->ops->flush(xid, tcon, &smbfile->fid);
cifsFileInfo_put(smbfile); cifsFileInfo_put(smbfile);

View File

@@ -1997,7 +1997,7 @@ int smb3_init_fs_context(struct fs_context *fc)
ctx->backupuid_specified = false; /* no backup intent for a user */ ctx->backupuid_specified = false; /* no backup intent for a user */
ctx->backupgid_specified = false; /* no backup intent for a group */ ctx->backupgid_specified = false; /* no backup intent for a group */
ctx->retrans = 1; ctx->retrans = 0;
ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT; ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT;
ctx->symlink_type = CIFS_SYMLINK_TYPE_DEFAULT; ctx->symlink_type = CIFS_SYMLINK_TYPE_DEFAULT;
ctx->nonativesocket = 0; ctx->nonativesocket = 0;

View File

@@ -2997,7 +2997,7 @@ int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start,
} }
} }
cfile = find_readable_file(cifs_i, false); cfile = find_readable_file(cifs_i, FIND_ANY);
if (cfile == NULL) if (cfile == NULL)
return -EINVAL; return -EINVAL;
@@ -3050,7 +3050,7 @@ int cifs_file_set_size(const unsigned int xid, struct dentry *dentry,
size, false); size, false);
cifs_dbg(FYI, "%s: set_file_size: rc = %d\n", __func__, rc); cifs_dbg(FYI, "%s: set_file_size: rc = %d\n", __func__, rc);
} else { } else {
open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY); open_file = find_writable_file(cifsInode, FIND_FSUID_ONLY);
if (open_file) { if (open_file) {
tcon = tlink_tcon(open_file->tlink); tcon = tlink_tcon(open_file->tlink);
server = tcon->ses->server; server = tcon->ses->server;
@@ -3219,7 +3219,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
open_file->fid.netfid, open_file->fid.netfid,
open_file->pid); open_file->pid);
} else { } else {
open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY); open_file = find_writable_file(cifsInode, FIND_FSUID_ONLY);
if (open_file) { if (open_file) {
pTcon = tlink_tcon(open_file->tlink); pTcon = tlink_tcon(open_file->tlink);
rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args,

View File

@@ -960,7 +960,7 @@ smb_set_file_info(struct inode *inode, const char *full_path,
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
/* if the file is already open for write, just use that fileid */ /* if the file is already open for write, just use that fileid */
open_file = find_writable_file(cinode, FIND_WR_FSUID_ONLY); open_file = find_writable_file(cinode, FIND_FSUID_ONLY);
if (open_file) { if (open_file) {
fid.netfid = open_file->fid.netfid; fid.netfid = open_file->fid.netfid;

View File

@@ -1156,7 +1156,7 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name,
cifs_i = CIFS_I(inode); cifs_i = CIFS_I(inode);
dosattrs = cifs_i->cifsAttrs | ATTR_READONLY; dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
data.Attributes = cpu_to_le32(dosattrs); data.Attributes = cpu_to_le32(dosattrs);
cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile); cifs_get_writable_path(tcon, name, FIND_ANY, &cfile);
oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES, oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,
FILE_CREATE, CREATE_NOT_FILE, ACL_NO_MODE); FILE_CREATE, CREATE_NOT_FILE, ACL_NO_MODE);
tmprc = smb2_compound_op(xid, tcon, cifs_sb, name, tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
@@ -1336,14 +1336,13 @@ int smb2_rename_path(const unsigned int xid,
__u32 co = file_create_options(source_dentry); __u32 co = file_create_options(source_dentry);
drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb); drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile); cifs_get_writable_path(tcon, from_name, FIND_WITH_DELETE, &cfile);
int rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb, int rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
co, DELETE, SMB2_OP_RENAME, cfile, source_dentry); co, DELETE, SMB2_OP_RENAME, cfile, source_dentry);
if (rc == -EINVAL) { if (rc == -EINVAL) {
cifs_dbg(FYI, "invalid lease key, resending request without lease"); cifs_dbg(FYI, "invalid lease key, resending request without lease");
cifs_get_writable_path(tcon, from_name, cifs_get_writable_path(tcon, from_name, FIND_WITH_DELETE, &cfile);
FIND_WR_WITH_DELETE, &cfile);
rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb, rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
co, DELETE, SMB2_OP_RENAME, cfile, NULL); co, DELETE, SMB2_OP_RENAME, cfile, NULL);
} }
@@ -1377,7 +1376,7 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
in_iov.iov_base = &eof; in_iov.iov_base = &eof;
in_iov.iov_len = sizeof(eof); in_iov.iov_len = sizeof(eof);
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); cifs_get_writable_path(tcon, full_path, FIND_ANY, &cfile);
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_DATA, oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_DATA,
FILE_OPEN, 0, ACL_NO_MODE); FILE_OPEN, 0, ACL_NO_MODE);
@@ -1387,7 +1386,7 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
cfile, NULL, NULL, dentry); cfile, NULL, NULL, dentry);
if (rc == -EINVAL) { if (rc == -EINVAL) {
cifs_dbg(FYI, "invalid lease key, resending request without lease"); cifs_dbg(FYI, "invalid lease key, resending request without lease");
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); cifs_get_writable_path(tcon, full_path, FIND_ANY, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, rc = smb2_compound_op(xid, tcon, cifs_sb,
full_path, &oparms, &in_iov, full_path, &oparms, &in_iov,
&(int){SMB2_OP_SET_EOF}, 1, &(int){SMB2_OP_SET_EOF}, 1,
@@ -1417,7 +1416,7 @@ smb2_set_file_info(struct inode *inode, const char *full_path,
(buf->LastWriteTime == 0) && (buf->ChangeTime == 0)) { (buf->LastWriteTime == 0) && (buf->ChangeTime == 0)) {
if (buf->Attributes == 0) if (buf->Attributes == 0)
goto out; /* would be a no op, no sense sending this */ goto out; /* would be a no op, no sense sending this */
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); cifs_get_writable_path(tcon, full_path, FIND_ANY, &cfile);
} }
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_ATTRIBUTES, oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_ATTRIBUTES,
@@ -1476,7 +1475,7 @@ struct inode *smb2_create_reparse_inode(struct cifs_open_info_data *data,
if (tcon->posix_extensions) { if (tcon->posix_extensions) {
cmds[1] = SMB2_OP_POSIX_QUERY_INFO; cmds[1] = SMB2_OP_POSIX_QUERY_INFO;
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); cifs_get_writable_path(tcon, full_path, FIND_ANY, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL); in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
if (!rc) { if (!rc) {
@@ -1485,7 +1484,7 @@ struct inode *smb2_create_reparse_inode(struct cifs_open_info_data *data,
} }
} else { } else {
cmds[1] = SMB2_OP_QUERY_INFO; cmds[1] = SMB2_OP_QUERY_INFO;
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); cifs_get_writable_path(tcon, full_path, FIND_ANY, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL); in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
if (!rc) { if (!rc) {
@@ -1636,13 +1635,12 @@ int smb2_rename_pending_delete(const char *full_path,
iov[1].iov_base = utf16_path; iov[1].iov_base = utf16_path;
iov[1].iov_len = sizeof(*utf16_path) * UniStrlen((wchar_t *)utf16_path); iov[1].iov_len = sizeof(*utf16_path) * UniStrlen((wchar_t *)utf16_path);
cifs_get_writable_path(tcon, full_path, FIND_WR_WITH_DELETE, &cfile); cifs_get_writable_path(tcon, full_path, FIND_WITH_DELETE, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, iov, rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, iov,
cmds, num_cmds, cfile, NULL, NULL, dentry); cmds, num_cmds, cfile, NULL, NULL, dentry);
if (rc == -EINVAL) { if (rc == -EINVAL) {
cifs_dbg(FYI, "invalid lease key, resending request without lease\n"); cifs_dbg(FYI, "invalid lease key, resending request without lease\n");
cifs_get_writable_path(tcon, full_path, cifs_get_writable_path(tcon, full_path, FIND_WITH_DELETE, &cfile);
FIND_WR_WITH_DELETE, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, iov, rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, iov,
cmds, num_cmds, cfile, NULL, NULL, NULL); cmds, num_cmds, cfile, NULL, NULL, NULL);
} }

View File

@@ -109,6 +109,9 @@ int __init smb2_init_maperror(void)
} }
#if IS_ENABLED(CONFIG_SMB_KUNIT_TESTS) #if IS_ENABLED(CONFIG_SMB_KUNIT_TESTS)
#define EXPORT_SYMBOL_FOR_SMB_TEST(sym) \
EXPORT_SYMBOL_FOR_MODULES(sym, "smb2maperror_test")
/* Previous prototype for eliminating the build warning. */ /* Previous prototype for eliminating the build warning. */
const struct status_to_posix_error *smb2_get_err_map_test(__u32 smb2_status); const struct status_to_posix_error *smb2_get_err_map_test(__u32 smb2_status);
@@ -116,11 +119,11 @@ const struct status_to_posix_error *smb2_get_err_map_test(__u32 smb2_status)
{ {
return smb2_get_err_map(smb2_status); return smb2_get_err_map(smb2_status);
} }
EXPORT_SYMBOL_GPL(smb2_get_err_map_test); EXPORT_SYMBOL_FOR_SMB_TEST(smb2_get_err_map_test);
const struct status_to_posix_error *smb2_error_map_table_test = smb2_error_map_table; const struct status_to_posix_error *smb2_error_map_table_test = smb2_error_map_table;
EXPORT_SYMBOL_GPL(smb2_error_map_table_test); EXPORT_SYMBOL_FOR_SMB_TEST(smb2_error_map_table_test);
unsigned int smb2_error_map_num = ARRAY_SIZE(smb2_error_map_table); unsigned int smb2_error_map_num = ARRAY_SIZE(smb2_error_map_table);
EXPORT_SYMBOL_GPL(smb2_error_map_num); EXPORT_SYMBOL_FOR_SMB_TEST(smb2_error_map_num);
#endif #endif

View File

@@ -628,6 +628,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
struct smb_sockaddr_in6 *p6; struct smb_sockaddr_in6 *p6;
struct cifs_server_iface *info = NULL, *iface = NULL, *niface = NULL; struct cifs_server_iface *info = NULL, *iface = NULL, *niface = NULL;
struct cifs_server_iface tmp_iface; struct cifs_server_iface tmp_iface;
__be16 port;
ssize_t bytes_left; ssize_t bytes_left;
size_t next = 0; size_t next = 0;
int nb_iface = 0; int nb_iface = 0;
@@ -662,6 +663,15 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
goto out; goto out;
} }
spin_lock(&ses->server->srv_lock);
if (ses->server->dstaddr.ss_family == AF_INET)
port = ((struct sockaddr_in *)&ses->server->dstaddr)->sin_port;
else if (ses->server->dstaddr.ss_family == AF_INET6)
port = ((struct sockaddr_in6 *)&ses->server->dstaddr)->sin6_port;
else
port = cpu_to_be16(CIFS_PORT);
spin_unlock(&ses->server->srv_lock);
while (bytes_left >= (ssize_t)sizeof(*p)) { while (bytes_left >= (ssize_t)sizeof(*p)) {
memset(&tmp_iface, 0, sizeof(tmp_iface)); memset(&tmp_iface, 0, sizeof(tmp_iface));
/* default to 1Gbps when link speed is unset */ /* default to 1Gbps when link speed is unset */
@@ -682,7 +692,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
memcpy(&addr4->sin_addr, &p4->IPv4Address, 4); memcpy(&addr4->sin_addr, &p4->IPv4Address, 4);
/* [MS-SMB2] 2.2.32.5.1.1 Clients MUST ignore these */ /* [MS-SMB2] 2.2.32.5.1.1 Clients MUST ignore these */
addr4->sin_port = cpu_to_be16(CIFS_PORT); addr4->sin_port = port;
cifs_dbg(FYI, "%s: ipv4 %pI4\n", __func__, cifs_dbg(FYI, "%s: ipv4 %pI4\n", __func__,
&addr4->sin_addr); &addr4->sin_addr);
@@ -696,7 +706,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
/* [MS-SMB2] 2.2.32.5.1.2 Clients MUST ignore these */ /* [MS-SMB2] 2.2.32.5.1.2 Clients MUST ignore these */
addr6->sin6_flowinfo = 0; addr6->sin6_flowinfo = 0;
addr6->sin6_scope_id = 0; addr6->sin6_scope_id = 0;
addr6->sin6_port = cpu_to_be16(CIFS_PORT); addr6->sin6_port = port;
cifs_dbg(FYI, "%s: ipv6 %pI6\n", __func__, cifs_dbg(FYI, "%s: ipv6 %pI6\n", __func__,
&addr6->sin6_addr); &addr6->sin6_addr);
@@ -3352,7 +3362,7 @@ get_smb2_acl(struct cifs_sb_info *cifs_sb,
struct cifsFileInfo *open_file = NULL; struct cifsFileInfo *open_file = NULL;
if (inode && !(info & SACL_SECINFO)) if (inode && !(info & SACL_SECINFO))
open_file = find_readable_file(CIFS_I(inode), true); open_file = find_readable_file(CIFS_I(inode), FIND_FSUID_ONLY);
if (!open_file || (info & SACL_SECINFO)) if (!open_file || (info & SACL_SECINFO))
return get_smb2_acl_by_path(cifs_sb, path, pacllen, info); return get_smb2_acl_by_path(cifs_sb, path, pacllen, info);
@@ -3898,7 +3908,7 @@ static loff_t smb3_llseek(struct file *file, struct cifs_tcon *tcon, loff_t offs
* some servers (Windows2016) will not reflect recent writes in * some servers (Windows2016) will not reflect recent writes in
* QUERY_ALLOCATED_RANGES until SMB2_flush is called. * QUERY_ALLOCATED_RANGES until SMB2_flush is called.
*/ */
wrcfile = find_writable_file(cifsi, FIND_WR_ANY); wrcfile = find_writable_file(cifsi, FIND_ANY);
if (wrcfile) { if (wrcfile) {
filemap_write_and_wait(inode->i_mapping); filemap_write_and_wait(inode->i_mapping);
smb2_flush_file(xid, tcon, &wrcfile->fid); smb2_flush_file(xid, tcon, &wrcfile->fid);

View File

@@ -5307,7 +5307,10 @@ replay_again:
memset(&rqst, 0, sizeof(struct smb_rqst)); memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = iov; rqst.rq_iov = iov;
rqst.rq_nvec = n_vec + 1; /* iov[0] is the SMB header; move payload to rq_iter for encryption safety */
rqst.rq_nvec = 1;
iov_iter_kvec(&rqst.rq_iter, ITER_SOURCE, &iov[1], n_vec,
io_parms->length);
if (retries) { if (retries) {
/* Back-off before retry */ /* Back-off before retry */