Skip to content

Commit

Permalink
Merge tag 'v6.8-rc-part1-smb-client' of git://git.samba.org/sfrench/c…
Browse files Browse the repository at this point in the history
…ifs-2.6

Pull smb client fixes from Steve French:
 "Various smb client fixes, most related to better handling special file
  types:

   - Improve handling of special file types:
      - performance improvement (better compounding and better caching
        of readdir entries that are reparse points)
      - extend support for creating special files (sockets, fifos,
        block/char devices)
      - fix renaming and hardlinking of reparse points
      - extend support for creating symlinks with IO_REPARSE_TAG_SYMLINK

   - Multichannel logging improvement

   - Exception handling fix

   - Minor cleanups"

* tag 'v6.8-rc-part1-smb-client' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: update internal module version number for cifs.ko
  cifs: remove unneeded return statement
  cifs: make cifs_chan_update_iface() a void function
  cifs: delete unnecessary NULL checks in cifs_chan_update_iface()
  cifs: get rid of dup length check in parse_reparse_point()
  smb: client: stop revalidating reparse points unnecessarily
  cifs: Pass unbyteswapped eof value into SMB2_set_eof()
  smb3: Improve exception handling in allocate_mr_list()
  cifs: fix in logging in cifs_chan_update_iface
  smb: client: handle special files and symlinks in SMB3 POSIX
  smb: client: cleanup smb2_query_reparse_point()
  smb: client: allow creating symlinks via reparse points
  smb: client: fix hardlinking of reparse points
  smb: client: fix renaming of reparse points
  smb: client: optimise reparse point querying
  smb: client: allow creating special files via reparse points
  smb: client: extend smb2_compound_op() to accept more commands
  smb: client: Fix minor whitespace errors and warnings
  • Loading branch information
Linus Torvalds committed Jan 11, 2024
2 parents 587217f + 26ba1bf commit 84e9a2d
Show file tree
Hide file tree
Showing 18 changed files with 1,131 additions and 829 deletions.
4 changes: 2 additions & 2 deletions fs/smb/client/cifsfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,6 @@ extern const struct export_operations cifs_export_ops;
#endif /* CONFIG_CIFS_NFSD_EXPORT */

/* when changing internal version - update following two lines at same time */
#define SMB3_PRODUCT_BUILD 46
#define CIFS_VERSION "2.46"
#define SMB3_PRODUCT_BUILD 47
#define CIFS_VERSION "2.47"
#endif /* _CIFSFS_H */
47 changes: 34 additions & 13 deletions fs/smb/client/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@ struct cifs_open_info_data {
bool symlink;
};
struct {
/* ioctl response buffer */
struct {
int buftype;
struct kvec iov;
} io;
__u32 tag;
union {
struct reparse_data_buffer *buf;
Expand All @@ -205,13 +210,17 @@ struct cifs_open_info_data {
};
};

#define cifs_open_data_reparse(d) \
((d)->reparse_point || \
(le32_to_cpu((d)->fi.Attributes) & ATTR_REPARSE))

static inline void cifs_free_open_info(struct cifs_open_info_data *data)
static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data)
{
kfree(data->symlink_target);
struct smb2_file_all_info *fi = &data->fi;
u32 attrs = le32_to_cpu(fi->Attributes);
bool ret;

ret = data->reparse_point || (attrs & ATTR_REPARSE);
if (ret)
attrs |= ATTR_REPARSE;
fi->Attributes = cpu_to_le32(attrs);
return ret;
}

