]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ksmbd: clean up lease response flags and directory leases
authorNamjae Jeon <linkinjeon@kernel.org>
Thu, 18 Jun 2026 01:34:24 +0000 (10:34 +0900)
committerSteve French <stfrench@microsoft.com>
Tue, 23 Jun 2026 01:15:03 +0000 (20:15 -0500)
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>
fs/smb/server/oplock.c

index cc5eb95ab3f2d690f85bc01726ff50c132525cda..8ae6a6afbe041d408ecd08df1600b2d4ce2b7d5f 100644 (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;