Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2e44b288 authored by Pavel Shilovsky's avatar Pavel Shilovsky Committed by Steve French
Browse files

CIFS: Process oplocks for SMB2

parent d324f08d
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -328,6 +328,8 @@ struct smb_version_operations {
			 struct cifs_fid *);
	/* calculate a size of SMB message */
	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 {
+4 −0
Original line number Diff line number Diff line
@@ -819,6 +819,10 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
		cifs_dump_mem("Bad SMB: ", buf,
			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)
		return length;

+22 −2
Original line number Diff line number Diff line
@@ -34,6 +34,26 @@
#include "fscache.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
smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
	       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;
	*oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;

	rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid,
		       &fid->volatile_fid, desired_access, disposition,
		       0, 0, smb2_data);
		       0, 0, (__u8 *)oplock, smb2_data);
	if (rc)
		goto out;

@@ -79,7 +100,6 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
	}

out:
	*oplock = 0;
	kfree(smb2_data);
	kfree(smb2_path);
	return rc;
+2 −1
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
	int rc, tmprc = 0;
	u64 persistent_fid, volatile_fid;
	__le16 *utf16_path;
	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;

	utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
	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,
		       desired_access, create_disposition, file_attributes,
		       create_options, NULL);
		       create_options, &oplock, NULL);
	if (rc) {
		kfree(utf16_path);
		return rc;
+30 −4
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include "smb2proto.h"
#include "cifsproto.h"
#include "cifs_debug.h"
#include "smb2status.h"

static int
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;
	__u64 persistent_fid, volatile_fid;
	__le16 *utf16_path;
	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;

	utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
	if (!utf16_path)
		return -ENOMEM;

	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) {
		kfree(utf16_path);
		return rc;
@@ -358,10 +360,10 @@ smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
static void
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.volatile_fid = fid->volatile_fid;
	/* cifs_set_oplock_level(cinode, oplock); */
	smb2_set_oplock_level(cinode, oplock);
	/* 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;
	int rc;
	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
	__u64 persistent_fid, volatile_fid;

	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,
		       FILE_READ_ATTRIBUTES | FILE_READ_DATA, FILE_OPEN, 0, 0,
		       NULL);
		       &oplock, NULL);
	kfree(utf16_path);
	if (rc) {
		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);
}

/*
* 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 = {
	.setup_request = smb2_setup_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,
	.close_dir = smb2_close_dir,
	.calc_smb_size = smb2_calc_size,
	.is_status_pending = smb2_is_status_pending,
};

struct smb_version_values smb21_values = {
Loading