Re: [PATCH] ksmbd: use F_SETLK to force vfs_file_lock() to return asynchronously

From: Vasily Averin
Date: Wed Dec 22 2021 - 01:51:23 EST


On 22.12.2021 08:25, Namjae Jeon wrote:
> 2021-12-22 13:32 GMT+09:00, Vasily Averin <vvs@xxxxxxxxxxxxx>:
>> On 22.12.2021 05:50, Namjae Jeon wrote:
>>> 2021-12-21 22:08 GMT+09:00, Vasily Averin <vvs@xxxxxxxxxxxxx>:
>>>> On 21.12.2021 15:02, Namjae Jeon wrote:
>>>>> 2021-12-19 18:34 GMT+09:00, Vasily Averin <vvs@xxxxxxxxxxxxx>:
>>>>>> To avoid possible deadlock ksmbd should process locks asynchronously.
>>>>>> Callers expecting vfs_file_locks() to return asynchronously should
>>>>>> only
>>>>>> use F_SETLK, not F_SETLKW.
>>>>> Should I check this patch instead of
>>>>> [PATCH] ksmbd: force "fail immediately" flag on fs with its own ->lock
>>>>> ?
>>>>
>>>> no, these patches are independent and both ones are required.
>>>> current patch fixes incorrect kernel thread behaviour:
>>>> kernel threads should not use F_SETLKW for locking requests.
>>> How does this patch work? posix_lock_file in vfs_lock_file() does not use
>>> cmd.
>>> And your patch still leaves FL_SLEEP.
>>
>> "use F_SETLK, not F_SETLKW" was copy-pasted from requirement described in
>> comment above vfs_lock_file().
>>
>> posix_lock_file() is not used in all ->lock() functions, and use F_SETLKW
>> forces some of affected filesystem use blocking locks:
> What I'm saying is that when we apply "ksmbd: force "fail immediately"
> flag on fs with its own ->lock ", this patch is meaningless. How is
> ->lock() with F_SETLKW called?

I got your point finally,
yes, you are right, now this cannot happen.
However I'm going to fix all affected filesystems and then revert
"ksmbd: force "fail immediately" flag on fs with its own ->lock"
When this happen and ksmbd will still use IS_SETLKW it will trigger the problems described below.

Thank you,
Vasily Averin

>> fs/ceph/locks.c::ceph_lock()
>> /* set wait bit as appropriate, then make command as Ceph expects
>> it*/
>> if (IS_GETLK(cmd))
>> op = CEPH_MDS_OP_GETFILELOCK;
>> else if (IS_SETLKW(cmd))
>> wait = 1
>>
>> nfs v3 handles it in nlmclnt_proc
>> fs/lockd/clntproc.c::nlmclnt_proc
>> if (IS_SETLK(cmd) || IS_SETLKW(cmd)) {
>> if (fl->fl_type != F_UNLCK) {
>> call->a_args.block = IS_SETLKW(cmd) ? 1 : 0;
>>
>>
>> nvs v4 handles it in nfs4_retry_setlk()
>> fs/nfs/nfs4proc.c()::nfs4_retry_setlk()
>> while(!signalled()) {
>> status = nfs4_proc_setlk(state, cmd, request);
>> if ((status != -EAGAIN) || IS_SETLK(cmd))
>> break;
>>
>> gfs2_lock and ocfs calls dlm_posix_lock()
>> dlm_posix_lock::dlm_posix_lock()
>> op->info.wait = IS_SETLKW(cmd)
>>
>> So if ksmbd will try to export these file systems it can be deadlocked on
>> blocking locks processing,
>> even with my patch dropped FL_SLEEP.
>>
>> To be honest, some other filesystems, contrary, ignores cmd and handles
>> FL_SLEEP instead:
>> cifs_lock and fuse_setlk. Moreover, locks_lock_file_wait() is widely used
>> too,
>> (and can block if FL_SLEEP is set). Some of these cases looks like bugs,
>> its careful processing requires some time, therefore right now, to quickly
>> work around
>> all these cases kernel export threads (nfsd/lockd/ksmbd) can drop to
>> FL_SLEEP flag).
>>
>> I think it makes sense to create new bug on bugzilla.kernel.org, explain all
>> details of this problem,
>> and keep you informed about progress with filesystems fixes. When all file
>> systems will be fixed,
>> it allows you to revert "ksmbd: force "fail immediately" flag on fs with its
>> own ->lock"
>>
>> Thank you,
>> Vasily Averin
>>
>>>> "[PATCH] ksmbd: force "fail immediately" flag on fs with its own ->lock"
>>>> tries to workaround the incorrect behaviour of some exported
>>>> filesystems.
>>>>
>>>> Currently this way is used in nfsd and lockd, however it is not fully
>>>> correct,
>>>> and I still search some better solution, so perhaps
>>>> '[PATCH] ksmbd: force "fail immediately" flag on fs with its own ->lock'
>>>> will be dropped later.
>>>>
>>>> Thank you,
>>>> Vasily Averin
>>>>
>>>>>> Signed-off-by: Vasily Averin <vvs@xxxxxxxxxxxxx>
>>>>>> ---
>>>>>> fs/ksmbd/smb2pdu.c | 4 ++--
>>>>>> 1 file changed, 2 insertions(+), 2 deletions(-)
>>>>>>
>>>>>> diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c
>>>>>> index 0c020deb76bb..34f333549767 100644
>>>>>> --- a/fs/ksmbd/smb2pdu.c
>>>>>> +++ b/fs/ksmbd/smb2pdu.c
>>>>>> @@ -6646,13 +6646,13 @@ static int smb2_set_flock_flags(struct
>>>>>> file_lock
>>>>>> *flock, int flags)
>>>>>> switch (flags) {
>>>>>> case SMB2_LOCKFLAG_SHARED:
>>>>>> ksmbd_debug(SMB, "received shared request\n");
>>>>>> - cmd = F_SETLKW;
>>>>>> + cmd = F_SETLK;
>>>>>> flock->fl_type = F_RDLCK;
>>>>>> flock->fl_flags |= FL_SLEEP;
>>>>>> break;
>>>>>> case SMB2_LOCKFLAG_EXCLUSIVE:
>>>>>> ksmbd_debug(SMB, "received exclusive request\n");
>>>>>> - cmd = F_SETLKW;
>>>>>> + cmd = F_SETLK;
>>>>>> flock->fl_type = F_WRLCK;
>>>>>> flock->fl_flags |= FL_SLEEP;
>>>>>> break;
>>>>>> --
>>>>>> 2.25.1
>>>>>>
>>>>>>
>>>>
>>>>
>>
>>