CIFS: Process oplocks for SMB2
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com> Signed-off-by: Steve French <smfrench@gmail.com>
This commit is contained in:
parent
d324f08d6a
commit
2e44b28878
|
@ -328,6 +328,8 @@ struct smb_version_operations {
|
||||||
struct cifs_fid *);
|
struct cifs_fid *);
|
||||||
/* calculate a size of SMB message */
|
/* calculate a size of SMB message */
|
||||||
unsigned int (*calc_smb_size)(void *);
|
unsigned int (*calc_smb_size)(void *);
|
||||||
|
/* check for STATUS_PENDING and process it in a positive case */
|
||||||
|
bool (*is_status_pending)(char *, struct TCP_Server_Info *, int);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct smb_version_values {
|
struct smb_version_values {
|
||||||
|
|
|
@ -819,6 +819,10 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||||
cifs_dump_mem("Bad SMB: ", buf,
|
cifs_dump_mem("Bad SMB: ", buf,
|
||||||
min_t(unsigned int, server->total_read, 48));
|
min_t(unsigned int, server->total_read, 48));
|
||||||
|
|
||||||
|
if (server->ops->is_status_pending &&
|
||||||
|
server->ops->is_status_pending(buf, server, length))
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (!mid)
|
if (!mid)
|
||||||
return length;
|
return length;
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,26 @@
|
||||||
#include "fscache.h"
|
#include "fscache.h"
|
||||||
#include "smb2proto.h"
|
#include "smb2proto.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
|
||||||
|
{
|
||||||
|
oplock &= 0xFF;
|
||||||
|
if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
|
||||||
|
cinode->clientCanCacheAll = true;
|
||||||
|
cinode->clientCanCacheRead = true;
|
||||||
|
cFYI(1, "Exclusive Oplock granted on inode %p",
|
||||||
|
&cinode->vfs_inode);
|
||||||
|
} else if (oplock == SMB2_OPLOCK_LEVEL_II) {
|
||||||
|
cinode->clientCanCacheAll = false;
|
||||||
|
cinode->clientCanCacheRead = true;
|
||||||
|
cFYI(1, "Level II Oplock granted on inode %p",
|
||||||
|
&cinode->vfs_inode);
|
||||||
|
} else {
|
||||||
|
cinode->clientCanCacheAll = false;
|
||||||
|
cinode->clientCanCacheRead = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
|
smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
|
||||||
int disposition, int desired_access, int create_options,
|
int disposition, int desired_access, int create_options,
|
||||||
|
@ -58,10 +78,11 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
|
||||||
}
|
}
|
||||||
|
|
||||||
desired_access |= FILE_READ_ATTRIBUTES;
|
desired_access |= FILE_READ_ATTRIBUTES;
|
||||||
|
*oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
|
||||||
|
|
||||||
rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid,
|
rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid,
|
||||||
&fid->volatile_fid, desired_access, disposition,
|
&fid->volatile_fid, desired_access, disposition,
|
||||||
0, 0, smb2_data);
|
0, 0, (__u8 *)oplock, smb2_data);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -79,7 +100,6 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
*oplock = 0;
|
|
||||||
kfree(smb2_data);
|
kfree(smb2_data);
|
||||||
kfree(smb2_path);
|
kfree(smb2_path);
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
@ -47,6 +47,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
int rc, tmprc = 0;
|
int rc, tmprc = 0;
|
||||||
u64 persistent_fid, volatile_fid;
|
u64 persistent_fid, volatile_fid;
|
||||||
__le16 *utf16_path;
|
__le16 *utf16_path;
|
||||||
|
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||||
|
|
||||||
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
||||||
if (!utf16_path)
|
if (!utf16_path)
|
||||||
|
@ -54,7 +55,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
|
|
||||||
rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
|
rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
|
||||||
desired_access, create_disposition, file_attributes,
|
desired_access, create_disposition, file_attributes,
|
||||||
create_options, NULL);
|
create_options, &oplock, NULL);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
kfree(utf16_path);
|
kfree(utf16_path);
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "smb2proto.h"
|
#include "smb2proto.h"
|
||||||
#include "cifsproto.h"
|
#include "cifsproto.h"
|
||||||
#include "cifs_debug.h"
|
#include "cifs_debug.h"
|
||||||
|
#include "smb2status.h"
|
||||||
|
|
||||||
static int
|
static int
|
||||||
change_conf(struct TCP_Server_Info *server)
|
change_conf(struct TCP_Server_Info *server)
|
||||||
|
@ -207,13 +208,14 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
int rc;
|
int rc;
|
||||||
__u64 persistent_fid, volatile_fid;
|
__u64 persistent_fid, volatile_fid;
|
||||||
__le16 *utf16_path;
|
__le16 *utf16_path;
|
||||||
|
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||||
|
|
||||||
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
||||||
if (!utf16_path)
|
if (!utf16_path)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
|
rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
|
||||||
FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, NULL);
|
FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, &oplock, NULL);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
kfree(utf16_path);
|
kfree(utf16_path);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -358,10 +360,10 @@ smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
|
||||||
static void
|
static void
|
||||||
smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
|
smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
|
||||||
{
|
{
|
||||||
/* struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); */
|
struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
|
||||||
cfile->fid.persistent_fid = fid->persistent_fid;
|
cfile->fid.persistent_fid = fid->persistent_fid;
|
||||||
cfile->fid.volatile_fid = fid->volatile_fid;
|
cfile->fid.volatile_fid = fid->volatile_fid;
|
||||||
/* cifs_set_oplock_level(cinode, oplock); */
|
smb2_set_oplock_level(cinode, oplock);
|
||||||
/* cinode->can_cache_brlcks = cinode->clientCanCacheAll; */
|
/* cinode->can_cache_brlcks = cinode->clientCanCacheAll; */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,6 +434,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
{
|
{
|
||||||
__le16 *utf16_path;
|
__le16 *utf16_path;
|
||||||
int rc;
|
int rc;
|
||||||
|
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||||
__u64 persistent_fid, volatile_fid;
|
__u64 persistent_fid, volatile_fid;
|
||||||
|
|
||||||
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
|
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
|
||||||
|
@ -440,7 +443,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
|
|
||||||
rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
|
rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
|
||||||
FILE_READ_ATTRIBUTES | FILE_READ_DATA, FILE_OPEN, 0, 0,
|
FILE_READ_ATTRIBUTES | FILE_READ_DATA, FILE_OPEN, 0, 0,
|
||||||
NULL);
|
&oplock, NULL);
|
||||||
kfree(utf16_path);
|
kfree(utf16_path);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cERROR(1, "open dir failed");
|
cERROR(1, "open dir failed");
|
||||||
|
@ -477,6 +480,28 @@ smb2_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
|
return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we negotiate SMB2 protocol and get STATUS_PENDING - update
|
||||||
|
* the number of credits and return true. Otherwise - return false.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length)
|
||||||
|
{
|
||||||
|
struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
|
||||||
|
|
||||||
|
if (le32_to_cpu(hdr->Status) != STATUS_PENDING)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!length) {
|
||||||
|
spin_lock(&server->req_lock);
|
||||||
|
server->credits += le16_to_cpu(hdr->CreditRequest);
|
||||||
|
spin_unlock(&server->req_lock);
|
||||||
|
wake_up(&server->request_q);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
struct smb_version_operations smb21_operations = {
|
struct smb_version_operations smb21_operations = {
|
||||||
.setup_request = smb2_setup_request,
|
.setup_request = smb2_setup_request,
|
||||||
.setup_async_request = smb2_setup_async_request,
|
.setup_async_request = smb2_setup_async_request,
|
||||||
|
@ -530,6 +555,7 @@ struct smb_version_operations smb21_operations = {
|
||||||
.query_dir_next = smb2_query_dir_next,
|
.query_dir_next = smb2_query_dir_next,
|
||||||
.close_dir = smb2_close_dir,
|
.close_dir = smb2_close_dir,
|
||||||
.calc_smb_size = smb2_calc_size,
|
.calc_smb_size = smb2_calc_size,
|
||||||
|
.is_status_pending = smb2_is_status_pending,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct smb_version_values smb21_values = {
|
struct smb_version_values smb21_values = {
|
||||||
|
|
|
@ -872,7 +872,7 @@ int
|
||||||
SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
|
SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
|
||||||
u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access,
|
u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access,
|
||||||
__u32 create_disposition, __u32 file_attributes, __u32 create_options,
|
__u32 create_disposition, __u32 file_attributes, __u32 create_options,
|
||||||
struct smb2_file_all_info *buf)
|
__u8 *oplock, struct smb2_file_all_info *buf)
|
||||||
{
|
{
|
||||||
struct smb2_create_req *req;
|
struct smb2_create_req *req;
|
||||||
struct smb2_create_rsp *rsp;
|
struct smb2_create_rsp *rsp;
|
||||||
|
@ -895,9 +895,9 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/* if (server->oplocks)
|
if (server->oplocks)
|
||||||
req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_BATCH;
|
req->RequestedOplockLevel = *oplock;
|
||||||
else */
|
else
|
||||||
req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
|
req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
|
||||||
req->ImpersonationLevel = IL_IMPERSONATION;
|
req->ImpersonationLevel = IL_IMPERSONATION;
|
||||||
req->DesiredAccess = cpu_to_le32(desired_access);
|
req->DesiredAccess = cpu_to_le32(desired_access);
|
||||||
|
@ -954,6 +954,8 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
|
||||||
buf->NumberOfLinks = cpu_to_le32(1);
|
buf->NumberOfLinks = cpu_to_le32(1);
|
||||||
buf->DeletePending = 0;
|
buf->DeletePending = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*oplock = rsp->OplockLevel;
|
||||||
creat_exit:
|
creat_exit:
|
||||||
free_rsp_buf(resp_buftype, rsp);
|
free_rsp_buf(resp_buftype, rsp);
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
@ -82,6 +82,7 @@ extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
int desired_access, int create_options,
|
int desired_access, int create_options,
|
||||||
struct cifs_fid *fid, __u32 *oplock,
|
struct cifs_fid *fid, __u32 *oplock,
|
||||||
FILE_ALL_INFO *buf, struct cifs_sb_info *cifs_sb);
|
FILE_ALL_INFO *buf, struct cifs_sb_info *cifs_sb);
|
||||||
|
extern void smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SMB2 Worker functions - most of protocol specific implementation details
|
* SMB2 Worker functions - most of protocol specific implementation details
|
||||||
|
@ -99,7 +100,7 @@ extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
__le16 *path, u64 *persistent_fid, u64 *volatile_fid,
|
__le16 *path, u64 *persistent_fid, u64 *volatile_fid,
|
||||||
__u32 desired_access, __u32 create_disposition,
|
__u32 desired_access, __u32 create_disposition,
|
||||||
__u32 file_attributes, __u32 create_options,
|
__u32 file_attributes, __u32 create_options,
|
||||||
struct smb2_file_all_info *buf);
|
__u8 *oplock, struct smb2_file_all_info *buf);
|
||||||
extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
|
extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
u64 persistent_file_id, u64 volatile_file_id);
|
u64 persistent_file_id, u64 volatile_file_id);
|
||||||
extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
|
extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
|
|
Reference in New Issue