ksmbd: clean up lease response flags and directory leases

Do not echo reserved v1 lease flags back to clients. For lease v2
responses, only return BREAK_IN_PROGRESS and PARENT_LEASE_KEY_SET when
they are meaningful, and preserve the parent lease key in the response.

Allow directory leases whenever the request is a valid lease v2 request,
and initialize v2 lease epochs from the first server-granted state change.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
Namjae Jeon 2026-06-18 10:34:24 +09:00 committed by Steve French
parent 5015191096
commit 0fa8abc6ab

View File

@ -34,6 +34,11 @@ static bool lease_v2_flags_valid(__le32 flags)
return !(flags & ~SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE);
}
static bool lease_has_parent_key(struct lease *lease)
{
return lease->flags & SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE;
}
/**
* alloc_opinfo() - allocate a new opinfo object for oplock info
* @work: smb work
@ -126,7 +131,7 @@ static int alloc_lease(struct oplock_info *opinfo, struct lease_ctx_info *lctx)
lease->is_dir = lctx->is_dir;
memcpy(lease->parent_lease_key, lctx->parent_lease_key, SMB2_LEASE_KEY_SIZE);
lease->version = lctx->version;
lease->epoch = le16_to_cpu(lctx->epoch) + 1;
lease->epoch = lctx->version == 2 ? 1 : 0;
INIT_LIST_HEAD(&opinfo->lease_entry);
opinfo->o_lease = lease;
@ -1228,9 +1233,7 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
/* Only v2 leases handle the directory */
if (S_ISDIR(file_inode(fp->filp)->i_mode)) {
if (!lctx || lctx->version != 2 ||
(lctx->flags != SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE &&
!lctx->epoch))
if (!lctx || lctx->version != 2)
return 0;
}
@ -1493,14 +1496,17 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
{
if (lease->version == 2) {
struct create_lease_v2 *buf = (struct create_lease_v2 *)rbuf;
__le32 flags = lease->flags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE;
memset(buf, 0, sizeof(struct create_lease_v2));
memcpy(buf->lcontext.LeaseKey, lease->lease_key,
SMB2_LEASE_KEY_SIZE);
buf->lcontext.LeaseFlags = lease->flags;
if (lease_has_parent_key(lease))
flags |= SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE;
buf->lcontext.LeaseFlags = flags;
buf->lcontext.Epoch = cpu_to_le16(lease->epoch);
buf->lcontext.LeaseState = lease->state;
if (lease->flags == SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE)
if (lease_has_parent_key(lease))
memcpy(buf->lcontext.ParentLeaseKey, lease->parent_lease_key,
SMB2_LEASE_KEY_SIZE);
buf->ccontext.DataOffset = cpu_to_le16(offsetof
@ -1518,7 +1524,8 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
memset(buf, 0, sizeof(struct create_lease));
memcpy(buf->lcontext.LeaseKey, lease->lease_key, SMB2_LEASE_KEY_SIZE);
buf->lcontext.LeaseFlags = lease->flags;
buf->lcontext.LeaseFlags =
lease->flags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE;
buf->lcontext.LeaseState = lease->state;
buf->ccontext.DataOffset = cpu_to_le16(offsetof
(struct create_lease, lcontext));
@ -1583,7 +1590,7 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
lreq->req_state = lc->lcontext.LeaseState;
lreq->flags = lc->lcontext.LeaseFlags;
lreq->flags = 0;
lreq->duration = lc->lcontext.LeaseDuration;
if (!lease_state_valid(lreq->req_state))
goto err_out;