mirror of
https://github.com/torvalds/linux.git
synced 2025-04-09 14:45:27 +00:00
18 smb3/cifs client fixes
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmfvTpMACgkQiiy9cAdy T1Honwv/SQEGf0ELO97Ek8aTio1dKi7Z+sDpwBwTQbVI9jdO8/Jj7MzbOHhZ9XSC JWGrUHZD8ssFGxktTQj+Mfk8LAMMm2yDeOOCwMZthLwkC00qPNIhaP5rvVdTbeSj J6jGzFWkBmPxIs1ljazKKts84YiiNu0QbZupmROgWe64KzNdYO7I3f32msgzjOKz wzdh6AQ+/WfrzCBX5AxpBohKrceY+NGjKYNc0YIvQ4MYC+P9pmK/71mgqucoUtrr gwQA7ctNsXd+tX93Q6yY0BmiuV1fzrsUrAjZGP58juwJ8uTapN0Mm5szcbiIVpF2 CseFahAVAhtUg/AaAPgdsz9OqnvmKZLaabNtzGdrmgepz3l9Y+njZqx23kyKiwIT 5cnXmytfghUr7TQToSlPP9PpC1oyJV/xwcuC90gx5LhCpa13+i6b4eFO/IlZe6LB UyE26MAm+ZDY8kcCfK0thSwdz36E1ieURwDmOEFqACOJL5wVMuy0GQTL4lsHqWfZ unukaR2e =KNE4 -----END PGP SIGNATURE----- Merge tag '6.15-rc-part2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6 Pull more smb client updates from Steve French: - reconnect fixes: three for updating rsize/wsize and an SMB1 reconnect fix - RFC1001 fixes: fixing connections to nonstandard ports, and negprot retries - fix mfsymlinks to old servers - make mapping of open flags for SMB1 more accurate - permission fixes: adding retry on open for write, and one for stat to workaround unexpected access denied - add two new xattrs, one for retrieving SACL and one for retrieving owner (without having to retrieve the whole ACL) - fix mount parm validation for echo_interval - minor cleanup (including removing now unneeded cifs_truncate_page) * tag '6.15-rc-part2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: update internal version number cifs: Implement is_network_name_deleted for SMB1 cifs: Remove cifs_truncate_page() as it should be superfluous cifs: Do not add FILE_READ_ATTRIBUTES when using GENERIC_READ/EXECUTE/ALL cifs: Improve SMB2+ stat() to work also without FILE_READ_ATTRIBUTES cifs: Add fallback for SMB2 CREATE without FILE_READ_ATTRIBUTES cifs: Fix querying and creating MF symlinks over SMB1 cifs: Fix access_flags_to_smbopen_mode cifs: Fix negotiate retry functionality cifs: Improve handling of NetBIOS packets cifs: Allow to disable or force initialization of NetBIOS session cifs: Add a new xattr system.smb3_ntsd_owner for getting or setting owner cifs: Add a new xattr system.smb3_ntsd_sacl for getting or setting SACLs smb: client: Update IO sizes after reconnection smb: client: Store original IO parameters and prevent zero IO sizes smb:client: smb: client: Add reverse mapping from tcon to superblocks cifs: remove unreachable code in cifs_get_tcp_session() cifs: fix integer overflow in match_server()
This commit is contained in:
commit
9f867ba24d
@ -49,6 +49,7 @@
|
||||
|
||||
struct cifs_sb_info {
|
||||
struct rb_root tlink_tree;
|
||||
struct list_head tcon_sb_link;
|
||||
spinlock_t tlink_tree_lock;
|
||||
struct tcon_link *master_tlink;
|
||||
struct nls_table *local_nls;
|
||||
|
@ -135,7 +135,6 @@ extern ssize_t cifs_file_copychunk_range(unsigned int xid,
|
||||
|
||||
extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
||||
extern void cifs_setsize(struct inode *inode, loff_t offset);
|
||||
extern int cifs_truncate_page(struct address_space *mapping, loff_t from);
|
||||
|
||||
struct smb3_fs_context;
|
||||
extern struct dentry *cifs_smb3_do_mount(struct file_system_type *fs_type,
|
||||
@ -146,6 +145,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 53
|
||||
#define CIFS_VERSION "2.53"
|
||||
#define SMB3_PRODUCT_BUILD 54
|
||||
#define CIFS_VERSION "2.54"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
@ -714,6 +714,8 @@ struct TCP_Server_Info {
|
||||
spinlock_t srv_lock; /* protect anything here that is not protected */
|
||||
__u64 conn_id; /* connection identifier (useful for debugging) */
|
||||
int srv_count; /* reference counter */
|
||||
int rfc1001_sessinit; /* whether to estasblish netbios session */
|
||||
bool with_rfc1001; /* if netbios session is used */
|
||||
/* 15 character server name + 0x20 16th byte indicating type = srv */
|
||||
char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
|
||||
struct smb_version_operations *ops;
|
||||
@ -1321,7 +1323,8 @@ struct cifs_tcon {
|
||||
#endif
|
||||
struct list_head pending_opens; /* list of incomplete opens */
|
||||
struct cached_fids *cfids;
|
||||
/* BB add field for back pointer to sb struct(s)? */
|
||||
struct list_head cifs_sb_list;
|
||||
spinlock_t sb_list_lock;
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
struct delayed_work dfs_cache_work;
|
||||
struct list_head dfs_ses_list;
|
||||
@ -1718,6 +1721,7 @@ struct mid_q_entry {
|
||||
void *resp_buf; /* pointer to received SMB header */
|
||||
unsigned int resp_buf_size;
|
||||
int mid_state; /* wish this were enum but can not pass to wait_event */
|
||||
int mid_rc; /* rc for MID_RC */
|
||||
unsigned int mid_flags;
|
||||
__le16 command; /* smb command code */
|
||||
unsigned int optype; /* operation type */
|
||||
@ -1880,6 +1884,7 @@ static inline bool is_replayable_error(int error)
|
||||
#define MID_RESPONSE_MALFORMED 0x10
|
||||
#define MID_SHUTDOWN 0x20
|
||||
#define MID_RESPONSE_READY 0x40 /* ready for other process handle the rsp */
|
||||
#define MID_RC 0x80 /* mid_rc contains custom rc */
|
||||
|
||||
/* Flags */
|
||||
#define MID_WAIT_CANCELLED 1 /* Cancelled while waiting for response */
|
||||
|
@ -1041,15 +1041,31 @@ static __u16 convert_disposition(int disposition)
|
||||
static int
|
||||
access_flags_to_smbopen_mode(const int access_flags)
|
||||
{
|
||||
int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
|
||||
/*
|
||||
* SYSTEM_SECURITY grants both read and write access to SACL, treat is as read/write.
|
||||
* MAXIMUM_ALLOWED grants as many access as possible, so treat it as read/write too.
|
||||
* SYNCHRONIZE as is does not grant any specific access, so do not check its mask.
|
||||
* If only SYNCHRONIZE bit is specified then fallback to read access.
|
||||
*/
|
||||
bool with_write_flags = access_flags & (FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_EA |
|
||||
FILE_DELETE_CHILD | FILE_WRITE_ATTRIBUTES | DELETE |
|
||||
WRITE_DAC | WRITE_OWNER | SYSTEM_SECURITY |
|
||||
MAXIMUM_ALLOWED | GENERIC_WRITE | GENERIC_ALL);
|
||||
bool with_read_flags = access_flags & (FILE_READ_DATA | FILE_READ_EA | FILE_EXECUTE |
|
||||
FILE_READ_ATTRIBUTES | READ_CONTROL |
|
||||
SYSTEM_SECURITY | MAXIMUM_ALLOWED | GENERIC_ALL |
|
||||
GENERIC_EXECUTE | GENERIC_READ);
|
||||
bool with_execute_flags = access_flags & (FILE_EXECUTE | MAXIMUM_ALLOWED | GENERIC_ALL |
|
||||
GENERIC_EXECUTE);
|
||||
|
||||
if (masked_flags == GENERIC_READ)
|
||||
return SMBOPEN_READ;
|
||||
else if (masked_flags == GENERIC_WRITE)
|
||||
if (with_write_flags && with_read_flags)
|
||||
return SMBOPEN_READWRITE;
|
||||
else if (with_write_flags)
|
||||
return SMBOPEN_WRITE;
|
||||
|
||||
/* just go for read/write */
|
||||
return SMBOPEN_READWRITE;
|
||||
else if (with_execute_flags)
|
||||
return SMBOPEN_EXECUTE;
|
||||
else
|
||||
return SMBOPEN_READ;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -371,7 +371,7 @@ static bool cifs_tcp_ses_needs_reconnect(struct TCP_Server_Info *server, int num
|
||||
*
|
||||
*/
|
||||
static int __cifs_reconnect(struct TCP_Server_Info *server,
|
||||
bool mark_smb_session)
|
||||
bool mark_smb_session, bool once)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
@ -399,6 +399,9 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,
|
||||
if (rc) {
|
||||
cifs_server_unlock(server);
|
||||
cifs_dbg(FYI, "%s: reconnect error %d\n", __func__, rc);
|
||||
/* If was asked to reconnect only once, do not try it more times */
|
||||
if (once)
|
||||
break;
|
||||
msleep(3000);
|
||||
} else {
|
||||
atomic_inc(&tcpSesReconnectCount);
|
||||
@ -564,19 +567,33 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server)
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cifs_reconnect(struct TCP_Server_Info *server, bool mark_smb_session)
|
||||
static int
|
||||
_cifs_reconnect(struct TCP_Server_Info *server, bool mark_smb_session, bool once)
|
||||
{
|
||||
if (!server->leaf_fullpath)
|
||||
return __cifs_reconnect(server, mark_smb_session);
|
||||
return __cifs_reconnect(server, mark_smb_session, once);
|
||||
return reconnect_dfs_server(server);
|
||||
}
|
||||
#else
|
||||
int cifs_reconnect(struct TCP_Server_Info *server, bool mark_smb_session)
|
||||
static int
|
||||
_cifs_reconnect(struct TCP_Server_Info *server, bool mark_smb_session, bool once)
|
||||
{
|
||||
return __cifs_reconnect(server, mark_smb_session);
|
||||
return __cifs_reconnect(server, mark_smb_session, once);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
cifs_reconnect(struct TCP_Server_Info *server, bool mark_smb_session)
|
||||
{
|
||||
return _cifs_reconnect(server, mark_smb_session, false);
|
||||
}
|
||||
|
||||
static int
|
||||
cifs_reconnect_once(struct TCP_Server_Info *server)
|
||||
{
|
||||
return _cifs_reconnect(server, true, true);
|
||||
}
|
||||
|
||||
static void
|
||||
cifs_echo_request(struct work_struct *work)
|
||||
{
|
||||
@ -803,26 +820,110 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
|
||||
/* Regular SMB response */
|
||||
return true;
|
||||
case RFC1002_SESSION_KEEP_ALIVE:
|
||||
/*
|
||||
* RFC 1002 session keep alive can sent by the server only when
|
||||
* we established a RFC 1002 session. But Samba servers send
|
||||
* RFC 1002 session keep alive also over port 445 on which
|
||||
* RFC 1002 session is not established.
|
||||
*/
|
||||
cifs_dbg(FYI, "RFC 1002 session keep alive\n");
|
||||
break;
|
||||
case RFC1002_POSITIVE_SESSION_RESPONSE:
|
||||
cifs_dbg(FYI, "RFC 1002 positive session response\n");
|
||||
/*
|
||||
* RFC 1002 positive session response cannot be returned
|
||||
* for SMB request. RFC 1002 session response is handled
|
||||
* exclusively in ip_rfc1001_connect() function.
|
||||
*/
|
||||
cifs_server_dbg(VFS, "RFC 1002 positive session response (unexpected)\n");
|
||||
cifs_reconnect(server, true);
|
||||
break;
|
||||
case RFC1002_NEGATIVE_SESSION_RESPONSE:
|
||||
/*
|
||||
* We get this from Windows 98 instead of an error on
|
||||
* SMB negprot response.
|
||||
* SMB negprot response, when we have not established
|
||||
* RFC 1002 session (which means ip_rfc1001_connect()
|
||||
* was skipped). Note that same still happens with
|
||||
* Windows Server 2022 when connecting via port 139.
|
||||
* So for this case when mount option -o nonbsessinit
|
||||
* was not specified, try to reconnect with establishing
|
||||
* RFC 1002 session. If new socket establishment with
|
||||
* RFC 1002 session was successful then return to the
|
||||
* mid's caller -EAGAIN, so it can retry the request.
|
||||
*/
|
||||
cifs_dbg(FYI, "RFC 1002 negative session response\n");
|
||||
/* give server a second to clean up */
|
||||
msleep(1000);
|
||||
/*
|
||||
* Always try 445 first on reconnect since we get NACK
|
||||
* on some if we ever connected to port 139 (the NACK
|
||||
* is since we do not begin with RFC1001 session
|
||||
* initialize frame).
|
||||
*/
|
||||
cifs_set_port((struct sockaddr *)&server->dstaddr, CIFS_PORT);
|
||||
if (!cifs_rdma_enabled(server) &&
|
||||
server->tcpStatus == CifsInNegotiate &&
|
||||
!server->with_rfc1001 &&
|
||||
server->rfc1001_sessinit != 0) {
|
||||
int rc, mid_rc;
|
||||
struct mid_q_entry *mid, *nmid;
|
||||
LIST_HEAD(dispose_list);
|
||||
|
||||
cifs_dbg(FYI, "RFC 1002 negative session response during SMB Negotiate, retrying with NetBIOS session\n");
|
||||
|
||||
/*
|
||||
* Before reconnect, delete all pending mids for this
|
||||
* server, so reconnect would not signal connection
|
||||
* aborted error to mid's callbacks. Note that for this
|
||||
* server there should be exactly one pending mid
|
||||
* corresponding to SMB1/SMB2 Negotiate packet.
|
||||
*/
|
||||
spin_lock(&server->mid_lock);
|
||||
list_for_each_entry_safe(mid, nmid, &server->pending_mid_q, qhead) {
|
||||
kref_get(&mid->refcount);
|
||||
list_move(&mid->qhead, &dispose_list);
|
||||
mid->mid_flags |= MID_DELETED;
|
||||
}
|
||||
spin_unlock(&server->mid_lock);
|
||||
|
||||
/* Now try to reconnect once with NetBIOS session. */
|
||||
server->with_rfc1001 = true;
|
||||
rc = cifs_reconnect_once(server);
|
||||
|
||||
/*
|
||||
* If reconnect was successful then indicate -EAGAIN
|
||||
* to mid's caller. If reconnect failed with -EAGAIN
|
||||
* then mask it as -EHOSTDOWN, so mid's caller would
|
||||
* know that it failed.
|
||||
*/
|
||||
if (rc == 0)
|
||||
mid_rc = -EAGAIN;
|
||||
else if (rc == -EAGAIN)
|
||||
mid_rc = -EHOSTDOWN;
|
||||
else
|
||||
mid_rc = rc;
|
||||
|
||||
/*
|
||||
* After reconnect (either successful or unsuccessful)
|
||||
* deliver reconnect status to mid's caller via mid's
|
||||
* callback. Use MID_RC state which indicates that the
|
||||
* return code should be read from mid_rc member.
|
||||
*/
|
||||
list_for_each_entry_safe(mid, nmid, &dispose_list, qhead) {
|
||||
list_del_init(&mid->qhead);
|
||||
mid->mid_rc = mid_rc;
|
||||
mid->mid_state = MID_RC;
|
||||
mid->callback(mid);
|
||||
release_mid(mid);
|
||||
}
|
||||
|
||||
/*
|
||||
* If reconnect failed then wait two seconds. In most
|
||||
* cases we were been called from the mount context and
|
||||
* delivered failure to mid's callback will stop this
|
||||
* receiver task thread and fails the mount process.
|
||||
* So wait two seconds to prevent another reconnect
|
||||
* in this task thread, which would be useless as the
|
||||
* mount context will fail at all.
|
||||
*/
|
||||
if (rc != 0)
|
||||
msleep(2000);
|
||||
} else {
|
||||
cifs_server_dbg(VFS, "RFC 1002 negative session response (unexpected)\n");
|
||||
cifs_reconnect(server, true);
|
||||
}
|
||||
break;
|
||||
case RFC1002_RETARGET_SESSION_RESPONSE:
|
||||
cifs_server_dbg(VFS, "RFC 1002 retarget session response (unexpected)\n");
|
||||
cifs_reconnect(server, true);
|
||||
break;
|
||||
default:
|
||||
@ -1701,6 +1802,8 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
|
||||
ctx->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
|
||||
memcpy(tcp_ses->server_RFC1001_name,
|
||||
ctx->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
|
||||
tcp_ses->rfc1001_sessinit = ctx->rfc1001_sessinit;
|
||||
tcp_ses->with_rfc1001 = false;
|
||||
tcp_ses->session_estab = false;
|
||||
tcp_ses->sequence_number = 0;
|
||||
tcp_ses->channel_sequence_num = 0; /* only tracked for primary channel */
|
||||
@ -1731,12 +1834,8 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
|
||||
*/
|
||||
tcp_ses->tcpStatus = CifsNew;
|
||||
++tcp_ses->srv_count;
|
||||
tcp_ses->echo_interval = ctx->echo_interval * HZ;
|
||||
|
||||
if (ctx->echo_interval >= SMB_ECHO_INTERVAL_MIN &&
|
||||
ctx->echo_interval <= SMB_ECHO_INTERVAL_MAX)
|
||||
tcp_ses->echo_interval = ctx->echo_interval * HZ;
|
||||
else
|
||||
tcp_ses->echo_interval = SMB_ECHO_INTERVAL_DEFAULT * HZ;
|
||||
if (tcp_ses->rdma) {
|
||||
#ifndef CONFIG_CIFS_SMB_DIRECT
|
||||
cifs_dbg(VFS, "CONFIG_CIFS_SMB_DIRECT is not enabled\n");
|
||||
@ -3221,6 +3320,7 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
server->with_rfc1001 = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3332,7 +3432,16 @@ generic_ip_connect(struct TCP_Server_Info *server)
|
||||
return rc;
|
||||
}
|
||||
trace_smb3_connect_done(server->hostname, server->conn_id, &server->dstaddr);
|
||||
if (sport == htons(RFC1001_PORT))
|
||||
|
||||
/*
|
||||
* Establish RFC1001 NetBIOS session when it was explicitly requested
|
||||
* by mount option -o nbsessinit, or when connecting to default RFC1001
|
||||
* server port (139) and it was not explicitly disabled by mount option
|
||||
* -o nonbsessinit.
|
||||
*/
|
||||
if (server->with_rfc1001 ||
|
||||
server->rfc1001_sessinit == 1 ||
|
||||
(server->rfc1001_sessinit == -1 && sport == htons(RFC1001_PORT)))
|
||||
rc = ip_rfc1001_connect(server);
|
||||
|
||||
return rc;
|
||||
@ -3481,6 +3590,7 @@ int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb)
|
||||
struct smb3_fs_context *ctx = cifs_sb->ctx;
|
||||
|
||||
INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks);
|
||||
INIT_LIST_HEAD(&cifs_sb->tcon_sb_link);
|
||||
|
||||
spin_lock_init(&cifs_sb->tlink_tree_lock);
|
||||
cifs_sb->tlink_tree = RB_ROOT;
|
||||
@ -3713,6 +3823,10 @@ static int mount_setup_tlink(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
|
||||
tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
|
||||
spin_unlock(&cifs_sb->tlink_tree_lock);
|
||||
|
||||
spin_lock(&tcon->sb_list_lock);
|
||||
list_add(&cifs_sb->tcon_sb_link, &tcon->cifs_sb_list);
|
||||
spin_unlock(&tcon->sb_list_lock);
|
||||
|
||||
queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks,
|
||||
TLINK_IDLE_EXPIRE);
|
||||
return 0;
|
||||
@ -4054,9 +4168,19 @@ cifs_umount(struct cifs_sb_info *cifs_sb)
|
||||
struct rb_root *root = &cifs_sb->tlink_tree;
|
||||
struct rb_node *node;
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_tcon *tcon = NULL;
|
||||
|
||||
cancel_delayed_work_sync(&cifs_sb->prune_tlinks);
|
||||
|
||||
if (cifs_sb->master_tlink) {
|
||||
tcon = cifs_sb->master_tlink->tl_tcon;
|
||||
if (tcon) {
|
||||
spin_lock(&tcon->sb_list_lock);
|
||||
list_del_init(&cifs_sb->tcon_sb_link);
|
||||
spin_unlock(&tcon->sb_list_lock);
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock(&cifs_sb->tlink_tree_lock);
|
||||
while ((node = rb_first(root))) {
|
||||
tlink = rb_entry(node, struct tcon_link, tl_rbnode);
|
||||
@ -4078,11 +4202,13 @@ int
|
||||
cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,
|
||||
struct TCP_Server_Info *server)
|
||||
{
|
||||
bool in_retry = false;
|
||||
int rc = 0;
|
||||
|
||||
if (!server->ops->need_neg || !server->ops->negotiate)
|
||||
return -ENOSYS;
|
||||
|
||||
retry:
|
||||
/* only send once per connect */
|
||||
spin_lock(&server->srv_lock);
|
||||
if (server->tcpStatus != CifsGood &&
|
||||
@ -4102,6 +4228,14 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,
|
||||
spin_unlock(&server->srv_lock);
|
||||
|
||||
rc = server->ops->negotiate(xid, ses, server);
|
||||
if (rc == -EAGAIN) {
|
||||
/* Allow one retry attempt */
|
||||
if (!in_retry) {
|
||||
in_retry = true;
|
||||
goto retry;
|
||||
}
|
||||
rc = -EHOSTDOWN;
|
||||
}
|
||||
if (rc == 0) {
|
||||
spin_lock(&server->srv_lock);
|
||||
if (server->tcpStatus == CifsInNegotiate)
|
||||
|
@ -135,6 +135,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = {
|
||||
fsparam_flag("witness", Opt_witness),
|
||||
fsparam_flag_no("nativesocket", Opt_nativesocket),
|
||||
fsparam_flag_no("unicode", Opt_unicode),
|
||||
fsparam_flag_no("nbsessinit", Opt_nbsessinit),
|
||||
|
||||
/* Mount options which take uid or gid */
|
||||
fsparam_uid("backupuid", Opt_backupuid),
|
||||
@ -968,6 +969,10 @@ static int smb3_verify_reconfigure_ctx(struct fs_context *fc,
|
||||
cifs_errorf(fc, "can not change unicode during remount\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (new_ctx->rfc1001_sessinit != old_ctx->rfc1001_sessinit) {
|
||||
cifs_errorf(fc, "can not change nbsessinit during remount\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1333,6 +1338,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
|
||||
case Opt_rsize:
|
||||
ctx->rsize = result.uint_32;
|
||||
ctx->got_rsize = true;
|
||||
ctx->vol_rsize = ctx->rsize;
|
||||
break;
|
||||
case Opt_wsize:
|
||||
ctx->wsize = result.uint_32;
|
||||
@ -1348,6 +1354,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
|
||||
ctx->wsize, PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
ctx->vol_wsize = ctx->wsize;
|
||||
break;
|
||||
case Opt_acregmax:
|
||||
if (result.uint_32 > CIFS_MAX_ACTIMEO / HZ) {
|
||||
@ -1383,6 +1390,11 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
|
||||
ctx->closetimeo = HZ * result.uint_32;
|
||||
break;
|
||||
case Opt_echo_interval:
|
||||
if (result.uint_32 < SMB_ECHO_INTERVAL_MIN ||
|
||||
result.uint_32 > SMB_ECHO_INTERVAL_MAX) {
|
||||
cifs_errorf(fc, "echo interval is out of bounds\n");
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
ctx->echo_interval = result.uint_32;
|
||||
break;
|
||||
case Opt_snapshot:
|
||||
@ -1602,6 +1614,10 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
|
||||
if (i == RFC1001_NAME_LEN && param->string[i] != 0)
|
||||
pr_warn("server netbiosname longer than 15 truncated\n");
|
||||
break;
|
||||
case Opt_nbsessinit:
|
||||
ctx->rfc1001_sessinit = !result.negated;
|
||||
cifs_dbg(FYI, "rfc1001_sessinit set to %d\n", ctx->rfc1001_sessinit);
|
||||
break;
|
||||
case Opt_ver:
|
||||
/* version of mount userspace tools, not dialect */
|
||||
/* If interface changes in mount.cifs bump to new ver */
|
||||
@ -1889,13 +1905,16 @@ int smb3_init_fs_context(struct fs_context *fc)
|
||||
memset(ctx->source_rfc1001_name, 0x20, RFC1001_NAME_LEN);
|
||||
for (i = 0; i < strnlen(nodename, RFC1001_NAME_LEN); i++)
|
||||
ctx->source_rfc1001_name[i] = toupper(nodename[i]);
|
||||
|
||||
ctx->source_rfc1001_name[RFC1001_NAME_LEN] = 0;
|
||||
|
||||
/*
|
||||
* null target name indicates to use *SMBSERVR default called name
|
||||
* if we end up sending RFC1001 session initialize
|
||||
*/
|
||||
ctx->target_rfc1001_name[0] = 0;
|
||||
|
||||
ctx->rfc1001_sessinit = -1; /* autodetect based on port number */
|
||||
|
||||
ctx->cred_uid = current_uid();
|
||||
ctx->linux_uid = current_uid();
|
||||
ctx->linux_gid = current_gid();
|
||||
|
@ -174,6 +174,7 @@ enum cifs_param {
|
||||
Opt_iocharset,
|
||||
Opt_netbiosname,
|
||||
Opt_servern,
|
||||
Opt_nbsessinit,
|
||||
Opt_ver,
|
||||
Opt_vers,
|
||||
Opt_sec,
|
||||
@ -216,6 +217,7 @@ struct smb3_fs_context {
|
||||
char *iocharset; /* local code page for mapping to and from Unicode */
|
||||
char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */
|
||||
char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */
|
||||
int rfc1001_sessinit;
|
||||
kuid_t cred_uid;
|
||||
kuid_t linux_uid;
|
||||
kgid_t linux_gid;
|
||||
@ -280,6 +282,9 @@ struct smb3_fs_context {
|
||||
bool use_client_guid:1;
|
||||
/* reuse existing guid for multichannel */
|
||||
u8 client_guid[SMB2_CLIENT_GUID_SIZE];
|
||||
/* User-specified original r/wsize value */
|
||||
unsigned int vol_rsize;
|
||||
unsigned int vol_wsize;
|
||||
unsigned int bsize;
|
||||
unsigned int rasize;
|
||||
unsigned int rsize;
|
||||
|
@ -2901,23 +2901,6 @@ int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int cifs_truncate_page(struct address_space *mapping, loff_t from)
|
||||
{
|
||||
pgoff_t index = from >> PAGE_SHIFT;
|
||||
unsigned offset = from & (PAGE_SIZE - 1);
|
||||
struct page *page;
|
||||
int rc = 0;
|
||||
|
||||
page = grab_cache_page(mapping, index);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
zero_user_segment(page, offset, PAGE_SIZE);
|
||||
unlock_page(page);
|
||||
put_page(page);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void cifs_setsize(struct inode *inode, loff_t offset)
|
||||
{
|
||||
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
|
||||
@ -3012,8 +2995,6 @@ set_size_out:
|
||||
*/
|
||||
attrs->ia_ctime = attrs->ia_mtime = current_time(inode);
|
||||
attrs->ia_valid |= ATTR_CTIME | ATTR_MTIME;
|
||||
|
||||
cifs_truncate_page(inode->i_mapping, inode->i_size);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
@ -258,7 +258,7 @@ cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_open_parms oparms;
|
||||
struct cifs_io_parms io_parms = {0};
|
||||
int buf_type = CIFS_NO_BUFFER;
|
||||
FILE_ALL_INFO file_info;
|
||||
struct cifs_open_info_data query_data;
|
||||
|
||||
oparms = (struct cifs_open_parms) {
|
||||
.tcon = tcon,
|
||||
@ -270,11 +270,11 @@ cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
|
||||
.fid = &fid,
|
||||
};
|
||||
|
||||
rc = CIFS_open(xid, &oparms, &oplock, &file_info);
|
||||
rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, &query_data);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
|
||||
if (query_data.fi.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
|
||||
rc = -ENOENT;
|
||||
/* it's not a symlink */
|
||||
goto out;
|
||||
@ -313,7 +313,7 @@ cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
|
||||
.fid = &fid,
|
||||
};
|
||||
|
||||
rc = CIFS_open(xid, &oparms, &oplock, NULL);
|
||||
rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
@ -137,8 +137,10 @@ tcon_info_alloc(bool dir_leases_enabled, enum smb3_tcon_ref_trace trace)
|
||||
spin_lock_init(&ret_buf->tc_lock);
|
||||
INIT_LIST_HEAD(&ret_buf->openFileList);
|
||||
INIT_LIST_HEAD(&ret_buf->tcon_list);
|
||||
INIT_LIST_HEAD(&ret_buf->cifs_sb_list);
|
||||
spin_lock_init(&ret_buf->open_file_lock);
|
||||
spin_lock_init(&ret_buf->stat_lock);
|
||||
spin_lock_init(&ret_buf->sb_list_lock);
|
||||
atomic_set(&ret_buf->num_local_opens, 0);
|
||||
atomic_set(&ret_buf->num_remote_opens, 0);
|
||||
ret_buf->stats_from_time = ktime_get_real_seconds();
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "cifspdu.h"
|
||||
#include "cifs_unicode.h"
|
||||
#include "fs_context.h"
|
||||
#include "nterr.h"
|
||||
#include "smberr.h"
|
||||
|
||||
/*
|
||||
* An NT cancel request header looks just like the original request except:
|
||||
@ -426,13 +428,6 @@ cifs_negotiate(const unsigned int xid,
|
||||
{
|
||||
int rc;
|
||||
rc = CIFSSMBNegotiate(xid, ses, server);
|
||||
if (rc == -EAGAIN) {
|
||||
/* retry only once on 1st time connection */
|
||||
set_credits(server, 1);
|
||||
rc = CIFSSMBNegotiate(xid, ses, server);
|
||||
if (rc == -EAGAIN)
|
||||
rc = -EHOSTDOWN;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -444,8 +439,8 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
|
||||
unsigned int wsize;
|
||||
|
||||
/* start with specified wsize, or default */
|
||||
if (ctx->wsize)
|
||||
wsize = ctx->wsize;
|
||||
if (ctx->got_wsize)
|
||||
wsize = ctx->vol_wsize;
|
||||
else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
|
||||
wsize = CIFS_DEFAULT_IOSIZE;
|
||||
else
|
||||
@ -497,7 +492,7 @@ cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
|
||||
else
|
||||
defsize = server->maxBuf - sizeof(READ_RSP);
|
||||
|
||||
rsize = ctx->rsize ? ctx->rsize : defsize;
|
||||
rsize = ctx->got_rsize ? ctx->vol_rsize : defsize;
|
||||
|
||||
/*
|
||||
* no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to
|
||||
@ -1069,6 +1064,47 @@ cifs_make_node(unsigned int xid, struct inode *inode,
|
||||
full_path, mode, dev);
|
||||
}
|
||||
|
||||
static bool
|
||||
cifs_is_network_name_deleted(char *buf, struct TCP_Server_Info *server)
|
||||
{
|
||||
struct smb_hdr *shdr = (struct smb_hdr *)buf;
|
||||
struct TCP_Server_Info *pserver;
|
||||
struct cifs_ses *ses;
|
||||
struct cifs_tcon *tcon;
|
||||
|
||||
if (shdr->Flags2 & SMBFLG2_ERR_STATUS) {
|
||||
if (shdr->Status.CifsError != cpu_to_le32(NT_STATUS_NETWORK_NAME_DELETED))
|
||||
return false;
|
||||
} else {
|
||||
if (shdr->Status.DosError.ErrorClass != ERRSRV ||
|
||||
shdr->Status.DosError.Error != cpu_to_le16(ERRinvtid))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If server is a channel, select the primary channel */
|
||||
pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
|
||||
if (cifs_ses_exiting(ses))
|
||||
continue;
|
||||
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
|
||||
if (tcon->tid == shdr->Tid) {
|
||||
spin_lock(&tcon->tc_lock);
|
||||
tcon->need_reconnect = true;
|
||||
spin_unlock(&tcon->tc_lock);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
pr_warn_once("Server share %s deleted.\n",
|
||||
tcon->tree_name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct smb_version_operations smb1_operations = {
|
||||
.send_cancel = send_nt_cancel,
|
||||
.compare_fids = cifs_compare_fids,
|
||||
@ -1153,6 +1189,7 @@ struct smb_version_operations smb1_operations = {
|
||||
.get_acl_by_fid = get_cifs_acl_by_fid,
|
||||
.set_acl = set_cifs_acl,
|
||||
.make_node = cifs_make_node,
|
||||
.is_network_name_deleted = cifs_is_network_name_deleted,
|
||||
};
|
||||
|
||||
struct smb_version_values smb1_values = {
|
||||
|
@ -152,16 +152,35 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32
|
||||
int err_buftype = CIFS_NO_BUFFER;
|
||||
struct cifs_fid *fid = oparms->fid;
|
||||
struct network_resiliency_req nr_ioctl_req;
|
||||
bool retry_without_read_attributes = false;
|
||||
|
||||
smb2_path = cifs_convert_path_to_utf16(oparms->path, oparms->cifs_sb);
|
||||
if (smb2_path == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
oparms->desired_access |= FILE_READ_ATTRIBUTES;
|
||||
/*
|
||||
* GENERIC_READ, GENERIC_EXECUTE, GENERIC_ALL and MAXIMUM_ALLOWED
|
||||
* contains also FILE_READ_ATTRIBUTES access right. So do not append
|
||||
* FILE_READ_ATTRIBUTES when not needed and prevent calling code path
|
||||
* for retry_without_read_attributes.
|
||||
*/
|
||||
if (!(oparms->desired_access & FILE_READ_ATTRIBUTES) &&
|
||||
!(oparms->desired_access & GENERIC_READ) &&
|
||||
!(oparms->desired_access & GENERIC_EXECUTE) &&
|
||||
!(oparms->desired_access & GENERIC_ALL) &&
|
||||
!(oparms->desired_access & MAXIMUM_ALLOWED)) {
|
||||
oparms->desired_access |= FILE_READ_ATTRIBUTES;
|
||||
retry_without_read_attributes = true;
|
||||
}
|
||||
smb2_oplock = SMB2_OPLOCK_LEVEL_BATCH;
|
||||
|
||||
rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov,
|
||||
&err_buftype);
|
||||
if (rc == -EACCES && retry_without_read_attributes) {
|
||||
oparms->desired_access &= ~FILE_READ_ATTRIBUTES;
|
||||
rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov,
|
||||
&err_buftype);
|
||||
}
|
||||
if (rc && data) {
|
||||
struct smb2_hdr *hdr = err_iov.iov_base;
|
||||
|
||||
|
@ -38,6 +38,7 @@ enum smb2_compound_ops {
|
||||
SMB2_OP_SET_REPARSE,
|
||||
SMB2_OP_GET_REPARSE,
|
||||
SMB2_OP_QUERY_WSL_EA,
|
||||
SMB2_OP_OPEN_QUERY,
|
||||
};
|
||||
|
||||
/* Used when constructing chained read requests. */
|
||||
|
@ -176,6 +176,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct kvec *out_iov, int *out_buftype, struct dentry *dentry)
|
||||
{
|
||||
|
||||
struct smb2_create_rsp *create_rsp = NULL;
|
||||
struct smb2_query_info_rsp *qi_rsp = NULL;
|
||||
struct smb2_compound_vars *vars = NULL;
|
||||
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
@ -265,7 +266,13 @@ replay_again:
|
||||
num_rqst++;
|
||||
rc = 0;
|
||||
|
||||
for (i = 0; i < num_cmds; i++) {
|
||||
i = 0;
|
||||
|
||||
/* Skip the leading explicit OPEN operation */
|
||||
if (num_cmds > 0 && cmds[0] == SMB2_OP_OPEN_QUERY)
|
||||
i++;
|
||||
|
||||
for (; i < num_cmds; i++) {
|
||||
/* Operation */
|
||||
switch (cmds[i]) {
|
||||
case SMB2_OP_QUERY_INFO:
|
||||
@ -640,6 +647,27 @@ finished:
|
||||
}
|
||||
|
||||
tmp_rc = rc;
|
||||
|
||||
if (rc == 0 && num_cmds > 0 && cmds[0] == SMB2_OP_OPEN_QUERY) {
|
||||
create_rsp = rsp_iov[0].iov_base;
|
||||
idata = in_iov[0].iov_base;
|
||||
idata->fi.CreationTime = create_rsp->CreationTime;
|
||||
idata->fi.LastAccessTime = create_rsp->LastAccessTime;
|
||||
idata->fi.LastWriteTime = create_rsp->LastWriteTime;
|
||||
idata->fi.ChangeTime = create_rsp->ChangeTime;
|
||||
idata->fi.Attributes = create_rsp->FileAttributes;
|
||||
idata->fi.AllocationSize = create_rsp->AllocationSize;
|
||||
idata->fi.EndOfFile = create_rsp->EndofFile;
|
||||
if (le32_to_cpu(idata->fi.NumberOfLinks) == 0)
|
||||
idata->fi.NumberOfLinks = cpu_to_le32(1); /* dummy value */
|
||||
idata->fi.DeletePending = 0;
|
||||
idata->fi.Directory = !!(le32_to_cpu(create_rsp->FileAttributes) & ATTR_DIRECTORY);
|
||||
|
||||
/* smb2_parse_contexts() fills idata->fi.IndexNumber */
|
||||
rc = smb2_parse_contexts(server, &rsp_iov[0], &oparms->fid->epoch,
|
||||
oparms->fid->lease_key, &oplock, &idata->fi, NULL);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_cmds; i++) {
|
||||
char *buf = rsp_iov[i + i].iov_base;
|
||||
|
||||
@ -978,6 +1006,43 @@ int smb2_query_path_info(const unsigned int xid,
|
||||
case 0:
|
||||
rc = parse_create_response(data, cifs_sb, full_path, &out_iov[0]);
|
||||
break;
|
||||
case -EACCES:
|
||||
/*
|
||||
* If SMB2_OP_QUERY_INFO (called when POSIX extensions are not used) failed with
|
||||
* STATUS_ACCESS_DENIED then it means that caller does not have permission to
|
||||
* open the path with FILE_READ_ATTRIBUTES access and therefore cannot issue
|
||||
* SMB2_OP_QUERY_INFO command.
|
||||
*
|
||||
* There is an alternative way how to query limited information about path but still
|
||||
* suitable for stat() syscall. SMB2 OPEN/CREATE operation returns in its successful
|
||||
* response subset of query information.
|
||||
*
|
||||
* So try to open the path without FILE_READ_ATTRIBUTES but with MAXIMUM_ALLOWED
|
||||
* access which will grant the maximum possible access to the file and the response
|
||||
* will contain required query information for stat() syscall.
|
||||
*/
|
||||
|
||||
if (tcon->posix_extensions)
|
||||
break;
|
||||
|
||||
num_cmds = 1;
|
||||
cmds[0] = SMB2_OP_OPEN_QUERY;
|
||||
in_iov[0].iov_base = data;
|
||||
in_iov[0].iov_len = sizeof(*data);
|
||||
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, MAXIMUM_ALLOWED,
|
||||
FILE_OPEN, create_options, ACL_NO_MODE);
|
||||
free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov));
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
&oparms, in_iov, cmds, num_cmds,
|
||||
cfile, out_iov, out_buftype, NULL);
|
||||
|
||||
hdr = out_iov[0].iov_base;
|
||||
if (!hdr || out_buftype[0] == CIFS_NO_BUFFER)
|
||||
goto out;
|
||||
|
||||
if (!rc)
|
||||
rc = parse_create_response(data, cifs_sb, full_path, &out_iov[0]);
|
||||
break;
|
||||
case -EOPNOTSUPP:
|
||||
/*
|
||||
* BB TODO: When support for special files added to Samba
|
||||
|
@ -464,12 +464,20 @@ smb2_negotiate(const unsigned int xid,
|
||||
server->CurrentMid = 0;
|
||||
spin_unlock(&server->mid_lock);
|
||||
rc = SMB2_negotiate(xid, ses, server);
|
||||
/* BB we probably don't need to retry with modern servers */
|
||||
if (rc == -EAGAIN)
|
||||
rc = -EHOSTDOWN;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
prevent_zero_iosize(unsigned int size, const char *type)
|
||||
{
|
||||
if (size == 0) {
|
||||
cifs_dbg(VFS, "SMB: Zero %ssize calculated, using minimum value %u\n",
|
||||
type, CIFS_MIN_DEFAULT_IOSIZE);
|
||||
return CIFS_MIN_DEFAULT_IOSIZE;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
|
||||
{
|
||||
@ -477,12 +485,12 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
|
||||
unsigned int wsize;
|
||||
|
||||
/* start with specified wsize, or default */
|
||||
wsize = ctx->wsize ? ctx->wsize : CIFS_DEFAULT_IOSIZE;
|
||||
wsize = ctx->got_wsize ? ctx->vol_wsize : CIFS_DEFAULT_IOSIZE;
|
||||
wsize = min_t(unsigned int, wsize, server->max_write);
|
||||
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
|
||||
wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE);
|
||||
|
||||
return wsize;
|
||||
return prevent_zero_iosize(wsize, "w");
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
@ -492,7 +500,7 @@ smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
|
||||
unsigned int wsize;
|
||||
|
||||
/* start with specified wsize, or default */
|
||||
wsize = ctx->wsize ? ctx->wsize : SMB3_DEFAULT_IOSIZE;
|
||||
wsize = ctx->got_wsize ? ctx->vol_wsize : SMB3_DEFAULT_IOSIZE;
|
||||
wsize = min_t(unsigned int, wsize, server->max_write);
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
if (server->rdma) {
|
||||
@ -514,7 +522,7 @@ smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
|
||||
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
|
||||
wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE);
|
||||
|
||||
return wsize;
|
||||
return prevent_zero_iosize(wsize, "w");
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
@ -524,13 +532,13 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
|
||||
unsigned int rsize;
|
||||
|
||||
/* start with specified rsize, or default */
|
||||
rsize = ctx->rsize ? ctx->rsize : CIFS_DEFAULT_IOSIZE;
|
||||
rsize = ctx->got_rsize ? ctx->vol_rsize : CIFS_DEFAULT_IOSIZE;
|
||||
rsize = min_t(unsigned int, rsize, server->max_read);
|
||||
|
||||
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
|
||||
rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE);
|
||||
|
||||
return rsize;
|
||||
return prevent_zero_iosize(rsize, "r");
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
@ -540,7 +548,7 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
|
||||
unsigned int rsize;
|
||||
|
||||
/* start with specified rsize, or default */
|
||||
rsize = ctx->rsize ? ctx->rsize : SMB3_DEFAULT_IOSIZE;
|
||||
rsize = ctx->got_rsize ? ctx->vol_rsize : SMB3_DEFAULT_IOSIZE;
|
||||
rsize = min_t(unsigned int, rsize, server->max_read);
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
if (server->rdma) {
|
||||
@ -563,7 +571,7 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
|
||||
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
|
||||
rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE);
|
||||
|
||||
return rsize;
|
||||
return prevent_zero_iosize(rsize, "r");
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3526,8 +3534,6 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
|
||||
if (rc == 0) {
|
||||
netfs_resize_file(&cifsi->netfs, new_eof, true);
|
||||
cifs_setsize(inode, new_eof);
|
||||
cifs_truncate_page(inode->i_mapping, inode->i_size);
|
||||
truncate_setsize(inode, new_eof);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
@ -43,6 +43,7 @@
|
||||
#endif
|
||||
#include "cached_dir.h"
|
||||
#include "compress.h"
|
||||
#include "fs_context.h"
|
||||
|
||||
/*
|
||||
* The following table defines the expected "StructureSize" of SMB2 requests
|
||||
@ -4089,6 +4090,24 @@ smb2_echo_callback(struct mid_q_entry *mid)
|
||||
add_credits(server, &credits, CIFS_ECHO_OP);
|
||||
}
|
||||
|
||||
static void cifs_renegotiate_iosize(struct TCP_Server_Info *server,
|
||||
struct cifs_tcon *tcon)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
|
||||
if (server == NULL || tcon == NULL)
|
||||
return;
|
||||
|
||||
spin_lock(&tcon->sb_list_lock);
|
||||
list_for_each_entry(cifs_sb, &tcon->cifs_sb_list, tcon_sb_link) {
|
||||
cifs_sb->ctx->rsize =
|
||||
server->ops->negotiate_rsize(tcon, cifs_sb->ctx);
|
||||
cifs_sb->ctx->wsize =
|
||||
server->ops->negotiate_wsize(tcon, cifs_sb->ctx);
|
||||
}
|
||||
spin_unlock(&tcon->sb_list_lock);
|
||||
}
|
||||
|
||||
void smb2_reconnect_server(struct work_struct *work)
|
||||
{
|
||||
struct TCP_Server_Info *server = container_of(work,
|
||||
@ -4174,9 +4193,10 @@ void smb2_reconnect_server(struct work_struct *work)
|
||||
|
||||
list_for_each_entry_safe(tcon, tcon2, &tmp_list, rlist) {
|
||||
rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server, true);
|
||||
if (!rc)
|
||||
if (!rc) {
|
||||
cifs_renegotiate_iosize(server, tcon);
|
||||
cifs_reopen_persistent_handles(tcon);
|
||||
else
|
||||
} else
|
||||
resched = true;
|
||||
list_del_init(&tcon->rlist);
|
||||
if (tcon->ipc)
|
||||
|
@ -894,6 +894,9 @@ cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
|
||||
case MID_SHUTDOWN:
|
||||
rc = -EHOSTDOWN;
|
||||
break;
|
||||
case MID_RC:
|
||||
rc = mid->mid_rc;
|
||||
break;
|
||||
default:
|
||||
if (!(mid->mid_flags & MID_DELETED)) {
|
||||
list_del_init(&mid->qhead);
|
||||
|
@ -31,6 +31,8 @@
|
||||
* secure, replaced by SMB2 (then even more highly secure SMB3) many years ago
|
||||
*/
|
||||
#define SMB3_XATTR_CIFS_ACL "system.smb3_acl" /* DACL only */
|
||||
#define SMB3_XATTR_CIFS_NTSD_SACL "system.smb3_ntsd_sacl" /* SACL only */
|
||||
#define SMB3_XATTR_CIFS_NTSD_OWNER "system.smb3_ntsd_owner" /* owner only */
|
||||
#define SMB3_XATTR_CIFS_NTSD "system.smb3_ntsd" /* owner plus DACL */
|
||||
#define SMB3_XATTR_CIFS_NTSD_FULL "system.smb3_ntsd_full" /* owner/DACL/SACL */
|
||||
#define SMB3_XATTR_ATTRIB "smb3.dosattrib" /* full name: user.smb3.dosattrib */
|
||||
@ -38,6 +40,7 @@
|
||||
/* BB need to add server (Samba e.g) support for security and trusted prefix */
|
||||
|
||||
enum { XATTR_USER, XATTR_CIFS_ACL, XATTR_ACL_ACCESS, XATTR_ACL_DEFAULT,
|
||||
XATTR_CIFS_NTSD_SACL, XATTR_CIFS_NTSD_OWNER,
|
||||
XATTR_CIFS_NTSD, XATTR_CIFS_NTSD_FULL };
|
||||
|
||||
static int cifs_attrib_set(unsigned int xid, struct cifs_tcon *pTcon,
|
||||
@ -160,6 +163,8 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
|
||||
break;
|
||||
|
||||
case XATTR_CIFS_ACL:
|
||||
case XATTR_CIFS_NTSD_SACL:
|
||||
case XATTR_CIFS_NTSD_OWNER:
|
||||
case XATTR_CIFS_NTSD:
|
||||
case XATTR_CIFS_NTSD_FULL: {
|
||||
struct smb_ntsd *pacl;
|
||||
@ -187,6 +192,13 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
|
||||
CIFS_ACL_GROUP |
|
||||
CIFS_ACL_DACL);
|
||||
break;
|
||||
case XATTR_CIFS_NTSD_OWNER:
|
||||
aclflags = (CIFS_ACL_OWNER |
|
||||
CIFS_ACL_GROUP);
|
||||
break;
|
||||
case XATTR_CIFS_NTSD_SACL:
|
||||
aclflags = CIFS_ACL_SACL;
|
||||
break;
|
||||
case XATTR_CIFS_ACL:
|
||||
default:
|
||||
aclflags = CIFS_ACL_DACL;
|
||||
@ -308,6 +320,8 @@ static int cifs_xattr_get(const struct xattr_handler *handler,
|
||||
break;
|
||||
|
||||
case XATTR_CIFS_ACL:
|
||||
case XATTR_CIFS_NTSD_SACL:
|
||||
case XATTR_CIFS_NTSD_OWNER:
|
||||
case XATTR_CIFS_NTSD:
|
||||
case XATTR_CIFS_NTSD_FULL: {
|
||||
/*
|
||||
@ -327,6 +341,12 @@ static int cifs_xattr_get(const struct xattr_handler *handler,
|
||||
case XATTR_CIFS_NTSD:
|
||||
extra_info = OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO;
|
||||
break;
|
||||
case XATTR_CIFS_NTSD_OWNER:
|
||||
extra_info = OWNER_SECINFO | GROUP_SECINFO;
|
||||
break;
|
||||
case XATTR_CIFS_NTSD_SACL:
|
||||
extra_info = SACL_SECINFO;
|
||||
break;
|
||||
case XATTR_CIFS_ACL:
|
||||
default:
|
||||
extra_info = DACL_SECINFO;
|
||||
@ -448,6 +468,20 @@ static const struct xattr_handler smb3_acl_xattr_handler = {
|
||||
.set = cifs_xattr_set,
|
||||
};
|
||||
|
||||
static const struct xattr_handler smb3_ntsd_sacl_xattr_handler = {
|
||||
.name = SMB3_XATTR_CIFS_NTSD_SACL,
|
||||
.flags = XATTR_CIFS_NTSD_SACL,
|
||||
.get = cifs_xattr_get,
|
||||
.set = cifs_xattr_set,
|
||||
};
|
||||
|
||||
static const struct xattr_handler smb3_ntsd_owner_xattr_handler = {
|
||||
.name = SMB3_XATTR_CIFS_NTSD_OWNER,
|
||||
.flags = XATTR_CIFS_NTSD_OWNER,
|
||||
.get = cifs_xattr_get,
|
||||
.set = cifs_xattr_set,
|
||||
};
|
||||
|
||||
static const struct xattr_handler cifs_cifs_ntsd_xattr_handler = {
|
||||
.name = CIFS_XATTR_CIFS_NTSD,
|
||||
.flags = XATTR_CIFS_NTSD,
|
||||
@ -493,6 +527,8 @@ const struct xattr_handler * const cifs_xattr_handlers[] = {
|
||||
&cifs_os2_xattr_handler,
|
||||
&cifs_cifs_acl_xattr_handler,
|
||||
&smb3_acl_xattr_handler, /* alias for above since avoiding "cifs" */
|
||||
&smb3_ntsd_sacl_xattr_handler,
|
||||
&smb3_ntsd_owner_xattr_handler,
|
||||
&cifs_cifs_ntsd_xattr_handler,
|
||||
&smb3_ntsd_xattr_handler, /* alias for above since avoiding "cifs" */
|
||||
&cifs_cifs_ntsd_full_xattr_handler,
|
||||
|
@ -95,6 +95,9 @@
|
||||
*/
|
||||
#define SMB3_DEFAULT_IOSIZE (4 * 1024 * 1024)
|
||||
|
||||
/* According to MS-SMB2 specification The minimum recommended value is 65536.*/
|
||||
#define CIFS_MIN_DEFAULT_IOSIZE (65536)
|
||||
|
||||
/*
|
||||
* SMB2 Header Definition
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user