/*
Expand Down Expand Up @@ -390,12 +399,17 @@ struct smb_version_operations {
int (*rename_pending_delete)(const char *, struct dentry *,
const unsigned int);
/* send rename request */
int (*rename)(const unsigned int, struct cifs_tcon *, const char *,
const char *, struct cifs_sb_info *);
int (*rename)(const unsigned int xid,
struct cifs_tcon *tcon,
struct dentry *source_dentry,
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb);
/* send create hardlink request */
int (*create_hardlink)(const unsigned int, struct cifs_tcon *,
const char *, const char *,
struct cifs_sb_info *);
int (*create_hardlink)(const unsigned int xid,
struct cifs_tcon *tcon,
struct dentry *source_dentry,
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb);
/* query symlink target */
int (*query_symlink)(const unsigned int xid,
struct cifs_tcon *tcon,
Expand Down Expand Up @@ -560,6 +574,12 @@ struct smb_version_operations {
int (*parse_reparse_point)(struct cifs_sb_info *cifs_sb,
struct kvec *rsp_iov,
struct cifs_open_info_data *data);
int (*create_reparse_symlink)(const unsigned int xid,
struct inode *inode,
struct dentry *dentry,
struct cifs_tcon *tcon,
const char *full_path,
const char *symname);
};

struct smb_version_values {
Expand Down Expand Up @@ -1545,6 +1565,7 @@ struct cifsInodeInfo {
spinlock_t deferred_lock; /* protection on deferred list */
bool lease_granted; /* Flag to indicate whether lease or oplock is granted. */
char *symlink_target;
__u32 reparse_tag;
};

static inline struct cifsInodeInfo *
Expand Down Expand Up @@ -2238,8 +2259,8 @@ static inline void cifs_sg_set_buf(struct sg_table *sgtable,

struct smb2_compound_vars {
struct cifs_open_parms oparms;
struct kvec rsp_iov[3];
struct smb_rqst rqst[3];
struct kvec rsp_iov[MAX_COMPOUND];
struct smb_rqst rqst[MAX_COMPOUND];
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
struct kvec qi_iov;
struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
Expand Down
32 changes: 23 additions & 9 deletions fs/smb/client/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,12 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
struct cifs_fattr *fattr,
struct cifs_open_info_data *data);
extern int smb311_posix_get_inode_info(struct inode **pinode, const char *search_path,
struct super_block *sb, unsigned int xid);

extern int smb311_posix_get_inode_info(struct inode **inode,
const char *full_path,
struct cifs_open_info_data *data,
struct super_block *sb,
const unsigned int xid);
extern int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path,
struct super_block *sb, unsigned int xid);
Expand Down Expand Up @@ -435,16 +439,19 @@ extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
int remap_special_chars);
extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb);
extern int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb);
int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
struct dentry *source_dentry,
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb);
extern int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *tcon,
int netfid, const char *target_name,
const struct nls_table *nls_codepage,
int remap_special_chars);
extern int CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb);
int CIFSCreateHardLink(const unsigned int xid,
struct cifs_tcon *tcon,
struct dentry *source_dentry,
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb);
extern int CIFSUnixCreateHardLink(const unsigned int xid,
struct cifs_tcon *tcon,
const char *fromName, const char *toName,
Expand Down Expand Up @@ -649,7 +656,7 @@ cifs_chan_is_iface_active(struct cifs_ses *ses,
struct TCP_Server_Info *server);
void
cifs_disable_secondary_channels(struct cifs_ses *ses);
int
void
cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server);
int
SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon, bool in_mount);
Expand Down Expand Up @@ -760,4 +767,11 @@ static inline void release_mid(struct mid_q_entry *mid)
kref_put(&mid->refcount, __release_mid);
}

static inline void cifs_free_open_info(struct cifs_open_info_data *data)
{
kfree(data->symlink_target);
free_rsp_buf(data->reparse.io.buftype, data->reparse.io.iov.iov_base);
memset(data, 0, sizeof(*data));
}

#endif /* _CIFSPROTO_H */
31 changes: 21 additions & 10 deletions fs/smb/client/cifssmb.c
Original file line number Diff line number Diff line change
Expand Up @@ -2149,10 +2149,10 @@ CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
return rc;
}

int
CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb)
int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
struct dentry *source_dentry,
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb)
{
int rc = 0;
RENAME_REQ *pSMB = NULL;
Expand Down Expand Up @@ -2530,10 +2530,11 @@ CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
return rc;
}

int
CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb)
int CIFSCreateHardLink(const unsigned int xid,
struct cifs_tcon *tcon,
struct dentry *source_dentry,
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb)
{
int rc = 0;
NT_RENAME_REQ *pSMB = NULL;
Expand Down Expand Up @@ -2699,11 +2700,12 @@ int cifs_query_reparse_point(const unsigned int xid,
u32 *tag, struct kvec *rsp,
int *rsp_buftype)
{
struct reparse_data_buffer *buf;
struct cifs_open_parms oparms;
TRANSACT_IOCTL_REQ *io_req = NULL;
TRANSACT_IOCTL_RSP *io_rsp = NULL;
struct cifs_fid fid;
__u32 data_offset, data_count;
__u32 data_offset, data_count, len;
__u8 *start, *end;
int io_rsp_len;
int oplock = 0;
Expand Down Expand Up @@ -2773,7 +2775,16 @@ int cifs_query_reparse_point(const unsigned int xid,
goto error;
}

*tag = le32_to_cpu(((struct reparse_data_buffer *)start)->ReparseTag);
data_count = le16_to_cpu(io_rsp->ByteCount);
buf = (struct reparse_data_buffer *)start;
len = sizeof(*buf);
if (data_count < len ||
data_count < le16_to_cpu(buf->ReparseDataLength) + len) {
rc = -EIO;
goto error;
}

*tag = le32_to_cpu(buf->ReparseTag);
rsp->iov_base = io_rsp;
rsp->iov_len = io_rsp_len;
*rsp_buftype = CIFS_LARGE_BUFFER;
Expand Down
25 changes: 17 additions & 8 deletions fs/smb/client/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,7 @@ static int reconnect_target_unlocked(struct TCP_Server_Info *server, struct dfs_
static int reconnect_dfs_server(struct TCP_Server_Info *server)
{
struct dfs_cache_tgt_iterator *target_hint = NULL;

DFS_CACHE_TGT_LIST(tl);
int num_targets = 0;
int rc = 0;
Expand Down Expand Up @@ -745,6 +746,7 @@ cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
{
struct msghdr smb_msg = {};
struct kvec iov = {.iov_base = buf, .iov_len = to_read};

iov_iter_kvec(&smb_msg.msg_iter, ITER_DEST, &iov, 1, to_read);

return cifs_readv_from_socket(server, &smb_msg);
Expand Down Expand Up @@ -1400,11 +1402,13 @@ cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs)
case AF_INET: {
struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr;
struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs;

return (saddr4->sin_addr.s_addr == vaddr4->sin_addr.s_addr);
}
case AF_INET6: {
struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr;
struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)rhs;

return (ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr)
&& saddr6->sin6_scope_id == vaddr6->sin6_scope_id);
}
Expand Down Expand Up @@ -2599,8 +2603,8 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
rc = -EOPNOTSUPP;
goto out_fail;
} else {
cifs_dbg(VFS, "Check vers= mount option. SMB3.11 "
"disabled but required for POSIX extensions\n");
cifs_dbg(VFS,
"Check vers= mount option. SMB3.11 disabled but required for POSIX extensions\n");
rc = -EOPNOTSUPP;
goto out_fail;
}
Expand Down Expand Up @@ -2743,7 +2747,6 @@ cifs_put_tlink(struct tcon_link *tlink)
if (!IS_ERR(tlink_tcon(tlink)))
cifs_put_tcon(tlink_tcon(tlink));
kfree(tlink);
return;
}

