Commit 84e9a2d5 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'v6.8-rc-part1-smb-client' of git://git.samba.org/sfrench/cifs-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
parents 587217f9 26ba1bf3
...@@ -152,6 +152,6 @@ extern const struct export_operations cifs_export_ops; ...@@ -152,6 +152,6 @@ extern const struct export_operations cifs_export_ops;
#endif /* CONFIG_CIFS_NFSD_EXPORT */ #endif /* CONFIG_CIFS_NFSD_EXPORT */
/* when changing internal version - update following two lines at same time */ /* when changing internal version - update following two lines at same time */
#define SMB3_PRODUCT_BUILD 46 #define SMB3_PRODUCT_BUILD 47
#define CIFS_VERSION "2.46" #define CIFS_VERSION "2.47"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */
...@@ -192,6 +192,11 @@ struct cifs_open_info_data { ...@@ -192,6 +192,11 @@ struct cifs_open_info_data {
bool symlink; bool symlink;
}; };
struct { struct {
/* ioctl response buffer */
struct {
int buftype;
struct kvec iov;
} io;
__u32 tag; __u32 tag;
union { union {
struct reparse_data_buffer *buf; struct reparse_data_buffer *buf;
...@@ -205,13 +210,17 @@ struct cifs_open_info_data { ...@@ -205,13 +210,17 @@ struct cifs_open_info_data {
}; };
}; };
#define cifs_open_data_reparse(d) \ static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data)
((d)->reparse_point || \
(le32_to_cpu((d)->fi.Attributes) & ATTR_REPARSE))
static inline void cifs_free_open_info(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;
} }
/* /*
...@@ -390,12 +399,17 @@ struct smb_version_operations { ...@@ -390,12 +399,17 @@ struct smb_version_operations {
int (*rename_pending_delete)(const char *, struct dentry *, int (*rename_pending_delete)(const char *, struct dentry *,
const unsigned int); const unsigned int);
/* send rename request */ /* send rename request */
int (*rename)(const unsigned int, struct cifs_tcon *, const char *, int (*rename)(const unsigned int xid,
const char *, struct cifs_sb_info *); 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 */ /* send create hardlink request */
int (*create_hardlink)(const unsigned int, struct cifs_tcon *, int (*create_hardlink)(const unsigned int xid,
const char *, const char *, struct cifs_tcon *tcon,
struct cifs_sb_info *); struct dentry *source_dentry,
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb);
/* query symlink target */ /* query symlink target */
int (*query_symlink)(const unsigned int xid, int (*query_symlink)(const unsigned int xid,
struct cifs_tcon *tcon, struct cifs_tcon *tcon,
...@@ -560,6 +574,12 @@ struct smb_version_operations { ...@@ -560,6 +574,12 @@ struct smb_version_operations {
int (*parse_reparse_point)(struct cifs_sb_info *cifs_sb, int (*parse_reparse_point)(struct cifs_sb_info *cifs_sb,
struct kvec *rsp_iov, struct kvec *rsp_iov,
struct cifs_open_info_data *data); 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 { struct smb_version_values {
...@@ -1545,6 +1565,7 @@ struct cifsInodeInfo { ...@@ -1545,6 +1565,7 @@ struct cifsInodeInfo {
spinlock_t deferred_lock; /* protection on deferred list */ spinlock_t deferred_lock; /* protection on deferred list */
bool lease_granted; /* Flag to indicate whether lease or oplock is granted. */ bool lease_granted; /* Flag to indicate whether lease or oplock is granted. */
char *symlink_target; char *symlink_target;
__u32 reparse_tag;
}; };
static inline struct cifsInodeInfo * static inline struct cifsInodeInfo *
...@@ -2238,8 +2259,8 @@ static inline void cifs_sg_set_buf(struct sg_table *sgtable, ...@@ -2238,8 +2259,8 @@ static inline void cifs_sg_set_buf(struct sg_table *sgtable,
struct smb2_compound_vars { struct smb2_compound_vars {
struct cifs_open_parms oparms; struct cifs_open_parms oparms;
struct kvec rsp_iov[3]; struct kvec rsp_iov[MAX_COMPOUND];
struct smb_rqst rqst[3]; struct smb_rqst rqst[MAX_COMPOUND];
struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
struct kvec qi_iov; struct kvec qi_iov;
struct kvec io_iov[SMB2_IOCTL_IOV_SIZE]; struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
......
...@@ -211,8 +211,12 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path, ...@@ -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, bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
struct cifs_fattr *fattr, struct cifs_fattr *fattr,
struct cifs_open_info_data *data); 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, extern int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path, const unsigned char *search_path,
struct super_block *sb, unsigned int xid); struct super_block *sb, unsigned int xid);
...@@ -435,16 +439,19 @@ extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -435,16 +439,19 @@ extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
int remap_special_chars); int remap_special_chars);
extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb); const char *name, struct cifs_sb_info *cifs_sb);
extern int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon, int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
const char *from_name, const char *to_name, struct dentry *source_dentry,
struct cifs_sb_info *cifs_sb); 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, extern int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *tcon,
int netfid, const char *target_name, int netfid, const char *target_name,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,
int remap_special_chars); int remap_special_chars);
extern int CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon, int CIFSCreateHardLink(const unsigned int xid,
const char *from_name, const char *to_name, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb); 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, extern int CIFSUnixCreateHardLink(const unsigned int xid,
struct cifs_tcon *tcon, struct cifs_tcon *tcon,
const char *fromName, const char *toName, const char *fromName, const char *toName,
...@@ -649,7 +656,7 @@ cifs_chan_is_iface_active(struct cifs_ses *ses, ...@@ -649,7 +656,7 @@ cifs_chan_is_iface_active(struct cifs_ses *ses,
struct TCP_Server_Info *server); struct TCP_Server_Info *server);
void void
cifs_disable_secondary_channels(struct cifs_ses *ses); cifs_disable_secondary_channels(struct cifs_ses *ses);
int void
cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server); cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server);
int int
SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon, bool in_mount); SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon, bool in_mount);
...@@ -760,4 +767,11 @@ static inline void release_mid(struct mid_q_entry *mid) ...@@ -760,4 +767,11 @@ static inline void release_mid(struct mid_q_entry *mid)
kref_put(&mid->refcount, __release_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 */ #endif /* _CIFSPROTO_H */
...@@ -2149,10 +2149,10 @@ CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id) ...@@ -2149,10 +2149,10 @@ CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
return rc; return rc;
} }
int int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon, struct dentry *source_dentry,
const char *from_name, const char *to_name, const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb) struct cifs_sb_info *cifs_sb)
{ {
int rc = 0; int rc = 0;
RENAME_REQ *pSMB = NULL; RENAME_REQ *pSMB = NULL;
...@@ -2530,10 +2530,11 @@ CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2530,10 +2530,11 @@ CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
return rc; return rc;
} }
int int CIFSCreateHardLink(const unsigned int xid,
CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_tcon *tcon,
const char *from_name, const char *to_name, struct dentry *source_dentry,
struct cifs_sb_info *cifs_sb) const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb)
{ {
int rc = 0; int rc = 0;
NT_RENAME_REQ *pSMB = NULL; NT_RENAME_REQ *pSMB = NULL;
...@@ -2699,11 +2700,12 @@ int cifs_query_reparse_point(const unsigned int xid, ...@@ -2699,11 +2700,12 @@ int cifs_query_reparse_point(const unsigned int xid,
u32 *tag, struct kvec *rsp, u32 *tag, struct kvec *rsp,
int *rsp_buftype) int *rsp_buftype)
{ {
struct reparse_data_buffer *buf;
struct cifs_open_parms oparms; struct cifs_open_parms oparms;
TRANSACT_IOCTL_REQ *io_req = NULL; TRANSACT_IOCTL_REQ *io_req = NULL;
TRANSACT_IOCTL_RSP *io_rsp = NULL; TRANSACT_IOCTL_RSP *io_rsp = NULL;
struct cifs_fid fid; struct cifs_fid fid;
__u32 data_offset, data_count; __u32 data_offset, data_count, len;
__u8 *start, *end; __u8 *start, *end;
int io_rsp_len; int io_rsp_len;
int oplock = 0; int oplock = 0;
...@@ -2773,7 +2775,16 @@ int cifs_query_reparse_point(const unsigned int xid, ...@@ -2773,7 +2775,16 @@ int cifs_query_reparse_point(const unsigned int xid,
goto error; 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_base = io_rsp;
rsp->iov_len = io_rsp_len; rsp->iov_len = io_rsp_len;
*rsp_buftype = CIFS_LARGE_BUFFER; *rsp_buftype = CIFS_LARGE_BUFFER;
......
...@@ -483,6 +483,7 @@ static int reconnect_target_unlocked(struct TCP_Server_Info *server, struct dfs_ ...@@ -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) static int reconnect_dfs_server(struct TCP_Server_Info *server)
{ {
struct dfs_cache_tgt_iterator *target_hint = NULL; struct dfs_cache_tgt_iterator *target_hint = NULL;
DFS_CACHE_TGT_LIST(tl); DFS_CACHE_TGT_LIST(tl);
int num_targets = 0; int num_targets = 0;
int rc = 0; int rc = 0;
...@@ -745,6 +746,7 @@ cifs_read_from_socket(struct TCP_Server_Info *server, char *buf, ...@@ -745,6 +746,7 @@ cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
{ {
struct msghdr smb_msg = {}; struct msghdr smb_msg = {};
struct kvec iov = {.iov_base = buf, .iov_len = to_read}; struct kvec iov = {.iov_base = buf, .iov_len = to_read};
iov_iter_kvec(&smb_msg.msg_iter, ITER_DEST, &iov, 1, to_read); iov_iter_kvec(&smb_msg.msg_iter, ITER_DEST, &iov, 1, to_read);
return cifs_readv_from_socket(server, &smb_msg); return cifs_readv_from_socket(server, &smb_msg);
...@@ -1400,11 +1402,13 @@ cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs) ...@@ -1400,11 +1402,13 @@ cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs)
case AF_INET: { case AF_INET: {
struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr; struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr;
struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs; struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs;
return (saddr4->sin_addr.s_addr == vaddr4->sin_addr.s_addr); return (saddr4->sin_addr.s_addr == vaddr4->sin_addr.s_addr);
} }
case AF_INET6: { case AF_INET6: {
struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr; struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr;
struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)rhs; struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)rhs;
return (ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr) return (ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr)
&& saddr6->sin6_scope_id == vaddr6->sin6_scope_id); && saddr6->sin6_scope_id == vaddr6->sin6_scope_id);
} }
...@@ -2599,8 +2603,8 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx) ...@@ -2599,8 +2603,8 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
goto out_fail; goto out_fail;
} else { } else {
cifs_dbg(VFS, "Check vers= mount option. SMB3.11 " cifs_dbg(VFS,
"disabled but required for POSIX extensions\n"); "Check vers= mount option. SMB3.11 disabled but required for POSIX extensions\n");
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
goto out_fail; goto out_fail;
} }
...@@ -2743,7 +2747,6 @@ cifs_put_tlink(struct tcon_link *tlink) ...@@ -2743,7 +2747,6 @@ cifs_put_tlink(struct tcon_link *tlink)
if (!IS_ERR(tlink_tcon(tlink))) if (!IS_ERR(tlink_tcon(tlink)))
cifs_put_tcon(tlink_tcon(tlink)); cifs_put_tcon(tlink_tcon(tlink));
kfree(tlink); kfree(tlink);
return;
} }
static int static int
...@@ -2884,6 +2887,7 @@ static inline void ...@@ -2884,6 +2887,7 @@ static inline void
cifs_reclassify_socket4(struct socket *sock) cifs_reclassify_socket4(struct socket *sock)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
BUG_ON(!sock_allow_reclassification(sk)); BUG_ON(!sock_allow_reclassification(sk));
sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS", sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
&cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]); &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
...@@ -2893,6 +2897,7 @@ static inline void ...@@ -2893,6 +2897,7 @@ static inline void
cifs_reclassify_socket6(struct socket *sock) cifs_reclassify_socket6(struct socket *sock)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
BUG_ON(!sock_allow_reclassification(sk)); BUG_ON(!sock_allow_reclassification(sk));
sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS", sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
&cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]); &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
...@@ -2927,15 +2932,18 @@ static int ...@@ -2927,15 +2932,18 @@ static int
bind_socket(struct TCP_Server_Info *server) bind_socket(struct TCP_Server_Info *server)
{ {
int rc = 0; int rc = 0;
if (server->srcaddr.ss_family != AF_UNSPEC) { if (server->srcaddr.ss_family != AF_UNSPEC) {
/* Bind to the specified local IP address */ /* Bind to the specified local IP address */
struct socket *socket = server->ssocket; struct socket *socket = server->ssocket;
rc = kernel_bind(socket, rc = kernel_bind(socket,
(struct sockaddr *) &server->srcaddr, (struct sockaddr *) &server->srcaddr,
sizeof(server->srcaddr)); sizeof(server->srcaddr));
if (rc < 0) { if (rc < 0) {
struct sockaddr_in *saddr4; struct sockaddr_in *saddr4;
struct sockaddr_in6 *saddr6; struct sockaddr_in6 *saddr6;
saddr4 = (struct sockaddr_in *)&server->srcaddr; saddr4 = (struct sockaddr_in *)&server->srcaddr;
saddr6 = (struct sockaddr_in6 *)&server->srcaddr; saddr6 = (struct sockaddr_in6 *)&server->srcaddr;
if (saddr6->sin6_family == AF_INET6) if (saddr6->sin6_family == AF_INET6)
...@@ -3165,6 +3173,7 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, ...@@ -3165,6 +3173,7 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
if (!CIFSSMBQFSUnixInfo(xid, tcon)) { if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
__u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability); __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
cifs_dbg(FYI, "unix caps which server supports %lld\n", cap); cifs_dbg(FYI, "unix caps which server supports %lld\n", cap);
/* /*
* check for reconnect case in which we do not * check for reconnect case in which we do not
...@@ -3668,7 +3677,7 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses, ...@@ -3668,7 +3677,7 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
smb_buffer_response = smb_buffer; smb_buffer_response = smb_buffer;
header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, 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->Mid = get_next_mid(ses->server);
smb_buffer->Uid = ses->Suid; smb_buffer->Uid = ses->Suid;
...@@ -3687,12 +3696,12 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses, ...@@ -3687,12 +3696,12 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
if (ses->server->sign) if (ses->server->sign)
smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
if (ses->capabilities & CAP_STATUS32) { if (ses->capabilities & CAP_STATUS32)
smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
}
if (ses->capabilities & CAP_DFS) { if (ses->capabilities & CAP_DFS)
smb_buffer->Flags2 |= SMBFLG2_DFS; smb_buffer->Flags2 |= SMBFLG2_DFS;
}
if (ses->capabilities & CAP_UNICODE) { if (ses->capabilities & CAP_UNICODE) {
smb_buffer->Flags2 |= SMBFLG2_UNICODE; smb_buffer->Flags2 |= SMBFLG2_UNICODE;
length = length =
......
...@@ -680,9 +680,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, ...@@ -680,9 +680,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
full_path, d_inode(direntry)); full_path, d_inode(direntry));
again: again:
if (pTcon->posix_extensions) if (pTcon->posix_extensions) {
rc = smb311_posix_get_inode_info(&newInode, full_path, parent_dir_inode->i_sb, xid); rc = smb311_posix_get_inode_info(&newInode, full_path, NULL,
else if (pTcon->unix_ext) { parent_dir_inode->i_sb, xid);
} else if (pTcon->unix_ext) {
rc = cifs_get_inode_info_unix(&newInode, full_path, rc = cifs_get_inode_info_unix(&newInode, full_path,
parent_dir_inode->i_sb, xid); parent_dir_inode->i_sb, xid);
} else { } else {
......
...@@ -1020,14 +1020,16 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush) ...@@ -1020,14 +1020,16 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
if (!is_interrupt_error(rc)) if (!is_interrupt_error(rc))
mapping_set_error(inode->i_mapping, rc); mapping_set_error(inode->i_mapping, rc);
if (tcon->posix_extensions) if (tcon->posix_extensions) {
rc = smb311_posix_get_inode_info(&inode, full_path, inode->i_sb, xid); rc = smb311_posix_get_inode_info(&inode, full_path,
else if (tcon->unix_ext) NULL, inode->i_sb, xid);
} else if (tcon->unix_ext) {
rc = cifs_get_inode_info_unix(&inode, full_path, rc = cifs_get_inode_info_unix(&inode, full_path,
inode->i_sb, xid); inode->i_sb, xid);
else } else {
rc = cifs_get_inode_info(&inode, full_path, NULL, rc = cifs_get_inode_info(&inode, full_path, NULL,
inode->i_sb, xid, NULL); inode->i_sb, xid, NULL);
}
} }
/* /*
* Else we are writing out data to server already and could deadlock if * Else we are writing out data to server already and could deadlock if
......
This diff is collapsed.
...@@ -510,8 +510,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, ...@@ -510,8 +510,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
rc = -ENOSYS; rc = -ENOSYS;
goto cifs_hl_exit; goto cifs_hl_exit;
} }
rc = server->ops->create_hardlink(xid, tcon, from_name, to_name, rc = server->ops->create_hardlink(xid, tcon, old_file,
cifs_sb); from_name, to_name, cifs_sb);
if ((rc == -EIO) || (rc == -EINVAL)) if ((rc == -EIO) || (rc == -EINVAL))
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
} }
...@@ -569,6 +569,7 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode, ...@@ -569,6 +569,7 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
int rc = -EOPNOTSUPP; int rc = -EOPNOTSUPP;
unsigned int xid; unsigned int xid;
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct TCP_Server_Info *server;
struct tcon_link *tlink; struct tcon_link *tlink;
struct cifs_tcon *pTcon; struct cifs_tcon *pTcon;
const char *full_path; const char *full_path;
...@@ -590,6 +591,7 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode, ...@@ -590,6 +591,7 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
goto symlink_exit; goto symlink_exit;
} }
pTcon = tlink_tcon(tlink); pTcon = tlink_tcon(tlink);
server = cifs_pick_channel(pTcon->ses);
full_path = build_path_from_dentry(direntry, page); full_path = build_path_from_dentry(direntry, page);
if (IS_ERR(full_path)) { if (IS_ERR(full_path)) {
...@@ -601,27 +603,32 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode, ...@@ -601,27 +603,32 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
cifs_dbg(FYI, "symname is %s\n", symname); cifs_dbg(FYI, "symname is %s\n", symname);
/* BB what if DFS and this volume is on different share? BB */ /* BB what if DFS and this volume is on different share? BB */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname); rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname);
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
else if (pTcon->unix_ext) } else if (pTcon->unix_ext) {
rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_remap(cifs_sb)); cifs_remap(cifs_sb));
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
/* else } else if (server->ops->create_reparse_symlink) {
rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName, rc = server->ops->create_reparse_symlink(xid, inode, direntry,
cifs_sb_target->local_nls); */ pTcon, full_path,
symname);
goto symlink_exit;
}
if (rc == 0) { if (rc == 0) {
if (pTcon->posix_extensions) if (pTcon->posix_extensions) {
rc = smb311_posix_get_inode_info(&newinode, full_path, inode->i_sb, xid); rc = smb311_posix_get_inode_info(&newinode, full_path,
else if (pTcon->unix_ext) NULL, inode->i_sb, xid);
} else if (pTcon->unix_ext) {
rc = cifs_get_inode_info_unix(&newinode, full_path, rc = cifs_get_inode_info_unix(&newinode, full_path,
inode->i_sb, xid); inode->i_sb, xid);
else } else {
rc = cifs_get_inode_info(&newinode, full_path, NULL, rc = cifs_get_inode_info(&newinode, full_path, NULL,
inode->i_sb, xid, NULL); inode->i_sb, xid, NULL);
}
if (rc != 0) { if (rc != 0) {
cifs_dbg(FYI, "Create symlink ok, getinodeinfo fail rc = %d\n", cifs_dbg(FYI, "Create symlink ok, getinodeinfo fail rc = %d\n",
......
...@@ -55,6 +55,23 @@ static inline void dump_cifs_file_struct(struct file *file, char *label) ...@@ -55,6 +55,23 @@ static inline void dump_cifs_file_struct(struct file *file, char *label)
} }
#endif /* DEBUG2 */ #endif /* DEBUG2 */
/*
* Match a reparse point inode if reparse tag and ctime haven't changed.
*
* Windows Server updates ctime of reparse points when their data have changed.
* The server doesn't allow changing reparse tags from existing reparse points,
* though it's worth checking.
*/
static inline bool reparse_inode_match(struct inode *inode,
struct cifs_fattr *fattr)
{
struct timespec64 ctime = inode_get_ctime(inode);
return (CIFS_I(inode)->cifsAttrs & ATTR_REPARSE) &&
CIFS_I(inode)->reparse_tag == fattr->cf_cifstag &&
timespec64_equal(&ctime, &fattr->cf_ctime);
}
/* /*
* Attempt to preload the dcache with the results from the FIND_FIRST/NEXT * Attempt to preload the dcache with the results from the FIND_FIRST/NEXT
* *
...@@ -71,6 +88,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, ...@@ -71,6 +88,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
struct super_block *sb = parent->d_sb; struct super_block *sb = parent->d_sb;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
int rc;
cifs_dbg(FYI, "%s: for %s\n", __func__, name->name); cifs_dbg(FYI, "%s: for %s\n", __func__, name->name);
...@@ -82,9 +100,11 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, ...@@ -82,9 +100,11 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
* We'll end up doing an on the wire call either way and * We'll end up doing an on the wire call either way and
* this spares us an invalidation. * this spares us an invalidation.
*/ */
if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
return;
retry: retry:
if ((fattr->cf_cifsattrs & ATTR_REPARSE) ||
(fattr->cf_flags & CIFS_FATTR_NEED_REVAL))
return;
dentry = d_alloc_parallel(parent, name, &wq); dentry = d_alloc_parallel(parent, name, &wq);
} }
if (IS_ERR(dentry)) if (IS_ERR(dentry))
...@@ -104,12 +124,34 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, ...@@ -104,12 +124,34 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
fattr->cf_uniqueid = CIFS_I(inode)->uniqueid; fattr->cf_uniqueid = CIFS_I(inode)->uniqueid;
/* update inode in place /*
* if both i_ino and i_mode didn't change */ * Update inode in place if both i_ino and i_mode didn't
if (CIFS_I(inode)->uniqueid == fattr->cf_uniqueid && * change.
cifs_fattr_to_inode(inode, fattr) == 0) { */
dput(dentry); if (CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) {
return; /*
* Query dir responses don't provide enough
* information about reparse points other than
* their reparse tags. Save an invalidation by
* not clobbering the existing mode, size and
* symlink target (if any) when reparse tag and
* ctime haven't changed.
*/
rc = 0;
if (fattr->cf_cifsattrs & ATTR_REPARSE) {
if (likely(reparse_inode_match(inode, fattr))) {
fattr->cf_mode = inode->i_mode;
fattr->cf_eof = CIFS_I(inode)->server_eof;
fattr->cf_symlink_target = NULL;
} else {
CIFS_I(inode)->time = 0;
rc = -ESTALE;
}
}
if (!rc && !cifs_fattr_to_inode(inode, fattr)) {
dput(dentry);
return;
}
} }
} }
d_invalidate(dentry); d_invalidate(dentry);
...@@ -127,29 +169,6 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, ...@@ -127,29 +169,6 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
dput(dentry); dput(dentry);
} }
static bool reparse_file_needs_reval(const struct cifs_fattr *fattr)
{
if (!(fattr->cf_cifsattrs & ATTR_REPARSE))
return false;
/*
* The DFS tags should be only intepreted by server side as per
* MS-FSCC 2.1.2.1, but let's include them anyway.
*
* Besides, if cf_cifstag is unset (0), then we still need it to be
* revalidated to know exactly what reparse point it is.
*/
switch (fattr->cf_cifstag) {
case IO_REPARSE_TAG_DFS:
case IO_REPARSE_TAG_DFSR:
case IO_REPARSE_TAG_SYMLINK:
case IO_REPARSE_TAG_NFS:
case IO_REPARSE_TAG_MOUNT_POINT:
case 0:
return true;
}
return false;
}
static void static void
cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
{ {
...@@ -181,14 +200,6 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) ...@@ -181,14 +200,6 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
} }
out_reparse: out_reparse:
/*
* We need to revalidate it further to make a decision about whether it
* is a symbolic link, DFS referral or a reparse point with a direct
* access like junctions, deduplicated files, NFS symlinks.
*/
if (reparse_file_needs_reval(fattr))
fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
/* non-unix readdir doesn't provide nlink */ /* non-unix readdir doesn't provide nlink */
fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK; fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
...@@ -269,9 +280,6 @@ cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info, ...@@ -269,9 +280,6 @@ cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info,
fattr->cf_dtype = DT_REG; fattr->cf_dtype = DT_REG;
} }
if (reparse_file_needs_reval(fattr))
fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
sid_to_id(cifs_sb, &parsed.owner, fattr, SIDOWNER); sid_to_id(cifs_sb, &parsed.owner, fattr, SIDOWNER);
sid_to_id(cifs_sb, &parsed.group, fattr, SIDGROUP); sid_to_id(cifs_sb, &parsed.group, fattr, SIDGROUP);
} }
...@@ -331,38 +339,6 @@ cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info, ...@@ -331,38 +339,6 @@ cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info,
cifs_fill_common_info(fattr, cifs_sb); cifs_fill_common_info(fattr, cifs_sb);
} }
/* BB eventually need to add the following helper function to
resolve NT_STATUS_STOPPED_ON_SYMLINK return code when
we try to do FindFirst on (NTFS) directory symlinks */
/*
int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb,
unsigned int xid)
{
__u16 fid;
int len;
int oplock = 0;
int rc;
struct cifs_tcon *ptcon = cifs_sb_tcon(cifs_sb);
char *tmpbuffer;
rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ,
OPEN_REPARSE_POINT, &fid, &oplock, NULL,
cifs_sb->local_nls,
cifs_remap(cifs_sb);
if (!rc) {
tmpbuffer = kmalloc(maxpath);
rc = CIFSSMBQueryReparseLinkInfo(xid, ptcon, full_path,
tmpbuffer,
maxpath -1,
fid,
cifs_sb->local_nls);
if (CIFSSMBClose(xid, ptcon, fid)) {
cifs_dbg(FYI, "Error closing temporary reparsepoint open\n");
}
}
}
*/
static int static int
_initiate_cifs_search(const unsigned int xid, struct file *file, _initiate_cifs_search(const unsigned int xid, struct file *file,
const char *full_path) const char *full_path)
...@@ -431,13 +407,10 @@ _initiate_cifs_search(const unsigned int xid, struct file *file, ...@@ -431,13 +407,10 @@ _initiate_cifs_search(const unsigned int xid, struct file *file,
&cifsFile->fid, search_flags, &cifsFile->fid, search_flags,
&cifsFile->srch_inf); &cifsFile->srch_inf);
if (rc == 0) if (rc == 0) {
cifsFile->invalidHandle = false; cifsFile->invalidHandle = false;
/* BB add following call to handle readdir on new NTFS symlink errors } else if ((rc == -EOPNOTSUPP) &&
else if STATUS_STOPPED_ON_SYMLINK (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
call get_symlink_reparse_path and retry with new path */
else if ((rc == -EOPNOTSUPP) &&
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
goto ffirst_retry; goto ffirst_retry;
} }
......
...@@ -356,10 +356,9 @@ cifs_disable_secondary_channels(struct cifs_ses *ses) ...@@ -356,10 +356,9 @@ cifs_disable_secondary_channels(struct cifs_ses *ses)
/* /*
* update the iface for the channel if necessary. * update the iface for the channel if necessary.
* will return 0 when iface is updated, 1 if removed, 2 otherwise
* Must be called with chan_lock held. * Must be called with chan_lock held.
*/ */
int void
cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server) cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
{ {
unsigned int chan_index; unsigned int chan_index;
...@@ -368,20 +367,19 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server) ...@@ -368,20 +367,19 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
struct cifs_server_iface *old_iface = NULL; struct cifs_server_iface *old_iface = NULL;
struct cifs_server_iface *last_iface = NULL; struct cifs_server_iface *last_iface = NULL;
struct sockaddr_storage ss; struct sockaddr_storage ss;
int rc = 0;
spin_lock(&ses->chan_lock); spin_lock(&ses->chan_lock);
chan_index = cifs_ses_get_chan_index(ses, server); chan_index = cifs_ses_get_chan_index(ses, server);
if (chan_index == CIFS_INVAL_CHAN_INDEX) { if (chan_index == CIFS_INVAL_CHAN_INDEX) {
spin_unlock(&ses->chan_lock); spin_unlock(&ses->chan_lock);
return 0; return;
} }
if (ses->chans[chan_index].iface) { if (ses->chans[chan_index].iface) {
old_iface = ses->chans[chan_index].iface; old_iface = ses->chans[chan_index].iface;
if (old_iface->is_active) { if (old_iface->is_active) {
spin_unlock(&ses->chan_lock); spin_unlock(&ses->chan_lock);
return 1; return;
} }
} }
spin_unlock(&ses->chan_lock); spin_unlock(&ses->chan_lock);
...@@ -394,7 +392,7 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server) ...@@ -394,7 +392,7 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
if (!ses->iface_count) { if (!ses->iface_count) {
spin_unlock(&ses->iface_lock); spin_unlock(&ses->iface_lock);
cifs_dbg(VFS, "server %s does not advertise interfaces\n", ses->server->hostname); cifs_dbg(VFS, "server %s does not advertise interfaces\n", ses->server->hostname);
return 0; return;
} }
last_iface = list_last_entry(&ses->iface_list, struct cifs_server_iface, last_iface = list_last_entry(&ses->iface_list, struct cifs_server_iface,
...@@ -434,16 +432,21 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server) ...@@ -434,16 +432,21 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
} }
if (list_entry_is_head(iface, &ses->iface_list, iface_head)) { if (list_entry_is_head(iface, &ses->iface_list, iface_head)) {
rc = 1;
iface = NULL; iface = NULL;
cifs_dbg(FYI, "unable to find a suitable iface\n"); cifs_dbg(FYI, "unable to find a suitable iface\n");
} }
if (!iface) { if (!iface) {
cifs_dbg(FYI, "unable to get the interface matching: %pIS\n", if (!chan_index)
&ss); cifs_dbg(FYI, "unable to get the interface matching: %pIS\n",
&ss);
else {
cifs_dbg(FYI, "unable to find another interface to replace: %pIS\n",
&old_iface->sockaddr);
}
spin_unlock(&ses->iface_lock); spin_unlock(&ses->iface_lock);
return 0; return;
} }
/* now drop the ref to the current iface */ /* now drop the ref to the current iface */
...@@ -459,34 +462,24 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server) ...@@ -459,34 +462,24 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
iface->weight_fulfilled++; iface->weight_fulfilled++;
kref_put(&old_iface->refcount, release_iface); kref_put(&old_iface->refcount, release_iface);
} else if (old_iface) {
/* if a new candidate is not found, keep things as is */
cifs_dbg(FYI, "could not replace iface: %pIS\n",
&old_iface->sockaddr);
} else if (!chan_index) { } else if (!chan_index) {
/* special case: update interface for primary channel */ /* special case: update interface for primary channel */
if (iface) { cifs_dbg(FYI, "referencing primary channel iface: %pIS\n",
cifs_dbg(FYI, "referencing primary channel iface: %pIS\n", &iface->sockaddr);
&iface->sockaddr); iface->num_channels++;
iface->num_channels++; iface->weight_fulfilled++;
iface->weight_fulfilled++;
}
} }
spin_unlock(&ses->iface_lock); spin_unlock(&ses->iface_lock);
if (iface) { spin_lock(&ses->chan_lock);
spin_lock(&ses->chan_lock); chan_index = cifs_ses_get_chan_index(ses, server);
chan_index = cifs_ses_get_chan_index(ses, server); if (chan_index == CIFS_INVAL_CHAN_INDEX) {
if (chan_index == CIFS_INVAL_CHAN_INDEX) {
spin_unlock(&ses->chan_lock);
return 0;
}
ses->chans[chan_index].iface = iface;
spin_unlock(&ses->chan_lock); spin_unlock(&ses->chan_lock);
return;
} }
return rc; ses->chans[chan_index].iface = iface;
spin_unlock(&ses->chan_lock);
} }
/* /*
......
...@@ -23,17 +23,21 @@ ...@@ -23,17 +23,21 @@
* Identifiers for functions that use the open, operation, close pattern * Identifiers for functions that use the open, operation, close pattern
* in smb2inode.c:smb2_compound_op() * in smb2inode.c:smb2_compound_op()
*/ */
#define SMB2_OP_SET_DELETE 1 enum smb2_compound_ops {
#define SMB2_OP_SET_INFO 2 SMB2_OP_SET_DELETE = 1,
#define SMB2_OP_QUERY_INFO 3 SMB2_OP_SET_INFO,
#define SMB2_OP_QUERY_DIR 4 SMB2_OP_QUERY_INFO,
#define SMB2_OP_MKDIR 5 SMB2_OP_QUERY_DIR,
#define SMB2_OP_RENAME 6 SMB2_OP_MKDIR,
#define SMB2_OP_DELETE 7 SMB2_OP_RENAME,
#define SMB2_OP_HARDLINK 8 SMB2_OP_DELETE,
#define SMB2_OP_SET_EOF 9 SMB2_OP_HARDLINK,
#define SMB2_OP_RMDIR 10 SMB2_OP_SET_EOF,
#define SMB2_OP_POSIX_QUERY_INFO 11 SMB2_OP_RMDIR,
SMB2_OP_POSIX_QUERY_INFO,
SMB2_OP_SET_REPARSE,
SMB2_OP_GET_REPARSE
};
/* Used when constructing chained read requests. */ /* Used when constructing chained read requests. */
#define CHAINED_REQUEST 1 #define CHAINED_REQUEST 1
......
This diff is collapsed.
This diff is collapsed.
...@@ -5347,18 +5347,18 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5347,18 +5347,18 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
int int
SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
u64 volatile_fid, u32 pid, __le64 *eof) u64 volatile_fid, u32 pid, loff_t new_eof)
{ {
struct smb2_file_eof_info info; struct smb2_file_eof_info info;
void *data; void *data;
unsigned int size; unsigned int size;
info.EndOfFile = *eof; info.EndOfFile = cpu_to_le64(new_eof);
data = &info; data = &info;
size = sizeof(struct smb2_file_eof_info); size = sizeof(struct smb2_file_eof_info);
trace_smb3_set_eof(xid, persistent_fid, tcon->tid, tcon->ses->Suid, le64_to_cpu(*eof)); trace_smb3_set_eof(xid, persistent_fid, tcon->tid, tcon->ses->Suid, new_eof);
return send_set_info(xid, tcon, persistent_fid, volatile_fid, return send_set_info(xid, tcon, persistent_fid, volatile_fid,
pid, FILE_END_OF_FILE_INFORMATION, SMB2_O_INFO_FILE, pid, FILE_END_OF_FILE_INFORMATION, SMB2_O_INFO_FILE,
......
...@@ -56,6 +56,18 @@ extern int smb3_handle_read_data(struct TCP_Server_Info *server, ...@@ -56,6 +56,18 @@ extern int smb3_handle_read_data(struct TCP_Server_Info *server,
extern int smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon, extern int smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const char *path, struct cifs_sb_info *cifs_sb, const char *path,
__u32 *reparse_tag); __u32 *reparse_tag);
struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
struct super_block *sb,
const unsigned int xid,
struct cifs_tcon *tcon,
const char *full_path,
struct kvec *iov);
int smb2_query_reparse_point(const unsigned int xid,
struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
const char *full_path,
u32 *tag, struct kvec *rsp,
int *rsp_buftype);
int smb2_query_path_info(const unsigned int xid, int smb2_query_path_info(const unsigned int xid,
struct cifs_tcon *tcon, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, struct cifs_sb_info *cifs_sb,
...@@ -80,12 +92,16 @@ extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -80,12 +92,16 @@ extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb); const char *name, struct cifs_sb_info *cifs_sb);
extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb); const char *name, struct cifs_sb_info *cifs_sb);
extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon, int smb2_rename_path(const unsigned int xid,
const char *from_name, const char *to_name, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb); struct dentry *source_dentry,
extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon, const char *from_name, const char *to_name,
const char *from_name, const char *to_name, struct cifs_sb_info *cifs_sb);
struct cifs_sb_info *cifs_sb); int smb2_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);
extern int smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, extern int smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const unsigned char *path, struct cifs_sb_info *cifs_sb, const unsigned char *path,
char *pbuf, unsigned int *pbytes_written); char *pbuf, unsigned int *pbytes_written);
...@@ -205,7 +221,7 @@ extern int SMB2_query_directory_init(unsigned int xid, struct cifs_tcon *tcon, ...@@ -205,7 +221,7 @@ extern int SMB2_query_directory_init(unsigned int xid, struct cifs_tcon *tcon,
extern void SMB2_query_directory_free(struct smb_rqst *rqst); extern void SMB2_query_directory_free(struct smb_rqst *rqst);
extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, u32 pid, u64 persistent_fid, u64 volatile_fid, u32 pid,
__le64 *eof); loff_t new_eof);
extern int SMB2_set_info_init(struct cifs_tcon *tcon, extern int SMB2_set_info_init(struct cifs_tcon *tcon,
struct TCP_Server_Info *server, struct TCP_Server_Info *server,
struct smb_rqst *rqst, struct smb_rqst *rqst,
...@@ -289,4 +305,5 @@ int smb311_posix_query_path_info(const unsigned int xid, ...@@ -289,4 +305,5 @@ int smb311_posix_query_path_info(const unsigned int xid,
int posix_info_parse(const void *beg, const void *end, int posix_info_parse(const void *beg, const void *end,
struct smb2_posix_info_parsed *out); struct smb2_posix_info_parsed *out);
int posix_info_sid_size(const void *beg, const void *end); int posix_info_sid_size(const void *beg, const void *end);
#endif /* _SMB2PROTO_H */ #endif /* _SMB2PROTO_H */
...@@ -2136,7 +2136,7 @@ static int allocate_mr_list(struct smbd_connection *info) ...@@ -2136,7 +2136,7 @@ static int allocate_mr_list(struct smbd_connection *info)
for (i = 0; i < info->responder_resources * 2; i++) { for (i = 0; i < info->responder_resources * 2; i++) {
smbdirect_mr = kzalloc(sizeof(*smbdirect_mr), GFP_KERNEL); smbdirect_mr = kzalloc(sizeof(*smbdirect_mr), GFP_KERNEL);
if (!smbdirect_mr) if (!smbdirect_mr)
goto out; goto cleanup_entries;
smbdirect_mr->mr = ib_alloc_mr(info->pd, info->mr_type, smbdirect_mr->mr = ib_alloc_mr(info->pd, info->mr_type,
info->max_frmr_depth); info->max_frmr_depth);
if (IS_ERR(smbdirect_mr->mr)) { if (IS_ERR(smbdirect_mr->mr)) {
...@@ -2162,7 +2162,7 @@ static int allocate_mr_list(struct smbd_connection *info) ...@@ -2162,7 +2162,7 @@ static int allocate_mr_list(struct smbd_connection *info)
out: out:
kfree(smbdirect_mr); kfree(smbdirect_mr);
cleanup_entries:
list_for_each_entry_safe(smbdirect_mr, tmp, &info->mr_list, list) { list_for_each_entry_safe(smbdirect_mr, tmp, &info->mr_list, list) {
list_del(&smbdirect_mr->list); list_del(&smbdirect_mr->list);
ib_dereg_mr(smbdirect_mr->mr); ib_dereg_mr(smbdirect_mr->mr);
......
...@@ -370,11 +370,12 @@ DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(rename_enter); ...@@ -370,11 +370,12 @@ DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(rename_enter);
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(rmdir_enter); DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(rmdir_enter);
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_eof_enter); DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_eof_enter);
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_info_compound_enter); DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_info_compound_enter);
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_reparse_compound_enter);
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(get_reparse_compound_enter);
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(delete_enter); DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(delete_enter);
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(mkdir_enter); DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(mkdir_enter);
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(tdis_enter); DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(tdis_enter);
DECLARE_EVENT_CLASS(smb3_inf_compound_done_class, DECLARE_EVENT_CLASS(smb3_inf_compound_done_class,
TP_PROTO(unsigned int xid, TP_PROTO(unsigned int xid,
__u32 tid, __u32 tid,
...@@ -408,6 +409,8 @@ DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(rename_done); ...@@ -408,6 +409,8 @@ DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(rename_done);
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(rmdir_done); DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(rmdir_done);
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_eof_done); DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_eof_done);
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_info_compound_done); DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_info_compound_done);
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_reparse_compound_done);
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(get_reparse_compound_done);
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(delete_done); DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(delete_done);
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(mkdir_done); DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(mkdir_done);
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(tdis_done); DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(tdis_done);
...@@ -451,6 +454,8 @@ DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(rename_err); ...@@ -451,6 +454,8 @@ DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(rename_err);
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(rmdir_err); DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(rmdir_err);
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_eof_err); DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_eof_err);
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_info_compound_err); DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_info_compound_err);
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_reparse_compound_err);
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(get_reparse_compound_err);
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(mkdir_err); DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(mkdir_err);
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(delete_err); DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(delete_err);
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(tdis_err); DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(tdis_err);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment