Commit f0aec17d authored by Pavel Shilovsky's avatar Pavel Shilovsky

Update 4.1 sources from stable (v4.1.27)

parent d5b88c2b
...@@ -50,7 +50,7 @@ void cifs_vfs_err(const char *fmt, ...) ...@@ -50,7 +50,7 @@ void cifs_vfs_err(const char *fmt, ...)
vaf.fmt = fmt; vaf.fmt = fmt;
vaf.va = &args; vaf.va = &args;
pr_err("CIFS VFS: %pV", &vaf); pr_err_ratelimited("CIFS VFS: %pV", &vaf);
va_end(args); va_end(args);
} }
......
...@@ -51,14 +51,13 @@ __printf(1, 2) void cifs_vfs_err(const char *fmt, ...); ...@@ -51,14 +51,13 @@ __printf(1, 2) void cifs_vfs_err(const char *fmt, ...);
/* information message: e.g., configuration, major event */ /* information message: e.g., configuration, major event */
#define cifs_dbg(type, fmt, ...) \ #define cifs_dbg(type, fmt, ...) \
do { \ do { \
if (type == FYI) { \ if (type == FYI && cifsFYI & CIFS_INFO) { \
if (cifsFYI & CIFS_INFO) { \ pr_debug_ratelimited("%s: " \
pr_debug("%s: " fmt, __FILE__, ##__VA_ARGS__); \ fmt, __FILE__, ##__VA_ARGS__); \
} \
} else if (type == VFS) { \ } else if (type == VFS) { \
cifs_vfs_err(fmt, ##__VA_ARGS__); \ cifs_vfs_err(fmt, ##__VA_ARGS__); \
} else if (type == NOISY && type != 0) { \ } else if (type == NOISY && type != 0) { \
pr_debug(fmt, ##__VA_ARGS__); \ pr_debug_ratelimited(fmt, ##__VA_ARGS__); \
} \ } \
} while (0) } while (0)
......
...@@ -24,10 +24,13 @@ ...@@ -24,10 +24,13 @@
#include <linux/string.h> #include <linux/string.h>
#include <keys/user-type.h> #include <keys/user-type.h>
#include <linux/key-type.h> #include <linux/key-type.h>
#include <linux/keyctl.h>
#include <linux/inet.h> #include <linux/inet.h>
#include "cifsglob.h" #include "cifsglob.h"
#include "cifs_spnego.h" #include "cifs_spnego.h"
#include "cifs_debug.h" #include "cifs_debug.h"
#include "cifsproto.h"
static const struct cred *spnego_cred;
/* create a new cifs key */ /* create a new cifs key */
static int static int
...@@ -102,6 +105,7 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo) ...@@ -102,6 +105,7 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo)
size_t desc_len; size_t desc_len;
struct key *spnego_key; struct key *spnego_key;
const char *hostname = server->hostname; const char *hostname = server->hostname;
const struct cred *saved_cred;
/* length of fields (with semicolons): ver=0xyz ip4=ipaddress /* length of fields (with semicolons): ver=0xyz ip4=ipaddress
host=hostname sec=mechanism uid=0xFF user=username */ host=hostname sec=mechanism uid=0xFF user=username */
...@@ -163,7 +167,9 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo) ...@@ -163,7 +167,9 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo)
sprintf(dp, ";pid=0x%x", current->pid); sprintf(dp, ";pid=0x%x", current->pid);
cifs_dbg(FYI, "key description = %s\n", description); cifs_dbg(FYI, "key description = %s\n", description);
saved_cred = override_creds(spnego_cred);
spnego_key = request_key(&cifs_spnego_key_type, description, ""); spnego_key = request_key(&cifs_spnego_key_type, description, "");
revert_creds(saved_cred);
#ifdef CONFIG_CIFS_DEBUG2 #ifdef CONFIG_CIFS_DEBUG2
if (cifsFYI && !IS_ERR(spnego_key)) { if (cifsFYI && !IS_ERR(spnego_key)) {
...@@ -177,3 +183,64 @@ out: ...@@ -177,3 +183,64 @@ out:
kfree(description); kfree(description);
return spnego_key; return spnego_key;
} }
int
init_cifs_spnego(void)
{
struct cred *cred;
struct key *keyring;
int ret;
cifs_dbg(FYI, "Registering the %s key type\n",
cifs_spnego_key_type.name);
/*
* Create an override credential set with special thread keyring for
* spnego upcalls.
*/
cred = prepare_kernel_cred(NULL);
if (!cred)
return -ENOMEM;
keyring = keyring_alloc(".cifs_spnego",
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ,
KEY_ALLOC_NOT_IN_QUOTA, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto failed_put_cred;
}
ret = register_key_type(&cifs_spnego_key_type);
if (ret < 0)
goto failed_put_key;
/*
* instruct request_key() to use this special keyring as a cache for
* the results it looks up
*/
set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
cred->thread_keyring = keyring;
cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
spnego_cred = cred;
cifs_dbg(FYI, "cifs spnego keyring: %d\n", key_serial(keyring));
return 0;
failed_put_key:
key_put(keyring);
failed_put_cred:
put_cred(cred);
return ret;
}
void
exit_cifs_spnego(void)
{
key_revoke(spnego_cred->thread_keyring);
unregister_key_type(&cifs_spnego_key_type);
put_cred(spnego_cred);
cifs_dbg(FYI, "Unregistered %s key type\n", cifs_spnego_key_type.name);
}
...@@ -714,7 +714,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -714,7 +714,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL); ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL);
if (!ses->auth_key.response) { if (!ses->auth_key.response) {
rc = ENOMEM; rc = -ENOMEM;
ses->auth_key.len = 0; ses->auth_key.len = 0;
goto setup_ntlmv2_rsp_ret; goto setup_ntlmv2_rsp_ret;
} }
......
...@@ -1241,7 +1241,7 @@ init_cifs(void) ...@@ -1241,7 +1241,7 @@ init_cifs(void)
goto out_destroy_mids; goto out_destroy_mids;
#ifdef CONFIG_CIFS_UPCALL #ifdef CONFIG_CIFS_UPCALL
rc = register_key_type(&cifs_spnego_key_type); rc = init_cifs_spnego();
if (rc) if (rc)
goto out_destroy_request_bufs; goto out_destroy_request_bufs;
#endif /* CONFIG_CIFS_UPCALL */ #endif /* CONFIG_CIFS_UPCALL */
...@@ -1264,7 +1264,7 @@ out_init_cifs_idmap: ...@@ -1264,7 +1264,7 @@ out_init_cifs_idmap:
out_register_key_type: out_register_key_type:
#endif #endif
#ifdef CONFIG_CIFS_UPCALL #ifdef CONFIG_CIFS_UPCALL
unregister_key_type(&cifs_spnego_key_type); exit_cifs_spnego();
out_destroy_request_bufs: out_destroy_request_bufs:
#endif #endif
cifs_destroy_request_bufs(); cifs_destroy_request_bufs();
......
...@@ -31,19 +31,15 @@ ...@@ -31,19 +31,15 @@
* so that it will fit. We use hash_64 to convert the value to 31 bits, and * so that it will fit. We use hash_64 to convert the value to 31 bits, and
* then add 1, to ensure that we don't end up with a 0 as the value. * then add 1, to ensure that we don't end up with a 0 as the value.
*/ */
#if BITS_PER_LONG == 64
static inline ino_t static inline ino_t
cifs_uniqueid_to_ino_t(u64 fileid) cifs_uniqueid_to_ino_t(u64 fileid)
{ {
if ((sizeof(ino_t)) < (sizeof(u64)))
return (ino_t)hash_64(fileid, (sizeof(ino_t) * 8) - 1) + 1;
return (ino_t)fileid; return (ino_t)fileid;
} }
#else
static inline ino_t
cifs_uniqueid_to_ino_t(u64 fileid)
{
return (ino_t)hash_64(fileid, (sizeof(ino_t) * 8) - 1) + 1;
}
#endif
extern struct file_system_type cifs_fs_type; extern struct file_system_type cifs_fs_type;
extern const struct address_space_operations cifs_addr_ops; extern const struct address_space_operations cifs_addr_ops;
......
...@@ -60,6 +60,8 @@ do { \ ...@@ -60,6 +60,8 @@ do { \
} while (0) } while (0)
extern int init_cifs_idmap(void); extern int init_cifs_idmap(void);
extern void exit_cifs_idmap(void); extern void exit_cifs_idmap(void);
extern int init_cifs_spnego(void);
extern void exit_cifs_spnego(void);
extern char *build_path_from_dentry(struct dentry *); extern char *build_path_from_dentry(struct dentry *);
extern char *cifs_build_path_to_root(struct smb_vol *vol, extern char *cifs_build_path_to_root(struct smb_vol *vol,
struct cifs_sb_info *cifs_sb, struct cifs_sb_info *cifs_sb,
......
...@@ -1402,11 +1402,10 @@ openRetry: ...@@ -1402,11 +1402,10 @@ openRetry:
* current bigbuf. * current bigbuf.
*/ */
static int static int
cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) discard_remaining_data(struct TCP_Server_Info *server)
{ {
unsigned int rfclen = get_rfc1002_length(server->smallbuf); unsigned int rfclen = get_rfc1002_length(server->smallbuf);
int remaining = rfclen + 4 - server->total_read; int remaining = rfclen + 4 - server->total_read;
struct cifs_readdata *rdata = mid->callback_data;
while (remaining > 0) { while (remaining > 0) {
int length; int length;
...@@ -1420,10 +1419,20 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) ...@@ -1420,10 +1419,20 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
remaining -= length; remaining -= length;
} }
dequeue_mid(mid, rdata->result);
return 0; return 0;
} }
static int
cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
int length;
struct cifs_readdata *rdata = mid->callback_data;
length = discard_remaining_data(server);
dequeue_mid(mid, rdata->result);
return length;
}
int int
cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{ {
...@@ -1452,6 +1461,12 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) ...@@ -1452,6 +1461,12 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
return length; return length;
server->total_read += length; server->total_read += length;
if (server->ops->is_status_pending &&
server->ops->is_status_pending(buf, server, 0)) {
discard_remaining_data(server);
return -1;
}
/* Was the SMB read successful? */ /* Was the SMB read successful? */
rdata->result = server->ops->map_error(buf, false); rdata->result = server->ops->map_error(buf, false);
if (rdata->result != 0) { if (rdata->result != 0) {
......
...@@ -358,7 +358,6 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -358,7 +358,6 @@ cifs_reconnect(struct TCP_Server_Info *server)
server->session_key.response = NULL; server->session_key.response = NULL;
server->session_key.len = 0; server->session_key.len = 0;
server->lstrp = jiffies; server->lstrp = jiffies;
mutex_unlock(&server->srv_mutex);
/* mark submitted MIDs for retry and issue callback */ /* mark submitted MIDs for retry and issue callback */
INIT_LIST_HEAD(&retry_list); INIT_LIST_HEAD(&retry_list);
...@@ -371,6 +370,7 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -371,6 +370,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
list_move(&mid_entry->qhead, &retry_list); list_move(&mid_entry->qhead, &retry_list);
} }
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
mutex_unlock(&server->srv_mutex);
cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__); cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__);
list_for_each_safe(tmp, tmp2, &retry_list) { list_for_each_safe(tmp, tmp2, &retry_list) {
......
...@@ -847,6 +847,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx) ...@@ -847,6 +847,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
* if buggy server returns . and .. late do we want to * if buggy server returns . and .. late do we want to
* check for that here? * check for that here?
*/ */
*tmp_buf = 0;
rc = cifs_filldir(current_entry, file, ctx, rc = cifs_filldir(current_entry, file, ctx,
tmp_buf, max_len); tmp_buf, max_len);
if (rc) { if (rc) {
......
...@@ -400,19 +400,27 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer, ...@@ -400,19 +400,27 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
sec_blob->LmChallengeResponse.MaximumLength = 0; sec_blob->LmChallengeResponse.MaximumLength = 0;
sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer);
rc = setup_ntlmv2_rsp(ses, nls_cp); if (ses->user_name != NULL) {
if (rc) { rc = setup_ntlmv2_rsp(ses, nls_cp);
cifs_dbg(VFS, "Error %d during NTLMSSP authentication\n", rc); if (rc) {
goto setup_ntlmv2_ret; cifs_dbg(VFS, "Error %d during NTLMSSP authentication\n", rc);
goto setup_ntlmv2_ret;
}
memcpy(tmp, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
ses->auth_key.len - CIFS_SESS_KEY_SIZE);
tmp += ses->auth_key.len - CIFS_SESS_KEY_SIZE;
sec_blob->NtChallengeResponse.Length =
cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE);
sec_blob->NtChallengeResponse.MaximumLength =
cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE);
} else {
/*
* don't send an NT Response for anonymous access
*/
sec_blob->NtChallengeResponse.Length = 0;
sec_blob->NtChallengeResponse.MaximumLength = 0;
} }
memcpy(tmp, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
ses->auth_key.len - CIFS_SESS_KEY_SIZE);
tmp += ses->auth_key.len - CIFS_SESS_KEY_SIZE;
sec_blob->NtChallengeResponse.Length =
cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE);
sec_blob->NtChallengeResponse.MaximumLength =
cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE);
if (ses->domainName == NULL) { if (ses->domainName == NULL) {
sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
...@@ -670,20 +678,24 @@ sess_auth_lanman(struct sess_data *sess_data) ...@@ -670,20 +678,24 @@ sess_auth_lanman(struct sess_data *sess_data)
pSMB->req.hdr.Flags2 &= ~SMBFLG2_UNICODE; pSMB->req.hdr.Flags2 &= ~SMBFLG2_UNICODE;
/* no capabilities flags in old lanman negotiation */ if (ses->user_name != NULL) {
pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE); /* no capabilities flags in old lanman negotiation */
pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE);
/* Calculate hash with password and copy into bcc_ptr.
* Encryption Key (stored as in cryptkey) gets used if the /* Calculate hash with password and copy into bcc_ptr.
* security mode bit in Negottiate Protocol response states * Encryption Key (stored as in cryptkey) gets used if the
* to use challenge/response method (i.e. Password bit is 1). * security mode bit in Negottiate Protocol response states
*/ * to use challenge/response method (i.e. Password bit is 1).
rc = calc_lanman_hash(ses->password, ses->server->cryptkey, */
ses->server->sec_mode & SECMODE_PW_ENCRYPT ? rc = calc_lanman_hash(ses->password, ses->server->cryptkey,
true : false, lnm_session_key); ses->server->sec_mode & SECMODE_PW_ENCRYPT ?
true : false, lnm_session_key);
memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_AUTH_RESP_SIZE);
bcc_ptr += CIFS_AUTH_RESP_SIZE; memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_AUTH_RESP_SIZE);
bcc_ptr += CIFS_AUTH_RESP_SIZE;
} else {
pSMB->old_req.PasswordLength = 0;
}
/* /*
* can not sign if LANMAN negotiated so no need * can not sign if LANMAN negotiated so no need
...@@ -769,26 +781,31 @@ sess_auth_ntlm(struct sess_data *sess_data) ...@@ -769,26 +781,31 @@ sess_auth_ntlm(struct sess_data *sess_data)
capabilities = cifs_ssetup_hdr(ses, pSMB); capabilities = cifs_ssetup_hdr(ses, pSMB);
pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
pSMB->req_no_secext.CaseInsensitivePasswordLength = if (ses->user_name != NULL) {
cpu_to_le16(CIFS_AUTH_RESP_SIZE); pSMB->req_no_secext.CaseInsensitivePasswordLength =
pSMB->req_no_secext.CaseSensitivePasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE);
cpu_to_le16(CIFS_AUTH_RESP_SIZE); pSMB->req_no_secext.CaseSensitivePasswordLength =
cpu_to_le16(CIFS_AUTH_RESP_SIZE);
/* calculate ntlm response and session key */
rc = setup_ntlm_response(ses, sess_data->nls_cp); /* calculate ntlm response and session key */
if (rc) { rc = setup_ntlm_response(ses, sess_data->nls_cp);
cifs_dbg(VFS, "Error %d during NTLM authentication\n", if (rc) {
rc); cifs_dbg(VFS, "Error %d during NTLM authentication\n",
goto out; rc);
} goto out;
}
/* copy ntlm response */ /* copy ntlm response */
memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
CIFS_AUTH_RESP_SIZE); CIFS_AUTH_RESP_SIZE);
bcc_ptr += CIFS_AUTH_RESP_SIZE; bcc_ptr += CIFS_AUTH_RESP_SIZE;
memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
CIFS_AUTH_RESP_SIZE); CIFS_AUTH_RESP_SIZE);
bcc_ptr += CIFS_AUTH_RESP_SIZE; bcc_ptr += CIFS_AUTH_RESP_SIZE;
} else {
pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
pSMB->req_no_secext.CaseSensitivePasswordLength = 0;
}
if (ses->capabilities & CAP_UNICODE) { if (ses->capabilities & CAP_UNICODE) {
/* unicode strings must be word aligned */ /* unicode strings must be word aligned */
...@@ -878,22 +895,26 @@ sess_auth_ntlmv2(struct sess_data *sess_data) ...@@ -878,22 +895,26 @@ sess_auth_ntlmv2(struct sess_data *sess_data)
/* LM2 password would be here if we supported it */ /* LM2 password would be here if we supported it */
pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
/* calculate nlmv2 response and session key */ if (ses->user_name != NULL) {
rc = setup_ntlmv2_rsp(ses, sess_data->nls_cp); /* calculate nlmv2 response and session key */
if (rc) { rc = setup_ntlmv2_rsp(ses, sess_data->nls_cp);
cifs_dbg(VFS, "Error %d during NTLMv2 authentication\n", rc); if (rc) {
goto out; cifs_dbg(VFS, "Error %d during NTLMv2 authentication\n", rc);
} goto out;
}
memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
ses->auth_key.len - CIFS_SESS_KEY_SIZE); ses->auth_key.len - CIFS_SESS_KEY_SIZE);
bcc_ptr += ses->auth_key.len - CIFS_SESS_KEY_SIZE; bcc_ptr += ses->auth_key.len - CIFS_SESS_KEY_SIZE;
/* set case sensitive password length after tilen may get /* set case sensitive password length after tilen may get
* assigned, tilen is 0 otherwise. * assigned, tilen is 0 otherwise.
*/ */
pSMB->req_no_secext.CaseSensitivePasswordLength = pSMB->req_no_secext.CaseSensitivePasswordLength =
cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE); cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE);
} else {
pSMB->req_no_secext.CaseSensitivePasswordLength = 0;
}
if (ses->capabilities & CAP_UNICODE) { if (ses->capabilities & CAP_UNICODE) {
if (sess_data->iov[0].iov_len % 2) { if (sess_data->iov[0].iov_len % 2) {
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#define SMB2_OP_DELETE 7 #define SMB2_OP_DELETE 7
#define SMB2_OP_HARDLINK 8 #define SMB2_OP_HARDLINK 8
#define SMB2_OP_SET_EOF 9 #define SMB2_OP_SET_EOF 9
#define SMB2_OP_RMDIR 10
/* Used when constructing chained read requests. */ /* Used when constructing chained read requests. */
#define CHAINED_REQUEST 1 #define CHAINED_REQUEST 1
......
...@@ -81,6 +81,10 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -81,6 +81,10 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
* SMB2_open() call. * SMB2_open() call.
*/ */
break; break;
case SMB2_OP_RMDIR:
tmprc = SMB2_rmdir(xid, tcon, fid.persistent_fid,
fid.volatile_fid);
break;
case SMB2_OP_RENAME: case SMB2_OP_RENAME:
tmprc = SMB2_rename(xid, tcon, fid.persistent_fid, tmprc = SMB2_rename(xid, tcon, fid.persistent_fid,
fid.volatile_fid, (__le16 *)data); fid.volatile_fid, (__le16 *)data);
...@@ -192,8 +196,8 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, ...@@ -192,8 +196,8 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
struct cifs_sb_info *cifs_sb) struct cifs_sb_info *cifs_sb)
{ {
return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
CREATE_NOT_FILE | CREATE_DELETE_ON_CLOSE, CREATE_NOT_FILE,
NULL, SMB2_OP_DELETE); NULL, SMB2_OP_RMDIR);
} }
int int
......
...@@ -1042,21 +1042,25 @@ parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp, ...@@ -1042,21 +1042,25 @@ parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp,
{ {
char *data_offset; char *data_offset;
struct create_context *cc; struct create_context *cc;
unsigned int next = 0; unsigned int next;
unsigned int remaining;
char *name; char *name;
data_offset = (char *)rsp + 4 + le32_to_cpu(rsp->CreateContextsOffset); data_offset = (char *)rsp + 4 + le32_to_cpu(rsp->CreateContextsOffset);
remaining = le32_to_cpu(rsp->CreateContextsLength);
cc = (struct create_context *)data_offset; cc = (struct create_context *)data_offset;
do { while (remaining >= sizeof(struct create_context)) {
cc = (struct create_context *)((char *)cc + next);
name = le16_to_cpu(cc->NameOffset) + (char *)cc; name = le16_to_cpu(cc->NameOffset) + (char *)cc;
if (le16_to_cpu(cc->NameLength) != 4 || if (le16_to_cpu(cc->NameLength) == 4 &&
strncmp(name, "RqLs", 4)) { strncmp(name, "RqLs", 4) == 0)
next = le32_to_cpu(cc->Next); return server->ops->parse_lease_buf(cc, epoch);
continue;
} next = le32_to_cpu(cc->Next);
return server->ops->parse_lease_buf(cc, epoch); if (!next)
} while (next != 0); break;
remaining -= next;
cc = (struct create_context *)((char *)cc + next);
}
return 0; return 0;
} }
...@@ -2380,6 +2384,22 @@ SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2380,6 +2384,22 @@ SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
} }
int int
SMB2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid)
{
__u8 delete_pending = 1;
void *data;
unsigned int size;
data = &delete_pending;
size = 1; /* sizeof __u8 */
return send_set_info(xid, tcon, persistent_fid, volatile_fid,
current->tgid, FILE_DISPOSITION_INFORMATION, 1, &data,
&size);
}
int
SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon, SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, __le16 *target_file) u64 persistent_fid, u64 volatile_fid, __le16 *target_file)
{ {
......
...@@ -140,6 +140,8 @@ extern int SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -140,6 +140,8 @@ extern int SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, u64 persistent_fid, u64 volatile_fid,
__le16 *target_file); __le16 *target_file);
extern int SMB2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid);
extern int SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, u64 persistent_fid, u64 volatile_fid,
__le16 *target_file); __le16 *target_file);
......
...@@ -576,14 +576,16 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, ...@@ -576,14 +576,16 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
cifs_in_send_dec(server); cifs_in_send_dec(server);
cifs_save_when_sent(mid); cifs_save_when_sent(mid);
if (rc < 0) if (rc < 0) {
server->sequence_number -= 2; server->sequence_number -= 2;
cifs_delete_mid(mid);
}
mutex_unlock(&server->srv_mutex); mutex_unlock(&server->srv_mutex);
if (rc == 0) if (rc == 0)
return 0; return 0;
cifs_delete_mid(mid);
add_credits_and_wake_if(server, credits, optype); add_credits_and_wake_if(server, credits, optype);
return rc; return rc;
} }
......
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