]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ksmbd: break RH leases before delete-on-close
authorNamjae Jeon <linkinjeon@kernel.org>
Thu, 18 Jun 2026 12:33:07 +0000 (21:33 +0900)
committerSteve French <stfrench@microsoft.com>
Tue, 23 Jun 2026 01:15:04 +0000 (20:15 -0500)
The delete paths only marked the opened file delete pending or
delete-on-close.  When another client still held a read/handle lease, no
lease break was sent before the delete state changed.

smb2.lease.unlink uses a create request with FILE_DELETE_ON_CLOSE and
expects the second client's unlink to break the first client's RH lease to
R with ACK_REQUIRED set.  SetInfo(FileDispositionInformation) has the same
lease-breaking requirement.

Break level-II/read-handle leases before setting delete pending or
delete-on-close so clients are notified before the file is removed.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/smb2pdu.c

index b84062b16a75ad156c65585dfe7a721fb0888324..f1a0bce0c1f762220aa6b632a8c9cd556ebac7d2 100644 (file)
@@ -3653,8 +3653,10 @@ int smb2_open(struct ksmbd_work *work)
                        goto err_out1;
        }
 
-       if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)
+       if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE) {
+               smb_break_all_levII_oplock(work, fp, 0);
                ksmbd_fd_set_delete_on_close(fp, file_info);
+       }
 
        if (need_truncate) {
                rc = smb2_create_truncate(&fp->filp->f_path);
@@ -6584,7 +6586,8 @@ static int set_rename_info(struct ksmbd_work *work, struct ksmbd_file *fp,
        return smb2_rename(work, fp, rename_info, work->conn->local_nls);
 }
 
-static int set_file_disposition_info(struct ksmbd_file *fp,
+static int set_file_disposition_info(struct ksmbd_work *work,
+                                    struct ksmbd_file *fp,
                                     struct smb2_file_disposition_info *file_info)
 {
        struct inode *inode;
@@ -6599,6 +6602,7 @@ static int set_file_disposition_info(struct ksmbd_file *fp,
                if (S_ISDIR(inode->i_mode) &&
                    ksmbd_vfs_empty_dir(fp) == -ENOTEMPTY)
                        return -EBUSY;
+               smb_break_all_levII_oplock(work, fp, 0);
                ksmbd_set_inode_pending_delete(fp);
        } else {
                ksmbd_clear_inode_pending_delete(fp);
@@ -6725,7 +6729,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
                if (buf_len < sizeof(struct smb2_file_disposition_info))
                        return -EMSGSIZE;
 
-               return set_file_disposition_info(fp,
+               return set_file_disposition_info(work, fp,
                                                 (struct smb2_file_disposition_info *)buffer);
        }
        case FILE_FULL_EA_INFORMATION: