Commit ade62d8b authored by Namjae Jeon's avatar Namjae Jeon
Browse files

cifsd: set epoch in smb2_lease_break response



When running generic/591 after smb2 leases is enable, all smb2 lease ack
requests failed in ksmbd. because cifs client seems to support only smb2
v2 lease. So cifs doesn't update lease state in ack request if epoch is
not set in smb2 lease break request from ksmbd. epoch is used for smb2
v2 leases. So this patch add smb2 create v2 lease context and set
increased epoch in smb2 lease break response.

Signed-off-by: default avatarNamjae Jeon <namjae.jeon@samsung.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 6c4e675a
Loading
Loading
Loading
Loading
+69 −26
Original line number Diff line number Diff line
@@ -102,6 +102,9 @@ static int alloc_lease(struct oplock_info *opinfo, struct lease_ctx_info *lctx)
	lease->new_state = 0;
	lease->flags = lctx->flags;
	lease->duration = lctx->duration;
	memcpy(lease->parent_lease_key, lctx->parent_lease_key, SMB2_LEASE_KEY_SIZE);
	lease->version = lctx->version;
	lease->epoch = 0;
	INIT_LIST_HEAD(&opinfo->lease_entry);
	opinfo->o_lease = lease;

@@ -750,7 +753,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk)

	rsp = work->response_buf;
	rsp->StructureSize = cpu_to_le16(44);
	rsp->Reserved = 0;
	rsp->Epoch = br_info->epoch;
	rsp->Flags = 0;

	if (br_info->curr_state & (SMB2_LEASE_WRITE_CACHING_LE |
@@ -798,6 +801,10 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo)

	br_info->curr_state = lease->state;
	br_info->new_state = lease->new_state;
	if (lease->version == 2)
		br_info->epoch = cpu_to_le16(++lease->epoch);
	else
		br_info->epoch = 0;
	memcpy(br_info->lease_key, lease->lease_key, SMB2_LEASE_KEY_SIZE);

	work->request_buf = (char *)br_info;
@@ -1084,11 +1091,8 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
	__le32 prev_op_state = 0;

	/* not support directory lease */
	if (S_ISDIR(file_inode(fp->filp)->i_mode)) {
		if (lctx)
			lctx->dlease = 1;
	if (S_ISDIR(file_inode(fp->filp)->i_mode))
		return 0;
	}

	opinfo = alloc_opinfo(work, pid, tid);
	if (!opinfo)
@@ -1328,9 +1332,32 @@ __u8 smb2_map_lease_to_oplock(__le32 lease_state)
 */
void create_lease_buf(u8 *rbuf, struct lease *lease)
{
	struct create_lease *buf = (struct create_lease *)rbuf;
	char *LeaseKey = (char *)&lease->lease_key;

	if (lease->version == 2) {
		struct create_lease_v2 *buf = (struct create_lease_v2 *)rbuf;
		char *ParentLeaseKey = (char *)&lease->parent_lease_key;

		memset(buf, 0, sizeof(struct create_lease_v2));
		buf->lcontext.LeaseKeyLow = *((__le64 *)LeaseKey);
		buf->lcontext.LeaseKeyHigh = *((__le64 *)(LeaseKey + 8));
		buf->lcontext.LeaseFlags = lease->flags;
		buf->lcontext.LeaseState = lease->state;
		buf->lcontext.ParentLeaseKeyLow = *((__le64 *)ParentLeaseKey);
		buf->lcontext.ParentLeaseKeyHigh = *((__le64 *)(ParentLeaseKey + 8));
		buf->ccontext.DataOffset = cpu_to_le16(offsetof
				(struct create_lease_v2, lcontext));
		buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context_v2));
		buf->ccontext.NameOffset = cpu_to_le16(offsetof
				(struct create_lease_v2, Name));
		buf->ccontext.NameLength = cpu_to_le16(4);
		buf->Name[0] = 'R';
		buf->Name[1] = 'q';
		buf->Name[2] = 'L';
		buf->Name[3] = 's';
	} else {
		struct create_lease *buf = (struct create_lease *)rbuf;

		memset(buf, 0, sizeof(struct create_lease));
		buf->lcontext.LeaseKeyLow = *((__le64 *)LeaseKey);
		buf->lcontext.LeaseKeyHigh = *((__le64 *)(LeaseKey + 8));
@@ -1347,6 +1374,7 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
		buf->Name[2] = 'L';
		buf->Name[3] = 's';
	}
}

/**
 * parse_lease_state() - parse lease context containted in file open request
@@ -1382,12 +1410,27 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
	} while (next != 0);

	if (found) {
		if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) {
			struct create_lease_v2 *lc = (struct create_lease_v2 *)cc;

			*((__le64 *)lreq->lease_key) = lc->lcontext.LeaseKeyLow;
			*((__le64 *)(lreq->lease_key + 8)) = lc->lcontext.LeaseKeyHigh;
			lreq->req_state = lc->lcontext.LeaseState;
			lreq->flags = lc->lcontext.LeaseFlags;
			lreq->duration = lc->lcontext.LeaseDuration;
			*((__le64 *)lreq->parent_lease_key) = lc->lcontext.ParentLeaseKeyLow;
			*((__le64 *)(lreq->parent_lease_key + 8)) = lc->lcontext.ParentLeaseKeyHigh;
			lreq->version = 2;
		} else {
			struct create_lease *lc = (struct create_lease *)cc;

			*((__le64 *)lreq->lease_key) = lc->lcontext.LeaseKeyLow;
			*((__le64 *)(lreq->lease_key + 8)) = lc->lcontext.LeaseKeyHigh;
			lreq->req_state = lc->lcontext.LeaseState;
			lreq->flags = lc->lcontext.LeaseFlags;
			lreq->duration = lc->lcontext.LeaseDuration;
			lreq->version = 1;
		}
		return lreq;
	}

+10 −5
Original line number Diff line number Diff line
@@ -41,7 +41,8 @@ struct lease_ctx_info {
	__le32			req_state;
	__le32			flags;
	__le64			duration;
	int dlease;
	__u8			parent_lease_key[SMB2_LEASE_KEY_SIZE];
	int			version;
};

struct lease_table {
@@ -57,6 +58,9 @@ struct lease {
	__le32			new_state;
	__le32			flags;
	__le64			duration;
	__u8			parent_lease_key[SMB2_LEASE_KEY_SIZE];
	int			version;
	unsigned short		epoch;
	struct lease_table	*l_lb;
};

@@ -86,6 +90,7 @@ struct oplock_info {
struct lease_break_info {
	__le32			curr_state;
	__le32			new_state;
	__le16			epoch;
	char			lease_key[SMB2_LEASE_KEY_SIZE];
};

+3 −3
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ static struct smb_version_values smb30_server_values = {
	.cap_unix = 0,
	.cap_nt_find = SMB2_NT_FIND,
	.cap_large_files = SMB2_LARGE_FILES,
	.create_lease_size = sizeof(struct create_lease),
	.create_lease_size = sizeof(struct create_lease_v2),
	.create_durable_size = sizeof(struct create_durable_rsp),
	.create_durable_v2_size = sizeof(struct create_durable_v2_rsp),
	.create_mxac_size = sizeof(struct create_mxac_rsp),
@@ -83,7 +83,7 @@ static struct smb_version_values smb302_server_values = {
	.cap_unix = 0,
	.cap_nt_find = SMB2_NT_FIND,
	.cap_large_files = SMB2_LARGE_FILES,
	.create_lease_size = sizeof(struct create_lease),
	.create_lease_size = sizeof(struct create_lease_v2),
	.create_durable_size = sizeof(struct create_durable_rsp),
	.create_durable_v2_size = sizeof(struct create_durable_v2_rsp),
	.create_mxac_size = sizeof(struct create_mxac_rsp),
@@ -109,7 +109,7 @@ static struct smb_version_values smb311_server_values = {
	.cap_unix = 0,
	.cap_nt_find = SMB2_NT_FIND,
	.cap_large_files = SMB2_LARGE_FILES,
	.create_lease_size = sizeof(struct create_lease),
	.create_lease_size = sizeof(struct create_lease_v2),
	.create_durable_size = sizeof(struct create_durable_rsp),
	.create_durable_v2_size = sizeof(struct create_durable_v2_rsp),
	.create_mxac_size = sizeof(struct create_mxac_rsp),
+20 −1
Original line number Diff line number Diff line
@@ -735,12 +735,31 @@ struct lease_context {
	__le64 LeaseDuration;
} __packed;

struct lease_context_v2 {
	__le64 LeaseKeyLow;
	__le64 LeaseKeyHigh;
	__le32 LeaseState;
	__le32 LeaseFlags;
	__le64 LeaseDuration;
	__le64 ParentLeaseKeyLow;
	__le64 ParentLeaseKeyHigh;
	__le16 Epoch;
	__le16 Reserved;
} __packed;

struct create_lease {
	struct create_context ccontext;
	__u8   Name[8];
	struct lease_context lcontext;
} __packed;

struct create_lease_v2 {
	struct create_context ccontext;
	__u8   Name[8];
	struct lease_context_v2 lcontext;
	__u8   Pad[4];
} __packed;

/* Currently defined values for close flags */
#define SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB	cpu_to_le16(0x0001)
struct smb2_close_req {
@@ -1249,7 +1268,7 @@ struct smb2_oplock_break {
struct smb2_lease_break {
	struct smb2_hdr hdr;
	__le16 StructureSize; /* Must be 44 */
	__le16 Reserved;
	__le16 Epoch;
	__le32 Flags;
	__u8   LeaseKey[16];
	__le32 CurrentLeaseState;