smb: client: add ParentLeaseKey support
authorHenrique Carvalho <henrique.carvalho@suse.com>
Thu, 8 May 2025 16:09:51 +0000 (13:09 -0300)
committerSteve French <stfrench@microsoft.com>
Mon, 2 Jun 2025 01:46:45 +0000 (20:46 -0500)
According to MS-SMB2 3.2.4.3.8, when opening a file the client must
lookup its parent directory, copy that entry’s LeaseKey into
ParentLeaseKey, and set SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET.

Extend lease context functions to carry a parent_lease_key and
lease_flags and to add them to the lease context buffer accordingly in
smb3_create_lease_buf. Also add a parent_lease_key field to struct
cifs_fid and lease_flags to cifs_open_parms.

Only applies to the SMB 3.x dialect family.

Fixes: f047390a097e ("CIFS: Add create lease v2 context for SMB3")
Signed-off-by: Henrique Carvalho <henrique.carvalho@suse.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/cifsglob.h
fs/smb/client/smb2ops.c
fs/smb/client/smb2pdu.c

index 4d097b074b5fd9ff858686f852fc44753de9dcb2..2ad9835d91ab2eb03d4907e0d7eb681118ea88ff 100644 (file)
@@ -556,7 +556,7 @@ struct smb_version_operations {
        void (*set_oplock_level)(struct cifsInodeInfo *cinode, __u32 oplock, __u16 epoch,
                                 bool *purge_cache);
        /* create lease context buffer for CREATE request */
-       char * (*create_lease_buf)(u8 *lease_key, u8 oplock);
+       char * (*create_lease_buf)(u8 *lease_key, u8 oplock, u8 *parent_lease_key, __le32 le_flags);
        /* parse lease context buffer and return oplock/epoch info */
        __u8 (*parse_lease_buf)(void *buf, __u16 *epoch, char *lkey);
        ssize_t (*copychunk_range)(const unsigned int,
@@ -1442,6 +1442,7 @@ struct cifs_open_parms {
        bool reconnect:1;
        bool replay:1; /* indicates that this open is for a replay */
        struct kvec *ea_cctx;
+       __le32 lease_flags;
 };
 
 struct cifs_fid {
@@ -1449,6 +1450,7 @@ struct cifs_fid {
        __u64 persistent_fid;   /* persist file id for smb2 */
        __u64 volatile_fid;     /* volatile file id for smb2 */
        __u8 lease_key[SMB2_LEASE_KEY_SIZE];    /* lease key for smb2 */
+       __u8 parent_lease_key[SMB2_LEASE_KEY_SIZE];
        __u8 create_guid[16];
        __u32 access;
        struct cifs_pending_open *pending_open;
index 2fe8eeb98535631e7e70b226617707827ec58999..bab9f567d9b7b378a859bb1dabff960156c3c487 100644 (file)
@@ -4069,7 +4069,7 @@ map_oplock_to_lease(u8 oplock)
 }
 
 static char *
-smb2_create_lease_buf(u8 *lease_key, u8 oplock)
+smb2_create_lease_buf(u8 *lease_key, u8 oplock, u8 *parent_lease_key, __le32 flags)
 {
        struct create_lease *buf;
 
@@ -4095,7 +4095,7 @@ smb2_create_lease_buf(u8 *lease_key, u8 oplock)
 }
 
 static char *
-smb3_create_lease_buf(u8 *lease_key, u8 oplock)
+smb3_create_lease_buf(u8 *lease_key, u8 oplock, u8 *parent_lease_key, __le32 flags)
 {
        struct create_lease_v2 *buf;
 
@@ -4105,6 +4105,9 @@ smb3_create_lease_buf(u8 *lease_key, u8 oplock)
 
        memcpy(&buf->lcontext.LeaseKey, lease_key, SMB2_LEASE_KEY_SIZE);
        buf->lcontext.LeaseState = map_oplock_to_lease(oplock);
+       buf->lcontext.LeaseFlags = flags;
+       if (flags & SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE)
+               memcpy(&buf->lcontext.ParentLeaseKey, parent_lease_key, SMB2_LEASE_KEY_SIZE);
 
        buf->ccontext.DataOffset = cpu_to_le16(offsetof
                                        (struct create_lease_v2, lcontext));
index 701a138b82c801692572c550746e5b3539dd698f..4677013a3d025e3ead742a692321adcc6d9c84af 100644 (file)
@@ -2392,11 +2392,16 @@ static int
 add_lease_context(struct TCP_Server_Info *server,
                  struct smb2_create_req *req,
                  struct kvec *iov,
-                 unsigned int *num_iovec, u8 *lease_key, __u8 *oplock)
+                 unsigned int *num_iovec,
+                 u8 *lease_key,
+                 __u8 *oplock,
+                 u8 *parent_lease_key,
+                 __le32 flags)
 {
        unsigned int num = *num_iovec;
 
-       iov[num].iov_base = server->ops->create_lease_buf(lease_key, *oplock);
+       iov[num].iov_base = server->ops->create_lease_buf(lease_key, *oplock,
+                                                         parent_lease_key, flags);
        if (iov[num].iov_base == NULL)
                return -ENOMEM;
        iov[num].iov_len = server->vals->create_lease_size;
@@ -3069,7 +3074,9 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
                req->RequestedOplockLevel = *oplock; /* no srv lease support */
        else {
                rc = add_lease_context(server, req, iov, &n_iov,
-                                      oparms->fid->lease_key, oplock);
+                                      oparms->fid->lease_key, oplock,
+                                      oparms->fid->parent_lease_key,
+                                      oparms->lease_flags);
                if (rc)
                        return rc;
        }