static int
Expand Down Expand Up @@ -2884,6 +2887,7 @@ static inline void
cifs_reclassify_socket4(struct socket *sock)
{
struct sock *sk = sock->sk;

BUG_ON(!sock_allow_reclassification(sk));
sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
&cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
Expand All @@ -2893,6 +2897,7 @@ static inline void
cifs_reclassify_socket6(struct socket *sock)
{
struct sock *sk = sock->sk;

BUG_ON(!sock_allow_reclassification(sk));
sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
&cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
Expand Down Expand Up @@ -2927,15 +2932,18 @@ static int
bind_socket(struct TCP_Server_Info *server)
{
int rc = 0;

if (server->srcaddr.ss_family != AF_UNSPEC) {
/* Bind to the specified local IP address */
struct socket *socket = server->ssocket;

rc = kernel_bind(socket,
(struct sockaddr *) &server->srcaddr,
sizeof(server->srcaddr));
if (rc < 0) {
struct sockaddr_in *saddr4;
struct sockaddr_in6 *saddr6;

saddr4 = (struct sockaddr_in *)&server->srcaddr;
saddr6 = (struct sockaddr_in6 *)&server->srcaddr;
if (saddr6->sin6_family == AF_INET6)
Expand Down Expand Up @@ -3165,6 +3173,7 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,

if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
__u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);

cifs_dbg(FYI, "unix caps which server supports %lld\n", cap);
/*
* check for reconnect case in which we do not
Expand Down Expand Up @@ -3668,7 +3677,7 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
smb_buffer_response = smb_buffer;

header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
NULL /*no tid */ , 4 /*wct */ );
NULL /*no tid */, 4 /*wct */);

smb_buffer->Mid = get_next_mid(ses->server);
smb_buffer->Uid = ses->Suid;
Expand All @@ -3687,12 +3696,12 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
if (ses->server->sign)
smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;

if (ses->capabilities & CAP_STATUS32) {
if (ses->capabilities & CAP_STATUS32)
smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
}
if (ses->capabilities & CAP_DFS) {

if (ses->capabilities & CAP_DFS)
smb_buffer->Flags2 |= SMBFLG2_DFS;
}

if (ses->capabilities & CAP_UNICODE) {
smb_buffer->Flags2 |= SMBFLG2_UNICODE;
length =
Expand Down
7 changes: 4 additions & 3 deletions fs/smb/client/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -680,9 +680,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
full_path, d_inode(direntry));

again:
if (pTcon->posix_extensions)
rc = smb311_posix_get_inode_info(&newInode, full_path, parent_dir_inode->i_sb, xid);
else if (pTcon->unix_ext) {
if (pTcon->posix_extensions) {
rc = smb311_posix_get_inode_info(&newInode, full_path, NULL,
parent_dir_inode->i_sb, xid);
} else if (pTcon->unix_ext) {
rc = cifs_get_inode_info_unix(&newInode, full_path,
parent_dir_inode->i_sb, xid);
} else {
Expand Down
10 changes: 6 additions & 4 deletions fs/smb/client/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -1020,14 +1020,16 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
if (!is_interrupt_error(rc))
mapping_set_error(inode->i_mapping, rc);

if (tcon->posix_extensions)
rc = smb311_posix_get_inode_info(&inode, full_path, inode->i_sb, xid);
else if (tcon->unix_ext)
if (tcon->posix_extensions) {
rc = smb311_posix_get_inode_info(&inode, full_path,
NULL, inode->i_sb, xid);
} else if (tcon->unix_ext) {
rc = cifs_get_inode_info_unix(&inode, full_path,
inode->i_sb, xid);
else
} else {
rc = cifs_get_inode_info(&inode, full_path, NULL,
inode->i_sb, xid, NULL);
}
}
/*
* Else we are writing out data to server already and could deadlock if
Expand Down
Loading

0 comments on commit 84e9a2d

Please sign in to comment.