]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ksmbd: return success for deferred final close
authorNamjae Jeon <linkinjeon@kernel.org>
Sun, 21 Jun 2026 10:41:08 +0000 (19:41 +0900)
committerSteve French <stfrench@microsoft.com>
Tue, 23 Jun 2026 01:15:05 +0000 (20:15 -0500)
ksmbd_close_fd() marks an open file as FP_CLOSED and drops the file table
reference. If another in-flight request still holds a reference, the final
close is deferred until that request drops its reference.

The function currently returns -EINVAL in that deferred-final-close case
because fp is cleared when the reference count does not reach zero.  That
turns a valid close into STATUS_FILE_CLOSED.

smb2.compound_find.compound_find_close sends QUERY_DIRECTORY and then
closes the same directory handle before receiving the find response.
The query holds a reference while it builds the response, so close must
mark the handle closed and return success even though final teardown is
delayed. Track whether the handle was successfully transitioned to
FP_CLOSED and return success when only the final close is deferred.

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

index 98c5bac93d634e8d281ae5977673b993c0ccf0a9..b617edef950aa537aba844d990cd623b535ea0f3 100644 (file)
@@ -640,6 +640,7 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id)
 {
        struct ksmbd_file       *fp;
        struct ksmbd_file_table *ft;
+       bool closed = false;
 
        if (!has_file_id(id))
                return 0;
@@ -654,6 +655,7 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id)
                        fp = NULL;
                else {
                        fp->f_state = FP_CLOSED;
+                       closed = true;
                        if (!atomic_dec_and_test(&fp->refcount))
                                fp = NULL;
                }
@@ -661,7 +663,7 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id)
        write_unlock(&ft->lock);
 
        if (!fp)
-               return -EINVAL;
+               return closed ? 0 : -EINVAL;
 
        __put_fd_final(work, fp);
        return 0;